mirror of
https://github.com/reactos/CMake.git
synced 2025-03-07 11:27:10 +00:00
Merge branch 'upstream-curl' into update-curl
* upstream-curl: curl 2018-05-15 (cb013830)
This commit is contained in:
commit
3e913b819d
20
Utilities/cmcurl/CMake/FindBrotli.cmake
Normal file
20
Utilities/cmcurl/CMake/FindBrotli.cmake
Normal file
@ -0,0 +1,20 @@
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_path(BROTLI_INCLUDE_DIR "brotli/decode.h")
|
||||
|
||||
find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon)
|
||||
find_library(BROTLIDEC_LIBRARY NAMES brotlidec)
|
||||
|
||||
find_package_handle_standard_args(BROTLI
|
||||
FOUND_VAR
|
||||
BROTLI_FOUND
|
||||
REQUIRED_VARS
|
||||
BROTLIDEC_LIBRARY
|
||||
BROTLICOMMON_LIBRARY
|
||||
BROTLI_INCLUDE_DIR
|
||||
FAIL_MESSAGE
|
||||
"Could NOT find BROTLI"
|
||||
)
|
||||
|
||||
set(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR})
|
||||
set(BROTLI_LIBRARIES ${BROTLICOMMON_LIBRARY} ${BROTLIDEC_LIBRARY})
|
@ -90,7 +90,7 @@ endif()
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# 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
|
||||
@ -328,16 +328,6 @@ if(BORLAND)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-")
|
||||
endif(BORLAND)
|
||||
|
||||
if(CURL_WERROR)
|
||||
if(MSVC_VERSION)
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /WX")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /WX")
|
||||
else()
|
||||
# this assumes clang or gcc style options
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
|
||||
endif()
|
||||
endif(CURL_WERROR)
|
||||
|
||||
# If we are on AIX, do the _ALL_SOURCE magic
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES AIX)
|
||||
set(_ALL_SOURCE 1)
|
||||
@ -398,6 +388,7 @@ check_function_exists(gethostname HAVE_GETHOSTNAME)
|
||||
if(WIN32)
|
||||
check_library_exists_concat("ws2_32" getch HAVE_LIBWS2_32)
|
||||
check_library_exists_concat("winmm" getch HAVE_LIBWINMM)
|
||||
list(APPEND CURL_LIBS "advapi32")
|
||||
endif()
|
||||
|
||||
# check SSL libraries
|
||||
@ -644,6 +635,18 @@ if(CURL_SPECIAL_LIBZ)
|
||||
set(HAVE_ZLIB_H 0)
|
||||
endif()
|
||||
|
||||
option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF)
|
||||
set(HAVE_BROTLI OFF)
|
||||
if(CURL_BROTLI)
|
||||
find_package(BROTLI QUIET)
|
||||
if(BROTLI_FOUND)
|
||||
set(HAVE_BROTLI ON)
|
||||
list(APPEND CURL_LIBS ${BROTLI_LIBRARIES})
|
||||
include_directories(${BROTLI_INCLUDE_DIRS})
|
||||
list(APPEND CMAKE_REQUIRED_INCLUDES ${BROTLI_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#libSSH2
|
||||
option(CMAKE_USE_LIBSSH2 "Use libSSH2" ON)
|
||||
mark_as_advanced(CMAKE_USE_LIBSSH2)
|
||||
@ -1237,6 +1240,15 @@ if(MSVC)
|
||||
endif(CMAKE_C_FLAGS MATCHES "/W[0-4]")
|
||||
endif(MSVC)
|
||||
|
||||
if(CURL_WERROR)
|
||||
if(MSVC_VERSION)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
|
||||
else()
|
||||
# this assumes clang or gcc style options
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
|
||||
endif()
|
||||
endif(CURL_WERROR)
|
||||
|
||||
# Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it).
|
||||
function(TRANSFORM_MAKEFILE_INC INPUT_FILE OUTPUT_FILE)
|
||||
file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT)
|
||||
|
@ -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
|
||||
@ -245,7 +245,9 @@ typedef size_t (*curl_write_callback)(char *buffer,
|
||||
size_t nitems,
|
||||
void *outstream);
|
||||
|
||||
|
||||
/* This callback will be called when a new resolver request is made */
|
||||
typedef int (*curl_resolver_start_callback)(void *resolver_state,
|
||||
void *reserved, void *userdata);
|
||||
|
||||
/* enumeration of file types */
|
||||
typedef enum {
|
||||
@ -577,6 +579,8 @@ typedef enum {
|
||||
CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */
|
||||
CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer
|
||||
*/
|
||||
CURLE_RECURSIVE_API_CALL, /* 93 - an api function was called from
|
||||
inside a callback */
|
||||
CURL_LAST /* never use! */
|
||||
} CURLcode;
|
||||
|
||||
@ -789,6 +793,11 @@ typedef enum {
|
||||
SSL backends where such behavior is present. */
|
||||
#define CURLSSLOPT_NO_REVOKE (1<<1)
|
||||
|
||||
/* The default connection attempt delay in milliseconds for happy eyeballs.
|
||||
CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document
|
||||
this value, keep them in sync. */
|
||||
#define CURL_HET_DEFAULT 200L
|
||||
|
||||
#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
|
||||
the obsolete stuff removed! */
|
||||
|
||||
@ -1662,7 +1671,7 @@ typedef enum {
|
||||
* Only supported by the c-ares DNS backend */
|
||||
CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222),
|
||||
|
||||
/* Set the local IPv4 address to use for outgoing DNS requests.
|
||||
/* Set the local IPv6 address to use for outgoing DNS requests.
|
||||
* Only supported by the c-ares DNS backend */
|
||||
CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223),
|
||||
|
||||
@ -1819,6 +1828,25 @@ typedef enum {
|
||||
/* Post MIME data. */
|
||||
CINIT(MIMEPOST, OBJECTPOINT, 269),
|
||||
|
||||
/* Time to use with the CURLOPT_TIMECONDITION. Specified in number of
|
||||
seconds since 1 Jan 1970. */
|
||||
CINIT(TIMEVALUE_LARGE, OFF_T, 270),
|
||||
|
||||
/* Head start in milliseconds to give happy eyeballs. */
|
||||
CINIT(HAPPY_EYEBALLS_TIMEOUT_MS, LONG, 271),
|
||||
|
||||
/* Function that will be called before a resolver request is made */
|
||||
CINIT(RESOLVER_START_FUNCTION, FUNCTIONPOINT, 272),
|
||||
|
||||
/* User data to pass to the resolver start callback. */
|
||||
CINIT(RESOLVER_START_DATA, OBJECTPOINT, 273),
|
||||
|
||||
/* send HAProxy PROXY protocol header? */
|
||||
CINIT(HAPROXYPROTOCOL, LONG, 274),
|
||||
|
||||
/* shuffle addresses before use when DNS returns multiple */
|
||||
CINIT(DNS_SHUFFLE_ADDRESSES, LONG, 275),
|
||||
|
||||
CURLOPT_LASTENTRY /* the last unused */
|
||||
} CURLoption;
|
||||
|
||||
@ -2459,6 +2487,7 @@ typedef enum {
|
||||
CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12,
|
||||
CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13,
|
||||
CURLINFO_FILETIME = CURLINFO_LONG + 14,
|
||||
CURLINFO_FILETIME_T = CURLINFO_OFF_T + 14,
|
||||
CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15,
|
||||
CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15,
|
||||
CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16,
|
||||
|
@ -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
|
||||
@ -26,16 +26,16 @@
|
||||
a script at release-time. This was made its own header file in 7.11.2 */
|
||||
|
||||
/* This is the global package copyright */
|
||||
#define LIBCURL_COPYRIGHT "1996 - 2017 Daniel Stenberg, <daniel@haxx.se>."
|
||||
#define LIBCURL_COPYRIGHT "1996 - 2018 Daniel Stenberg, <daniel@haxx.se>."
|
||||
|
||||
/* This is the version number of the libcurl package from which this header
|
||||
file origins: */
|
||||
#define LIBCURL_VERSION "7.58.0"
|
||||
#define LIBCURL_VERSION "7.60.0"
|
||||
|
||||
/* The numeric version number is also available "in parts" by using these
|
||||
defines: */
|
||||
#define LIBCURL_VERSION_MAJOR 7
|
||||
#define LIBCURL_VERSION_MINOR 58
|
||||
#define LIBCURL_VERSION_MINOR 60
|
||||
#define LIBCURL_VERSION_PATCH 0
|
||||
|
||||
/* This is the numeric version of the libcurl version number, meant for easier
|
||||
@ -57,7 +57,7 @@
|
||||
CURL_VERSION_BITS() macro since curl's own configure script greps for it
|
||||
and needs it to contain the full number.
|
||||
*/
|
||||
#define LIBCURL_VERSION_NUM 0x073A00
|
||||
#define LIBCURL_VERSION_NUM 0x073C00
|
||||
|
||||
/*
|
||||
* This is the date and time when the full source package was created. The
|
||||
|
@ -70,6 +70,8 @@ typedef enum {
|
||||
CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */
|
||||
CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was
|
||||
attempted to get added - again */
|
||||
CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
|
||||
callback */
|
||||
CURLM_LAST
|
||||
} CURLMcode;
|
||||
|
||||
@ -184,8 +186,8 @@ CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle,
|
||||
*
|
||||
* Returns: CURLMcode type, general multi error code. *NOTE* that this only
|
||||
* returns errors etc regarding the whole multi stack. There might
|
||||
* still have occurred problems on invidual transfers even when this
|
||||
* returns OK.
|
||||
* still have occurred problems on individual transfers even when
|
||||
* this returns OK.
|
||||
*/
|
||||
CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle,
|
||||
int *running_handles);
|
||||
|
@ -300,7 +300,9 @@
|
||||
|
||||
#elif defined(__SUNPRO_C) /* Oracle Solaris Studio */
|
||||
# if !defined(__LP64) && (defined(__ILP32) || \
|
||||
defined(__i386) || defined(__sparcv8))
|
||||
defined(__i386) || \
|
||||
defined(__sparcv8) || \
|
||||
defined(__sparcv8plus))
|
||||
# define CURL_TYPEOF_CURL_OFF_T long long
|
||||
# define CURL_FORMAT_CURL_OFF_T "lld"
|
||||
# define CURL_FORMAT_CURL_OFF_TU "llu"
|
||||
|
@ -54,6 +54,9 @@ __extension__ ({ \
|
||||
if(_curl_is_write_cb_option(_curl_opt)) \
|
||||
if(!_curl_is_write_cb(value)) \
|
||||
_curl_easy_setopt_err_write_callback(); \
|
||||
if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION) \
|
||||
if(!_curl_is_resolver_start_callback(value)) \
|
||||
_curl_easy_setopt_err_resolver_start_callback(); \
|
||||
if((_curl_opt) == CURLOPT_READFUNCTION) \
|
||||
if(!_curl_is_read_cb(value)) \
|
||||
_curl_easy_setopt_err_read_cb(); \
|
||||
@ -170,6 +173,10 @@ _CURL_WARNING(_curl_easy_setopt_err_string,
|
||||
)
|
||||
_CURL_WARNING(_curl_easy_setopt_err_write_callback,
|
||||
"curl_easy_setopt expects a curl_write_callback argument for this option")
|
||||
_CURL_WARNING(_curl_easy_setopt_err_resolver_start_callback,
|
||||
"curl_easy_setopt expects a "
|
||||
"curl_resolver_start_callback argument for this option"
|
||||
)
|
||||
_CURL_WARNING(_curl_easy_setopt_err_read_cb,
|
||||
"curl_easy_setopt expects a curl_read_callback argument for this option")
|
||||
_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb,
|
||||
@ -354,6 +361,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
|
||||
(option) == CURLOPT_SSH_KEYDATA || \
|
||||
(option) == CURLOPT_SSL_CTX_DATA || \
|
||||
(option) == CURLOPT_WRITEDATA || \
|
||||
(option) == CURLOPT_RESOLVER_START_DATA || \
|
||||
0)
|
||||
|
||||
/* evaluates to true if option takes a POST data argument (void* or char*) */
|
||||
@ -504,6 +512,11 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
|
||||
(__builtin_types_compatible_p(__typeof__(func), type) || \
|
||||
__builtin_types_compatible_p(__typeof__(func) *, type))
|
||||
|
||||
/* evaluates to true if expr is of type curl_resolver_start_callback */
|
||||
#define _curl_is_resolver_start_callback(expr) \
|
||||
(_curl_is_NULL(expr) || \
|
||||
_curl_callback_compatible((expr), curl_resolver_start_callback))
|
||||
|
||||
/* evaluates to true if expr is of type curl_read_callback or "similar" */
|
||||
#define _curl_is_read_cb(expr) \
|
||||
(_curl_is_NULL(expr) || \
|
||||
|
@ -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
|
||||
@ -29,8 +29,8 @@ 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/darwinssl.c vtls/gskit.c \
|
||||
vtls/mbedtls.c
|
||||
vtls/cyassl.c vtls/schannel.c vtls/schannel_verify.c \
|
||||
vtls/darwinssl.c vtls/gskit.c vtls/mbedtls.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 \
|
||||
@ -46,7 +46,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
|
||||
http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c \
|
||||
strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c \
|
||||
inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c \
|
||||
ssh.c ssh-libssh.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \
|
||||
ssh.c ssh-libssh.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \
|
||||
curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \
|
||||
pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \
|
||||
openldap.c curl_gethostname.c gopher.c idn_win32.c \
|
||||
@ -54,7 +54,7 @@ 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
|
||||
mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.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 +74,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_path.h curl_ctype.h curl_range.h
|
||||
|
||||
LIB_RCFILES = libcurl.rc
|
||||
|
||||
|
@ -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
|
||||
@ -79,6 +79,10 @@
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
struct resdata {
|
||||
struct curltime start;
|
||||
};
|
||||
|
||||
/*
|
||||
* Curl_resolver_global_init()
|
||||
* Called from curl_global_init() to initialize global resolver environment.
|
||||
@ -102,11 +106,13 @@ void Curl_resolver_global_cleanup(void)
|
||||
* Curl_resolver_init()
|
||||
* Called from curl_easy_init() -> Curl_open() to initialize resolver
|
||||
* URL-state specific environment ('resolver' member of the UrlState
|
||||
* structure). Does nothing here.
|
||||
* structure).
|
||||
*/
|
||||
CURLcode Curl_resolver_init(void **resolver)
|
||||
{
|
||||
(void)resolver;
|
||||
*resolver = calloc(1, sizeof(struct resdata));
|
||||
if(!*resolver)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@ -114,24 +120,22 @@ CURLcode Curl_resolver_init(void **resolver)
|
||||
* Curl_resolver_cleanup()
|
||||
* Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
|
||||
* URL-state specific environment ('resolver' member of the UrlState
|
||||
* structure). Does nothing here.
|
||||
* structure).
|
||||
*/
|
||||
void Curl_resolver_cleanup(void *resolver)
|
||||
{
|
||||
(void)resolver;
|
||||
free(resolver);
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_resolver_duphandle()
|
||||
* Called from curl_easy_duphandle() to duplicate resolver URL state-specific
|
||||
* environment ('resolver' member of the UrlState structure). Does nothing
|
||||
* here.
|
||||
* environment ('resolver' member of the UrlState structure).
|
||||
*/
|
||||
int Curl_resolver_duphandle(void **to, void *from)
|
||||
{
|
||||
(void)to;
|
||||
(void)from;
|
||||
return CURLE_OK;
|
||||
return Curl_resolver_init(to);
|
||||
}
|
||||
|
||||
static void destroy_async_data(struct Curl_async *);
|
||||
@ -561,9 +565,22 @@ int Curl_resolver_getsock(struct connectdata *conn,
|
||||
curl_socket_t *socks,
|
||||
int numsocks)
|
||||
{
|
||||
(void)conn;
|
||||
time_t milli;
|
||||
timediff_t ms;
|
||||
struct Curl_easy *data = conn->data;
|
||||
struct resdata *reslv = (struct resdata *)data->state.resolver;
|
||||
(void)socks;
|
||||
(void)numsocks;
|
||||
ms = Curl_timediff(Curl_now(), reslv->start);
|
||||
if(ms < 10)
|
||||
milli = ms/3;
|
||||
else if(ms <= 50)
|
||||
milli = 10;
|
||||
else if(ms <= 250)
|
||||
milli = 50;
|
||||
else
|
||||
milli = 200;
|
||||
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -577,6 +594,8 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
|
||||
int *waitp)
|
||||
{
|
||||
struct in_addr in;
|
||||
struct Curl_easy *data = conn->data;
|
||||
struct resdata *reslv = (struct resdata *)data->state.resolver;
|
||||
|
||||
*waitp = 0; /* default to synchronous response */
|
||||
|
||||
@ -584,14 +603,17 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
|
||||
/* This is a dotted IP address 123.123.123.123-style */
|
||||
return Curl_ip2addr(AF_INET, &in, hostname, port);
|
||||
|
||||
reslv->start = Curl_now();
|
||||
|
||||
/* fire up a new resolver thread! */
|
||||
if(init_resolve_thread(conn, hostname, port, NULL)) {
|
||||
*waitp = 1; /* expect asynchronous response */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* fall-back to blocking version */
|
||||
return Curl_ipv4_resolve_r(hostname, port);
|
||||
failf(conn->data, "getaddrinfo() thread failed\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else /* !HAVE_GETADDRINFO */
|
||||
@ -605,10 +627,10 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
|
||||
int *waitp)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
Curl_addrinfo *res;
|
||||
int error;
|
||||
char sbuf[12];
|
||||
int pf = PF_INET;
|
||||
struct Curl_easy *data = conn->data;
|
||||
struct resdata *reslv = (struct resdata *)data->state.resolver;
|
||||
|
||||
*waitp = 0; /* default to synchronous response */
|
||||
|
||||
@ -658,27 +680,16 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
|
||||
|
||||
snprintf(sbuf, sizeof(sbuf), "%d", port);
|
||||
|
||||
reslv->start = Curl_now();
|
||||
/* fire up a new resolver thread! */
|
||||
if(init_resolve_thread(conn, hostname, port, &hints)) {
|
||||
*waitp = 1; /* expect asynchronous response */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* fall-back to blocking version */
|
||||
infof(conn->data, "init_resolve_thread() failed for %s; %s\n",
|
||||
hostname, Curl_strerror(conn, errno));
|
||||
failf(data, "getaddrinfo() thread failed to start\n");
|
||||
return NULL;
|
||||
|
||||
error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res);
|
||||
if(error) {
|
||||
infof(conn->data, "getaddrinfo() failed for %s:%d; %s\n",
|
||||
hostname, port, Curl_strerror(conn, SOCKERRNO));
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
Curl_addrinfo_set_port(res, port);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
|
@ -619,8 +619,8 @@ void Curl_persistconninfo(struct connectdata *conn)
|
||||
|
||||
/* retrieves ip address and port from a sockaddr structure.
|
||||
note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
|
||||
static bool getaddressinfo(struct sockaddr *sa, char *addr,
|
||||
long *port)
|
||||
bool Curl_getaddressinfo(struct sockaddr *sa, char *addr,
|
||||
long *port)
|
||||
{
|
||||
unsigned short us_port;
|
||||
struct sockaddr_in *si = NULL;
|
||||
@ -700,16 +700,16 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
|
||||
return;
|
||||
}
|
||||
|
||||
if(!getaddressinfo((struct sockaddr*)&ssrem,
|
||||
conn->primary_ip, &conn->primary_port)) {
|
||||
if(!Curl_getaddressinfo((struct sockaddr*)&ssrem,
|
||||
conn->primary_ip, &conn->primary_port)) {
|
||||
failf(data, "ssrem inet_ntop() failed with errno %d: %s",
|
||||
errno, Curl_strerror(conn, errno));
|
||||
return;
|
||||
}
|
||||
memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
|
||||
|
||||
if(!getaddressinfo((struct sockaddr*)&ssloc,
|
||||
conn->local_ip, &conn->local_port)) {
|
||||
if(!Curl_getaddressinfo((struct sockaddr*)&ssloc,
|
||||
conn->local_ip, &conn->local_port)) {
|
||||
failf(data, "ssloc inet_ntop() failed with errno %d: %s",
|
||||
errno, Curl_strerror(conn, errno));
|
||||
return;
|
||||
@ -783,7 +783,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
||||
|
||||
/* should we try another protocol family? */
|
||||
if(i == 0 && conn->tempaddr[1] == NULL &&
|
||||
Curl_timediff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) {
|
||||
(Curl_timediff(now, conn->connecttime) >=
|
||||
data->set.happy_eyeballs_timeout)) {
|
||||
trynextip(conn, sockindex, 1);
|
||||
}
|
||||
}
|
||||
@ -1005,8 +1006,8 @@ static CURLcode singleipconnect(struct connectdata *conn,
|
||||
return CURLE_OK;
|
||||
|
||||
/* store remote address and port used in this connection attempt */
|
||||
if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
|
||||
ipaddress, &port)) {
|
||||
if(!Curl_getaddressinfo((struct sockaddr*)&addr.sa_addr,
|
||||
ipaddress, &port)) {
|
||||
/* malformed address or bug in inet_ntop, try next address */
|
||||
failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
|
||||
errno, Curl_strerror(conn, errno));
|
||||
@ -1033,9 +1034,11 @@ static CURLcode singleipconnect(struct connectdata *conn,
|
||||
|
||||
if(data->set.fsockopt) {
|
||||
/* activate callback for setting socket options */
|
||||
Curl_set_in_callback(data, true);
|
||||
error = data->set.fsockopt(data->set.sockopt_client,
|
||||
sockfd,
|
||||
CURLSOCKTYPE_IPCXN);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
|
||||
isconnected = TRUE;
|
||||
@ -1204,7 +1207,8 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||
}
|
||||
|
||||
data->info.numconnects++; /* to track the number of connections made */
|
||||
Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS);
|
||||
Curl_expire(conn->data, data->set.happy_eyeballs_timeout,
|
||||
EXPIRE_HAPPY_EYEBALLS);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
@ -1311,8 +1315,12 @@ int Curl_closesocket(struct connectdata *conn,
|
||||
status */
|
||||
conn->sock_accepted[SECONDARYSOCKET] = FALSE;
|
||||
else {
|
||||
int rc;
|
||||
Curl_multi_closed(conn, sock);
|
||||
return conn->fclosesocket(conn->closesocket_client, sock);
|
||||
Curl_set_in_callback(conn->data, true);
|
||||
rc = conn->fclosesocket(conn->closesocket_client, sock);
|
||||
Curl_set_in_callback(conn->data, false);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1363,7 +1371,7 @@ CURLcode Curl_socket(struct connectdata *conn,
|
||||
addr->addrlen = sizeof(struct Curl_sockaddr_storage);
|
||||
memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
|
||||
|
||||
if(data->set.fopensocket)
|
||||
if(data->set.fopensocket) {
|
||||
/*
|
||||
* If the opensocket callback is set, all the destination address
|
||||
* information is passed to the callback. Depending on this information the
|
||||
@ -1373,9 +1381,12 @@ CURLcode Curl_socket(struct connectdata *conn,
|
||||
* might have been changed and this 'new' address will actually be used
|
||||
* here to connect.
|
||||
*/
|
||||
Curl_set_in_callback(data, true);
|
||||
*sockfd = data->set.fopensocket(data->set.opensocket_client,
|
||||
CURLSOCKTYPE_IPCXN,
|
||||
(struct curl_sockaddr *)addr);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
else
|
||||
/* opensocket callback not set, so simply create the socket now */
|
||||
*sockfd = socket(addr->family, addr->socktype, addr->protocol);
|
||||
|
@ -41,8 +41,6 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
|
||||
bool duringconnect);
|
||||
|
||||
#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
|
||||
#define HAPPY_EYEBALLS_TIMEOUT 200 /* milliseconds to wait between
|
||||
IPv4/IPv6 connection attempts */
|
||||
|
||||
/*
|
||||
* Used to extract socket and connectdata struct for the most recent
|
||||
@ -77,6 +75,11 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd);
|
||||
void Curl_persistconninfo(struct connectdata *conn);
|
||||
int Curl_closesocket(struct connectdata *conn, curl_socket_t sock);
|
||||
|
||||
/*
|
||||
* Get presentation format IP address and port from a sockaddr.
|
||||
*/
|
||||
bool Curl_getaddressinfo(struct sockaddr *sa, char *addr, long *port);
|
||||
|
||||
/*
|
||||
* The Curl_sockaddr_ex structure is basically libcurl's external API
|
||||
* curl_sockaddr structure with enough space available to directly hold any
|
||||
|
@ -726,7 +726,7 @@ static void identity_close_writer(struct connectdata *conn,
|
||||
|
||||
static const content_encoding identity_encoding = {
|
||||
"identity",
|
||||
NULL,
|
||||
"none",
|
||||
identity_init_writer,
|
||||
identity_unencode_write,
|
||||
identity_close_writer,
|
||||
@ -873,10 +873,9 @@ static contenc_writer *new_unencoding_writer(struct connectdata *conn,
|
||||
contenc_writer *downstream)
|
||||
{
|
||||
size_t sz = offsetof(contenc_writer, params) + handler->paramsize;
|
||||
contenc_writer *writer = (contenc_writer *) malloc(sz);
|
||||
contenc_writer *writer = (contenc_writer *) calloc(1, sz);
|
||||
|
||||
if(writer) {
|
||||
memset(writer, 0, sz);
|
||||
writer->handler = handler;
|
||||
writer->downstream = downstream;
|
||||
if(handler->init_writer(conn, writer)) {
|
||||
|
@ -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
|
||||
@ -142,6 +142,28 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the given string is an IP(v4|v6) address.
|
||||
*/
|
||||
static bool isip(const char *domain)
|
||||
{
|
||||
struct in_addr addr;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct in6_addr addr6;
|
||||
#endif
|
||||
|
||||
if(Curl_inet_pton(AF_INET, domain, &addr)
|
||||
#ifdef ENABLE_IPV6
|
||||
|| Curl_inet_pton(AF_INET6, domain, &addr6)
|
||||
#endif
|
||||
) {
|
||||
/* domain name given as IP address */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* matching cookie path and url path
|
||||
* RFC6265 5.1.4 Paths and Path-Match
|
||||
@ -217,6 +239,62 @@ pathmatched:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the top-level domain, for optimal hashing.
|
||||
*/
|
||||
static const char *get_top_domain(const char * const domain, size_t *outlen)
|
||||
{
|
||||
size_t len;
|
||||
const char *first = NULL, *last;
|
||||
|
||||
if(!domain)
|
||||
return NULL;
|
||||
|
||||
len = strlen(domain);
|
||||
last = memrchr(domain, '.', len);
|
||||
if(last) {
|
||||
first = memrchr(domain, '.', (size_t) (last - domain));
|
||||
if(first)
|
||||
len -= (size_t) (++first - domain);
|
||||
}
|
||||
|
||||
if(outlen)
|
||||
*outlen = len;
|
||||
|
||||
return first? first: domain;
|
||||
}
|
||||
|
||||
/*
|
||||
* A case-insensitive hash for the cookie domains.
|
||||
*/
|
||||
static size_t cookie_hash_domain(const char *domain, const size_t len)
|
||||
{
|
||||
const char *end = domain + len;
|
||||
size_t h = 5381;
|
||||
|
||||
while(domain < end) {
|
||||
h += h << 5;
|
||||
h ^= Curl_raw_toupper(*domain++);
|
||||
}
|
||||
|
||||
return (h % COOKIE_HASH_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash this domain.
|
||||
*/
|
||||
static size_t cookiehash(const char * const domain)
|
||||
{
|
||||
const char *top;
|
||||
size_t len;
|
||||
|
||||
if(!domain || isip(domain))
|
||||
return 0;
|
||||
|
||||
top = get_top_domain(domain, &len);
|
||||
return cookie_hash_domain(top, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* cookie path sanitize
|
||||
*/
|
||||
@ -303,50 +381,31 @@ static void remove_expired(struct CookieInfo *cookies)
|
||||
{
|
||||
struct Cookie *co, *nx, *pv;
|
||||
curl_off_t now = (curl_off_t)time(NULL);
|
||||
unsigned int i;
|
||||
|
||||
co = cookies->cookies;
|
||||
pv = NULL;
|
||||
while(co) {
|
||||
nx = co->next;
|
||||
if(co->expires && co->expires < now) {
|
||||
if(!pv) {
|
||||
cookies->cookies = co->next;
|
||||
for(i = 0; i < COOKIE_HASH_SIZE; i++) {
|
||||
co = cookies->cookies[i];
|
||||
pv = NULL;
|
||||
while(co) {
|
||||
nx = co->next;
|
||||
if(co->expires && co->expires < now) {
|
||||
if(!pv) {
|
||||
cookies->cookies[i] = co->next;
|
||||
}
|
||||
else {
|
||||
pv->next = co->next;
|
||||
}
|
||||
cookies->numcookies--;
|
||||
freecookie(co);
|
||||
}
|
||||
else {
|
||||
pv->next = co->next;
|
||||
pv = co;
|
||||
}
|
||||
cookies->numcookies--;
|
||||
freecookie(co);
|
||||
co = nx;
|
||||
}
|
||||
else {
|
||||
pv = co;
|
||||
}
|
||||
co = nx;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the given string is an IP(v4|v6) address.
|
||||
*/
|
||||
static bool isip(const char *domain)
|
||||
{
|
||||
struct in_addr addr;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct in6_addr addr6;
|
||||
#endif
|
||||
|
||||
if(Curl_inet_pton(AF_INET, domain, &addr)
|
||||
#ifdef ENABLE_IPV6
|
||||
|| Curl_inet_pton(AF_INET6, domain, &addr6)
|
||||
#endif
|
||||
) {
|
||||
/* domain name given as IP address */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Curl_cookie_add()
|
||||
@ -368,6 +427,7 @@ Curl_cookie_add(struct Curl_easy *data,
|
||||
|
||||
struct CookieInfo *c,
|
||||
bool httpheader, /* TRUE if HTTP header-style line */
|
||||
bool noexpire, /* if TRUE, skip remove_expired() */
|
||||
char *lineptr, /* first character of the line */
|
||||
const char *domain, /* default domain */
|
||||
const char *path) /* full path used when this cookie is set,
|
||||
@ -380,6 +440,7 @@ Curl_cookie_add(struct Curl_easy *data,
|
||||
time_t now = time(NULL);
|
||||
bool replace_old = FALSE;
|
||||
bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
|
||||
size_t myhash;
|
||||
|
||||
#ifdef USE_LIBPSL
|
||||
const psl_ctx_t *psl;
|
||||
@ -430,9 +491,6 @@ Curl_cookie_add(struct Curl_easy *data,
|
||||
size_t nlen = strlen(name);
|
||||
const char *endofn = &ptr[ nlen ];
|
||||
|
||||
infof(data, "cookie size: name/val %d + %d bytes\n",
|
||||
nlen, len);
|
||||
|
||||
if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) ||
|
||||
((nlen + len) > MAX_NAME)) {
|
||||
/* too long individual name or contents, or too long combination of
|
||||
@ -470,10 +528,16 @@ Curl_cookie_add(struct Curl_easy *data,
|
||||
while(*whatptr && ISBLANK(*whatptr))
|
||||
whatptr++;
|
||||
|
||||
if(!co->name && sep) {
|
||||
if(!co->name) {
|
||||
/* The very first name/value pair is the actual cookie name */
|
||||
if(!sep) {
|
||||
/* Bad name/value pair. */
|
||||
badcookie = TRUE;
|
||||
break;
|
||||
}
|
||||
co->name = strdup(name);
|
||||
co->value = strdup(whatptr);
|
||||
done = TRUE;
|
||||
if(!co->name || !co->value) {
|
||||
badcookie = TRUE;
|
||||
break;
|
||||
@ -822,7 +886,8 @@ Curl_cookie_add(struct Curl_easy *data,
|
||||
the same domain and path as this */
|
||||
|
||||
/* at first, remove expired cookies */
|
||||
remove_expired(c);
|
||||
if(!noexpire)
|
||||
remove_expired(c);
|
||||
|
||||
#ifdef USE_LIBPSL
|
||||
/* Check if the domain is a Public Suffix and if yes, ignore the cookie.
|
||||
@ -839,7 +904,8 @@ Curl_cookie_add(struct Curl_easy *data,
|
||||
}
|
||||
#endif
|
||||
|
||||
clist = c->cookies;
|
||||
myhash = cookiehash(co->domain);
|
||||
clist = c->cookies[myhash];
|
||||
replace_old = FALSE;
|
||||
while(clist) {
|
||||
if(strcasecompare(clist->name, co->name)) {
|
||||
@ -925,7 +991,7 @@ Curl_cookie_add(struct Curl_easy *data,
|
||||
if(lastc)
|
||||
lastc->next = co;
|
||||
else
|
||||
c->cookies = co;
|
||||
c->cookies[myhash] = co;
|
||||
c->numcookies++; /* one more cookie in the jar */
|
||||
}
|
||||
|
||||
@ -1029,9 +1095,10 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
|
||||
while(*lineptr && ISBLANK(*lineptr))
|
||||
lineptr++;
|
||||
|
||||
Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
|
||||
Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL);
|
||||
}
|
||||
free(line); /* free the line buffer */
|
||||
remove_expired(c); /* run this once, not on every cookie */
|
||||
|
||||
if(fromfile)
|
||||
fclose(fp);
|
||||
@ -1137,8 +1204,9 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
|
||||
struct Cookie *mainco = NULL;
|
||||
size_t matches = 0;
|
||||
bool is_ip;
|
||||
const size_t myhash = cookiehash(host);
|
||||
|
||||
if(!c || !c->cookies)
|
||||
if(!c || !c->cookies[myhash])
|
||||
return NULL; /* no cookie struct or no cookies in the struct */
|
||||
|
||||
/* at first, remove expired cookies */
|
||||
@ -1147,7 +1215,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
|
||||
/* check if host is an IP(v4|v6) address */
|
||||
is_ip = isip(host);
|
||||
|
||||
co = c->cookies;
|
||||
co = c->cookies[myhash];
|
||||
|
||||
while(co) {
|
||||
/* only process this cookie if it is not expired or had no expire
|
||||
@ -1235,8 +1303,11 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
|
||||
void Curl_cookie_clearall(struct CookieInfo *cookies)
|
||||
{
|
||||
if(cookies) {
|
||||
Curl_cookie_freelist(cookies->cookies);
|
||||
cookies->cookies = NULL;
|
||||
unsigned int i;
|
||||
for(i = 0; i < COOKIE_HASH_SIZE; i++) {
|
||||
Curl_cookie_freelist(cookies->cookies[i]);
|
||||
cookies->cookies[i] = NULL;
|
||||
}
|
||||
cookies->numcookies = 0;
|
||||
}
|
||||
}
|
||||
@ -1270,31 +1341,37 @@ void Curl_cookie_freelist(struct Cookie *co)
|
||||
void Curl_cookie_clearsess(struct CookieInfo *cookies)
|
||||
{
|
||||
struct Cookie *first, *curr, *next, *prev = NULL;
|
||||
unsigned int i;
|
||||
|
||||
if(!cookies || !cookies->cookies)
|
||||
if(!cookies)
|
||||
return;
|
||||
|
||||
first = curr = prev = cookies->cookies;
|
||||
for(i = 0; i < COOKIE_HASH_SIZE; i++) {
|
||||
if(!cookies->cookies[i])
|
||||
continue;
|
||||
|
||||
for(; curr; curr = next) {
|
||||
next = curr->next;
|
||||
if(!curr->expires) {
|
||||
if(first == curr)
|
||||
first = next;
|
||||
first = curr = prev = cookies->cookies[i];
|
||||
|
||||
if(prev == curr)
|
||||
prev = next;
|
||||
for(; curr; curr = next) {
|
||||
next = curr->next;
|
||||
if(!curr->expires) {
|
||||
if(first == curr)
|
||||
first = next;
|
||||
|
||||
if(prev == curr)
|
||||
prev = next;
|
||||
else
|
||||
prev->next = next;
|
||||
|
||||
freecookie(curr);
|
||||
cookies->numcookies--;
|
||||
}
|
||||
else
|
||||
prev->next = next;
|
||||
|
||||
freecookie(curr);
|
||||
cookies->numcookies--;
|
||||
prev = curr;
|
||||
}
|
||||
else
|
||||
prev = curr;
|
||||
}
|
||||
|
||||
cookies->cookies = first;
|
||||
cookies->cookies[i] = first;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1307,9 +1384,12 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies)
|
||||
****************************************************************************/
|
||||
void Curl_cookie_cleanup(struct CookieInfo *c)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if(c) {
|
||||
free(c->filename);
|
||||
Curl_cookie_freelist(c->cookies);
|
||||
for(i = 0; i < COOKIE_HASH_SIZE; i++)
|
||||
Curl_cookie_freelist(c->cookies[i]);
|
||||
free(c); /* free the base struct as well */
|
||||
}
|
||||
}
|
||||
@ -1358,6 +1438,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
|
||||
FILE *out;
|
||||
bool use_stdout = FALSE;
|
||||
char *format_ptr;
|
||||
unsigned int i;
|
||||
|
||||
if((NULL == c) || (0 == c->numcookies))
|
||||
/* If there are no known cookies, we don't write or even create any
|
||||
@ -1367,6 +1448,10 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
|
||||
/* at first, remove expired cookies */
|
||||
remove_expired(c);
|
||||
|
||||
/* make sure we still have cookies after expiration */
|
||||
if(0 == c->numcookies)
|
||||
return 0;
|
||||
|
||||
if(!strcmp("-", dumphere)) {
|
||||
/* use stdout */
|
||||
out = stdout;
|
||||
@ -1383,18 +1468,20 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
|
||||
"# This file was generated by libcurl! Edit at your own risk.\n\n",
|
||||
out);
|
||||
|
||||
for(co = c->cookies; co; co = co->next) {
|
||||
if(!co->domain)
|
||||
continue;
|
||||
format_ptr = get_netscape_format(co);
|
||||
if(format_ptr == NULL) {
|
||||
fprintf(out, "#\n# Fatal libcurl error\n");
|
||||
if(!use_stdout)
|
||||
fclose(out);
|
||||
return 1;
|
||||
for(i = 0; i < COOKIE_HASH_SIZE; i++) {
|
||||
for(co = c->cookies[i]; co; co = co->next) {
|
||||
if(!co->domain)
|
||||
continue;
|
||||
format_ptr = get_netscape_format(co);
|
||||
if(format_ptr == NULL) {
|
||||
fprintf(out, "#\n# Fatal libcurl error\n");
|
||||
if(!use_stdout)
|
||||
fclose(out);
|
||||
return 1;
|
||||
}
|
||||
fprintf(out, "%s\n", format_ptr);
|
||||
free(format_ptr);
|
||||
}
|
||||
fprintf(out, "%s\n", format_ptr);
|
||||
free(format_ptr);
|
||||
}
|
||||
|
||||
if(!use_stdout)
|
||||
@ -1409,26 +1496,29 @@ static struct curl_slist *cookie_list(struct Curl_easy *data)
|
||||
struct curl_slist *beg;
|
||||
struct Cookie *c;
|
||||
char *line;
|
||||
unsigned int i;
|
||||
|
||||
if((data->cookies == NULL) ||
|
||||
(data->cookies->numcookies == 0))
|
||||
return NULL;
|
||||
|
||||
for(c = data->cookies->cookies; c; c = c->next) {
|
||||
if(!c->domain)
|
||||
continue;
|
||||
line = get_netscape_format(c);
|
||||
if(!line) {
|
||||
curl_slist_free_all(list);
|
||||
return NULL;
|
||||
for(i = 0; i < COOKIE_HASH_SIZE; i++) {
|
||||
for(c = data->cookies->cookies[i]; c; c = c->next) {
|
||||
if(!c->domain)
|
||||
continue;
|
||||
line = get_netscape_format(c);
|
||||
if(!line) {
|
||||
curl_slist_free_all(list);
|
||||
return NULL;
|
||||
}
|
||||
beg = Curl_slist_append_nodup(list, line);
|
||||
if(!beg) {
|
||||
free(line);
|
||||
curl_slist_free_all(list);
|
||||
return NULL;
|
||||
}
|
||||
list = beg;
|
||||
}
|
||||
beg = Curl_slist_append_nodup(list, line);
|
||||
if(!beg) {
|
||||
free(line);
|
||||
curl_slist_free_all(list);
|
||||
return NULL;
|
||||
}
|
||||
list = beg;
|
||||
}
|
||||
|
||||
return list;
|
||||
|
@ -45,9 +45,11 @@ struct Cookie {
|
||||
bool httponly; /* true if the httponly directive is present */
|
||||
};
|
||||
|
||||
#define COOKIE_HASH_SIZE 256
|
||||
|
||||
struct CookieInfo {
|
||||
/* linked list of cookies we know of */
|
||||
struct Cookie *cookies;
|
||||
struct Cookie *cookies[COOKIE_HASH_SIZE];
|
||||
|
||||
char *filename; /* file we read from/write to */
|
||||
bool running; /* state info, for cookie adding information */
|
||||
@ -67,7 +69,6 @@ struct CookieInfo {
|
||||
|
||||
*/
|
||||
#define MAX_COOKIE_LINE 5000
|
||||
#define MAX_COOKIE_LINE_TXT "4999"
|
||||
|
||||
/* This is the maximum length of a cookie name or content we deal with: */
|
||||
#define MAX_NAME 4096
|
||||
@ -80,7 +81,8 @@ struct Curl_easy;
|
||||
*/
|
||||
|
||||
struct Cookie *Curl_cookie_add(struct Curl_easy *data,
|
||||
struct CookieInfo *, bool header, char *lineptr,
|
||||
struct CookieInfo *, bool header, bool noexpiry,
|
||||
char *lineptr,
|
||||
const char *domain, const char *path);
|
||||
|
||||
struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *,
|
||||
|
@ -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
|
||||
@ -50,6 +50,10 @@
|
||||
# define in_addr_t unsigned long
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && defined(USE_UNIX_SOCKETS)
|
||||
#include <afunix.h>
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "curl_addrinfo.h"
|
||||
@ -341,7 +345,7 @@ Curl_he2ai(const struct hostent *he, int port)
|
||||
addr = (void *)ai->ai_addr; /* storage area for this info */
|
||||
|
||||
memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
|
||||
addr->sin_family = (unsigned short)(he->h_addrtype);
|
||||
addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
|
||||
addr->sin_port = htons((unsigned short)port);
|
||||
break;
|
||||
|
||||
@ -350,7 +354,7 @@ Curl_he2ai(const struct hostent *he, int port)
|
||||
addr6 = (void *)ai->ai_addr; /* storage area for this info */
|
||||
|
||||
memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
|
||||
addr6->sin6_family = (unsigned short)(he->h_addrtype);
|
||||
addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
|
||||
addr6->sin6_port = htons((unsigned short)port);
|
||||
break;
|
||||
#endif
|
||||
|
@ -389,6 +389,9 @@
|
||||
/* if zlib is available */
|
||||
#cmakedefine HAVE_LIBZ 1
|
||||
|
||||
/* if brotli is available */
|
||||
#cmakedefine HAVE_BROTLI 1
|
||||
|
||||
/* if your compiler supports LL */
|
||||
#cmakedefine HAVE_LL 1
|
||||
|
||||
|
133
Utilities/cmcurl/lib/curl_ctype.c
Normal file
133
Utilities/cmcurl/lib/curl_ctype.c
Normal file
@ -0,0 +1,133 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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"
|
||||
|
||||
#ifndef CURL_DOES_CONVERSIONS
|
||||
|
||||
#undef _U
|
||||
#define _U (1<<0) /* upper case */
|
||||
#undef _L
|
||||
#define _L (1<<1) /* lower case */
|
||||
#undef _N
|
||||
#define _N (1<<2) /* decimal numerical digit */
|
||||
#undef _S
|
||||
#define _S (1<<3) /* space */
|
||||
#undef _P
|
||||
#define _P (1<<4) /* punctuation */
|
||||
#undef _C
|
||||
#define _C (1<<5) /* control */
|
||||
#undef _X
|
||||
#define _X (1<<6) /* hexadecimal letter */
|
||||
#undef _B
|
||||
#define _B (1<<7) /* blank */
|
||||
|
||||
static const unsigned char ascii[128] = {
|
||||
_C, _C, _C, _C, _C, _C, _C, _C,
|
||||
_C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C,
|
||||
_C, _C, _C, _C, _C, _C, _C, _C,
|
||||
_C, _C, _C, _C, _C, _C, _C, _C,
|
||||
_S|_B, _P, _P, _P, _P, _P, _P, _P,
|
||||
_P, _P, _P, _P, _P, _P, _P, _P,
|
||||
_N, _N, _N, _N, _N, _N, _N, _N,
|
||||
_N, _N, _P, _P, _P, _P, _P, _P,
|
||||
_P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U,
|
||||
_U, _U, _U, _U, _U, _U, _U, _U,
|
||||
_U, _U, _U, _U, _U, _U, _U, _U,
|
||||
_U, _U, _U, _P, _P, _P, _P, _P,
|
||||
_P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L,
|
||||
_L, _L, _L, _L, _L, _L, _L, _L,
|
||||
_L, _L, _L, _L, _L, _L, _L, _L,
|
||||
_L, _L, _L, _P, _P, _P, _P, _C
|
||||
};
|
||||
|
||||
int Curl_isspace(int c)
|
||||
{
|
||||
if((c < 0) || (c >= 0x80))
|
||||
return FALSE;
|
||||
return (ascii[c] & _S);
|
||||
}
|
||||
|
||||
int Curl_isdigit(int c)
|
||||
{
|
||||
if((c < 0) || (c >= 0x80))
|
||||
return FALSE;
|
||||
return (ascii[c] & _N);
|
||||
}
|
||||
|
||||
int Curl_isalnum(int c)
|
||||
{
|
||||
if((c < 0) || (c >= 0x80))
|
||||
return FALSE;
|
||||
return (ascii[c] & (_N|_U|_L));
|
||||
}
|
||||
|
||||
int Curl_isxdigit(int c)
|
||||
{
|
||||
if((c < 0) || (c >= 0x80))
|
||||
return FALSE;
|
||||
return (ascii[c] & (_N|_X));
|
||||
}
|
||||
|
||||
int Curl_isgraph(int c)
|
||||
{
|
||||
if((c < 0) || (c >= 0x80) || (c == ' '))
|
||||
return FALSE;
|
||||
return (ascii[c] & (_N|_X|_U|_L|_P|_S));
|
||||
}
|
||||
|
||||
int Curl_isprint(int c)
|
||||
{
|
||||
if((c < 0) || (c >= 0x80))
|
||||
return FALSE;
|
||||
return (ascii[c] & (_N|_X|_U|_L|_P|_S));
|
||||
}
|
||||
|
||||
int Curl_isalpha(int c)
|
||||
{
|
||||
if((c < 0) || (c >= 0x80))
|
||||
return FALSE;
|
||||
return (ascii[c] & (_U|_L));
|
||||
}
|
||||
|
||||
int Curl_isupper(int c)
|
||||
{
|
||||
if((c < 0) || (c >= 0x80))
|
||||
return FALSE;
|
||||
return (ascii[c] & (_U));
|
||||
}
|
||||
|
||||
int Curl_islower(int c)
|
||||
{
|
||||
if((c < 0) || (c >= 0x80))
|
||||
return FALSE;
|
||||
return (ascii[c] & (_L));
|
||||
}
|
||||
|
||||
int Curl_iscntrl(int c)
|
||||
{
|
||||
if((c < 0) || (c >= 0x80))
|
||||
return FALSE;
|
||||
return (ascii[c] & (_C));
|
||||
}
|
||||
|
||||
#endif /* !CURL_DOES_CONVERSIONS */
|
81
Utilities/cmcurl/lib/curl_ctype.h
Normal file
81
Utilities/cmcurl/lib/curl_ctype.h
Normal file
@ -0,0 +1,81 @@
|
||||
#ifndef HEADER_CURL_CTYPE_H
|
||||
#define HEADER_CURL_CTYPE_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"
|
||||
|
||||
#ifdef CURL_DOES_CONVERSIONS
|
||||
|
||||
/*
|
||||
* Uppercase macro versions of ANSI/ISO is*() functions/macros which
|
||||
* avoid negative number inputs with argument byte codes > 127.
|
||||
*
|
||||
* For non-ASCII platforms the C library character classification routines
|
||||
* are used despite being locale-dependent, because this is better than
|
||||
* not to work at all.
|
||||
*/
|
||||
#include <ctype.h>
|
||||
|
||||
#define ISSPACE(x) (isspace((int) ((unsigned char)x)))
|
||||
#define ISDIGIT(x) (isdigit((int) ((unsigned char)x)))
|
||||
#define ISALNUM(x) (isalnum((int) ((unsigned char)x)))
|
||||
#define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
|
||||
#define ISGRAPH(x) (isgraph((int) ((unsigned char)x)))
|
||||
#define ISALPHA(x) (isalpha((int) ((unsigned char)x)))
|
||||
#define ISPRINT(x) (isprint((int) ((unsigned char)x)))
|
||||
#define ISUPPER(x) (isupper((int) ((unsigned char)x)))
|
||||
#define ISLOWER(x) (islower((int) ((unsigned char)x)))
|
||||
#define ISCNTRL(x) (iscntrl((int) ((unsigned char)x)))
|
||||
#define ISASCII(x) (isascii((int) ((unsigned char)x)))
|
||||
|
||||
#else
|
||||
|
||||
int Curl_isspace(int c);
|
||||
int Curl_isdigit(int c);
|
||||
int Curl_isalnum(int c);
|
||||
int Curl_isxdigit(int c);
|
||||
int Curl_isgraph(int c);
|
||||
int Curl_isprint(int c);
|
||||
int Curl_isalpha(int c);
|
||||
int Curl_isupper(int c);
|
||||
int Curl_islower(int c);
|
||||
int Curl_iscntrl(int c);
|
||||
|
||||
#define ISSPACE(x) (Curl_isspace((int) ((unsigned char)x)))
|
||||
#define ISDIGIT(x) (Curl_isdigit((int) ((unsigned char)x)))
|
||||
#define ISALNUM(x) (Curl_isalnum((int) ((unsigned char)x)))
|
||||
#define ISXDIGIT(x) (Curl_isxdigit((int) ((unsigned char)x)))
|
||||
#define ISGRAPH(x) (Curl_isgraph((int) ((unsigned char)x)))
|
||||
#define ISALPHA(x) (Curl_isalpha((int) ((unsigned char)x)))
|
||||
#define ISPRINT(x) (Curl_isprint((int) ((unsigned char)x)))
|
||||
#define ISUPPER(x) (Curl_isupper((int) ((unsigned char)x)))
|
||||
#define ISLOWER(x) (Curl_islower((int) ((unsigned char)x)))
|
||||
#define ISCNTRL(x) (Curl_iscntrl((int) ((unsigned char)x)))
|
||||
#define ISASCII(x) (((x) >= 0) && ((x) <= 0x80))
|
||||
|
||||
#endif
|
||||
|
||||
#define ISBLANK(x) (int)((((unsigned char)x) == ' ') || \
|
||||
(((unsigned char)x) == '\t'))
|
||||
|
||||
#endif /* HEADER_CURL_CTYPE_H */
|
@ -46,15 +46,8 @@
|
||||
#define CURLFNM_SPACE (CURLFNM_CHARSET_LEN + 9)
|
||||
#define CURLFNM_UPPER (CURLFNM_CHARSET_LEN + 10)
|
||||
|
||||
typedef enum {
|
||||
CURLFNM_LOOP_DEFAULT = 0,
|
||||
CURLFNM_LOOP_BACKSLASH
|
||||
} loop_state;
|
||||
|
||||
typedef enum {
|
||||
CURLFNM_SCHS_DEFAULT = 0,
|
||||
CURLFNM_SCHS_MAYRANGE,
|
||||
CURLFNM_SCHS_MAYRANGE2,
|
||||
CURLFNM_SCHS_RIGHTBR,
|
||||
CURLFNM_SCHS_RIGHTBRLEFTBR
|
||||
} setcharset_state;
|
||||
@ -64,6 +57,13 @@ typedef enum {
|
||||
CURLFNM_PKW_DDOT
|
||||
} parsekey_state;
|
||||
|
||||
typedef enum {
|
||||
CCLASS_OTHER = 0,
|
||||
CCLASS_DIGIT,
|
||||
CCLASS_UPPER,
|
||||
CCLASS_LOWER
|
||||
} char_class;
|
||||
|
||||
#define SETCHARSET_OK 1
|
||||
#define SETCHARSET_FAIL 0
|
||||
|
||||
@ -81,12 +81,12 @@ static int parsekeyword(unsigned char **pattern, unsigned char *charset)
|
||||
return SETCHARSET_FAIL;
|
||||
switch(state) {
|
||||
case CURLFNM_PKW_INIT:
|
||||
if(ISALPHA(c) && ISLOWER(c))
|
||||
if(ISLOWER(c))
|
||||
keyword[i] = c;
|
||||
else if(c == ':')
|
||||
state = CURLFNM_PKW_DDOT;
|
||||
else
|
||||
return 0;
|
||||
return SETCHARSET_FAIL;
|
||||
break;
|
||||
case CURLFNM_PKW_DDOT:
|
||||
if(c == ']')
|
||||
@ -123,14 +123,48 @@ static int parsekeyword(unsigned char **pattern, unsigned char *charset)
|
||||
return SETCHARSET_OK;
|
||||
}
|
||||
|
||||
/* Return the character class. */
|
||||
static char_class charclass(unsigned char c)
|
||||
{
|
||||
if(ISUPPER(c))
|
||||
return CCLASS_UPPER;
|
||||
if(ISLOWER(c))
|
||||
return CCLASS_LOWER;
|
||||
if(ISDIGIT(c))
|
||||
return CCLASS_DIGIT;
|
||||
return CCLASS_OTHER;
|
||||
}
|
||||
|
||||
/* Include a character or a range in set. */
|
||||
static void setcharorrange(unsigned char **pp, unsigned char *charset)
|
||||
{
|
||||
unsigned char *p = (*pp)++;
|
||||
unsigned char c = *p++;
|
||||
|
||||
charset[c] = 1;
|
||||
if(ISALNUM(c) && *p++ == '-') {
|
||||
char_class cc = charclass(c);
|
||||
unsigned char endrange = *p++;
|
||||
|
||||
if(endrange == '\\')
|
||||
endrange = *p++;
|
||||
if(endrange >= c && charclass(endrange) == cc) {
|
||||
while(c++ != endrange)
|
||||
if(charclass(c) == cc) /* Chars in class may be not consecutive. */
|
||||
charset[c] = 1;
|
||||
*pp = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
|
||||
static int setcharset(unsigned char **p, unsigned char *charset)
|
||||
{
|
||||
setcharset_state state = CURLFNM_SCHS_DEFAULT;
|
||||
unsigned char rangestart = 0;
|
||||
unsigned char lastchar = 0;
|
||||
bool something_found = FALSE;
|
||||
unsigned char c;
|
||||
|
||||
memset(charset, 0, CURLFNM_CHSET_SIZE);
|
||||
for(;;) {
|
||||
c = **p;
|
||||
if(!c)
|
||||
@ -138,14 +172,7 @@ static int setcharset(unsigned char **p, unsigned char *charset)
|
||||
|
||||
switch(state) {
|
||||
case CURLFNM_SCHS_DEFAULT:
|
||||
if(ISALNUM(c)) { /* ASCII value */
|
||||
rangestart = c;
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
state = CURLFNM_SCHS_MAYRANGE;
|
||||
something_found = TRUE;
|
||||
}
|
||||
else if(c == ']') {
|
||||
if(c == ']') {
|
||||
if(something_found)
|
||||
return SETCHARSET_OK;
|
||||
something_found = TRUE;
|
||||
@ -154,26 +181,16 @@ static int setcharset(unsigned char **p, unsigned char *charset)
|
||||
(*p)++;
|
||||
}
|
||||
else if(c == '[') {
|
||||
char c2 = *((*p) + 1);
|
||||
if(c2 == ':') { /* there has to be a keyword */
|
||||
(*p) += 2;
|
||||
if(parsekeyword(p, charset)) {
|
||||
state = CURLFNM_SCHS_DEFAULT;
|
||||
}
|
||||
else
|
||||
return SETCHARSET_FAIL;
|
||||
}
|
||||
unsigned char *pp = *p + 1;
|
||||
|
||||
if(*pp++ == ':' && parsekeyword(&pp, charset))
|
||||
*p = pp;
|
||||
else {
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
}
|
||||
something_found = TRUE;
|
||||
}
|
||||
else if(c == '?' || c == '*') {
|
||||
something_found = TRUE;
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
}
|
||||
else if(c == '^' || c == '!') {
|
||||
if(!something_found) {
|
||||
if(charset[CURLFNM_NEGATE]) {
|
||||
@ -189,81 +206,16 @@ static int setcharset(unsigned char **p, unsigned char *charset)
|
||||
}
|
||||
else if(c == '\\') {
|
||||
c = *(++(*p));
|
||||
if(ISPRINT((c))) {
|
||||
something_found = TRUE;
|
||||
state = CURLFNM_SCHS_MAYRANGE;
|
||||
charset[c] = 1;
|
||||
rangestart = c;
|
||||
(*p)++;
|
||||
}
|
||||
if(c)
|
||||
setcharorrange(p, charset);
|
||||
else
|
||||
return SETCHARSET_FAIL;
|
||||
}
|
||||
else {
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
charset['\\'] = 1;
|
||||
something_found = TRUE;
|
||||
}
|
||||
break;
|
||||
case CURLFNM_SCHS_MAYRANGE:
|
||||
if(c == '-') {
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
lastchar = '-';
|
||||
state = CURLFNM_SCHS_MAYRANGE2;
|
||||
else {
|
||||
setcharorrange(p, charset);
|
||||
something_found = TRUE;
|
||||
}
|
||||
else if(c == '[') {
|
||||
state = CURLFNM_SCHS_DEFAULT;
|
||||
}
|
||||
else if(ISALNUM(c)) {
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
}
|
||||
else if(c == '\\') {
|
||||
c = *(++(*p));
|
||||
if(ISPRINT(c)) {
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
}
|
||||
else
|
||||
return SETCHARSET_FAIL;
|
||||
}
|
||||
else if(c == ']') {
|
||||
return SETCHARSET_OK;
|
||||
}
|
||||
else
|
||||
return SETCHARSET_FAIL;
|
||||
break;
|
||||
case CURLFNM_SCHS_MAYRANGE2:
|
||||
if(c == ']') {
|
||||
return SETCHARSET_OK;
|
||||
}
|
||||
else if(c == '\\') {
|
||||
c = *(++(*p));
|
||||
if(ISPRINT(c)) {
|
||||
charset[c] = 1;
|
||||
state = CURLFNM_SCHS_DEFAULT;
|
||||
(*p)++;
|
||||
}
|
||||
else
|
||||
return SETCHARSET_FAIL;
|
||||
}
|
||||
else if(c >= rangestart) {
|
||||
if((ISLOWER(c) && ISLOWER(rangestart)) ||
|
||||
(ISDIGIT(c) && ISDIGIT(rangestart)) ||
|
||||
(ISUPPER(c) && ISUPPER(rangestart))) {
|
||||
charset[lastchar] = 0;
|
||||
rangestart++;
|
||||
while(rangestart++ <= c)
|
||||
charset[rangestart-1] = 1;
|
||||
(*p)++;
|
||||
state = CURLFNM_SCHS_DEFAULT;
|
||||
}
|
||||
else
|
||||
return SETCHARSET_FAIL;
|
||||
}
|
||||
else
|
||||
return SETCHARSET_FAIL;
|
||||
break;
|
||||
case CURLFNM_SCHS_RIGHTBR:
|
||||
if(c == '[') {
|
||||
@ -286,14 +238,11 @@ static int setcharset(unsigned char **p, unsigned char *charset)
|
||||
goto fail;
|
||||
break;
|
||||
case CURLFNM_SCHS_RIGHTBRLEFTBR:
|
||||
if(c == ']') {
|
||||
if(c == ']')
|
||||
return SETCHARSET_OK;
|
||||
}
|
||||
else {
|
||||
state = CURLFNM_SCHS_DEFAULT;
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
}
|
||||
state = CURLFNM_SCHS_DEFAULT;
|
||||
charset[c] = 1;
|
||||
(*p)++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -304,107 +253,93 @@ fail:
|
||||
static int loop(const unsigned char *pattern, const unsigned char *string,
|
||||
int maxstars)
|
||||
{
|
||||
loop_state state = CURLFNM_LOOP_DEFAULT;
|
||||
unsigned char *p = (unsigned char *)pattern;
|
||||
unsigned char *s = (unsigned char *)string;
|
||||
unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
|
||||
int rc = 0;
|
||||
|
||||
for(;;) {
|
||||
switch(state) {
|
||||
case CURLFNM_LOOP_DEFAULT:
|
||||
if(*p == '*') {
|
||||
if(!maxstars)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
while(*(p + 1) == '*') /* eliminate multiple stars */
|
||||
p++;
|
||||
if(*s == '\0' && *(p + 1) == '\0')
|
||||
return CURL_FNMATCH_MATCH;
|
||||
rc = loop(p + 1, s, maxstars - 1); /* *.txt matches .txt <=>
|
||||
.txt matches .txt */
|
||||
if(rc == CURL_FNMATCH_MATCH)
|
||||
return CURL_FNMATCH_MATCH;
|
||||
if(*s) /* let the star eat up one character */
|
||||
s++;
|
||||
else
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
}
|
||||
else if(*p == '?') {
|
||||
if(ISPRINT(*s)) {
|
||||
s++;
|
||||
p++;
|
||||
}
|
||||
else if(*s == '\0')
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
else
|
||||
return CURL_FNMATCH_FAIL; /* cannot deal with other character */
|
||||
}
|
||||
else if(*p == '\0') {
|
||||
if(*s == '\0')
|
||||
return CURL_FNMATCH_MATCH;
|
||||
unsigned char *pp;
|
||||
|
||||
switch(*p) {
|
||||
case '*':
|
||||
if(!maxstars)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
}
|
||||
else if(*p == '\\') {
|
||||
state = CURLFNM_LOOP_BACKSLASH;
|
||||
p++;
|
||||
}
|
||||
else if(*p == '[') {
|
||||
unsigned char *pp = p + 1; /* cannot handle with pointer to register */
|
||||
if(setcharset(&pp, charset)) {
|
||||
int found = FALSE;
|
||||
if(charset[(unsigned int)*s])
|
||||
found = TRUE;
|
||||
else if(charset[CURLFNM_ALNUM])
|
||||
found = ISALNUM(*s);
|
||||
else if(charset[CURLFNM_ALPHA])
|
||||
found = ISALPHA(*s);
|
||||
else if(charset[CURLFNM_DIGIT])
|
||||
found = ISDIGIT(*s);
|
||||
else if(charset[CURLFNM_XDIGIT])
|
||||
found = ISXDIGIT(*s);
|
||||
else if(charset[CURLFNM_PRINT])
|
||||
found = ISPRINT(*s);
|
||||
else if(charset[CURLFNM_SPACE])
|
||||
found = ISSPACE(*s);
|
||||
else if(charset[CURLFNM_UPPER])
|
||||
found = ISUPPER(*s);
|
||||
else if(charset[CURLFNM_LOWER])
|
||||
found = ISLOWER(*s);
|
||||
else if(charset[CURLFNM_BLANK])
|
||||
found = ISBLANK(*s);
|
||||
else if(charset[CURLFNM_GRAPH])
|
||||
found = ISGRAPH(*s);
|
||||
|
||||
if(charset[CURLFNM_NEGATE])
|
||||
found = !found;
|
||||
|
||||
if(found) {
|
||||
p = pp + 1;
|
||||
if(*s)
|
||||
/* don't advance if we're matching on an empty string */
|
||||
s++;
|
||||
memset(charset, 0, CURLFNM_CHSET_SIZE);
|
||||
}
|
||||
else
|
||||
/* Regroup consecutive stars and question marks. This can be done because
|
||||
'*?*?*' can be expressed as '??*'. */
|
||||
for(;;) {
|
||||
if(*++p == '\0')
|
||||
return CURL_FNMATCH_MATCH;
|
||||
if(*p == '?') {
|
||||
if(!*s++)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
}
|
||||
else
|
||||
return CURL_FNMATCH_FAIL;
|
||||
else if(*p != '*')
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if(*p++ != *s++)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
/* Skip string characters until we find a match with pattern suffix. */
|
||||
for(maxstars--; *s; s++) {
|
||||
if(loop(p, s, maxstars) == CURL_FNMATCH_MATCH)
|
||||
return CURL_FNMATCH_MATCH;
|
||||
}
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
case '?':
|
||||
if(!*s)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
s++;
|
||||
p++;
|
||||
break;
|
||||
case CURLFNM_LOOP_BACKSLASH:
|
||||
if(ISPRINT(*p)) {
|
||||
if(*p++ == *s++)
|
||||
state = CURLFNM_LOOP_DEFAULT;
|
||||
else
|
||||
case '\0':
|
||||
return *s? CURL_FNMATCH_NOMATCH: CURL_FNMATCH_MATCH;
|
||||
case '\\':
|
||||
if(p[1])
|
||||
p++;
|
||||
if(*s++ != *p++)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
break;
|
||||
case '[':
|
||||
pp = p + 1; /* Copy in case of syntax error in set. */
|
||||
if(setcharset(&pp, charset)) {
|
||||
int found = FALSE;
|
||||
if(!*s)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
if(charset[(unsigned int)*s])
|
||||
found = TRUE;
|
||||
else if(charset[CURLFNM_ALNUM])
|
||||
found = ISALNUM(*s);
|
||||
else if(charset[CURLFNM_ALPHA])
|
||||
found = ISALPHA(*s);
|
||||
else if(charset[CURLFNM_DIGIT])
|
||||
found = ISDIGIT(*s);
|
||||
else if(charset[CURLFNM_XDIGIT])
|
||||
found = ISXDIGIT(*s);
|
||||
else if(charset[CURLFNM_PRINT])
|
||||
found = ISPRINT(*s);
|
||||
else if(charset[CURLFNM_SPACE])
|
||||
found = ISSPACE(*s);
|
||||
else if(charset[CURLFNM_UPPER])
|
||||
found = ISUPPER(*s);
|
||||
else if(charset[CURLFNM_LOWER])
|
||||
found = ISLOWER(*s);
|
||||
else if(charset[CURLFNM_BLANK])
|
||||
found = ISBLANK(*s);
|
||||
else if(charset[CURLFNM_GRAPH])
|
||||
found = ISGRAPH(*s);
|
||||
|
||||
if(charset[CURLFNM_NEGATE])
|
||||
found = !found;
|
||||
|
||||
if(!found)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
p = pp + 1;
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
return CURL_FNMATCH_FAIL;
|
||||
|
||||
/* Syntax error in set: this must be taken as a regular character. */
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if(*p++ != *s++)
|
||||
return CURL_FNMATCH_NOMATCH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2011 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2011 - 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
|
||||
@ -27,6 +27,11 @@
|
||||
#include "curl_gssapi.h"
|
||||
#include "sendf.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
static char spnego_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02";
|
||||
gss_OID_desc Curl_spnego_mech_oid = { 6, &spnego_oid_bytes };
|
||||
static char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02";
|
||||
|
@ -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
|
||||
@ -44,17 +44,18 @@
|
||||
void *
|
||||
Curl_memrchr(const void *s, int c, size_t n)
|
||||
{
|
||||
const unsigned char *p = s;
|
||||
const unsigned char *q = s;
|
||||
if(n > 0) {
|
||||
const unsigned char *p = s;
|
||||
const unsigned char *q = s;
|
||||
|
||||
p += n - 1;
|
||||
p += n - 1;
|
||||
|
||||
while(p >= q) {
|
||||
if(*p == (unsigned char)c)
|
||||
return (void *)p;
|
||||
p--;
|
||||
while(p >= q) {
|
||||
if(*p == (unsigned char)c)
|
||||
return (void *)p;
|
||||
p--;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
@ -646,15 +646,6 @@ CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#ifndef SIZE_T_MAX
|
||||
/* some limits.h headers have this defined, some don't */
|
||||
#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
|
||||
#define SIZE_T_MAX 18446744073709551615U
|
||||
#else
|
||||
#define SIZE_T_MAX 4294967295U
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode
|
||||
* (uppercase UserName + Domain) as the data
|
||||
*/
|
||||
@ -754,12 +745,10 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
|
||||
len = NTLM_HMAC_MD5_LEN + NTLMv2_BLOB_LEN;
|
||||
|
||||
/* Allocate the response */
|
||||
ptr = malloc(len);
|
||||
ptr = calloc(1, len);
|
||||
if(!ptr)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
memset(ptr, 0, len);
|
||||
|
||||
/* Create the BLOB structure */
|
||||
snprintf((char *)ptr + NTLM_HMAC_MD5_LEN, NTLMv2_BLOB_LEN,
|
||||
"%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */
|
||||
|
@ -364,7 +364,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
|
||||
case NTLMSTATE_TYPE1:
|
||||
default:
|
||||
/* Use Samba's 'winbind' daemon to support NTLM authentication,
|
||||
* by delegating the NTLM challenge/response protocal to a helper
|
||||
* by delegating the NTLM challenge/response protocol to a helper
|
||||
* in ntlm_auth.
|
||||
* http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
|
||||
* https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
|
||||
|
@ -1,3 +1,5 @@
|
||||
#ifndef HEADER_CURL_PATH_H
|
||||
#define HEADER_CURL_PATH_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
@ -5,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
|
||||
@ -42,3 +44,4 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
|
||||
char **path);
|
||||
|
||||
CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir);
|
||||
#endif
|
||||
|
95
Utilities/cmcurl/lib/curl_range.c
Normal file
95
Utilities/cmcurl/lib/curl_range.c
Normal file
@ -0,0 +1,95 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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 <curl/curl.h>
|
||||
#include "curl_range.h"
|
||||
#include "sendf.h"
|
||||
#include "strtoofft.h"
|
||||
|
||||
/* Only include this function if one or more of FTP, FILE are enabled. */
|
||||
#if !defined(CURL_DISABLE_FTP) || !defined(CURL_DISABLE_FILE)
|
||||
|
||||
/*
|
||||
Check if this is a range download, and if so, set the internal variables
|
||||
properly.
|
||||
*/
|
||||
CURLcode Curl_range(struct connectdata *conn)
|
||||
{
|
||||
curl_off_t from, to;
|
||||
char *ptr;
|
||||
char *ptr2;
|
||||
struct Curl_easy *data = conn->data;
|
||||
|
||||
if(data->state.use_range && data->state.range) {
|
||||
CURLofft from_t;
|
||||
CURLofft to_t;
|
||||
from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
|
||||
if(from_t == CURL_OFFT_FLOW)
|
||||
return CURLE_RANGE_ERROR;
|
||||
while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
|
||||
ptr++;
|
||||
to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
|
||||
if(to_t == CURL_OFFT_FLOW)
|
||||
return CURLE_RANGE_ERROR;
|
||||
if((to_t == CURL_OFFT_INVAL) && !from_t) {
|
||||
/* X - */
|
||||
data->state.resume_from = from;
|
||||
DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n",
|
||||
from));
|
||||
}
|
||||
else if((from_t == CURL_OFFT_INVAL) && !to_t) {
|
||||
/* -Y */
|
||||
data->req.maxdownload = to;
|
||||
data->state.resume_from = -to;
|
||||
DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n",
|
||||
to));
|
||||
}
|
||||
else {
|
||||
/* X-Y */
|
||||
curl_off_t totalsize;
|
||||
|
||||
/* Ensure the range is sensible - to should follow from. */
|
||||
if(from > to)
|
||||
return CURLE_RANGE_ERROR;
|
||||
|
||||
totalsize = to - from;
|
||||
if(totalsize == CURL_OFF_T_MAX)
|
||||
return CURLE_RANGE_ERROR;
|
||||
|
||||
data->req.maxdownload = totalsize + 1; /* include last byte */
|
||||
data->state.resume_from = from;
|
||||
DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T
|
||||
" getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
|
||||
from, data->req.maxdownload));
|
||||
}
|
||||
DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T
|
||||
" to %" CURL_FORMAT_CURL_OFF_T ", totally %"
|
||||
CURL_FORMAT_CURL_OFF_T " bytes\n",
|
||||
from, to, data->req.maxdownload));
|
||||
}
|
||||
else
|
||||
data->req.maxdownload = -1;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#endif
|
30
Utilities/cmcurl/lib/curl_range.h
Normal file
30
Utilities/cmcurl/lib/curl_range.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef HEADER_CURL_RANGE_H
|
||||
#define HEADER_CURL_RANGE_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"
|
||||
#include "urldata.h"
|
||||
|
||||
CURLcode Curl_range(struct connectdata *conn);
|
||||
|
||||
#endif /* HEADER_CURL_RANGE_H */
|
@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2012 - 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
|
||||
@ -265,7 +265,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
|
||||
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
|
||||
conn->host.name;
|
||||
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
|
||||
#if defined(USE_KERBEROS5)
|
||||
#if defined(USE_KERBEROS5) || defined(USE_NTLM)
|
||||
const char *service = data->set.str[STRING_SERVICE_NAME] ?
|
||||
data->set.str[STRING_SERVICE_NAME] :
|
||||
sasl->params->service;
|
||||
@ -333,7 +333,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
|
||||
if(force_ir || data->set.sasl_ir)
|
||||
result = Curl_auth_create_ntlm_type1_message(data,
|
||||
conn->user, conn->passwd,
|
||||
&conn->ntlm, &resp, &len);
|
||||
service,
|
||||
hostname,
|
||||
&conn->ntlm, &resp,
|
||||
&len);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -361,15 +364,6 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
|
||||
conn->oauth_bearer,
|
||||
&resp, &len);
|
||||
}
|
||||
else if(enabledmechs & SASL_MECH_LOGIN) {
|
||||
mech = SASL_MECH_STRING_LOGIN;
|
||||
state1 = SASL_LOGIN;
|
||||
state2 = SASL_LOGIN_PASSWD;
|
||||
sasl->authused = SASL_MECH_LOGIN;
|
||||
|
||||
if(force_ir || data->set.sasl_ir)
|
||||
result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
|
||||
}
|
||||
else if(enabledmechs & SASL_MECH_PLAIN) {
|
||||
mech = SASL_MECH_STRING_PLAIN;
|
||||
state1 = SASL_PLAIN;
|
||||
@ -379,6 +373,15 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
|
||||
result = Curl_auth_create_plain_message(data, conn->user, conn->passwd,
|
||||
&resp, &len);
|
||||
}
|
||||
else if(enabledmechs & SASL_MECH_LOGIN) {
|
||||
mech = SASL_MECH_STRING_LOGIN;
|
||||
state1 = SASL_LOGIN;
|
||||
state2 = SASL_LOGIN_PASSWD;
|
||||
sasl->authused = SASL_MECH_LOGIN;
|
||||
|
||||
if(force_ir || data->set.sasl_ir)
|
||||
result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
|
||||
}
|
||||
}
|
||||
|
||||
if(!result && mech) {
|
||||
@ -419,13 +422,11 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
|
||||
char *chlg = NULL;
|
||||
size_t chlglen = 0;
|
||||
#endif
|
||||
#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5)
|
||||
#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
|
||||
defined(USE_NTLM)
|
||||
const char *service = data->set.str[STRING_SERVICE_NAME] ?
|
||||
data->set.str[STRING_SERVICE_NAME] :
|
||||
sasl->params->service;
|
||||
#endif
|
||||
#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
|
||||
defined(USE_NTLM)
|
||||
char *serverdata;
|
||||
#endif
|
||||
size_t len = 0;
|
||||
@ -496,6 +497,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
|
||||
/* Create the type-1 message */
|
||||
result = Curl_auth_create_ntlm_type1_message(data,
|
||||
conn->user, conn->passwd,
|
||||
service, hostname,
|
||||
&conn->ntlm, &resp, &len);
|
||||
newstate = SASL_NTLM_TYPE2MSG;
|
||||
break;
|
||||
|
@ -404,6 +404,11 @@
|
||||
# define LSEEK_ERROR (off_t)-1
|
||||
#endif
|
||||
|
||||
#ifndef SIZEOF_TIME_T
|
||||
/* assume default size of time_t to be 32 bit */
|
||||
#define SIZEOF_TIME_T 4
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Default sizeof(off_t) in case it hasn't been defined in config file.
|
||||
*/
|
||||
@ -439,6 +444,33 @@
|
||||
#endif
|
||||
#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1))
|
||||
|
||||
#if (SIZEOF_TIME_T == 4)
|
||||
# ifdef HAVE_TIME_T_UNSIGNED
|
||||
# define TIME_T_MAX UINT_MAX
|
||||
# define TIME_T_MIN 0
|
||||
# else
|
||||
# define TIME_T_MAX INT_MAX
|
||||
# define TIME_T_MIN INT_MIN
|
||||
# endif
|
||||
#else
|
||||
# ifdef HAVE_TIME_T_UNSIGNED
|
||||
# define TIME_T_MAX 0xFFFFFFFFFFFFFFFF
|
||||
# define TIME_T_MIN 0
|
||||
# else
|
||||
# define TIME_T_MAX 0x7FFFFFFFFFFFFFFF
|
||||
# define TIME_T_MIN (-TIME_T_MAX - 1)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SIZE_T_MAX
|
||||
/* some limits.h headers have this defined, some don't */
|
||||
#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
|
||||
#define SIZE_T_MAX 18446744073709551615U
|
||||
#else
|
||||
#define SIZE_T_MAX 4294967295U
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Arg 2 type for gethostname in case it hasn't been defined in config file.
|
||||
*/
|
||||
@ -622,11 +654,6 @@ int netware_init(void);
|
||||
#error "Both libidn2 and WinIDN are enabled, choose one."
|
||||
#endif
|
||||
|
||||
#ifndef SIZEOF_TIME_T
|
||||
/* assume default size of time_t to be 32 bit */
|
||||
#define SIZEOF_TIME_T 4
|
||||
#endif
|
||||
|
||||
#define LIBIDN_REQUIRED_VERSION "0.4.1"
|
||||
|
||||
#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \
|
||||
@ -766,11 +793,11 @@ endings either CRLF or LF so 't' is appropriate.
|
||||
# if defined(WIN32) || defined(__CYGWIN__)
|
||||
# define USE_RECV_BEFORE_SEND_WORKAROUND
|
||||
# endif
|
||||
#else /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */
|
||||
#else /* DONT_USE_RECV_BEFORE_SEND_WORKAROUND */
|
||||
# ifdef USE_RECV_BEFORE_SEND_WORKAROUND
|
||||
# undef USE_RECV_BEFORE_SEND_WORKAROUND
|
||||
# endif
|
||||
#endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */
|
||||
#endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUND */
|
||||
|
||||
/* Detect Windows App environment which has a restricted access
|
||||
* to the Win32 APIs. */
|
||||
@ -783,4 +810,9 @@ endings either CRLF or LF so 't' is appropriate.
|
||||
# endif
|
||||
# endif
|
||||
|
||||
/* for systems that don't detect this in configure, use a sensible default */
|
||||
#ifndef CURL_SA_FAMILY_T
|
||||
#define CURL_SA_FAMILY_T unsigned short
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_SETUP_H */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2013, 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
|
||||
@ -101,7 +101,6 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Definition of timeval struct for platforms that don't have it.
|
||||
*/
|
||||
@ -274,25 +273,6 @@ struct timeval {
|
||||
# define sfcntl fcntl
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Uppercase macro versions of ANSI/ISO is*() functions/macros which
|
||||
* avoid negative number inputs with argument byte codes > 127.
|
||||
*/
|
||||
|
||||
#define ISSPACE(x) (isspace((int) ((unsigned char)x)))
|
||||
#define ISDIGIT(x) (isdigit((int) ((unsigned char)x)))
|
||||
#define ISALNUM(x) (isalnum((int) ((unsigned char)x)))
|
||||
#define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
|
||||
#define ISGRAPH(x) (isgraph((int) ((unsigned char)x)))
|
||||
#define ISALPHA(x) (isalpha((int) ((unsigned char)x)))
|
||||
#define ISPRINT(x) (isprint((int) ((unsigned char)x)))
|
||||
#define ISUPPER(x) (isupper((int) ((unsigned char)x)))
|
||||
#define ISLOWER(x) (islower((int) ((unsigned char)x)))
|
||||
#define ISASCII(x) (isascii((int) ((unsigned char)x)))
|
||||
|
||||
#define ISBLANK(x) (int)((((unsigned char)x) == ' ') || \
|
||||
(((unsigned char)x) == '\t'))
|
||||
|
||||
#define TOLOWER(x) (tolower((int) ((unsigned char)x)))
|
||||
|
||||
|
||||
@ -347,6 +327,7 @@ struct timeval {
|
||||
#define FALSE false
|
||||
#endif
|
||||
|
||||
#include "curl_ctype.h"
|
||||
|
||||
/*
|
||||
* Macro WHILE_FALSE may be used to build single-iteration do-while loops,
|
||||
|
@ -61,6 +61,7 @@
|
||||
#include "strdup.h"
|
||||
#include "progress.h"
|
||||
#include "easyif.h"
|
||||
#include "multiif.h"
|
||||
#include "select.h"
|
||||
#include "sendf.h" /* for failf function prototype */
|
||||
#include "connect.h" /* for Curl_getconnectinfo */
|
||||
@ -73,6 +74,7 @@
|
||||
#include "sigpipe.h"
|
||||
#include "ssh.h"
|
||||
#include "setopt.h"
|
||||
#include "http_digest.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
@ -744,6 +746,10 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
|
||||
if(!data)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
|
||||
if(data->set.errorbuffer)
|
||||
/* clear this as early as possible */
|
||||
data->set.errorbuffer[0] = 0;
|
||||
|
||||
if(data->multi) {
|
||||
failf(data, "easy handle already used in multi handle");
|
||||
return CURLE_FAILED_INIT;
|
||||
@ -760,6 +766,9 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
|
||||
data->multi_easy = multi;
|
||||
}
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLE_RECURSIVE_API_CALL;
|
||||
|
||||
/* Copy the MAXCONNECTS option to the multi handle */
|
||||
curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, data->set.maxconnects);
|
||||
|
||||
@ -883,6 +892,9 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
|
||||
/* Duplicate mime data. */
|
||||
result = Curl_mime_duppart(&dst->set.mimepost, &src->set.mimepost);
|
||||
|
||||
if(src->set.resolve)
|
||||
dst->change.resolve = dst->set.resolve;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1017,6 +1029,7 @@ void curl_easy_reset(struct Curl_easy *data)
|
||||
/* zero out authentication data: */
|
||||
memset(&data->state.authhost, 0, sizeof(struct auth));
|
||||
memset(&data->state.authproxy, 0, sizeof(struct auth));
|
||||
Curl_digest_cleanup(data);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1028,6 +1041,9 @@ void curl_easy_reset(struct Curl_easy *data)
|
||||
* the pausing, you may get your write callback called at this point.
|
||||
*
|
||||
* Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
|
||||
*
|
||||
* NOTE: This is one of few API functions that are allowed to be called from
|
||||
* within a callback.
|
||||
*/
|
||||
CURLcode curl_easy_pause(struct Curl_easy *data, int action)
|
||||
{
|
||||
@ -1070,10 +1086,8 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
|
||||
/* even if one function returns error, this loops through and frees all
|
||||
buffers */
|
||||
if(!result)
|
||||
result = Curl_client_chop_write(conn,
|
||||
writebuf[i].type,
|
||||
writebuf[i].buf,
|
||||
writebuf[i].len);
|
||||
result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf,
|
||||
writebuf[i].len);
|
||||
free(writebuf[i].buf);
|
||||
}
|
||||
|
||||
@ -1092,6 +1106,10 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
|
||||
(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) )
|
||||
Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
|
||||
|
||||
/* This transfer may have been moved in or out of the bundle, update
|
||||
the corresponding socket callback, if used */
|
||||
Curl_updatesocket(data);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1132,6 +1150,9 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
|
||||
ssize_t n1;
|
||||
struct connectdata *c;
|
||||
|
||||
if(Curl_is_in_callback(data))
|
||||
return CURLE_RECURSIVE_API_CALL;
|
||||
|
||||
result = easy_connection(data, &sfd, &c);
|
||||
if(result)
|
||||
return result;
|
||||
@ -1159,6 +1180,9 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
|
||||
ssize_t n1;
|
||||
struct connectdata *c = NULL;
|
||||
|
||||
if(Curl_is_in_callback(data))
|
||||
return CURLE_RECURSIVE_API_CALL;
|
||||
|
||||
result = easy_connection(data, &sfd, &c);
|
||||
if(result)
|
||||
return result;
|
||||
|
@ -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
|
||||
@ -61,6 +61,7 @@
|
||||
#include "url.h"
|
||||
#include "parsedate.h" /* for the week day and month names */
|
||||
#include "warnless.h"
|
||||
#include "curl_range.h"
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
#include "curl_memory.h"
|
||||
@ -125,65 +126,6 @@ static CURLcode file_setup_connection(struct connectdata *conn)
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Check if this is a range download, and if so, set the internal variables
|
||||
properly. This code is copied from the FTP implementation and might as
|
||||
well be factored out.
|
||||
*/
|
||||
static CURLcode file_range(struct connectdata *conn)
|
||||
{
|
||||
curl_off_t from, to;
|
||||
curl_off_t totalsize = -1;
|
||||
char *ptr;
|
||||
char *ptr2;
|
||||
struct Curl_easy *data = conn->data;
|
||||
|
||||
if(data->state.use_range && data->state.range) {
|
||||
CURLofft from_t;
|
||||
CURLofft to_t;
|
||||
from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
|
||||
if(from_t == CURL_OFFT_FLOW)
|
||||
return CURLE_RANGE_ERROR;
|
||||
while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
|
||||
ptr++;
|
||||
to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
|
||||
if(to_t == CURL_OFFT_FLOW)
|
||||
return CURLE_RANGE_ERROR;
|
||||
if((to_t == CURL_OFFT_INVAL) && !from_t) {
|
||||
/* X - */
|
||||
data->state.resume_from = from;
|
||||
DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n",
|
||||
from));
|
||||
}
|
||||
else if((from_t == CURL_OFFT_INVAL) && !to_t) {
|
||||
/* -Y */
|
||||
data->req.maxdownload = to;
|
||||
data->state.resume_from = -to;
|
||||
DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n",
|
||||
to));
|
||||
}
|
||||
else {
|
||||
/* X-Y */
|
||||
totalsize = to-from;
|
||||
if(totalsize == CURL_OFF_T_MAX)
|
||||
/* this is too big to increase, so bail out */
|
||||
return CURLE_RANGE_ERROR;
|
||||
data->req.maxdownload = totalsize + 1; /* include last byte */
|
||||
data->state.resume_from = from;
|
||||
DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T
|
||||
" getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
|
||||
from, data->req.maxdownload));
|
||||
}
|
||||
DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T
|
||||
" to %" CURL_FORMAT_CURL_OFF_T ", totally %"
|
||||
CURL_FORMAT_CURL_OFF_T " bytes\n",
|
||||
from, to, data->req.maxdownload));
|
||||
}
|
||||
else
|
||||
data->req.maxdownload = -1;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* file_connect() gets called from Curl_protocol_connect() to allow us to
|
||||
* do protocol-specific actions at connect-time. We emulate a
|
||||
@ -461,12 +403,12 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
|
||||
/* we could stat it, then read out the size */
|
||||
expected_size = statbuf.st_size;
|
||||
/* and store the modification time */
|
||||
data->info.filetime = (long)statbuf.st_mtime;
|
||||
data->info.filetime = statbuf.st_mtime;
|
||||
fstated = TRUE;
|
||||
}
|
||||
|
||||
if(fstated && !data->state.range && data->set.timecondition) {
|
||||
if(!Curl_meets_timecondition(data, (time_t)data->info.filetime)) {
|
||||
if(!Curl_meets_timecondition(data, data->info.filetime)) {
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
@ -514,7 +456,9 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
|
||||
}
|
||||
|
||||
/* Check whether file range has been specified */
|
||||
file_range(conn);
|
||||
result = Curl_range(conn);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* Adjust the start offset in case we want to get the N last bytes
|
||||
* of the stream iff the filesize could be determined */
|
||||
|
@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2010 - 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,14 +33,11 @@ struct fileinfo *Curl_fileinfo_alloc(void)
|
||||
return calloc(1, sizeof(struct fileinfo));
|
||||
}
|
||||
|
||||
void Curl_fileinfo_dtor(void *user, void *element)
|
||||
void Curl_fileinfo_cleanup(struct fileinfo *finfo)
|
||||
{
|
||||
struct fileinfo *finfo = element;
|
||||
(void) user;
|
||||
if(!finfo)
|
||||
return;
|
||||
|
||||
Curl_safefree(finfo->info.b_data);
|
||||
|
||||
free(finfo);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2010, 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2010 - 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
|
||||
@ -31,7 +31,6 @@ struct fileinfo {
|
||||
};
|
||||
|
||||
struct fileinfo *Curl_fileinfo_alloc(void);
|
||||
|
||||
void Curl_fileinfo_dtor(void *, void *);
|
||||
void Curl_fileinfo_cleanup(struct fileinfo *finfo);
|
||||
|
||||
#endif /* HEADER_CURL_FILEINFO_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
|
||||
@ -153,60 +153,6 @@ static FormInfo * AddFormInfo(char *value,
|
||||
return form_info;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* ContentTypeForFilename()
|
||||
*
|
||||
* Provides content type for filename if one of the known types (else
|
||||
* (either the prevtype or the default is returned).
|
||||
*
|
||||
* Returns some valid contenttype for filename.
|
||||
*
|
||||
***************************************************************************/
|
||||
static const char *ContentTypeForFilename(const char *filename,
|
||||
const char *prevtype)
|
||||
{
|
||||
const char *contenttype = NULL;
|
||||
unsigned int i;
|
||||
/*
|
||||
* No type was specified, we scan through a few well-known
|
||||
* extensions and pick the first we match!
|
||||
*/
|
||||
struct ContentType {
|
||||
const char *extension;
|
||||
const char *type;
|
||||
};
|
||||
static const struct ContentType ctts[]={
|
||||
{".gif", "image/gif"},
|
||||
{".jpg", "image/jpeg"},
|
||||
{".jpeg", "image/jpeg"},
|
||||
{".txt", "text/plain"},
|
||||
{".html", "text/html"},
|
||||
{".xml", "application/xml"}
|
||||
};
|
||||
|
||||
if(prevtype)
|
||||
/* default to the previously set/used! */
|
||||
contenttype = prevtype;
|
||||
else
|
||||
contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
|
||||
|
||||
if(filename) { /* in case a NULL was passed in */
|
||||
for(i = 0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
|
||||
if(strlen(filename) >= strlen(ctts[i].extension)) {
|
||||
if(strcasecompare(filename +
|
||||
strlen(filename) - strlen(ctts[i].extension),
|
||||
ctts[i].extension)) {
|
||||
contenttype = ctts[i].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we have a contenttype by now */
|
||||
return contenttype;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FormAdd()
|
||||
@ -627,9 +573,15 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
|
||||
!form->contenttype) {
|
||||
char *f = form->flags & HTTPPOST_BUFFER?
|
||||
form->showfilename : form->value;
|
||||
char const *type;
|
||||
type = Curl_mime_contenttype(f);
|
||||
if(!type)
|
||||
type = prevtype;
|
||||
if(!type)
|
||||
type = FILE_CONTENTTYPE_DEFAULT;
|
||||
|
||||
/* our contenttype is missing */
|
||||
form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
|
||||
form->contenttype = strdup(type);
|
||||
if(!form->contenttype) {
|
||||
return_value = CURL_FORMADD_MEMORY;
|
||||
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
|
||||
@ -59,6 +59,7 @@
|
||||
#include "ftp.h"
|
||||
#include "fileinfo.h"
|
||||
#include "ftplistparser.h"
|
||||
#include "curl_range.h"
|
||||
#include "curl_sec.h"
|
||||
#include "strtoofft.h"
|
||||
#include "strcase.h"
|
||||
@ -310,9 +311,11 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
|
||||
int error = 0;
|
||||
|
||||
/* activate callback for setting socket options */
|
||||
Curl_set_in_callback(data, true);
|
||||
error = data->set.fsockopt(data->set.sockopt_client,
|
||||
s,
|
||||
CURLSOCKTYPE_ACCEPT);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
if(error) {
|
||||
close_secondarysocket(conn);
|
||||
@ -1471,7 +1474,7 @@ static CURLcode ftp_state_list(struct connectdata *conn)
|
||||
slashPos = strrchr(inpath, '/');
|
||||
n = slashPos - inpath;
|
||||
}
|
||||
result = Curl_urldecode(data, inpath, n, &lstArg, NULL, FALSE);
|
||||
result = Curl_urldecode(data, inpath, n, &lstArg, NULL, TRUE);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
@ -1535,7 +1538,7 @@ static CURLcode ftp_state_type(struct connectdata *conn)
|
||||
date. */
|
||||
if(data->set.opt_no_body && ftpc->file &&
|
||||
ftp_need_type(conn, data->set.prefer_ascii)) {
|
||||
/* The SIZE command is _not_ RFC 959 specified, and therefor many servers
|
||||
/* The SIZE command is _not_ RFC 959 specified, and therefore many servers
|
||||
may not support it! It is however the only way we have to get a file's
|
||||
size! */
|
||||
|
||||
@ -1615,8 +1618,10 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
|
||||
|
||||
/* Let's read off the proper amount of bytes from the input. */
|
||||
if(conn->seek_func) {
|
||||
Curl_set_in_callback(data, true);
|
||||
seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
|
||||
SEEK_SET);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
|
||||
if(seekerr != CURL_SEEKFUNC_OK) {
|
||||
@ -1783,7 +1788,7 @@ static CURLcode ftp_epsv_disable(struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(conn->bits.ipv6) {
|
||||
if(conn->bits.ipv6 && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)) {
|
||||
/* We can't disable EPSV when doing IPv6, so this is instead a fail */
|
||||
failf(conn->data, "Failed EPSV attempt, exiting\n");
|
||||
return CURLE_WEIRD_SERVER_REPLY;
|
||||
@ -1905,13 +1910,13 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||||
if(data->set.ftp_skip_ip) {
|
||||
/* told to ignore the remotely given IP but instead use the host we used
|
||||
for the control connection */
|
||||
infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
|
||||
infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead\n",
|
||||
ip[0], ip[1], ip[2], ip[3],
|
||||
conn->host.name);
|
||||
ftpc->newhost = strdup(control_address(conn));
|
||||
}
|
||||
else
|
||||
ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
|
||||
ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
|
||||
|
||||
if(!ftpc->newhost)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
@ -2060,7 +2065,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
|
||||
"%04d%02d%02d %02d:%02d:%02d GMT",
|
||||
year, month, day, hour, minute, second);
|
||||
/* now, convert this into a time() value: */
|
||||
data->info.filetime = (long)curl_getdate(timebuf, &secs);
|
||||
data->info.filetime = curl_getdate(timebuf, &secs);
|
||||
}
|
||||
|
||||
#ifdef CURL_FTP_HTTPSTYLE_HEAD
|
||||
@ -2072,7 +2077,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
|
||||
data->set.get_filetime &&
|
||||
(data->info.filetime >= 0) ) {
|
||||
char headerbuf[128];
|
||||
time_t filetime = (time_t)data->info.filetime;
|
||||
time_t filetime = data->info.filetime;
|
||||
struct tm buffer;
|
||||
const struct tm *tm = &buffer;
|
||||
|
||||
@ -3180,14 +3185,16 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
|
||||
|
||||
if(data->state.wildcardmatch) {
|
||||
if(data->set.chunk_end && ftpc->file) {
|
||||
Curl_set_in_callback(data, true);
|
||||
data->set.chunk_end(data->wildcard.customptr);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
ftpc->known_filesize = -1;
|
||||
}
|
||||
|
||||
if(!result)
|
||||
/* get the "raw" path */
|
||||
result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE);
|
||||
result = Curl_urldecode(data, path_to_use, 0, &path, NULL, TRUE);
|
||||
if(result) {
|
||||
/* We can limp along anyway (and should try to since we may already be in
|
||||
* the error path) */
|
||||
@ -3462,62 +3469,6 @@ ftp_pasv_verbose(struct connectdata *conn,
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Check if this is a range download, and if so, set the internal variables
|
||||
properly.
|
||||
*/
|
||||
|
||||
static CURLcode ftp_range(struct connectdata *conn)
|
||||
{
|
||||
curl_off_t from, to;
|
||||
char *ptr;
|
||||
struct Curl_easy *data = conn->data;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
|
||||
if(data->state.use_range && data->state.range) {
|
||||
CURLofft from_t;
|
||||
CURLofft to_t;
|
||||
from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
|
||||
if(from_t == CURL_OFFT_FLOW)
|
||||
return CURLE_RANGE_ERROR;
|
||||
while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
|
||||
ptr++;
|
||||
to_t = curlx_strtoofft(ptr, NULL, 0, &to);
|
||||
if(to_t == CURL_OFFT_FLOW)
|
||||
return CURLE_RANGE_ERROR;
|
||||
if((to_t == CURL_OFFT_INVAL) && !from_t) {
|
||||
/* X - */
|
||||
data->state.resume_from = from;
|
||||
DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
|
||||
" to end of file\n", from));
|
||||
}
|
||||
else if(!to_t && (from_t == CURL_OFFT_INVAL)) {
|
||||
/* -Y */
|
||||
data->req.maxdownload = to;
|
||||
data->state.resume_from = -to;
|
||||
DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
|
||||
" bytes\n", to));
|
||||
}
|
||||
else {
|
||||
/* X-Y */
|
||||
data->req.maxdownload = (to - from) + 1; /* include last byte */
|
||||
data->state.resume_from = from;
|
||||
DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
|
||||
" getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
|
||||
from, data->req.maxdownload));
|
||||
}
|
||||
DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
|
||||
" to %" CURL_FORMAT_CURL_OFF_T ", totally %"
|
||||
CURL_FORMAT_CURL_OFF_T " bytes\n",
|
||||
from, to, data->req.maxdownload));
|
||||
ftpc->dont_check = TRUE; /* don't check for successful transfer */
|
||||
}
|
||||
else
|
||||
data->req.maxdownload = -1;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ftp_do_more()
|
||||
*
|
||||
@ -3640,7 +3591,13 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
|
||||
/* download */
|
||||
ftp->downloadsize = -1; /* unknown as of yet */
|
||||
|
||||
result = ftp_range(conn);
|
||||
result = Curl_range(conn);
|
||||
|
||||
if(result == CURLE_OK && data->req.maxdownload >= 0) {
|
||||
/* Don't check for successful transfer */
|
||||
ftpc->dont_check = TRUE;
|
||||
}
|
||||
|
||||
if(result)
|
||||
;
|
||||
else if(data->set.ftp_list_only || !ftpc->file) {
|
||||
@ -3731,10 +3688,10 @@ CURLcode ftp_perform(struct connectdata *conn,
|
||||
|
||||
static void wc_data_dtor(void *ptr)
|
||||
{
|
||||
struct ftp_wc_tmpdata *tmp = ptr;
|
||||
if(tmp)
|
||||
Curl_ftp_parselist_data_free(&tmp->parser);
|
||||
free(tmp);
|
||||
struct ftp_wc *ftpwc = ptr;
|
||||
if(ftpwc && ftpwc->parser)
|
||||
Curl_ftp_parselist_data_free(&ftpwc->parser);
|
||||
free(ftpwc);
|
||||
}
|
||||
|
||||
static CURLcode init_wc_data(struct connectdata *conn)
|
||||
@ -3743,7 +3700,7 @@ static CURLcode init_wc_data(struct connectdata *conn)
|
||||
char *path = conn->data->state.path;
|
||||
struct WildcardData *wildcard = &(conn->data->wildcard);
|
||||
CURLcode result = CURLE_OK;
|
||||
struct ftp_wc_tmpdata *ftp_tmp;
|
||||
struct ftp_wc *ftpwc = NULL;
|
||||
|
||||
last_slash = strrchr(conn->data->state.path, '/');
|
||||
if(last_slash) {
|
||||
@ -3775,23 +3732,22 @@ static CURLcode init_wc_data(struct connectdata *conn)
|
||||
/* program continues only if URL is not ending with slash, allocate needed
|
||||
resources for wildcard transfer */
|
||||
|
||||
/* allocate ftp protocol specific temporary wildcard data */
|
||||
ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
|
||||
if(!ftp_tmp) {
|
||||
Curl_safefree(wildcard->pattern);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
/* allocate ftp protocol specific wildcard data */
|
||||
ftpwc = calloc(1, sizeof(struct ftp_wc));
|
||||
if(!ftpwc) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* INITIALIZE parselist structure */
|
||||
ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
|
||||
if(!ftp_tmp->parser) {
|
||||
Curl_safefree(wildcard->pattern);
|
||||
free(ftp_tmp);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
ftpwc->parser = Curl_ftp_parselist_data_alloc();
|
||||
if(!ftpwc->parser) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
|
||||
wildcard->tmp_dtor = wc_data_dtor;
|
||||
wildcard->protdata = ftpwc; /* put it to the WildcardData tmp pointer */
|
||||
wildcard->dtor = wc_data_dtor;
|
||||
|
||||
/* wildcard does not support NOCWD option (assert it?) */
|
||||
if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
|
||||
@ -3800,33 +3756,36 @@ static CURLcode init_wc_data(struct connectdata *conn)
|
||||
/* try to parse ftp url */
|
||||
result = ftp_parse_url_path(conn);
|
||||
if(result) {
|
||||
Curl_safefree(wildcard->pattern);
|
||||
wildcard->tmp_dtor(wildcard->tmp);
|
||||
wildcard->tmp_dtor = ZERO_NULL;
|
||||
wildcard->tmp = NULL;
|
||||
return result;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wildcard->path = strdup(conn->data->state.path);
|
||||
if(!wildcard->path) {
|
||||
Curl_safefree(wildcard->pattern);
|
||||
wildcard->tmp_dtor(wildcard->tmp);
|
||||
wildcard->tmp_dtor = ZERO_NULL;
|
||||
wildcard->tmp = NULL;
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* backup old write_function */
|
||||
ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
|
||||
ftpwc->backup.write_function = conn->data->set.fwrite_func;
|
||||
/* parsing write function */
|
||||
conn->data->set.fwrite_func = Curl_ftp_parselist;
|
||||
/* backup old file descriptor */
|
||||
ftp_tmp->backup.file_descriptor = conn->data->set.out;
|
||||
ftpwc->backup.file_descriptor = conn->data->set.out;
|
||||
/* let the writefunc callback know what curl pointer is working with */
|
||||
conn->data->set.out = conn;
|
||||
|
||||
infof(conn->data, "Wildcard - Parsing started\n");
|
||||
return CURLE_OK;
|
||||
|
||||
fail:
|
||||
if(ftpwc) {
|
||||
Curl_ftp_parselist_data_free(&ftpwc->parser);
|
||||
free(ftpwc);
|
||||
}
|
||||
Curl_safefree(wildcard->pattern);
|
||||
wildcard->dtor = ZERO_NULL;
|
||||
wildcard->protdata = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* This is called recursively */
|
||||
@ -3847,14 +3806,14 @@ static CURLcode wc_statemach(struct connectdata *conn)
|
||||
case CURLWC_MATCHING: {
|
||||
/* In this state is LIST response successfully parsed, so lets restore
|
||||
previous WRITEFUNCTION callback and WRITEDATA pointer */
|
||||
struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
|
||||
conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
|
||||
conn->data->set.out = ftp_tmp->backup.file_descriptor;
|
||||
ftp_tmp->backup.write_function = ZERO_NULL;
|
||||
ftp_tmp->backup.file_descriptor = NULL;
|
||||
struct ftp_wc *ftpwc = wildcard->protdata;
|
||||
conn->data->set.fwrite_func = ftpwc->backup.write_function;
|
||||
conn->data->set.out = ftpwc->backup.file_descriptor;
|
||||
ftpwc->backup.write_function = ZERO_NULL;
|
||||
ftpwc->backup.file_descriptor = NULL;
|
||||
wildcard->state = CURLWC_DOWNLOADING;
|
||||
|
||||
if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
|
||||
if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
|
||||
/* error found in LIST parsing */
|
||||
wildcard->state = CURLWC_CLEAN;
|
||||
return wc_statemach(conn);
|
||||
@ -3884,8 +3843,11 @@ static CURLcode wc_statemach(struct connectdata *conn)
|
||||
|
||||
infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
|
||||
if(conn->data->set.chunk_bgn) {
|
||||
long userresponse = conn->data->set.chunk_bgn(
|
||||
long userresponse;
|
||||
Curl_set_in_callback(conn->data, true);
|
||||
userresponse = conn->data->set.chunk_bgn(
|
||||
finfo, wildcard->customptr, (int)wildcard->filelist.size);
|
||||
Curl_set_in_callback(conn->data, false);
|
||||
switch(userresponse) {
|
||||
case CURL_CHUNK_BGN_FUNC_SKIP:
|
||||
infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
|
||||
@ -3921,8 +3883,11 @@ static CURLcode wc_statemach(struct connectdata *conn)
|
||||
} break;
|
||||
|
||||
case CURLWC_SKIP: {
|
||||
if(conn->data->set.chunk_end)
|
||||
if(conn->data->set.chunk_end) {
|
||||
Curl_set_in_callback(conn->data, true);
|
||||
conn->data->set.chunk_end(conn->data->wildcard.customptr);
|
||||
Curl_set_in_callback(conn->data, false);
|
||||
}
|
||||
Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
|
||||
wildcard->state = (wildcard->filelist.size == 0) ?
|
||||
CURLWC_CLEAN : CURLWC_DOWNLOADING;
|
||||
@ -3930,10 +3895,10 @@ static CURLcode wc_statemach(struct connectdata *conn)
|
||||
}
|
||||
|
||||
case CURLWC_CLEAN: {
|
||||
struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
|
||||
struct ftp_wc *ftpwc = wildcard->protdata;
|
||||
result = CURLE_OK;
|
||||
if(ftp_tmp)
|
||||
result = Curl_ftp_parselist_geterror(ftp_tmp->parser);
|
||||
if(ftpwc)
|
||||
result = Curl_ftp_parselist_geterror(ftpwc->parser);
|
||||
|
||||
wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
|
||||
} break;
|
||||
@ -3941,6 +3906,8 @@ static CURLcode wc_statemach(struct connectdata *conn)
|
||||
case CURLWC_DONE:
|
||||
case CURLWC_ERROR:
|
||||
case CURLWC_CLEAR:
|
||||
if(wildcard->dtor)
|
||||
wildcard->dtor(wildcard->protdata);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4193,7 +4160,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
|
||||
result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/",
|
||||
slash_pos ? dirlen : 1,
|
||||
&ftpc->dirs[0], NULL,
|
||||
FALSE);
|
||||
TRUE);
|
||||
if(result) {
|
||||
freedirs(ftpc);
|
||||
return result;
|
||||
@ -4300,7 +4267,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, FALSE);
|
||||
Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, TRUE);
|
||||
if(result) {
|
||||
freedirs(ftpc);
|
||||
return result;
|
||||
|
@ -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
|
||||
@ -81,7 +81,7 @@ typedef enum {
|
||||
|
||||
struct ftp_parselist_data; /* defined later in ftplistparser.c */
|
||||
|
||||
struct ftp_wc_tmpdata {
|
||||
struct ftp_wc {
|
||||
struct ftp_parselist_data *parser;
|
||||
|
||||
struct {
|
||||
|
@ -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
|
||||
@ -49,6 +49,7 @@
|
||||
#include "ftplistparser.h"
|
||||
#include "curl_fnmatch.h"
|
||||
#include "curl_memory.h"
|
||||
#include "multiif.h"
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
@ -184,10 +185,13 @@ struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
|
||||
}
|
||||
|
||||
|
||||
void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
|
||||
void Curl_ftp_parselist_data_free(struct ftp_parselist_data **parserp)
|
||||
{
|
||||
free(*pl_data);
|
||||
*pl_data = NULL;
|
||||
struct ftp_parselist_data *parser = *parserp;
|
||||
if(parser)
|
||||
Curl_fileinfo_cleanup(parser->file_data);
|
||||
free(parser);
|
||||
*parserp = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -269,9 +273,9 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
|
||||
{
|
||||
curl_fnmatch_callback compare;
|
||||
struct WildcardData *wc = &conn->data->wildcard;
|
||||
struct ftp_wc_tmpdata *tmpdata = wc->tmp;
|
||||
struct ftp_wc *ftpwc = wc->protdata;
|
||||
struct curl_llist *llist = &wc->filelist;
|
||||
struct ftp_parselist_data *parser = tmpdata->parser;
|
||||
struct ftp_parselist_data *parser = ftpwc->parser;
|
||||
bool add = TRUE;
|
||||
struct curl_fileinfo *finfo = &infop->info;
|
||||
|
||||
@ -294,6 +298,7 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
|
||||
compare = Curl_fnmatch;
|
||||
|
||||
/* filter pattern-corresponding filenames */
|
||||
Curl_set_in_callback(conn->data, true);
|
||||
if(compare(conn->data->set.fnmatch_data, wc->pattern,
|
||||
finfo->filename) == 0) {
|
||||
/* discard symlink which is containing multiple " -> " */
|
||||
@ -305,15 +310,16 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
|
||||
else {
|
||||
add = FALSE;
|
||||
}
|
||||
Curl_set_in_callback(conn->data, false);
|
||||
|
||||
if(add) {
|
||||
Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
|
||||
}
|
||||
else {
|
||||
Curl_fileinfo_dtor(NULL, finfo);
|
||||
Curl_fileinfo_cleanup(infop);
|
||||
}
|
||||
|
||||
tmpdata->parser->file_data = NULL;
|
||||
ftpwc->parser->file_data = NULL;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@ -322,8 +328,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
|
||||
{
|
||||
size_t bufflen = size*nmemb;
|
||||
struct connectdata *conn = (struct connectdata *)connptr;
|
||||
struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
|
||||
struct ftp_parselist_data *parser = tmpdata->parser;
|
||||
struct ftp_wc *ftpwc = conn->data->wildcard.protdata;
|
||||
struct ftp_parselist_data *parser = ftpwc->parser;
|
||||
struct fileinfo *infop;
|
||||
struct curl_fileinfo *finfo;
|
||||
unsigned long i = 0;
|
||||
@ -378,7 +384,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
|
||||
finfo->b_data = tmp;
|
||||
}
|
||||
else {
|
||||
Curl_fileinfo_dtor(NULL, parser->file_data);
|
||||
Curl_fileinfo_cleanup(parser->file_data);
|
||||
parser->file_data = NULL;
|
||||
parser->error = CURLE_OUT_OF_MEMORY;
|
||||
goto fail;
|
||||
@ -1000,12 +1006,13 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
|
||||
|
||||
i++;
|
||||
}
|
||||
return retsize;
|
||||
|
||||
fail:
|
||||
|
||||
/* Clean up any allocated memory. */
|
||||
if(parser->file_data) {
|
||||
Curl_fileinfo_dtor(NULL, parser->file_data);
|
||||
Curl_fileinfo_cleanup(parser->file_data);
|
||||
parser->file_data = NULL;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
@ -156,7 +156,12 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
|
||||
*param_longp = data->info.httpproxycode;
|
||||
break;
|
||||
case CURLINFO_FILETIME:
|
||||
*param_longp = data->info.filetime;
|
||||
if(data->info.filetime > LONG_MAX)
|
||||
*param_longp = LONG_MAX;
|
||||
else if(data->info.filetime < LONG_MIN)
|
||||
*param_longp = LONG_MIN;
|
||||
else
|
||||
*param_longp = (long)data->info.filetime;
|
||||
break;
|
||||
case CURLINFO_HEADER_SIZE:
|
||||
*param_longp = data->info.header_size;
|
||||
@ -253,6 +258,9 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
|
||||
curl_off_t *param_offt)
|
||||
{
|
||||
switch(info) {
|
||||
case CURLINFO_FILETIME_T:
|
||||
*param_offt = (curl_off_t)data->info.filetime;
|
||||
break;
|
||||
case CURLINFO_SIZE_UPLOAD_T:
|
||||
*param_offt = data->progress.uploaded;
|
||||
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
|
||||
@ -261,11 +261,11 @@ size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num)
|
||||
{
|
||||
const char *key_str = (const char *) key;
|
||||
const char *end = key_str + key_length;
|
||||
unsigned long h = 5381;
|
||||
size_t h = 5381;
|
||||
|
||||
while(key_str < end) {
|
||||
h += h << 5;
|
||||
h ^= (unsigned long) *key_str++;
|
||||
h ^= *key_str++;
|
||||
}
|
||||
|
||||
return (h % slots_num);
|
||||
|
@ -25,7 +25,7 @@
|
||||
#if defined(USE_OPENSSL) \
|
||||
|| defined(USE_AXTLS) \
|
||||
|| defined(USE_GSKIT) \
|
||||
|| (defined(USE_SCHANNEL) && defined(_WIN32_WCE))
|
||||
|| defined(USE_SCHANNEL)
|
||||
/* these backends use functions from this file */
|
||||
|
||||
#ifdef HAVE_NETINET_IN_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
|
||||
@ -54,10 +54,12 @@
|
||||
#include "sendf.h"
|
||||
#include "hostip.h"
|
||||
#include "hash.h"
|
||||
#include "rand.h"
|
||||
#include "share.h"
|
||||
#include "strerror.h"
|
||||
#include "url.h"
|
||||
#include "inet_ntop.h"
|
||||
#include "multiif.h"
|
||||
#include "warnless.h"
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
@ -365,6 +367,70 @@ Curl_fetch_addr(struct connectdata *conn,
|
||||
return dns;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_shuffle_addr() shuffles the order of addresses in a 'Curl_addrinfo'
|
||||
* struct by re-linking its linked list.
|
||||
*
|
||||
* The addr argument should be the address of a pointer to the head node of a
|
||||
* `Curl_addrinfo` list and it will be modified to point to the new head after
|
||||
* shuffling.
|
||||
*
|
||||
* Not declared static only to make it easy to use in a unit test!
|
||||
*
|
||||
* @unittest: 1608
|
||||
*/
|
||||
CURLcode Curl_shuffle_addr(struct Curl_easy *data, Curl_addrinfo **addr)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
const int num_addrs = Curl_num_addresses(*addr);
|
||||
|
||||
if(num_addrs > 1) {
|
||||
Curl_addrinfo **nodes;
|
||||
infof(data, "Shuffling %i addresses", num_addrs);
|
||||
|
||||
nodes = malloc(num_addrs*sizeof(*nodes));
|
||||
if(nodes) {
|
||||
int i;
|
||||
unsigned int *rnd;
|
||||
const size_t rnd_size = num_addrs * sizeof(*rnd);
|
||||
|
||||
/* build a plain array of Curl_addrinfo pointers */
|
||||
nodes[0] = *addr;
|
||||
for(i = 1; i < num_addrs; i++) {
|
||||
nodes[i] = nodes[i-1]->ai_next;
|
||||
}
|
||||
|
||||
rnd = malloc(rnd_size);
|
||||
if(rnd) {
|
||||
/* Fisher-Yates shuffle */
|
||||
if(Curl_rand(data, (unsigned char *)rnd, rnd_size) == CURLE_OK) {
|
||||
Curl_addrinfo *swap_tmp;
|
||||
for(i = num_addrs - 1; i > 0; i--) {
|
||||
swap_tmp = nodes[rnd[i] % (i + 1)];
|
||||
nodes[rnd[i] % (i + 1)] = nodes[i];
|
||||
nodes[i] = swap_tmp;
|
||||
}
|
||||
|
||||
/* relink list in the new order */
|
||||
for(i = 1; i < num_addrs; i++) {
|
||||
nodes[i-1]->ai_next = nodes[i];
|
||||
}
|
||||
|
||||
nodes[num_addrs-1]->ai_next = NULL;
|
||||
*addr = nodes[0];
|
||||
}
|
||||
free(rnd);
|
||||
}
|
||||
else
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
free(nodes);
|
||||
}
|
||||
else
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
|
||||
*
|
||||
@ -385,6 +451,13 @@ Curl_cache_addr(struct Curl_easy *data,
|
||||
struct Curl_dns_entry *dns;
|
||||
struct Curl_dns_entry *dns2;
|
||||
|
||||
/* shuffle addresses if requested */
|
||||
if(data->set.dns_shuffle_addresses) {
|
||||
CURLcode result = Curl_shuffle_addr(data, &addr);
|
||||
if(!result)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create an entry id, based upon the hostname and port */
|
||||
entry_id = create_hostcache_id(hostname, port);
|
||||
/* If we can't create the entry id, fail */
|
||||
@ -481,6 +554,17 @@ int Curl_resolv(struct connectdata *conn,
|
||||
if(!Curl_ipvalid(conn))
|
||||
return CURLRESOLV_ERROR;
|
||||
|
||||
/* notify the resolver start callback */
|
||||
if(data->set.resolver_start) {
|
||||
int st;
|
||||
Curl_set_in_callback(data, true);
|
||||
st = data->set.resolver_start(data->state.resolver, NULL,
|
||||
data->set.resolver_start_client);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(st)
|
||||
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 */
|
||||
@ -781,7 +865,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
||||
{
|
||||
struct curl_slist *hostp;
|
||||
char hostname[256];
|
||||
int port;
|
||||
int port = 0;
|
||||
|
||||
for(hostp = data->change.resolve; hostp; hostp = hostp->next) {
|
||||
if(!hostp->data)
|
||||
@ -819,32 +903,95 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
||||
}
|
||||
else {
|
||||
struct Curl_dns_entry *dns;
|
||||
Curl_addrinfo *addr;
|
||||
Curl_addrinfo *head = NULL, *tail = NULL;
|
||||
char *entry_id;
|
||||
size_t entry_len;
|
||||
char buffer[256];
|
||||
char *address = &buffer[0];
|
||||
char address[64];
|
||||
char *addresses = NULL;
|
||||
char *addr_begin;
|
||||
char *addr_end;
|
||||
char *port_ptr;
|
||||
char *end_ptr;
|
||||
char *host_end;
|
||||
unsigned long tmp_port;
|
||||
bool error = true;
|
||||
|
||||
if(3 != sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port,
|
||||
address)) {
|
||||
host_end = strchr(hostp->data, ':');
|
||||
if(!host_end ||
|
||||
((host_end - hostp->data) >= (ptrdiff_t)sizeof(hostname)))
|
||||
goto err;
|
||||
|
||||
memcpy(hostname, hostp->data, host_end - hostp->data);
|
||||
hostname[host_end - hostp->data] = '\0';
|
||||
|
||||
port_ptr = host_end + 1;
|
||||
tmp_port = strtoul(port_ptr, &end_ptr, 10);
|
||||
if(tmp_port > USHRT_MAX || end_ptr == port_ptr || *end_ptr != ':')
|
||||
goto err;
|
||||
|
||||
port = (int)tmp_port;
|
||||
addresses = end_ptr + 1;
|
||||
|
||||
while(*end_ptr) {
|
||||
size_t alen;
|
||||
Curl_addrinfo *ai;
|
||||
|
||||
addr_begin = end_ptr + 1;
|
||||
addr_end = strchr(addr_begin, ',');
|
||||
if(!addr_end)
|
||||
addr_end = addr_begin + strlen(addr_begin);
|
||||
end_ptr = addr_end;
|
||||
|
||||
/* allow IP(v6) address within [brackets] */
|
||||
if(*addr_begin == '[') {
|
||||
if(addr_end == addr_begin || *(addr_end - 1) != ']')
|
||||
goto err;
|
||||
++addr_begin;
|
||||
--addr_end;
|
||||
}
|
||||
|
||||
alen = addr_end - addr_begin;
|
||||
if(!alen)
|
||||
continue;
|
||||
|
||||
if(alen >= sizeof(address))
|
||||
goto err;
|
||||
|
||||
memcpy(address, addr_begin, alen);
|
||||
address[alen] = '\0';
|
||||
|
||||
#ifndef ENABLE_IPV6
|
||||
if(strchr(address, ':')) {
|
||||
infof(data, "Ignoring resolve address '%s', missing IPv6 support.\n",
|
||||
address);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
ai = Curl_str2addr(address, port);
|
||||
if(!ai) {
|
||||
infof(data, "Resolve address '%s' found illegal!\n", address);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(tail) {
|
||||
tail->ai_next = ai;
|
||||
tail = tail->ai_next;
|
||||
}
|
||||
else {
|
||||
head = tail = ai;
|
||||
}
|
||||
}
|
||||
|
||||
if(!head)
|
||||
goto err;
|
||||
|
||||
error = false;
|
||||
err:
|
||||
if(error) {
|
||||
infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n",
|
||||
hostp->data);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* allow IP(v6) address within [brackets] */
|
||||
if(address[0] == '[') {
|
||||
size_t alen = strlen(address);
|
||||
if(address[alen-1] != ']')
|
||||
/* it needs to also end with ] to be valid */
|
||||
continue;
|
||||
address[alen-1] = 0; /* zero terminate there */
|
||||
address++; /* pass the open bracket */
|
||||
}
|
||||
|
||||
addr = Curl_str2addr(address, port);
|
||||
if(!addr) {
|
||||
infof(data, "Address in '%s' found illegal!\n", hostp->data);
|
||||
Curl_freeaddrinfo(head);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -852,10 +999,9 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
||||
entry_id = create_hostcache_id(hostname, port);
|
||||
/* If we can't create the entry id, fail */
|
||||
if(!entry_id) {
|
||||
Curl_freeaddrinfo(addr);
|
||||
Curl_freeaddrinfo(head);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
entry_len = strlen(entry_id);
|
||||
|
||||
if(data->share)
|
||||
@ -869,7 +1015,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
||||
|
||||
if(!dns) {
|
||||
/* if not in the cache already, put this host in the cache */
|
||||
dns = Curl_cache_addr(data, addr, hostname, port);
|
||||
dns = Curl_cache_addr(data, head, hostname, port);
|
||||
if(dns) {
|
||||
dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */
|
||||
/* release the returned reference; the cache itself will keep the
|
||||
@ -880,19 +1026,19 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
|
||||
else {
|
||||
/* this is a duplicate, free it again */
|
||||
infof(data, "RESOLVE %s:%d is already cached, %s not stored!\n",
|
||||
hostname, port, address);
|
||||
Curl_freeaddrinfo(addr);
|
||||
hostname, port, addresses);
|
||||
Curl_freeaddrinfo(head);
|
||||
}
|
||||
|
||||
if(data->share)
|
||||
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
|
||||
|
||||
if(!dns) {
|
||||
Curl_freeaddrinfo(addr);
|
||||
Curl_freeaddrinfo(head);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
infof(data, "Added %s:%d:%s to DNS cache\n",
|
||||
hostname, port, address);
|
||||
hostname, port, addresses);
|
||||
}
|
||||
}
|
||||
data->change.resolve = NULL; /* dealt with now */
|
||||
|
@ -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
|
||||
@ -182,6 +182,17 @@ struct Curl_dns_entry *
|
||||
Curl_fetch_addr(struct connectdata *conn,
|
||||
const char *hostname,
|
||||
int port);
|
||||
|
||||
/*
|
||||
* Curl_shuffle_addr() shuffles the order of addresses in a 'Curl_addrinfo'
|
||||
* struct by re-linking its linked list.
|
||||
*
|
||||
* The addr argument should be the address of a pointer to the head node of a
|
||||
* `Curl_addrinfo` list and it will be modified to point to the new head after
|
||||
* shuffling.
|
||||
*/
|
||||
CURLcode Curl_shuffle_addr(struct Curl_easy *data, Curl_addrinfo **addr);
|
||||
|
||||
/*
|
||||
* Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
|
||||
*
|
||||
|
@ -92,6 +92,8 @@ static int http_getsock_do(struct connectdata *conn,
|
||||
int numsocks);
|
||||
static int http_should_fail(struct connectdata *conn);
|
||||
|
||||
static CURLcode add_haproxy_protocol_header(struct connectdata *conn);
|
||||
|
||||
#ifdef USE_SSL
|
||||
static CURLcode https_connecting(struct connectdata *conn, bool *done);
|
||||
static int https_getsock(struct connectdata *conn,
|
||||
@ -177,9 +179,9 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
|
||||
* if proxy headers are not available, then it will lookup into http header
|
||||
* link list
|
||||
*
|
||||
* It takes a connectdata struct as input instead of the Curl_easy simply
|
||||
* to know if this is a proxy request or not, as it then might check a
|
||||
* different header list.
|
||||
* It takes a connectdata struct as input instead of the Curl_easy simply to
|
||||
* know if this is a proxy request or not, as it then might check a different
|
||||
* header list. Provide the header prefix without colon!.
|
||||
*/
|
||||
char *Curl_checkProxyheaders(const struct connectdata *conn,
|
||||
const char *thisheader)
|
||||
@ -191,7 +193,8 @@ char *Curl_checkProxyheaders(const struct connectdata *conn,
|
||||
for(head = (conn->bits.proxy && data->set.sep_headers) ?
|
||||
data->set.proxyheaders : data->set.headers;
|
||||
head; head = head->next) {
|
||||
if(strncasecompare(head->data, thisheader, thislen))
|
||||
if(strncasecompare(head->data, thisheader, thislen) &&
|
||||
Curl_headersep(head->data[thislen]))
|
||||
return head->data;
|
||||
}
|
||||
|
||||
@ -211,8 +214,6 @@ char *Curl_copy_header_value(const char *header)
|
||||
char *value;
|
||||
size_t len;
|
||||
|
||||
DEBUGASSERT(header);
|
||||
|
||||
/* Find the end of the header name */
|
||||
while(*header && (*header != ':'))
|
||||
++header;
|
||||
@ -432,7 +433,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
|
||||
data left to send, keep on sending. */
|
||||
|
||||
/* rewind data when completely done sending! */
|
||||
if(!conn->bits.authneg) {
|
||||
if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) {
|
||||
conn->bits.rewindaftersend = TRUE;
|
||||
infof(data, "Rewind stream after send\n");
|
||||
}
|
||||
@ -614,9 +615,9 @@ output_auth_headers(struct connectdata *conn,
|
||||
if(authstatus->picked == CURLAUTH_BASIC) {
|
||||
/* Basic */
|
||||
if((proxy && conn->bits.proxy_user_passwd &&
|
||||
!Curl_checkProxyheaders(conn, "Proxy-authorization:")) ||
|
||||
!Curl_checkProxyheaders(conn, "Proxy-authorization")) ||
|
||||
(!proxy && conn->bits.user_passwd &&
|
||||
!Curl_checkheaders(conn, "Authorization:"))) {
|
||||
!Curl_checkheaders(conn, "Authorization"))) {
|
||||
auth = "Basic";
|
||||
result = http_output_basic(conn, proxy);
|
||||
if(result)
|
||||
@ -1357,6 +1358,13 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
|
||||
/* nothing else to do except wait right now - we're not done here. */
|
||||
return CURLE_OK;
|
||||
|
||||
if(conn->data->set.haproxyprotocol) {
|
||||
/* add HAProxy PROXY protocol header */
|
||||
result = add_haproxy_protocol_header(conn);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
if(conn->given->protocol & CURLPROTO_HTTPS) {
|
||||
/* perform SSL initialization */
|
||||
result = https_connecting(conn, done);
|
||||
@ -1382,6 +1390,47 @@ static int http_getsock_do(struct connectdata *conn,
|
||||
return GETSOCK_WRITESOCK(0);
|
||||
}
|
||||
|
||||
static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
|
||||
{
|
||||
char proxy_header[128];
|
||||
Curl_send_buffer *req_buffer;
|
||||
CURLcode result;
|
||||
char tcp_version[5];
|
||||
|
||||
/* Emit the correct prefix for IPv6 */
|
||||
if(conn->bits.ipv6) {
|
||||
strcpy(tcp_version, "TCP6");
|
||||
}
|
||||
else {
|
||||
strcpy(tcp_version, "TCP4");
|
||||
}
|
||||
|
||||
snprintf(proxy_header,
|
||||
sizeof proxy_header,
|
||||
"PROXY %s %s %s %li %li\r\n",
|
||||
tcp_version,
|
||||
conn->data->info.conn_local_ip,
|
||||
conn->data->info.conn_primary_ip,
|
||||
conn->data->info.conn_local_port,
|
||||
conn->data->info.conn_primary_port);
|
||||
|
||||
req_buffer = Curl_add_buffer_init();
|
||||
if(!req_buffer)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
result = Curl_add_bufferf(req_buffer, proxy_header);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = Curl_add_buffer_send(req_buffer,
|
||||
conn,
|
||||
&conn->data->info.request_size,
|
||||
0,
|
||||
FIRSTSOCKET);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef USE_SSL
|
||||
static CURLcode https_connecting(struct connectdata *conn, bool *done)
|
||||
{
|
||||
@ -1533,7 +1582,7 @@ static CURLcode expect100(struct Curl_easy *data,
|
||||
/* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
|
||||
Expect: 100-continue to the headers which actually speeds up post
|
||||
operations (as there is one packet coming back from the web server) */
|
||||
ptr = Curl_checkheaders(conn, "Expect:");
|
||||
ptr = Curl_checkheaders(conn, "Expect");
|
||||
if(ptr) {
|
||||
data->state.expect100header =
|
||||
Curl_compareheader(ptr, "Expect:", "100-continue");
|
||||
@ -1598,7 +1647,32 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
|
||||
headers = h[i];
|
||||
|
||||
while(headers) {
|
||||
char *semicolonp = NULL;
|
||||
ptr = strchr(headers->data, ':');
|
||||
if(!ptr) {
|
||||
char *optr;
|
||||
/* no colon, semicolon? */
|
||||
ptr = strchr(headers->data, ';');
|
||||
if(ptr) {
|
||||
optr = ptr;
|
||||
ptr++; /* pass the semicolon */
|
||||
while(*ptr && ISSPACE(*ptr))
|
||||
ptr++;
|
||||
|
||||
if(*ptr) {
|
||||
/* this may be used for something else in the future */
|
||||
optr = NULL;
|
||||
}
|
||||
else {
|
||||
if(*(--ptr) == ';') {
|
||||
/* send no-value custom header if terminated by semicolon */
|
||||
*ptr = ':';
|
||||
semicolonp = ptr;
|
||||
}
|
||||
}
|
||||
ptr = optr;
|
||||
}
|
||||
}
|
||||
if(ptr) {
|
||||
/* we require a colon for this to be a true header */
|
||||
|
||||
@ -1606,8 +1680,9 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
|
||||
while(*ptr && ISSPACE(*ptr))
|
||||
ptr++;
|
||||
|
||||
if(*ptr) {
|
||||
/* only send this if the contents was non-blank */
|
||||
if(*ptr || semicolonp) {
|
||||
/* only send this if the contents was non-blank or done special */
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(conn->allocptr.host &&
|
||||
/* a Host: header was sent already, don't pass on any custom Host:
|
||||
@ -1645,40 +1720,12 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
|
||||
!strcasecompare(data->state.first_host, conn->host.name)))
|
||||
;
|
||||
else {
|
||||
CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n",
|
||||
headers->data);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ptr = strchr(headers->data, ';');
|
||||
if(ptr) {
|
||||
|
||||
ptr++; /* pass the semicolon */
|
||||
while(*ptr && ISSPACE(*ptr))
|
||||
ptr++;
|
||||
|
||||
if(*ptr) {
|
||||
/* this may be used for something else in the future */
|
||||
}
|
||||
else {
|
||||
if(*(--ptr) == ';') {
|
||||
CURLcode result;
|
||||
|
||||
/* send no-value custom header if terminated by semicolon */
|
||||
*ptr = ':';
|
||||
result = Curl_add_bufferf(req_buffer, "%s\r\n",
|
||||
headers->data);
|
||||
|
||||
/* restore the previous value */
|
||||
*ptr = ';';
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
result = Curl_add_bufferf(req_buffer, "%s\r\n", headers->data);
|
||||
}
|
||||
if(semicolonp)
|
||||
*semicolonp = ';'; /* put back the semicolon */
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
headers = headers->next;
|
||||
@ -1869,7 +1916,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
it might have been used in the proxy connect, but if we have got a header
|
||||
with the user-agent string specified, we erase the previously made string
|
||||
here. */
|
||||
if(Curl_checkheaders(conn, "User-Agent:")) {
|
||||
if(Curl_checkheaders(conn, "User-Agent")) {
|
||||
free(conn->allocptr.uagent);
|
||||
conn->allocptr.uagent = NULL;
|
||||
}
|
||||
@ -1890,7 +1937,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
conn->bits.authneg = FALSE;
|
||||
|
||||
Curl_safefree(conn->allocptr.ref);
|
||||
if(data->change.referer && !Curl_checkheaders(conn, "Referer:")) {
|
||||
if(data->change.referer && !Curl_checkheaders(conn, "Referer")) {
|
||||
conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
|
||||
if(!conn->allocptr.ref)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
@ -1899,11 +1946,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
conn->allocptr.ref = NULL;
|
||||
|
||||
#if !defined(CURL_DISABLE_COOKIES)
|
||||
if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie:"))
|
||||
if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie"))
|
||||
addcookies = data->set.str[STRING_COOKIE];
|
||||
#endif
|
||||
|
||||
if(!Curl_checkheaders(conn, "Accept-Encoding:") &&
|
||||
if(!Curl_checkheaders(conn, "Accept-Encoding") &&
|
||||
data->set.str[STRING_ENCODING]) {
|
||||
Curl_safefree(conn->allocptr.accept_encoding);
|
||||
conn->allocptr.accept_encoding =
|
||||
@ -1919,22 +1966,29 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
#ifdef HAVE_LIBZ
|
||||
/* we only consider transfer-encoding magic if libz support is built-in */
|
||||
|
||||
if(!Curl_checkheaders(conn, "TE:") &&
|
||||
if(!Curl_checkheaders(conn, "TE") &&
|
||||
data->set.http_transfer_encoding) {
|
||||
/* When we are to insert a TE: header in the request, we must also insert
|
||||
TE in a Connection: header, so we need to merge the custom provided
|
||||
Connection: header and prevent the original to get sent. Note that if
|
||||
the user has inserted his/hers own TE: header we don't do this magic
|
||||
but then assume that the user will handle it all! */
|
||||
char *cptr = Curl_checkheaders(conn, "Connection:");
|
||||
char *cptr = Curl_checkheaders(conn, "Connection");
|
||||
#define TE_HEADER "TE: gzip\r\n"
|
||||
|
||||
Curl_safefree(conn->allocptr.te);
|
||||
|
||||
/* Create the (updated) Connection: header */
|
||||
conn->allocptr.te = cptr? aprintf("%s, TE\r\n" TE_HEADER, cptr):
|
||||
strdup("Connection: TE\r\n" TE_HEADER);
|
||||
if(cptr) {
|
||||
cptr = Curl_copy_header_value(cptr);
|
||||
if(!cptr)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* Create the (updated) Connection: header */
|
||||
conn->allocptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
|
||||
cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
|
||||
|
||||
free(cptr);
|
||||
if(!conn->allocptr.te)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -1958,7 +2012,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
}
|
||||
|
||||
if(http->sendit) {
|
||||
const char *cthdr = Curl_checkheaders(conn, "Content-Type:");
|
||||
const char *cthdr = Curl_checkheaders(conn, "Content-Type");
|
||||
|
||||
/* Read and seek body only. */
|
||||
http->sendit->flags |= MIME_BODY_ONLY;
|
||||
@ -1982,7 +2036,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
http->postsize = Curl_mime_size(http->sendit);
|
||||
}
|
||||
|
||||
ptr = Curl_checkheaders(conn, "Transfer-Encoding:");
|
||||
ptr = Curl_checkheaders(conn, "Transfer-Encoding");
|
||||
if(ptr) {
|
||||
/* Some kind of TE is requested, check if 'chunked' is chosen */
|
||||
data->req.upload_chunky =
|
||||
@ -2016,7 +2070,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
|
||||
Curl_safefree(conn->allocptr.host);
|
||||
|
||||
ptr = Curl_checkheaders(conn, "Host:");
|
||||
ptr = Curl_checkheaders(conn, "Host");
|
||||
if(ptr && (!data->state.this_is_a_follow ||
|
||||
strcasecompare(data->state.first_host, conn->host.name))) {
|
||||
#if !defined(CURL_DISABLE_COOKIES)
|
||||
@ -2055,7 +2109,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
#endif
|
||||
|
||||
if(strcmp("Host:", ptr)) {
|
||||
conn->allocptr.host = aprintf("%s\r\n", ptr);
|
||||
conn->allocptr.host = aprintf("Host:%s\r\n", &ptr[5]);
|
||||
if(!conn->allocptr.host)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -2078,7 +2132,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
host,
|
||||
conn->bits.ipv6_ip?"]":"");
|
||||
else
|
||||
conn->allocptr.host = aprintf("Host: %s%s%s:%hu\r\n",
|
||||
conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n",
|
||||
conn->bits.ipv6_ip?"[":"",
|
||||
host,
|
||||
conn->bits.ipv6_ip?"]":"",
|
||||
@ -2164,7 +2218,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
}
|
||||
#endif /* CURL_DISABLE_PROXY */
|
||||
|
||||
http->p_accept = Curl_checkheaders(conn, "Accept:")?NULL:"Accept: */*\r\n";
|
||||
http->p_accept = Curl_checkheaders(conn, "Accept")?NULL:"Accept: */*\r\n";
|
||||
|
||||
if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
|
||||
data->state.resume_from) {
|
||||
@ -2191,8 +2245,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
/* Now, let's read off the proper amount of bytes from the
|
||||
input. */
|
||||
if(conn->seek_func) {
|
||||
Curl_set_in_callback(data, true);
|
||||
seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
|
||||
SEEK_SET);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
|
||||
if(seekerr != CURL_SEEKFUNC_OK) {
|
||||
@ -2243,14 +2299,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
* ones if any such are specified.
|
||||
*/
|
||||
if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
|
||||
!Curl_checkheaders(conn, "Range:")) {
|
||||
!Curl_checkheaders(conn, "Range")) {
|
||||
/* if a line like this was already allocated, free the previous one */
|
||||
free(conn->allocptr.rangeline);
|
||||
conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
|
||||
data->state.range);
|
||||
}
|
||||
else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
|
||||
!Curl_checkheaders(conn, "Content-Range:")) {
|
||||
!Curl_checkheaders(conn, "Content-Range")) {
|
||||
|
||||
/* if a line like this was already allocated, free the previous one */
|
||||
free(conn->allocptr.rangeline);
|
||||
@ -2352,7 +2408,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
conn->allocptr.ref:"" /* Referer: <data> */,
|
||||
(conn->bits.httpproxy &&
|
||||
!conn->bits.tunnel_proxy &&
|
||||
!Curl_checkProxyheaders(conn, "Proxy-Connection:"))?
|
||||
!Curl_checkProxyheaders(conn, "Proxy-Connection"))?
|
||||
"Proxy-Connection: Keep-Alive\r\n":"",
|
||||
te
|
||||
);
|
||||
@ -2453,7 +2509,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
postsize = data->state.infilesize;
|
||||
|
||||
if((postsize != -1) && !data->req.upload_chunky &&
|
||||
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) {
|
||||
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) {
|
||||
/* only add Content-Length if not uploading chunked */
|
||||
result = Curl_add_bufferf(req_buffer,
|
||||
"Content-Length: %" CURL_FORMAT_CURL_OFF_T
|
||||
@ -2515,7 +2571,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
we don't upload data chunked, as RFC2616 forbids us to set both
|
||||
kinds of headers (Transfer-Encoding: chunked and Content-Length) */
|
||||
if(postsize != -1 && !data->req.upload_chunky &&
|
||||
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) {
|
||||
(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,
|
||||
@ -2540,7 +2596,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
the somewhat bigger ones we allow the app to disable it. Just make
|
||||
sure that the expect100header is always set to the preferred value
|
||||
here. */
|
||||
ptr = Curl_checkheaders(conn, "Expect:");
|
||||
ptr = Curl_checkheaders(conn, "Expect");
|
||||
if(ptr) {
|
||||
data->state.expect100header =
|
||||
Curl_compareheader(ptr, "Expect:", "100-continue");
|
||||
@ -2594,7 +2650,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
we don't upload data chunked, as RFC2616 forbids us to set both
|
||||
kinds of headers (Transfer-Encoding: chunked and Content-Length) */
|
||||
if((postsize != -1) && !data->req.upload_chunky &&
|
||||
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) {
|
||||
(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,
|
||||
@ -2604,7 +2660,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
return result;
|
||||
}
|
||||
|
||||
if(!Curl_checkheaders(conn, "Content-Type:")) {
|
||||
if(!Curl_checkheaders(conn, "Content-Type")) {
|
||||
result = Curl_add_bufferf(req_buffer,
|
||||
"Content-Type: application/"
|
||||
"x-www-form-urlencoded\r\n");
|
||||
@ -2616,7 +2672,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
the somewhat bigger ones we allow the app to disable it. Just make
|
||||
sure that the expect100header is always set to the preferred value
|
||||
here. */
|
||||
ptr = Curl_checkheaders(conn, "Expect:");
|
||||
ptr = Curl_checkheaders(conn, "Expect");
|
||||
if(ptr) {
|
||||
data->state.expect100header =
|
||||
Curl_compareheader(ptr, "Expect:", "100-continue");
|
||||
@ -2878,20 +2934,19 @@ static CURLcode header_append(struct Curl_easy *data,
|
||||
struct SingleRequest *k,
|
||||
size_t length)
|
||||
{
|
||||
if(k->hbuflen + length >= data->state.headersize) {
|
||||
size_t newsize = k->hbuflen + length;
|
||||
if(newsize > CURL_MAX_HTTP_HEADER) {
|
||||
/* The reason to have a max limit for this is to avoid the risk of a bad
|
||||
server feeding libcurl with a never-ending header that will cause
|
||||
reallocs infinitely */
|
||||
failf(data, "Rejected %zd bytes header (max is %d)!", newsize,
|
||||
CURL_MAX_HTTP_HEADER);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
if(newsize >= data->state.headersize) {
|
||||
/* We enlarge the header buffer as it is too small */
|
||||
char *newbuff;
|
||||
size_t hbufp_index;
|
||||
size_t newsize;
|
||||
|
||||
if(k->hbuflen + length > CURL_MAX_HTTP_HEADER) {
|
||||
/* The reason to have a max limit for this is to avoid the risk of a bad
|
||||
server feeding libcurl with a never-ending header that will cause
|
||||
reallocs infinitely */
|
||||
failf(data, "Avoided giant realloc for header (max is %d)!",
|
||||
CURL_MAX_HTTP_HEADER);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
newsize = CURLMAX((k->hbuflen + length) * 3 / 2, data->state.headersize*2);
|
||||
hbufp_index = k->hbufp - data->state.headerbuff;
|
||||
@ -2959,6 +3014,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
||||
{
|
||||
CURLcode result;
|
||||
struct SingleRequest *k = &data->req;
|
||||
ssize_t onread = *nread;
|
||||
char *ostr = k->str;
|
||||
|
||||
/* header line within buffer loop */
|
||||
do {
|
||||
@ -3023,7 +3080,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
||||
else {
|
||||
/* this was all we read so it's all a bad header */
|
||||
k->badheader = HEADER_ALLBAD;
|
||||
*nread = (ssize_t)rest_length;
|
||||
*nread = onread;
|
||||
k->str = ostr;
|
||||
return CURLE_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -3677,7 +3736,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
||||
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
|
||||
CURL_LOCK_ACCESS_SINGLE);
|
||||
Curl_cookie_add(data,
|
||||
data->cookies, TRUE, k->p + 11,
|
||||
data->cookies, TRUE, FALSE, k->p + 11,
|
||||
/* If there is a custom-set Host: name, use it
|
||||
here, or else use real peer host name. */
|
||||
conn->allocptr.cookiehost?
|
||||
@ -3692,7 +3751,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
||||
k->timeofdoc = curl_getdate(k->p + strlen("Last-Modified:"),
|
||||
&secs);
|
||||
if(data->set.get_filetime)
|
||||
data->info.filetime = (long)k->timeofdoc;
|
||||
data->info.filetime = k->timeofdoc;
|
||||
}
|
||||
else if((checkprefix("WWW-Authenticate:", k->p) &&
|
||||
(401 == k->httpcode)) ||
|
||||
|
@ -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
|
||||
@ -104,7 +104,7 @@ CURLcode Curl_http_perhapsrewind(struct connectdata *conn);
|
||||
|
||||
This value used to be fairly big (100K), but we must take into account that
|
||||
if the server rejects the POST due for authentication reasons, this data
|
||||
will always be uncondtionally sent and thus it may not be larger than can
|
||||
will always be unconditionally sent and thus it may not be larger than can
|
||||
always be afforded to send twice.
|
||||
|
||||
It must not be greater than 64K to work on VMS.
|
||||
@ -172,8 +172,6 @@ struct HTTP {
|
||||
size_t pauselen; /* the number of bytes left in data */
|
||||
bool closed; /* TRUE on HTTP2 stream close */
|
||||
bool close_handled; /* TRUE if stream closure is handled by libcurl */
|
||||
uint32_t error_code; /* HTTP/2 error code */
|
||||
|
||||
char *mem; /* points to a buffer in memory to store received data */
|
||||
size_t len; /* size of the buffer 'mem' points to */
|
||||
size_t memlen; /* size of data copied to mem */
|
||||
@ -188,9 +186,6 @@ struct HTTP {
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef int (*sending)(void); /* Curl_send */
|
||||
typedef int (*recving)(void); /* Curl_recv */
|
||||
|
||||
#ifdef USE_NGHTTP2
|
||||
/* h2 settings for this connection */
|
||||
struct h2settings {
|
||||
@ -199,15 +194,14 @@ struct h2settings {
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
struct http_conn {
|
||||
#ifdef USE_NGHTTP2
|
||||
#define H2_BINSETTINGS_LEN 80
|
||||
nghttp2_session *h2;
|
||||
uint8_t binsettings[H2_BINSETTINGS_LEN];
|
||||
size_t binlen; /* length of the binsettings data */
|
||||
sending send_underlying; /* underlying send Curl_send callback */
|
||||
recving recv_underlying; /* underlying recv Curl_recv callback */
|
||||
Curl_send *send_underlying; /* underlying send Curl_send callback */
|
||||
Curl_recv *recv_underlying; /* underlying recv Curl_recv callback */
|
||||
char *inbuf; /* buffer to receive data from underlying socket */
|
||||
size_t inbuflen; /* number of bytes filled in inbuf */
|
||||
size_t nread_inbuf; /* number of bytes read from in inbuf */
|
||||
@ -226,6 +220,7 @@ struct http_conn {
|
||||
/* list of settings that will be sent */
|
||||
nghttp2_settings_entry local_settings[3];
|
||||
size_t local_settings_num;
|
||||
uint32_t error_code; /* HTTP/2 error code */
|
||||
#else
|
||||
int unused; /* prevent a compiler warning */
|
||||
#endif
|
||||
|
@ -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,6 +41,7 @@
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#define H2_BUFSIZE 32768
|
||||
#define MIN(x,y) ((x)<(y)?(x):(y))
|
||||
|
||||
#if (NGHTTP2_VERSION_NUM < 0x010000)
|
||||
@ -65,6 +66,22 @@
|
||||
|
||||
#define HTTP2_HUGE_WINDOW_SIZE (1 << 30)
|
||||
|
||||
#ifdef DEBUG_HTTP2
|
||||
#define H2BUGF(x) x
|
||||
#else
|
||||
#define H2BUGF(x) do { } WHILE_FALSE
|
||||
#endif
|
||||
|
||||
|
||||
static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
||||
char *mem, size_t len, CURLcode *err);
|
||||
static bool http2_connisdead(struct connectdata *conn);
|
||||
static int h2_session_send(struct Curl_easy *data,
|
||||
nghttp2_session *h2);
|
||||
static int h2_process_pending_input(struct connectdata *conn,
|
||||
struct http_conn *httpc,
|
||||
CURLcode *err);
|
||||
|
||||
/*
|
||||
* Curl_http2_init_state() is called when the easy handle is created and
|
||||
* allows for HTTP/2 specific init of state.
|
||||
@ -91,6 +108,7 @@ static int http2_perform_getsock(const struct connectdata *conn,
|
||||
int numsocks)
|
||||
{
|
||||
const struct http_conn *c = &conn->proto.httpc;
|
||||
struct SingleRequest *k = &conn->data->req;
|
||||
int bitmap = GETSOCK_BLANK;
|
||||
(void)numsocks;
|
||||
|
||||
@ -102,7 +120,9 @@ static int http2_perform_getsock(const struct connectdata *conn,
|
||||
always be ready for one */
|
||||
bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
|
||||
|
||||
if(nghttp2_session_want_write(c->h2))
|
||||
/* we're still uploading or the HTTP/2 layer wants to send data */
|
||||
if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) ||
|
||||
nghttp2_session_want_write(c->h2))
|
||||
bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
|
||||
|
||||
return bitmap;
|
||||
@ -140,13 +160,14 @@ static CURLcode http2_disconnect(struct connectdata *conn,
|
||||
struct http_conn *c = &conn->proto.httpc;
|
||||
(void)dead_connection;
|
||||
|
||||
DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n"));
|
||||
H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n"));
|
||||
|
||||
nghttp2_session_del(c->h2);
|
||||
Curl_safefree(c->inbuf);
|
||||
http2_stream_free(conn->data->req.protop);
|
||||
conn->data->state.drain = 0;
|
||||
|
||||
DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n"));
|
||||
H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n"));
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
@ -158,29 +179,54 @@ static CURLcode http2_disconnect(struct connectdata *conn,
|
||||
* Instead, if it is readable, run Curl_connalive() to peek at the socket
|
||||
* and distinguish between closed and data.
|
||||
*/
|
||||
static bool http2_connisdead(struct connectdata *check)
|
||||
static bool http2_connisdead(struct connectdata *conn)
|
||||
{
|
||||
int sval;
|
||||
bool ret_val = TRUE;
|
||||
bool dead = TRUE;
|
||||
|
||||
sval = SOCKET_READABLE(check->sock[FIRSTSOCKET], 0);
|
||||
if(conn->bits.close)
|
||||
return TRUE;
|
||||
|
||||
sval = SOCKET_READABLE(conn->sock[FIRSTSOCKET], 0);
|
||||
if(sval == 0) {
|
||||
/* timeout */
|
||||
ret_val = FALSE;
|
||||
dead = FALSE;
|
||||
}
|
||||
else if(sval & CURL_CSELECT_ERR) {
|
||||
/* socket is in an error state */
|
||||
ret_val = TRUE;
|
||||
dead = TRUE;
|
||||
}
|
||||
else if(sval & CURL_CSELECT_IN) {
|
||||
/* readable with no error. could still be closed */
|
||||
ret_val = !Curl_connalive(check);
|
||||
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,
|
||||
only "protocol frames" */
|
||||
CURLcode result;
|
||||
struct http_conn *httpc = &conn->proto.httpc;
|
||||
ssize_t nread = -1;
|
||||
if(httpc->recv_underlying)
|
||||
/* if called "too early", this pointer isn't setup yet! */
|
||||
nread = ((Curl_recv *)httpc->recv_underlying)(
|
||||
conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
|
||||
if(nread != -1) {
|
||||
infof(conn->data,
|
||||
"%d bytes stray data read before trying h2 connection\n",
|
||||
(int)nread);
|
||||
httpc->nread_inbuf = 0;
|
||||
httpc->inbuflen = nread;
|
||||
(void)h2_process_pending_input(conn, httpc, &result);
|
||||
}
|
||||
else
|
||||
/* the read failed so let's say this is dead anyway */
|
||||
dead = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
return dead;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int http2_conncheck(struct connectdata *check,
|
||||
unsigned int checks_to_perform)
|
||||
{
|
||||
@ -204,7 +250,6 @@ void Curl_http2_setup_req(struct Curl_easy *data)
|
||||
http->status_code = -1;
|
||||
http->pausedata = NULL;
|
||||
http->pauselen = 0;
|
||||
http->error_code = NGHTTP2_NO_ERROR;
|
||||
http->closed = FALSE;
|
||||
http->close_handled = FALSE;
|
||||
http->mem = data->state.buffer;
|
||||
@ -217,6 +262,7 @@ void Curl_http2_setup_conn(struct connectdata *conn)
|
||||
{
|
||||
conn->proto.httpc.settings.max_concurrent_streams =
|
||||
DEFAULT_MAX_CONCURRENT_STREAMS;
|
||||
conn->proto.httpc.error_code = NGHTTP2_NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -428,7 +474,7 @@ static int push_promise(struct Curl_easy *data,
|
||||
const nghttp2_push_promise *frame)
|
||||
{
|
||||
int rv;
|
||||
DEBUGF(infof(data, "PUSH_PROMISE received, stream %u!\n",
|
||||
H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!\n",
|
||||
frame->promised_stream_id));
|
||||
if(data->multi->push_cb) {
|
||||
struct HTTP *stream;
|
||||
@ -448,7 +494,7 @@ static int push_promise(struct Curl_easy *data,
|
||||
heads.data = data;
|
||||
heads.frame = frame;
|
||||
/* ask the application */
|
||||
DEBUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
|
||||
H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
|
||||
|
||||
stream = data->req.protop;
|
||||
if(!stream) {
|
||||
@ -458,9 +504,11 @@ static int push_promise(struct Curl_easy *data,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
Curl_set_in_callback(data, true);
|
||||
rv = data->multi->push_cb(data, newhandle,
|
||||
stream->push_headers_used, &heads,
|
||||
data->multi->push_userp);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
/* free the headers again */
|
||||
for(i = 0; i<stream->push_headers_used; i++)
|
||||
@ -497,7 +545,7 @@ static int push_promise(struct Curl_easy *data,
|
||||
frame->promised_stream_id, newhandle);
|
||||
}
|
||||
else {
|
||||
DEBUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n"));
|
||||
H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n"));
|
||||
rv = 1;
|
||||
}
|
||||
fail:
|
||||
@ -511,7 +559,6 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
struct http_conn *httpc = &conn->proto.httpc;
|
||||
struct Curl_easy *data_s = NULL;
|
||||
struct HTTP *stream = NULL;
|
||||
static int lastStream = -1;
|
||||
int rv;
|
||||
size_t left, ncopy;
|
||||
int32_t stream_id = frame->hd.stream_id;
|
||||
@ -520,32 +567,30 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
/* stream ID zero is for connection-oriented stuff */
|
||||
if(frame->hd.type == NGHTTP2_SETTINGS) {
|
||||
uint32_t max_conn = httpc->settings.max_concurrent_streams;
|
||||
DEBUGF(infof(conn->data, "Got SETTINGS\n"));
|
||||
H2BUGF(infof(conn->data, "Got SETTINGS\n"));
|
||||
httpc->settings.max_concurrent_streams =
|
||||
nghttp2_session_get_remote_settings(
|
||||
session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
|
||||
httpc->settings.enable_push =
|
||||
nghttp2_session_get_remote_settings(
|
||||
session, NGHTTP2_SETTINGS_ENABLE_PUSH);
|
||||
DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
|
||||
H2BUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
|
||||
httpc->settings.max_concurrent_streams));
|
||||
DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
|
||||
H2BUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
|
||||
httpc->settings.enable_push?"TRUE":"false"));
|
||||
if(max_conn != httpc->settings.max_concurrent_streams) {
|
||||
/* only signal change if the value actually changed */
|
||||
infof(conn->data,
|
||||
"Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n");
|
||||
"Connection state changed (MAX_CONCURRENT_STREAMS == %d)!\n",
|
||||
httpc->settings.max_concurrent_streams);
|
||||
Curl_multi_connchanged(conn->data->multi);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
data_s = nghttp2_session_get_stream_user_data(session, stream_id);
|
||||
if(lastStream != stream_id) {
|
||||
lastStream = stream_id;
|
||||
}
|
||||
if(!data_s) {
|
||||
DEBUGF(infof(conn->data,
|
||||
H2BUGF(infof(conn->data,
|
||||
"No Curl_easy associated with stream: %x\n",
|
||||
stream_id));
|
||||
return 0;
|
||||
@ -553,12 +598,12 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
|
||||
stream = data_s->req.protop;
|
||||
if(!stream) {
|
||||
DEBUGF(infof(conn->data, "No proto pointer for stream: %x\n",
|
||||
H2BUGF(infof(data_s, "No proto pointer for stream: %x\n",
|
||||
stream_id));
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n",
|
||||
H2BUGF(infof(data_s, "on_frame_recv() header %x stream %x\n",
|
||||
frame->hd.type, stream_id));
|
||||
|
||||
switch(frame->hd.type) {
|
||||
@ -581,8 +626,10 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
}
|
||||
|
||||
/* nghttp2 guarantees that :status is received, and we store it to
|
||||
stream->status_code */
|
||||
DEBUGASSERT(stream->status_code != -1);
|
||||
stream->status_code. Fuzzing has proven this can still be reached
|
||||
without status code having been set. */
|
||||
if(stream->status_code == -1)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
|
||||
/* Only final status code signals the end of header */
|
||||
if(stream->status_code / 100 != 1) {
|
||||
@ -600,7 +647,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
ncopy);
|
||||
stream->nread_header_recvbuf += ncopy;
|
||||
|
||||
DEBUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n",
|
||||
H2BUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n",
|
||||
ncopy, stream_id, stream->mem));
|
||||
|
||||
stream->len -= ncopy;
|
||||
@ -629,7 +676,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEBUGF(infof(conn->data, "Got frame type %x for stream %u!\n",
|
||||
H2BUGF(infof(data_s, "Got frame type %x for stream %u!\n",
|
||||
frame->hd.type, stream_id));
|
||||
break;
|
||||
}
|
||||
@ -642,13 +689,13 @@ static int on_invalid_frame_recv(nghttp2_session *session,
|
||||
{
|
||||
struct Curl_easy *data_s = NULL;
|
||||
(void)userp;
|
||||
#if !defined(DEBUGBUILD) || defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
#if !defined(DEBUG_HTTP2) || defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
(void)lib_error_code;
|
||||
#endif
|
||||
|
||||
data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
|
||||
if(data_s) {
|
||||
DEBUGF(infof(data_s,
|
||||
H2BUGF(infof(data_s,
|
||||
"on_invalid_frame_recv() was called, error=%d:%s\n",
|
||||
lib_error_code, nghttp2_strerror(lib_error_code)));
|
||||
}
|
||||
@ -693,7 +740,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
|
||||
if(conn->data != data_s)
|
||||
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
|
||||
|
||||
DEBUGF(infof(data_s, "%zu data received for stream %u "
|
||||
H2BUGF(infof(data_s, "%zu data received for stream %u "
|
||||
"(%zu left in buffer %p, total %zu)\n",
|
||||
nread, stream_id,
|
||||
stream->len, stream->mem,
|
||||
@ -702,7 +749,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
|
||||
if(nread < len) {
|
||||
stream->pausedata = data + nread;
|
||||
stream->pauselen = len - nread;
|
||||
DEBUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
|
||||
H2BUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
|
||||
", stream %u\n",
|
||||
len - nread, stream_id));
|
||||
data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
|
||||
@ -730,7 +777,7 @@ static int before_frame_send(nghttp2_session *session,
|
||||
|
||||
data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
|
||||
if(data_s) {
|
||||
DEBUGF(infof(data_s, "before_frame_send() was called\n"));
|
||||
H2BUGF(infof(data_s, "before_frame_send() was called\n"));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -744,7 +791,7 @@ static int on_frame_send(nghttp2_session *session,
|
||||
|
||||
data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
|
||||
if(data_s) {
|
||||
DEBUGF(infof(data_s, "on_frame_send() was called, length = %zd\n",
|
||||
H2BUGF(infof(data_s, "on_frame_send() was called, length = %zd\n",
|
||||
frame->hd.length));
|
||||
}
|
||||
return 0;
|
||||
@ -755,13 +802,13 @@ static int on_frame_not_send(nghttp2_session *session,
|
||||
{
|
||||
struct Curl_easy *data_s;
|
||||
(void)userp;
|
||||
#if !defined(DEBUGBUILD) || defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
#if !defined(DEBUG_HTTP2) || defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
(void)lib_error_code;
|
||||
#endif
|
||||
|
||||
data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
|
||||
if(data_s) {
|
||||
DEBUGF(infof(data_s,
|
||||
H2BUGF(infof(data_s,
|
||||
"on_frame_not_send() was called, lib_error_code = %d\n",
|
||||
lib_error_code));
|
||||
}
|
||||
@ -777,6 +824,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
|
||||
(void)stream_id;
|
||||
|
||||
if(stream_id) {
|
||||
struct http_conn *httpc;
|
||||
/* get the stream from the hash based on Stream ID, stream ID zero is for
|
||||
connection-oriented stuff */
|
||||
data_s = nghttp2_session_get_stream_user_data(session, stream_id);
|
||||
@ -785,20 +833,21 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
|
||||
decided to reject stream (e.g., PUSH_PROMISE). */
|
||||
return 0;
|
||||
}
|
||||
DEBUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
|
||||
H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
|
||||
Curl_http2_strerror(error_code), error_code, stream_id));
|
||||
stream = data_s->req.protop;
|
||||
if(!stream)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
|
||||
stream->error_code = error_code;
|
||||
stream->closed = TRUE;
|
||||
data_s->state.drain++;
|
||||
conn->proto.httpc.drain_total++;
|
||||
httpc = &conn->proto.httpc;
|
||||
httpc->drain_total++;
|
||||
httpc->error_code = error_code;
|
||||
|
||||
/* remove the entry from the hash as the stream is now gone */
|
||||
nghttp2_session_set_stream_user_data(session, stream_id, 0);
|
||||
DEBUGF(infof(data_s, "Removed stream %u hash!\n", stream_id));
|
||||
H2BUGF(infof(data_s, "Removed stream %u hash!\n", stream_id));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -815,7 +864,7 @@ static int on_begin_headers(nghttp2_session *session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUGF(infof(data_s, "on_begin_headers() was called\n"));
|
||||
H2BUGF(infof(data_s, "on_begin_headers() was called\n"));
|
||||
|
||||
if(frame->hd.type != NGHTTP2_HEADERS) {
|
||||
return 0;
|
||||
@ -826,16 +875,12 @@ static int on_begin_headers(nghttp2_session *session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is trailer HEADERS started. Allocate buffer for them. */
|
||||
DEBUGF(infof(data_s, "trailer field started\n"));
|
||||
|
||||
DEBUGASSERT(stream->trailer_recvbuf == NULL);
|
||||
|
||||
stream->trailer_recvbuf = Curl_add_buffer_init();
|
||||
if(!stream->trailer_recvbuf) {
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
stream->trailer_recvbuf = Curl_add_buffer_init();
|
||||
if(!stream->trailer_recvbuf) {
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -928,7 +973,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
/* 4 is for ": " and "\r\n". */
|
||||
uint32_t n = (uint32_t)(namelen + valuelen + 4);
|
||||
|
||||
DEBUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
|
||||
H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
|
||||
value));
|
||||
|
||||
Curl_add_buffer(stream->trailer_recvbuf, &n, sizeof(n));
|
||||
@ -956,7 +1001,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
if(conn->data != data_s)
|
||||
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
|
||||
|
||||
DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n",
|
||||
H2BUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n",
|
||||
stream->status_code, data_s));
|
||||
return 0;
|
||||
}
|
||||
@ -972,7 +1017,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
if(conn->data != data_s)
|
||||
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
|
||||
|
||||
DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
|
||||
H2BUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
|
||||
value));
|
||||
|
||||
return 0; /* 0 is successful */
|
||||
@ -1021,15 +1066,13 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
|
||||
else if(nread == 0)
|
||||
return NGHTTP2_ERR_DEFERRED;
|
||||
|
||||
DEBUGF(infof(data_s, "data_source_read_callback: "
|
||||
H2BUGF(infof(data_s, "data_source_read_callback: "
|
||||
"returns %zu bytes stream %u\n",
|
||||
nread, stream_id));
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
#define H2_BUFSIZE 32768
|
||||
|
||||
#ifdef NGHTTP2_HAS_ERROR_CALLBACK
|
||||
static int error_callback(nghttp2_session *session,
|
||||
const char *msg,
|
||||
@ -1067,7 +1110,6 @@ void Curl_http2_done(struct connectdata *conn, bool premature)
|
||||
struct http_conn *httpc = &conn->proto.httpc;
|
||||
|
||||
if(http->header_recvbuf) {
|
||||
DEBUGF(infof(data, "free header_recvbuf!!\n"));
|
||||
Curl_add_buffer_free(http->header_recvbuf);
|
||||
http->header_recvbuf = NULL; /* clear the pointer */
|
||||
Curl_add_buffer_free(http->trailer_recvbuf);
|
||||
@ -1216,22 +1258,20 @@ static int should_close_session(struct http_conn *httpc)
|
||||
!nghttp2_session_want_write(httpc->h2);
|
||||
}
|
||||
|
||||
static int h2_session_send(struct Curl_easy *data,
|
||||
nghttp2_session *h2);
|
||||
|
||||
/*
|
||||
* h2_process_pending_input() processes pending input left in
|
||||
* httpc->inbuf. Then, call h2_session_send() to send pending data.
|
||||
* This function returns 0 if it succeeds, or -1 and error code will
|
||||
* be assigned to *err.
|
||||
*/
|
||||
static int h2_process_pending_input(struct Curl_easy *data,
|
||||
static int h2_process_pending_input(struct connectdata *conn,
|
||||
struct http_conn *httpc,
|
||||
CURLcode *err)
|
||||
{
|
||||
ssize_t nread;
|
||||
char *inbuf;
|
||||
ssize_t rv;
|
||||
struct Curl_easy *data = conn->data;
|
||||
|
||||
nread = httpc->inbuflen - httpc->nread_inbuf;
|
||||
inbuf = httpc->inbuf + httpc->nread_inbuf;
|
||||
@ -1246,7 +1286,7 @@ static int h2_process_pending_input(struct Curl_easy *data,
|
||||
}
|
||||
|
||||
if(nread == rv) {
|
||||
DEBUGF(infof(data,
|
||||
H2BUGF(infof(data,
|
||||
"h2_process_pending_input: All data in connection buffer "
|
||||
"processed\n"));
|
||||
httpc->inbuflen = 0;
|
||||
@ -1254,7 +1294,7 @@ static int h2_process_pending_input(struct Curl_easy *data,
|
||||
}
|
||||
else {
|
||||
httpc->nread_inbuf += rv;
|
||||
DEBUGF(infof(data,
|
||||
H2BUGF(infof(data,
|
||||
"h2_process_pending_input: %zu bytes left in connection "
|
||||
"buffer\n",
|
||||
httpc->inbuflen - httpc->nread_inbuf));
|
||||
@ -1267,9 +1307,15 @@ static int h2_process_pending_input(struct Curl_easy *data,
|
||||
}
|
||||
|
||||
if(should_close_session(httpc)) {
|
||||
DEBUGF(infof(data,
|
||||
H2BUGF(infof(data,
|
||||
"h2_process_pending_input: nothing to do in this session\n"));
|
||||
*err = CURLE_HTTP2;
|
||||
if(httpc->error_code)
|
||||
*err = CURLE_HTTP2;
|
||||
else {
|
||||
/* not an error per se, but should still close the connection */
|
||||
connclose(conn, "GOAWAY received");
|
||||
*err = CURLE_OK;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1300,7 +1346,7 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn)
|
||||
that it can signal EOF to nghttp2 */
|
||||
(void)nghttp2_session_resume_data(h2, stream->stream_id);
|
||||
|
||||
(void)h2_process_pending_input(conn->data, httpc, &result);
|
||||
(void)h2_process_pending_input(conn, httpc, &result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -1324,7 +1370,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
|
||||
data->state.drain = 0;
|
||||
|
||||
if(httpc->pause_stream_id == 0) {
|
||||
if(h2_process_pending_input(data, httpc, err) != 0) {
|
||||
if(h2_process_pending_input(conn, httpc, err) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -1333,17 +1379,25 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
|
||||
|
||||
/* Reset to FALSE to prevent infinite loop in readwrite_data function. */
|
||||
stream->closed = FALSE;
|
||||
if(stream->error_code != NGHTTP2_NO_ERROR) {
|
||||
if(httpc->error_code == NGHTTP2_REFUSED_STREAM) {
|
||||
H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!\n",
|
||||
stream->stream_id));
|
||||
connclose(conn, "REFUSED_STREAM"); /* don't use this anymore */
|
||||
data->state.refused_stream = TRUE;
|
||||
*err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
|
||||
return -1;
|
||||
}
|
||||
else if(httpc->error_code != NGHTTP2_NO_ERROR) {
|
||||
failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %d)",
|
||||
stream->stream_id, Curl_http2_strerror(stream->error_code),
|
||||
stream->error_code);
|
||||
stream->stream_id, Curl_http2_strerror(httpc->error_code),
|
||||
httpc->error_code);
|
||||
*err = CURLE_HTTP2_STREAM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!stream->bodystarted) {
|
||||
failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
|
||||
" all response header fields, teated as error",
|
||||
" all response header fields, treated as error",
|
||||
stream->stream_id);
|
||||
*err = CURLE_HTTP2_STREAM;
|
||||
return -1;
|
||||
@ -1370,7 +1424,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
|
||||
|
||||
stream->close_handled = TRUE;
|
||||
|
||||
DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
|
||||
H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1411,7 +1465,7 @@ static int h2_session_send(struct Curl_easy *data,
|
||||
|
||||
h2_pri_spec(data, &pri_spec);
|
||||
|
||||
DEBUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n",
|
||||
H2BUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n",
|
||||
stream->stream_id, data));
|
||||
rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id,
|
||||
&pri_spec);
|
||||
@ -1435,7 +1489,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
||||
(void)sockindex; /* we always do HTTP2 on sockindex 0 */
|
||||
|
||||
if(should_close_session(httpc)) {
|
||||
DEBUGF(infof(data,
|
||||
H2BUGF(infof(data,
|
||||
"http2_recv: nothing to do in this session\n"));
|
||||
*err = CURLE_HTTP2;
|
||||
return -1;
|
||||
@ -1461,16 +1515,16 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
||||
ncopy);
|
||||
stream->nread_header_recvbuf += ncopy;
|
||||
|
||||
DEBUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n",
|
||||
H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n",
|
||||
(int)ncopy));
|
||||
return ncopy;
|
||||
}
|
||||
|
||||
DEBUGF(infof(data, "http2_recv: easy %p (stream %u)\n",
|
||||
H2BUGF(infof(data, "http2_recv: easy %p (stream %u)\n",
|
||||
data, stream->stream_id));
|
||||
|
||||
if((data->state.drain) && stream->memlen) {
|
||||
DEBUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n",
|
||||
H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n",
|
||||
stream->memlen, stream->stream_id,
|
||||
stream->mem, mem));
|
||||
if(mem != stream->mem) {
|
||||
@ -1484,7 +1538,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
||||
/* We have paused nghttp2, but we have no pause data (see
|
||||
on_data_chunk_recv). */
|
||||
httpc->pause_stream_id = 0;
|
||||
if(h2_process_pending_input(data, httpc, &result) != 0) {
|
||||
if(h2_process_pending_input(conn, httpc, &result) != 0) {
|
||||
*err = result;
|
||||
return -1;
|
||||
}
|
||||
@ -1500,7 +1554,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
||||
|
||||
infof(data, "%zu data bytes written\n", nread);
|
||||
if(stream->pauselen == 0) {
|
||||
DEBUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id));
|
||||
H2BUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id));
|
||||
DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
|
||||
httpc->pause_stream_id = 0;
|
||||
|
||||
@ -1514,12 +1568,12 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
||||
frames, then we have to call it again with 0-length data.
|
||||
Without this, on_stream_close callback will not be called,
|
||||
and stream could be hanged. */
|
||||
if(h2_process_pending_input(data, httpc, &result) != 0) {
|
||||
if(h2_process_pending_input(conn, httpc, &result) != 0) {
|
||||
*err = result;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
DEBUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n",
|
||||
H2BUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n",
|
||||
nread, stream->stream_id));
|
||||
return nread;
|
||||
}
|
||||
@ -1532,7 +1586,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
||||
socket is not read. But it seems that usually streams are
|
||||
notified with its drain property, and socket is read again
|
||||
quickly. */
|
||||
DEBUGF(infof(data, "stream %x is paused, pause id: %x\n",
|
||||
H2BUGF(infof(data, "stream %x is paused, pause id: %x\n",
|
||||
stream->stream_id, httpc->pause_stream_id));
|
||||
*err = CURLE_AGAIN;
|
||||
return -1;
|
||||
@ -1561,12 +1615,12 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
||||
}
|
||||
|
||||
if(nread == 0) {
|
||||
failf(data, "Unexpected EOF");
|
||||
*err = CURLE_RECV_ERROR;
|
||||
return -1;
|
||||
H2BUGF(infof(data, "end of stream\n"));
|
||||
*err = CURLE_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUGF(infof(data, "nread=%zd\n", nread));
|
||||
H2BUGF(infof(data, "nread=%zd\n", nread));
|
||||
|
||||
httpc->inbuflen = nread;
|
||||
inbuf = httpc->inbuf;
|
||||
@ -1575,7 +1629,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
||||
nread = httpc->inbuflen - httpc->nread_inbuf;
|
||||
inbuf = httpc->inbuf + httpc->nread_inbuf;
|
||||
|
||||
DEBUGF(infof(data, "Use data left in connection buffer, nread=%zd\n",
|
||||
H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd\n",
|
||||
nread));
|
||||
}
|
||||
rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
|
||||
@ -1586,15 +1640,15 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
||||
*err = CURLE_RECV_ERROR;
|
||||
return -1;
|
||||
}
|
||||
DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv));
|
||||
H2BUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv));
|
||||
if(nread == rv) {
|
||||
DEBUGF(infof(data, "All data in connection buffer processed\n"));
|
||||
H2BUGF(infof(data, "All data in connection buffer processed\n"));
|
||||
httpc->inbuflen = 0;
|
||||
httpc->nread_inbuf = 0;
|
||||
}
|
||||
else {
|
||||
httpc->nread_inbuf += rv;
|
||||
DEBUGF(infof(data, "%zu bytes left in connection buffer\n",
|
||||
H2BUGF(infof(data, "%zu bytes left in connection buffer\n",
|
||||
httpc->inbuflen - httpc->nread_inbuf));
|
||||
}
|
||||
/* Always send pending frames in nghttp2 session, because
|
||||
@ -1606,21 +1660,21 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
||||
}
|
||||
|
||||
if(should_close_session(httpc)) {
|
||||
DEBUGF(infof(data, "http2_recv: nothing to do in this session\n"));
|
||||
H2BUGF(infof(data, "http2_recv: nothing to do in this session\n"));
|
||||
*err = CURLE_HTTP2;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(stream->memlen) {
|
||||
ssize_t retlen = stream->memlen;
|
||||
DEBUGF(infof(data, "http2_recv: returns %zd for stream %u\n",
|
||||
H2BUGF(infof(data, "http2_recv: returns %zd for stream %u\n",
|
||||
retlen, stream->stream_id));
|
||||
stream->memlen = 0;
|
||||
|
||||
if(httpc->pause_stream_id == stream->stream_id) {
|
||||
/* data for this stream is returned now, but this stream caused a pause
|
||||
already so we need it called again asap */
|
||||
DEBUGF(infof(data, "Data returned for PAUSED stream %u\n",
|
||||
H2BUGF(infof(data, "Data returned for PAUSED stream %u\n",
|
||||
stream->stream_id));
|
||||
}
|
||||
else if(!stream->closed) {
|
||||
@ -1637,7 +1691,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
||||
return http2_handle_stream_close(conn, data, stream, err);
|
||||
}
|
||||
*err = CURLE_AGAIN;
|
||||
DEBUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
|
||||
H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
|
||||
stream->stream_id));
|
||||
return -1;
|
||||
}
|
||||
@ -1739,7 +1793,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
||||
|
||||
(void)sockindex;
|
||||
|
||||
DEBUGF(infof(conn->data, "http2_send len=%zu\n", len));
|
||||
H2BUGF(infof(conn->data, "http2_send len=%zu\n", len));
|
||||
|
||||
if(stream->stream_id != -1) {
|
||||
if(stream->close_handled) {
|
||||
@ -1768,7 +1822,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
||||
stream->upload_len = 0;
|
||||
|
||||
if(should_close_session(httpc)) {
|
||||
DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
|
||||
H2BUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
|
||||
*err = CURLE_HTTP2;
|
||||
return -1;
|
||||
}
|
||||
@ -1781,7 +1835,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
||||
nghttp2_session_resume_data(h2, stream->stream_id);
|
||||
}
|
||||
|
||||
DEBUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len,
|
||||
H2BUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len,
|
||||
stream->stream_id));
|
||||
return len;
|
||||
}
|
||||
@ -1809,8 +1863,11 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Extract :method, :path from request line */
|
||||
line_end = strstr(hdbuf, "\r\n");
|
||||
/* Extract :method, :path from request line
|
||||
We do line endings with CRLF so checking for CR is enough */
|
||||
line_end = memchr(hdbuf, '\r', len);
|
||||
if(!line_end)
|
||||
goto fail;
|
||||
|
||||
/* Method does not contain spaces */
|
||||
end = memchr(hdbuf, ' ', line_end - hdbuf);
|
||||
@ -1868,8 +1925,10 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
||||
|
||||
hdbuf = line_end + 2;
|
||||
|
||||
line_end = strstr(hdbuf, "\r\n");
|
||||
if(line_end == hdbuf)
|
||||
/* check for next CR, but only within the piece of data left in the given
|
||||
buffer */
|
||||
line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem));
|
||||
if(!line_end || (line_end == hdbuf))
|
||||
goto fail;
|
||||
|
||||
/* header continuation lines are not supported */
|
||||
@ -1937,7 +1996,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
||||
for(i = 0; i < nheader; ++i) {
|
||||
acc += nva[i].namelen + nva[i].valuelen;
|
||||
|
||||
DEBUGF(infof(conn->data, "h2 header: %.*s:%.*s\n",
|
||||
H2BUGF(infof(conn->data, "h2 header: %.*s:%.*s\n",
|
||||
nva[i].namelen, nva[i].name,
|
||||
nva[i].valuelen, nva[i].value));
|
||||
}
|
||||
@ -1975,7 +2034,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
||||
Curl_safefree(nva);
|
||||
|
||||
if(stream_id < 0) {
|
||||
DEBUGF(infof(conn->data, "http2_send() send error\n"));
|
||||
H2BUGF(infof(conn->data, "http2_send() send error\n"));
|
||||
*err = CURLE_SEND_ERROR;
|
||||
return -1;
|
||||
}
|
||||
@ -1994,7 +2053,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
||||
}
|
||||
|
||||
if(should_close_session(httpc)) {
|
||||
DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
|
||||
H2BUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
|
||||
*err = CURLE_HTTP2;
|
||||
return -1;
|
||||
}
|
||||
@ -2078,8 +2137,8 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET];
|
||||
httpc->send_underlying = (sending)conn->send[FIRSTSOCKET];
|
||||
httpc->recv_underlying = conn->recv[FIRSTSOCKET];
|
||||
httpc->send_underlying = conn->send[FIRSTSOCKET];
|
||||
conn->recv[FIRSTSOCKET] = http2_recv;
|
||||
conn->send[FIRSTSOCKET] = http2_send;
|
||||
|
||||
@ -2152,7 +2211,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
|
||||
return CURLE_HTTP2;
|
||||
}
|
||||
|
||||
DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc));
|
||||
H2BUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc));
|
||||
|
||||
if((ssize_t)nread == nproc) {
|
||||
httpc->inbuflen = 0;
|
||||
@ -2172,7 +2231,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
|
||||
}
|
||||
|
||||
if(should_close_session(httpc)) {
|
||||
DEBUGF(infof(data,
|
||||
H2BUGF(infof(data,
|
||||
"nghttp2_session_send(): nothing to do in this session\n"));
|
||||
return CURLE_HTTP2;
|
||||
}
|
||||
|
@ -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
|
||||
@ -74,14 +74,18 @@
|
||||
|
||||
*/
|
||||
|
||||
#ifdef CURL_DOES_CONVERSIONS
|
||||
/* Check for an ASCII hex digit.
|
||||
We avoid the use of isxdigit to accommodate non-ASCII hosts. */
|
||||
static bool Curl_isxdigit(char digit)
|
||||
We avoid the use of ISXDIGIT to accommodate non-ASCII hosts. */
|
||||
static bool Curl_isxdigit_ascii(char digit)
|
||||
{
|
||||
return ( (digit >= 0x30 && digit <= 0x39) /* 0-9 */
|
||||
return (digit >= 0x30 && digit <= 0x39) /* 0-9 */
|
||||
|| (digit >= 0x41 && digit <= 0x46) /* A-F */
|
||||
|| (digit >= 0x61 && digit <= 0x66) /* a-f */) ? TRUE : FALSE;
|
||||
|| (digit >= 0x61 && digit <= 0x66); /* a-f */
|
||||
}
|
||||
#else
|
||||
#define Curl_isxdigit_ascii(x) Curl_isxdigit(x)
|
||||
#endif
|
||||
|
||||
void Curl_httpchunk_init(struct connectdata *conn)
|
||||
{
|
||||
@ -128,7 +132,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
|
||||
while(length) {
|
||||
switch(ch->state) {
|
||||
case CHUNK_HEX:
|
||||
if(Curl_isxdigit(*datap)) {
|
||||
if(Curl_isxdigit_ascii(*datap)) {
|
||||
if(ch->hexindex < MAXNUM_SIZE) {
|
||||
ch->hexbuffer[ch->hexindex] = *datap;
|
||||
datap++;
|
||||
@ -187,15 +191,15 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
|
||||
piece = curlx_sotouz((ch->datasize >= length)?length:ch->datasize);
|
||||
|
||||
/* Write the data portion available */
|
||||
if(conn->data->set.http_ce_skip || !k->writer_stack) {
|
||||
if(!k->ignorebody)
|
||||
if(!conn->data->set.http_te_skip && !k->ignorebody) {
|
||||
if(!conn->data->set.http_ce_skip && k->writer_stack)
|
||||
result = Curl_unencode_write(conn, k->writer_stack, datap, piece);
|
||||
else
|
||||
result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, piece);
|
||||
}
|
||||
else
|
||||
result = Curl_unencode_write(conn, k->writer_stack, datap, piece);
|
||||
|
||||
if(result)
|
||||
return CHUNKE_WRITE_ERROR;
|
||||
if(result)
|
||||
return CHUNKE_WRITE_ERROR;
|
||||
}
|
||||
|
||||
*wrote += piece;
|
||||
ch->datasize -= piece; /* decrease amount left to expect */
|
||||
|
@ -89,7 +89,7 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
|
||||
}
|
||||
}
|
||||
|
||||
/* Initilise the security context and decode our challenge */
|
||||
/* Initialize the security context and decode our challenge */
|
||||
result = Curl_auth_decode_spnego_message(data, userp, passwdp, service,
|
||||
host, header, neg_ctx);
|
||||
|
||||
|
@ -121,9 +121,11 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
|
||||
server, which is for a plain host or for a HTTP proxy */
|
||||
char **allocuserpwd;
|
||||
|
||||
/* point to the name and password for this */
|
||||
/* point to the username, password, service and host */
|
||||
const char *userp;
|
||||
const char *passwdp;
|
||||
const char *service = NULL;
|
||||
const char *hostname = NULL;
|
||||
|
||||
/* point to the correct struct with this */
|
||||
struct ntlmdata *ntlm;
|
||||
@ -141,6 +143,9 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
|
||||
allocuserpwd = &conn->allocptr.proxyuserpwd;
|
||||
userp = conn->http_proxy.user;
|
||||
passwdp = conn->http_proxy.passwd;
|
||||
service = conn->data->set.str[STRING_PROXY_SERVICE_NAME] ?
|
||||
conn->data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
|
||||
hostname = conn->http_proxy.host.name;
|
||||
ntlm = &conn->proxyntlm;
|
||||
authp = &conn->data->state.authproxy;
|
||||
}
|
||||
@ -148,6 +153,9 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
|
||||
allocuserpwd = &conn->allocptr.userpwd;
|
||||
userp = conn->user;
|
||||
passwdp = conn->passwd;
|
||||
service = conn->data->set.str[STRING_SERVICE_NAME] ?
|
||||
conn->data->set.str[STRING_SERVICE_NAME] : "HTTP";
|
||||
hostname = conn->host.name;
|
||||
ntlm = &conn->ntlm;
|
||||
authp = &conn->data->state.authhost;
|
||||
}
|
||||
@ -174,7 +182,9 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
|
||||
default: /* for the weird cases we (re)start here */
|
||||
/* Create a type-1 message */
|
||||
result = Curl_auth_create_ntlm_type1_message(conn->data, userp, passwdp,
|
||||
ntlm, &base64, &len);
|
||||
service, hostname,
|
||||
ntlm, &base64,
|
||||
&len);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
|
@ -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
|
||||
@ -221,7 +221,7 @@ static CURLcode CONNECT(struct connectdata *conn,
|
||||
if(!req_buffer)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
host_port = aprintf("%s:%hu", hostname, remote_port);
|
||||
host_port = aprintf("%s:%d", hostname, remote_port);
|
||||
if(!host_port) {
|
||||
Curl_add_buffer_free(req_buffer);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
@ -245,14 +245,14 @@ static CURLcode CONNECT(struct connectdata *conn,
|
||||
if(hostname != conn->host.name)
|
||||
ipv6_ip = (strchr(hostname, ':') != NULL);
|
||||
hostheader = /* host:port with IPv6 support */
|
||||
aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
|
||||
aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
|
||||
remote_port);
|
||||
if(!hostheader) {
|
||||
Curl_add_buffer_free(req_buffer);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if(!Curl_checkProxyheaders(conn, "Host:")) {
|
||||
if(!Curl_checkProxyheaders(conn, "Host")) {
|
||||
host = aprintf("Host: %s\r\n", hostheader);
|
||||
if(!host) {
|
||||
free(hostheader);
|
||||
@ -260,10 +260,10 @@ static CURLcode CONNECT(struct connectdata *conn,
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
if(!Curl_checkProxyheaders(conn, "Proxy-Connection:"))
|
||||
if(!Curl_checkProxyheaders(conn, "Proxy-Connection"))
|
||||
proxyconn = "Proxy-Connection: Keep-Alive\r\n";
|
||||
|
||||
if(!Curl_checkProxyheaders(conn, "User-Agent:") &&
|
||||
if(!Curl_checkProxyheaders(conn, "User-Agent") &&
|
||||
data->set.str[STRING_USERAGENT])
|
||||
useragent = conn->allocptr.uagent;
|
||||
|
||||
|
@ -85,7 +85,7 @@ krb5_decode(void *app_data, void *buf, int len,
|
||||
|
||||
enc.value = buf;
|
||||
enc.length = len;
|
||||
maj = gss_unseal(&min, *context, &enc, &dec, NULL, NULL);
|
||||
maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL);
|
||||
if(maj != GSS_S_COMPLETE) {
|
||||
if(len >= 4)
|
||||
strcpy(buf, "599 ");
|
||||
@ -119,11 +119,11 @@ krb5_encode(void *app_data, const void *from, int length, int level, void **to)
|
||||
int len;
|
||||
|
||||
/* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal
|
||||
* libraries modify the input buffer in gss_seal()
|
||||
* libraries modify the input buffer in gss_wrap()
|
||||
*/
|
||||
dec.value = (void *)from;
|
||||
dec.length = length;
|
||||
maj = gss_seal(&min, *context,
|
||||
maj = gss_wrap(&min, *context,
|
||||
level == PROT_PRIVATE,
|
||||
GSS_C_QOP_DEFAULT,
|
||||
&dec, &state, &enc);
|
||||
|
@ -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
|
||||
@ -484,6 +484,11 @@ static void MD5_Final(unsigned char *result, MD5_CTX *ctx)
|
||||
|
||||
#endif /* CRYPTO LIBS */
|
||||
|
||||
/* Disable this picky gcc-8 compiler warning */
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 8)
|
||||
#pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
#endif
|
||||
|
||||
const HMAC_params Curl_HMAC_MD5[] = {
|
||||
{
|
||||
(HMAC_hinit_func) MD5_Init, /* Hash initialization function. */
|
||||
|
@ -51,10 +51,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
#define FILE_CONTENTTYPE_DEFAULT "application/octet-stream"
|
||||
#define MULTIPART_CONTENTTYPE_DEFAULT "multipart/mixed"
|
||||
#define DISPOSITION_DEFAULT "attachment"
|
||||
|
||||
#define READ_ERROR ((size_t) -1)
|
||||
|
||||
/* Encoders. */
|
||||
@ -245,7 +241,7 @@ static FILE * vmsfopenread(const char *file, const char *mode)
|
||||
static char *Curl_basename(char *path)
|
||||
{
|
||||
/* Ignore all the details above for now and make a quick and simple
|
||||
implementaion here */
|
||||
implementation here */
|
||||
char *s1;
|
||||
char *s2;
|
||||
|
||||
@ -1197,7 +1193,10 @@ CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src)
|
||||
}
|
||||
|
||||
/* Duplicate other fields. */
|
||||
dst->encoder = src->encoder;
|
||||
if(dst != NULL)
|
||||
dst->encoder = src->encoder;
|
||||
else
|
||||
res = CURLE_WRITE_ERROR;
|
||||
if(!res)
|
||||
res = curl_mime_type(dst, src->mimetype);
|
||||
if(!res)
|
||||
@ -1206,7 +1205,7 @@ CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src)
|
||||
res = curl_mime_filename(dst, src->filename);
|
||||
|
||||
/* If an error occurred, rollback. */
|
||||
if(res)
|
||||
if(res && dst)
|
||||
Curl_mime_cleanpart(dst);
|
||||
|
||||
return res;
|
||||
@ -1642,8 +1641,7 @@ static CURLcode add_content_type(struct curl_slist **slp,
|
||||
boundary? boundary: "");
|
||||
}
|
||||
|
||||
|
||||
static const char *ContentTypeForFilename(const char *filename)
|
||||
const char *Curl_mime_contenttype(const char *filename)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@ -1715,14 +1713,14 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
|
||||
contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
|
||||
break;
|
||||
case MIMEKIND_FILE:
|
||||
contenttype = ContentTypeForFilename(part->filename);
|
||||
contenttype = Curl_mime_contenttype(part->filename);
|
||||
if(!contenttype)
|
||||
contenttype = ContentTypeForFilename(part->data);
|
||||
contenttype = Curl_mime_contenttype(part->data);
|
||||
if(!contenttype && part->filename)
|
||||
contenttype = FILE_CONTENTTYPE_DEFAULT;
|
||||
break;
|
||||
default:
|
||||
contenttype = ContentTypeForFilename(part->filename);
|
||||
contenttype = Curl_mime_contenttype(part->filename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,10 @@
|
||||
#define MIME_USERHEADERS_OWNER (1 << 0)
|
||||
#define MIME_BODY_ONLY (1 << 1)
|
||||
|
||||
#define FILE_CONTENTTYPE_DEFAULT "application/octet-stream"
|
||||
#define MULTIPART_CONTENTTYPE_DEFAULT "multipart/mixed"
|
||||
#define DISPOSITION_DEFAULT "attachment"
|
||||
|
||||
/* Part source kinds. */
|
||||
enum mimekind {
|
||||
MIMEKIND_NONE = 0, /* Part not set. */
|
||||
@ -134,5 +138,6 @@ size_t Curl_mime_read(char *buffer, size_t size, size_t nitems,
|
||||
void *instream);
|
||||
CURLcode Curl_mime_rewind(curl_mimepart *part);
|
||||
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...);
|
||||
const char *Curl_mime_contenttype(const char *filename);
|
||||
|
||||
#endif /* HEADER_CURL_MIME_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
|
||||
@ -77,6 +77,7 @@ static CURLMcode add_next_timeout(struct curltime now,
|
||||
struct Curl_easy *d);
|
||||
static CURLMcode multi_timeout(struct Curl_multi *multi,
|
||||
long *timeout_ms);
|
||||
static void process_pending_handles(struct Curl_multi *multi);
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
static const char * const statename[]={
|
||||
@ -366,6 +367,9 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
|
||||
if(data->multi)
|
||||
return CURLM_ADDED_ALREADY;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
/* Initialize timeout list for this handle */
|
||||
Curl_llist_init(&data->state.timeoutlist, NULL);
|
||||
|
||||
@ -375,6 +379,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
|
||||
* potential multi's connection cache growing which won't be undone in this
|
||||
* function no matter what.
|
||||
*/
|
||||
if(data->set.errorbuffer)
|
||||
data->set.errorbuffer[0] = 0;
|
||||
|
||||
/* set the easy handle */
|
||||
multistate(data, CURLM_STATE_INIT);
|
||||
@ -535,13 +541,14 @@ static CURLcode multi_done(struct connectdata **connp,
|
||||
result = CURLE_ABORTED_BY_CALLBACK;
|
||||
}
|
||||
|
||||
if(conn->send_pipe.size + conn->recv_pipe.size != 0 &&
|
||||
!data->set.reuse_forbid &&
|
||||
!conn->bits.close) {
|
||||
/* Stop if pipeline is not empty and we do not have to close
|
||||
connection. */
|
||||
process_pending_handles(data->multi); /* connection / multiplex */
|
||||
|
||||
if(conn->send_pipe.size || conn->recv_pipe.size) {
|
||||
/* Stop if pipeline is not empty . */
|
||||
data->easy_conn = NULL;
|
||||
DEBUGF(infof(data, "Connection still in use, no more multi_done now!\n"));
|
||||
DEBUGF(infof(data, "Connection still in use %d/%d, "
|
||||
"no more multi_done now!\n",
|
||||
conn->send_pipe.size, conn->recv_pipe.size));
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@ -640,6 +647,9 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
|
||||
if(!data->multi)
|
||||
return CURLM_OK; /* it is already removed so let's say it is fine! */
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE;
|
||||
easy_owns_conn = (data->easy_conn && (data->easy_conn->data == easy)) ?
|
||||
TRUE : FALSE;
|
||||
@ -650,10 +660,6 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
|
||||
/* this handle is "alive" so we need to count down the total number of
|
||||
alive connections when this is removed */
|
||||
multi->num_alive--;
|
||||
|
||||
/* When this handle gets removed, other handles may be able to get the
|
||||
connection */
|
||||
Curl_multi_process_pending_handles(multi);
|
||||
}
|
||||
|
||||
if(data->easy_conn &&
|
||||
@ -903,6 +909,9 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
data = multi->easyp;
|
||||
while(data) {
|
||||
bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
|
||||
@ -956,6 +965,9 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
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! */
|
||||
@ -1121,6 +1133,9 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
|
||||
{
|
||||
CURLMcode rc;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
rc = curl_multi_add_handle(multi, data);
|
||||
if(!rc) {
|
||||
struct SingleRequest *k = &data->req;
|
||||
@ -1327,7 +1342,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
|
||||
if(multi_ischanged(multi, TRUE)) {
|
||||
DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
|
||||
Curl_multi_process_pending_handles(multi);
|
||||
process_pending_handles(multi); /* pipelined/multiplexed */
|
||||
}
|
||||
|
||||
if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT &&
|
||||
@ -1773,16 +1788,17 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
case CURLM_STATE_DO_DONE:
|
||||
/* Move ourselves from the send to recv pipeline */
|
||||
Curl_move_handle_from_send_to_recv_pipe(data, data->easy_conn);
|
||||
/* Check if we can move pending requests to send pipe */
|
||||
Curl_multi_process_pending_handles(multi);
|
||||
|
||||
if(data->easy_conn->bits.multiplex || data->easy_conn->send_pipe.size)
|
||||
/* Check if we can move pending requests to send pipe */
|
||||
process_pending_handles(multi); /* pipelined/multiplexed */
|
||||
|
||||
/* Only perform the transfer if there's a good socket to work with.
|
||||
Having both BAD is a signal to skip immediately to DONE */
|
||||
if((data->easy_conn->sockfd != CURL_SOCKET_BAD) ||
|
||||
(data->easy_conn->writesockfd != CURL_SOCKET_BAD))
|
||||
multistate(data, CURLM_STATE_WAITPERFORM);
|
||||
else
|
||||
{
|
||||
else {
|
||||
if(data->state.wildcardmatch &&
|
||||
((data->easy_conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
|
||||
data->wildcard.state = CURLWC_DONE;
|
||||
@ -1811,22 +1827,26 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
if(!result) {
|
||||
send_timeout_ms = 0;
|
||||
if(data->set.max_send_speed > 0)
|
||||
send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
|
||||
data->progress.ul_limit_size,
|
||||
data->set.max_send_speed,
|
||||
data->progress.ul_limit_start,
|
||||
now);
|
||||
send_timeout_ms =
|
||||
Curl_pgrsLimitWaitTime(data->progress.uploaded,
|
||||
data->progress.ul_limit_size,
|
||||
data->set.max_send_speed,
|
||||
data->progress.ul_limit_start,
|
||||
now);
|
||||
|
||||
recv_timeout_ms = 0;
|
||||
if(data->set.max_recv_speed > 0)
|
||||
recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
|
||||
data->progress.dl_limit_size,
|
||||
data->set.max_recv_speed,
|
||||
data->progress.dl_limit_start,
|
||||
now);
|
||||
recv_timeout_ms =
|
||||
Curl_pgrsLimitWaitTime(data->progress.downloaded,
|
||||
data->progress.dl_limit_size,
|
||||
data->set.max_recv_speed,
|
||||
data->progress.dl_limit_start,
|
||||
now);
|
||||
|
||||
if(send_timeout_ms <= 0 && recv_timeout_ms <= 0)
|
||||
if(!send_timeout_ms && !recv_timeout_ms) {
|
||||
multistate(data, CURLM_STATE_PERFORM);
|
||||
Curl_ratelimit(data, now);
|
||||
}
|
||||
else if(send_timeout_ms >= recv_timeout_ms)
|
||||
Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
|
||||
else
|
||||
@ -1858,7 +1878,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
data->progress.dl_limit_start,
|
||||
now);
|
||||
|
||||
if(send_timeout_ms > 0 || recv_timeout_ms > 0) {
|
||||
if(send_timeout_ms || recv_timeout_ms) {
|
||||
Curl_ratelimit(data, now);
|
||||
multistate(data, CURLM_STATE_TOOFAST);
|
||||
if(send_timeout_ms >= recv_timeout_ms)
|
||||
Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
|
||||
@ -1926,9 +1947,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
if(data->easy_conn->recv_pipe.head)
|
||||
Curl_expire(data->easy_conn->recv_pipe.head->ptr, 0, EXPIRE_RUN_NOW);
|
||||
|
||||
/* Check if we can move pending requests to send pipe */
|
||||
Curl_multi_process_pending_handles(multi);
|
||||
|
||||
/* When we follow redirects or is set to retry the connection, we must
|
||||
to go back to the CONNECT state */
|
||||
if(data->req.newurl || retry) {
|
||||
@ -1985,8 +2003,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
|
||||
/* Remove ourselves from the receive pipeline, if we are there. */
|
||||
Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
|
||||
/* Check if we can move pending requests to send pipe */
|
||||
Curl_multi_process_pending_handles(multi);
|
||||
|
||||
if(data->easy_conn->bits.multiplex || data->easy_conn->send_pipe.size)
|
||||
/* Check if we can move pending requests to connection */
|
||||
process_pending_handles(multi); /* pipelined/multiplexing */
|
||||
|
||||
/* post-transfer command */
|
||||
res = multi_done(&data->easy_conn, result, FALSE);
|
||||
@ -2054,7 +2074,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
data->state.pipe_broke = FALSE;
|
||||
|
||||
/* Check if we can move pending requests to send pipe */
|
||||
Curl_multi_process_pending_handles(multi);
|
||||
process_pending_handles(multi); /* connection */
|
||||
|
||||
if(data->easy_conn) {
|
||||
/* if this has a connection, unsubscribe from the pipelines */
|
||||
@ -2127,6 +2147,9 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
data = multi->easyp;
|
||||
while(data) {
|
||||
CURLMcode result;
|
||||
@ -2174,6 +2197,9 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
|
||||
struct Curl_easy *nextdata;
|
||||
|
||||
if(GOOD_MULTI_HANDLE(multi)) {
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
multi->type = 0; /* not good anymore */
|
||||
|
||||
/* Firsrt remove all remaining easy handles */
|
||||
@ -2234,7 +2260,9 @@ CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
|
||||
|
||||
*msgs_in_queue = 0; /* default to none */
|
||||
|
||||
if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(&multi->msglist)) {
|
||||
if(GOOD_MULTI_HANDLE(multi) &&
|
||||
!multi->in_callback &&
|
||||
Curl_llist_count(&multi->msglist)) {
|
||||
/* there is one or more messages in the list */
|
||||
struct curl_llist_element *e;
|
||||
|
||||
@ -2396,6 +2424,12 @@ static void singlesocket(struct Curl_multi *multi,
|
||||
data->numsocks = num;
|
||||
}
|
||||
|
||||
void Curl_updatesocket(struct Curl_easy *data)
|
||||
{
|
||||
singlesocket(data->multi, data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Curl_multi_closed()
|
||||
*
|
||||
@ -2624,6 +2658,9 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
va_start(param, option);
|
||||
|
||||
switch(option) {
|
||||
@ -2688,7 +2725,10 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
|
||||
CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
|
||||
int *running_handles)
|
||||
{
|
||||
CURLMcode result = multi_socket(multi, FALSE, s, 0, running_handles);
|
||||
CURLMcode result;
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
result = multi_socket(multi, FALSE, s, 0, running_handles);
|
||||
if(CURLM_OK >= result)
|
||||
update_timer(multi);
|
||||
return result;
|
||||
@ -2697,8 +2737,10 @@ CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
|
||||
CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
|
||||
int ev_bitmask, int *running_handles)
|
||||
{
|
||||
CURLMcode result = multi_socket(multi, FALSE, s,
|
||||
ev_bitmask, running_handles);
|
||||
CURLMcode result;
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
|
||||
if(CURLM_OK >= result)
|
||||
update_timer(multi);
|
||||
return result;
|
||||
@ -2707,8 +2749,10 @@ CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
|
||||
CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
|
||||
|
||||
{
|
||||
CURLMcode result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0,
|
||||
running_handles);
|
||||
CURLMcode result;
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
|
||||
if(CURLM_OK >= result)
|
||||
update_timer(multi);
|
||||
return result;
|
||||
@ -2760,6 +2804,9 @@ CURLMcode curl_multi_timeout(struct Curl_multi *multi,
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
return multi_timeout(multi, timeout_ms);
|
||||
}
|
||||
|
||||
@ -2992,6 +3039,9 @@ CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
|
||||
{
|
||||
struct Curl_sh_entry *there = NULL;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
there = sh_getentry(&multi->sockhash, s);
|
||||
|
||||
if(!there)
|
||||
@ -3032,28 +3082,38 @@ struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
|
||||
return &multi->pipelining_server_bl;
|
||||
}
|
||||
|
||||
void Curl_multi_process_pending_handles(struct Curl_multi *multi)
|
||||
static void process_pending_handles(struct Curl_multi *multi)
|
||||
{
|
||||
struct curl_llist_element *e = multi->pending.head;
|
||||
|
||||
while(e) {
|
||||
if(e) {
|
||||
struct Curl_easy *data = e->ptr;
|
||||
struct curl_llist_element *next = e->next;
|
||||
|
||||
if(data->mstate == CURLM_STATE_CONNECT_PEND) {
|
||||
multistate(data, CURLM_STATE_CONNECT);
|
||||
DEBUGASSERT(data->mstate == CURLM_STATE_CONNECT_PEND);
|
||||
|
||||
/* Remove this node from the list */
|
||||
Curl_llist_remove(&multi->pending, e, NULL);
|
||||
multistate(data, CURLM_STATE_CONNECT);
|
||||
|
||||
/* Make sure that the handle will be processed soonish. */
|
||||
Curl_expire(data, 0, EXPIRE_RUN_NOW);
|
||||
}
|
||||
/* Remove this node from the list */
|
||||
Curl_llist_remove(&multi->pending, e, NULL);
|
||||
|
||||
e = next; /* operate on next handle */
|
||||
/* Make sure that the handle will be processed soonish. */
|
||||
Curl_expire(data, 0, EXPIRE_RUN_NOW);
|
||||
}
|
||||
}
|
||||
|
||||
void Curl_set_in_callback(struct Curl_easy *easy, bool value)
|
||||
{
|
||||
if(easy->multi_easy)
|
||||
easy->multi_easy->in_callback = value;
|
||||
else if(easy->multi)
|
||||
easy->multi->in_callback = value;
|
||||
}
|
||||
|
||||
bool Curl_is_in_callback(struct Curl_easy *easy)
|
||||
{
|
||||
return ((easy->multi && easy->multi->in_callback) ||
|
||||
(easy->multi_easy && easy->multi_easy->in_callback));
|
||||
}
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
void Curl_multi_dump(struct Curl_multi *multi)
|
||||
{
|
||||
|
@ -146,6 +146,7 @@ struct Curl_multi {
|
||||
void *timer_userp;
|
||||
struct curltime timer_lastcall; /* the fixed time for the timeout for the
|
||||
previous callback */
|
||||
bool in_callback; /* true while executing a callback */
|
||||
};
|
||||
|
||||
#endif /* HEADER_CURL_MULTIHANDLE_H */
|
||||
|
@ -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
|
||||
@ -26,11 +26,14 @@
|
||||
* Prototypes for library-wide functions provided by multi.c
|
||||
*/
|
||||
|
||||
void Curl_updatesocket(struct Curl_easy *data);
|
||||
void Curl_expire(struct Curl_easy *data, time_t milli, expire_id);
|
||||
void Curl_expire_clear(struct Curl_easy *data);
|
||||
void Curl_expire_done(struct Curl_easy *data, expire_id id);
|
||||
bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits);
|
||||
void Curl_multi_handlePipeBreak(struct Curl_easy *data);
|
||||
void Curl_set_in_callback(struct Curl_easy *data, bool value);
|
||||
bool Curl_is_in_callback(struct Curl_easy *easy);
|
||||
|
||||
/* Internal version of curl_multi_init() accepts size parameters for the
|
||||
socket and connection hashes */
|
||||
@ -56,8 +59,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize);
|
||||
void Curl_multi_dump(struct Curl_multi *multi);
|
||||
#endif
|
||||
|
||||
void Curl_multi_process_pending_handles(struct Curl_multi *multi);
|
||||
|
||||
/* Return the value of the CURLMOPT_MAX_HOST_CONNECTIONS option */
|
||||
size_t Curl_multi_max_host_connections(struct Curl_multi *multi);
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "formdata.h"
|
||||
#include "sendf.h"
|
||||
#include "urldata.h"
|
||||
#include "multiif.h"
|
||||
|
||||
#include "curl_memory.h"
|
||||
/* The last #include file should be: */
|
||||
@ -84,7 +85,10 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
|
||||
{
|
||||
if(data && data->set.convtonetwork) {
|
||||
/* use translation callback */
|
||||
CURLcode result = data->set.convtonetwork(buffer, length);
|
||||
CURLcode result;
|
||||
Curl_set_in_callback(data, true);
|
||||
result = data->set.convtonetwork(buffer, length);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(result) {
|
||||
failf(data,
|
||||
"CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
|
||||
@ -147,7 +151,10 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
|
||||
{
|
||||
if(data && data->set.convfromnetwork) {
|
||||
/* use translation callback */
|
||||
CURLcode result = data->set.convfromnetwork(buffer, length);
|
||||
CURLcode result;
|
||||
Curl_set_in_callback(data, true);
|
||||
result = data->set.convfromnetwork(buffer, length);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(result) {
|
||||
failf(data,
|
||||
"CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
|
||||
@ -210,7 +217,10 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
|
||||
{
|
||||
if(data && data->set.convfromutf8) {
|
||||
/* use translation callback */
|
||||
CURLcode result = data->set.convfromutf8(buffer, length);
|
||||
CURLcode result;
|
||||
Curl_set_in_callback(data, true);
|
||||
result = data->set.convfromutf8(buffer, length);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(result) {
|
||||
failf(data,
|
||||
"CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
|
||||
|
@ -186,11 +186,9 @@ int GetOrSetUpData(int id, libdata_t **appData,
|
||||
|
||||
app_data = (libdata_t *) get_app_data(id);
|
||||
if(!app_data) {
|
||||
app_data = malloc(sizeof(libdata_t));
|
||||
app_data = calloc(1, sizeof(libdata_t));
|
||||
|
||||
if(app_data) {
|
||||
memset(app_data, 0, sizeof(libdata_t));
|
||||
|
||||
app_data->tenbytes = malloc(10);
|
||||
app_data->lock = NXMutexAlloc(0, 0, &liblock);
|
||||
|
||||
|
@ -5,8 +5,8 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2010, 2017, Howard Chu, <hyc@openldap.org>
|
||||
* Copyright (C) 2011 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
|
||||
* Copyright (C) 2011 - 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
|
||||
@ -221,7 +221,7 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
|
||||
if(conn->handler->flags & PROTOPT_SSL)
|
||||
*ptr++ = 's';
|
||||
snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
|
||||
conn->host.name, conn->remote_port);
|
||||
conn->host.name, conn->remote_port);
|
||||
|
||||
#ifdef CURL_OPENLDAP_DEBUG
|
||||
static int do_trace = 0;
|
||||
@ -286,7 +286,7 @@ static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
|
||||
|
||||
tvp = &tv;
|
||||
|
||||
retry:
|
||||
retry:
|
||||
if(!li->didbind) {
|
||||
char *binddn;
|
||||
struct berval passwd;
|
||||
@ -472,8 +472,8 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
|
||||
return ret;
|
||||
|
||||
for(ent = ldap_first_message(li->ld, msg); ent;
|
||||
ent = ldap_next_message(li->ld, ent)) {
|
||||
struct berval bv, *bvals, **bvp = &bvals;
|
||||
ent = ldap_next_message(li->ld, ent)) {
|
||||
struct berval bv, *bvals;
|
||||
int binary = 0, msgtype;
|
||||
CURLcode writeerr;
|
||||
|
||||
@ -535,18 +535,40 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
|
||||
}
|
||||
data->req.bytecount += bv.bv_len + 5;
|
||||
|
||||
for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp);
|
||||
rc == LDAP_SUCCESS;
|
||||
rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp)) {
|
||||
for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals);
|
||||
rc == LDAP_SUCCESS;
|
||||
rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals)) {
|
||||
int i;
|
||||
|
||||
if(bv.bv_val == NULL) break;
|
||||
if(bv.bv_val == NULL)
|
||||
break;
|
||||
|
||||
if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7))
|
||||
binary = 1;
|
||||
else
|
||||
binary = 0;
|
||||
|
||||
if(bvals == NULL) {
|
||||
writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
|
||||
if(writeerr) {
|
||||
*err = writeerr;
|
||||
return -1;
|
||||
}
|
||||
writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
|
||||
bv.bv_len);
|
||||
if(writeerr) {
|
||||
*err = writeerr;
|
||||
return -1;
|
||||
}
|
||||
writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":\n", 2);
|
||||
if(writeerr) {
|
||||
*err = writeerr;
|
||||
return -1;
|
||||
}
|
||||
data->req.bytecount += bv.bv_len + 3;
|
||||
continue;
|
||||
}
|
||||
|
||||
for(i = 0; bvals[i].bv_val != NULL; i++) {
|
||||
int binval = 0;
|
||||
writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
|
||||
@ -555,24 +577,24 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
|
||||
return -1;
|
||||
}
|
||||
|
||||
writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
|
||||
bv.bv_len);
|
||||
if(writeerr) {
|
||||
*err = writeerr;
|
||||
return -1;
|
||||
}
|
||||
writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
|
||||
bv.bv_len);
|
||||
if(writeerr) {
|
||||
*err = writeerr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1);
|
||||
if(writeerr) {
|
||||
*err = writeerr;
|
||||
return -1;
|
||||
}
|
||||
if(writeerr) {
|
||||
*err = writeerr;
|
||||
return -1;
|
||||
}
|
||||
data->req.bytecount += bv.bv_len + 2;
|
||||
|
||||
if(!binary) {
|
||||
/* check for leading or trailing whitespace */
|
||||
if(ISSPACE(bvals[i].bv_val[0]) ||
|
||||
ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1]))
|
||||
ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1]))
|
||||
binval = 1;
|
||||
else {
|
||||
/* check for unprintable characters */
|
||||
@ -610,7 +632,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
|
||||
data->req.bytecount += 2;
|
||||
if(val_b64_sz > 0) {
|
||||
writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
|
||||
val_b64_sz);
|
||||
val_b64_sz);
|
||||
if(writeerr) {
|
||||
*err = writeerr;
|
||||
return -1;
|
||||
|
@ -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
|
||||
@ -119,6 +119,7 @@ static int parsedate(const char *date, time_t *output);
|
||||
#define tDAYZONE -60 /* offset for daylight savings time */
|
||||
static const struct tzinfo tz[]= {
|
||||
{"GMT", 0}, /* Greenwich Mean */
|
||||
{"UT", 0}, /* Universal Time */
|
||||
{"UTC", 0}, /* Universal (Coordinated) */
|
||||
{"WET", 0}, /* Western European */
|
||||
{"BST", 0 tDAYZONE}, /* British Summer */
|
||||
@ -276,26 +277,23 @@ struct my_tm {
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_year; /* full year */
|
||||
};
|
||||
|
||||
/* struct tm to time since epoch in GMT time zone.
|
||||
* This is similar to the standard mktime function but for GMT only, and
|
||||
* doesn't suffer from the various bugs and portability problems that
|
||||
* some systems' implementations have.
|
||||
*
|
||||
* Returns 0 on success, otherwise non-zero.
|
||||
*/
|
||||
static time_t my_timegm(struct my_tm *tm)
|
||||
static void my_timegm(struct my_tm *tm, time_t *t)
|
||||
{
|
||||
static const int month_days_cumulative [12] =
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
||||
int month, year, leap_days;
|
||||
|
||||
if(tm->tm_year < 70)
|
||||
/* we don't support years before 1970 as they will cause this function
|
||||
to return a negative value */
|
||||
return -1;
|
||||
|
||||
year = tm->tm_year + 1900;
|
||||
year = tm->tm_year;
|
||||
month = tm->tm_mon;
|
||||
if(month < 0) {
|
||||
year += (11 - month) / 12;
|
||||
@ -310,9 +308,9 @@ static time_t my_timegm(struct my_tm *tm)
|
||||
leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400)
|
||||
- (1969 / 4) + (1969 / 100) - (1969 / 400));
|
||||
|
||||
return ((((time_t) (year - 1970) * 365
|
||||
+ leap_days + month_days_cumulative [month] + tm->tm_mday - 1) * 24
|
||||
+ tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
|
||||
*t = ((((time_t) (year - 1970) * 365
|
||||
+ leap_days + month_days_cumulative[month] + tm->tm_mday - 1) * 24
|
||||
+ tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -436,7 +434,7 @@ static int parsedate(const char *date, time_t *output)
|
||||
tzoff = (val/100 * 60 + val%100)*60;
|
||||
|
||||
/* the + and - prefix indicates the local time compared to GMT,
|
||||
this we need ther reversed math to get what we want */
|
||||
this we need their reversed math to get what we want */
|
||||
tzoff = date[-1]=='+'?-tzoff:tzoff;
|
||||
}
|
||||
|
||||
@ -462,7 +460,7 @@ static int parsedate(const char *date, time_t *output)
|
||||
if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) {
|
||||
yearnum = val;
|
||||
found = TRUE;
|
||||
if(yearnum < 1900) {
|
||||
if(yearnum < 100) {
|
||||
if(yearnum > 70)
|
||||
yearnum += 1900;
|
||||
else
|
||||
@ -491,18 +489,39 @@ static int parsedate(const char *date, time_t *output)
|
||||
/* lacks vital info, fail */
|
||||
return PARSEDATE_FAIL;
|
||||
|
||||
#if SIZEOF_TIME_T < 5
|
||||
/* 32 bit time_t can only hold dates to the beginning of 2038 */
|
||||
if(yearnum > 2037) {
|
||||
*output = 0x7fffffff;
|
||||
return PARSEDATE_LATER;
|
||||
#ifdef HAVE_TIME_T_UNSIGNED
|
||||
if(yearnum < 1970) {
|
||||
/* only positive numbers cannot return earlier */
|
||||
*output = TIME_T_MIN;
|
||||
return PARSEDATE_SOONER;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(yearnum < 1970) {
|
||||
*output = 0;
|
||||
#if (SIZEOF_TIME_T < 5)
|
||||
|
||||
#ifdef HAVE_TIME_T_UNSIGNED
|
||||
/* an unsigned 32 bit time_t can only hold dates to 2106 */
|
||||
if(yearnum > 2105) {
|
||||
*output = TIME_T_MAX;
|
||||
return PARSEDATE_LATER;
|
||||
}
|
||||
#else
|
||||
/* a signed 32 bit time_t can only hold dates to the beginning of 2038 */
|
||||
if(yearnum > 2037) {
|
||||
*output = TIME_T_MAX;
|
||||
return PARSEDATE_LATER;
|
||||
}
|
||||
if(yearnum < 1903) {
|
||||
*output = TIME_T_MIN;
|
||||
return PARSEDATE_SOONER;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* The Gregorian calendar was introduced 1582 */
|
||||
if(yearnum < 1583)
|
||||
return PARSEDATE_FAIL;
|
||||
#endif
|
||||
|
||||
if((mdaynum > 31) || (monnum > 11) ||
|
||||
(hournum > 23) || (minnum > 59) || (secnum > 60))
|
||||
@ -513,31 +532,25 @@ static int parsedate(const char *date, time_t *output)
|
||||
tm.tm_hour = hournum;
|
||||
tm.tm_mday = mdaynum;
|
||||
tm.tm_mon = monnum;
|
||||
tm.tm_year = yearnum - 1900;
|
||||
tm.tm_year = yearnum;
|
||||
|
||||
/* my_timegm() returns a time_t. time_t is often 32 bits, even on many
|
||||
architectures that feature 64 bit 'long'.
|
||||
|
||||
Some systems have 64 bit time_t and deal with years beyond 2038. However,
|
||||
even on some of the systems with 64 bit time_t mktime() returns -1 for
|
||||
dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06)
|
||||
/* my_timegm() returns a time_t. time_t is often 32 bits, sometimes even on
|
||||
architectures that feature 64 bit 'long' but ultimately time_t is the
|
||||
correct data type to use.
|
||||
*/
|
||||
t = my_timegm(&tm);
|
||||
my_timegm(&tm, &t);
|
||||
|
||||
/* time zone adjust (cast t to int to compare to negative one) */
|
||||
if(-1 != (int)t) {
|
||||
/* Add the time zone diff between local time zone and GMT. */
|
||||
if(tzoff == -1)
|
||||
tzoff = 0;
|
||||
|
||||
/* Add the time zone diff between local time zone and GMT. */
|
||||
long delta = (long)(tzoff!=-1?tzoff:0);
|
||||
|
||||
if((delta>0) && (t > LONG_MAX - delta)) {
|
||||
*output = 0x7fffffff;
|
||||
return PARSEDATE_LATER; /* time_t overflow */
|
||||
}
|
||||
|
||||
t += delta;
|
||||
if((tzoff > 0) && (t > TIME_T_MAX - tzoff)) {
|
||||
*output = TIME_T_MAX;
|
||||
return PARSEDATE_LATER; /* time_t overflow */
|
||||
}
|
||||
|
||||
t += tzoff;
|
||||
|
||||
*output = t;
|
||||
|
||||
return PARSEDATE_OK;
|
||||
@ -549,10 +562,10 @@ time_t curl_getdate(const char *p, const time_t *now)
|
||||
int rc = parsedate(p, &parsed);
|
||||
(void)now; /* legacy argument from the past that we ignore */
|
||||
|
||||
switch(rc) {
|
||||
case PARSEDATE_OK:
|
||||
case PARSEDATE_LATER:
|
||||
case PARSEDATE_SOONER:
|
||||
if(rc == PARSEDATE_OK) {
|
||||
if(parsed == -1)
|
||||
/* avoid returning -1 for a working scenario */
|
||||
parsed++;
|
||||
return parsed;
|
||||
}
|
||||
/* everything else is fail */
|
||||
|
@ -304,7 +304,10 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
|
||||
* it would have been populated with something of size int to begin
|
||||
* with, even though its datatype may be larger than an int.
|
||||
*/
|
||||
DEBUGASSERT((ptr + pp->cache_size) <= (buf + data->set.buffer_size + 1));
|
||||
if((ptr + pp->cache_size) > (buf + data->set.buffer_size + 1)) {
|
||||
failf(data, "cached response data too big to handle");
|
||||
return CURLE_RECV_ERROR;
|
||||
}
|
||||
memcpy(ptr, pp->cache, pp->cache_size);
|
||||
gotbytes = (ssize_t)pp->cache_size;
|
||||
free(pp->cache); /* free the cache */
|
||||
|
@ -24,9 +24,13 @@
|
||||
|
||||
#include "urldata.h"
|
||||
#include "sendf.h"
|
||||
#include "multiif.h"
|
||||
#include "progress.h"
|
||||
#include "curl_printf.h"
|
||||
|
||||
/* check rate limits within this many recent milliseconds, at minimum. */
|
||||
#define MIN_RATE_LIMIT_PERIOD 3000
|
||||
|
||||
/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero
|
||||
byte) */
|
||||
static void time2str(char *r, curl_off_t seconds)
|
||||
@ -234,11 +238,12 @@ void Curl_pgrsStartNow(struct Curl_easy *data)
|
||||
data->progress.dl_limit_start.tv_usec = 0;
|
||||
/* clear all bits except HIDE and HEADERS_OUT */
|
||||
data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT;
|
||||
Curl_ratelimit(data, data->progress.start);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used to handle speed limits, calculating how much milliseconds we
|
||||
* need to wait until we're back under the speed limit, if needed.
|
||||
* This is used to handle speed limits, calculating how many milliseconds to
|
||||
* wait until we're back under the speed limit, if needed.
|
||||
*
|
||||
* The way it works is by having a "starting point" (time & amount of data
|
||||
* transferred by then) used in the speed computation, to be used instead of
|
||||
@ -250,73 +255,87 @@ void Curl_pgrsStartNow(struct Curl_easy *data)
|
||||
* the starting point, the limit (in bytes/s), the time of the starting point
|
||||
* and the current time.
|
||||
*
|
||||
* Returns -1 if no waiting is needed (not enough data transferred since
|
||||
* starting point yet), 0 when no waiting is needed but the starting point
|
||||
* should be reset (to current), or the number of milliseconds to wait to get
|
||||
* back under the speed limit.
|
||||
* Returns 0 if no waiting is needed or when no waiting is needed but the
|
||||
* starting point should be reset (to current); or the number of milliseconds
|
||||
* to wait to get back under the speed limit.
|
||||
*/
|
||||
long Curl_pgrsLimitWaitTime(curl_off_t cursize,
|
||||
curl_off_t startsize,
|
||||
curl_off_t limit,
|
||||
struct curltime start,
|
||||
struct curltime now)
|
||||
timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
|
||||
curl_off_t startsize,
|
||||
curl_off_t limit,
|
||||
struct curltime start,
|
||||
struct curltime now)
|
||||
{
|
||||
curl_off_t size = cursize - startsize;
|
||||
time_t minimum;
|
||||
time_t actual;
|
||||
|
||||
/* we don't have a starting point yet -- return 0 so it gets (re)set */
|
||||
if(start.tv_sec == 0 && start.tv_usec == 0)
|
||||
if(!limit || !size)
|
||||
return 0;
|
||||
|
||||
/* not enough data yet */
|
||||
if(size < limit)
|
||||
return -1;
|
||||
/*
|
||||
* 'minimum' is the number of milliseconds 'size' should take to download to
|
||||
* stay below 'limit'.
|
||||
*/
|
||||
if(size < CURL_OFF_T_MAX/1000)
|
||||
minimum = (time_t) (CURL_OFF_T_C(1000) * size / limit);
|
||||
else {
|
||||
minimum = (time_t) (size / limit);
|
||||
if(minimum < TIME_T_MAX/1000)
|
||||
minimum *= 1000;
|
||||
else
|
||||
minimum = TIME_T_MAX;
|
||||
}
|
||||
|
||||
minimum = (time_t) (CURL_OFF_T_C(1000) * size / limit);
|
||||
/*
|
||||
* 'actual' is the time in milliseconds it took to actually download the
|
||||
* last 'size' bytes.
|
||||
*/
|
||||
actual = Curl_timediff(now, start);
|
||||
|
||||
if(actual < minimum)
|
||||
/* this is a conversion on some systems (64bit time_t => 32bit long) */
|
||||
return (long)(minimum - actual);
|
||||
if(actual < minimum) {
|
||||
/* if it downloaded the data faster than the limit, make it wait the
|
||||
difference */
|
||||
return (minimum - actual);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the number of downloaded bytes so far.
|
||||
*/
|
||||
void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
|
||||
{
|
||||
struct curltime now = Curl_now();
|
||||
|
||||
data->progress.downloaded = size;
|
||||
}
|
||||
|
||||
/* download speed limit */
|
||||
if((data->set.max_recv_speed > 0) &&
|
||||
(Curl_pgrsLimitWaitTime(data->progress.downloaded,
|
||||
data->progress.dl_limit_size,
|
||||
data->set.max_recv_speed,
|
||||
data->progress.dl_limit_start,
|
||||
now) == 0)) {
|
||||
data->progress.dl_limit_start = now;
|
||||
data->progress.dl_limit_size = size;
|
||||
/*
|
||||
* Update the timestamp and sizestamp to use for rate limit calculations.
|
||||
*/
|
||||
void Curl_ratelimit(struct Curl_easy *data, struct curltime now)
|
||||
{
|
||||
/* don't set a new stamp unless the time since last update is long enough */
|
||||
if(data->set.max_recv_speed > 0) {
|
||||
if(Curl_timediff(now, data->progress.dl_limit_start) >=
|
||||
MIN_RATE_LIMIT_PERIOD) {
|
||||
data->progress.dl_limit_start = now;
|
||||
data->progress.dl_limit_size = data->progress.downloaded;
|
||||
}
|
||||
}
|
||||
if(data->set.max_send_speed > 0) {
|
||||
if(Curl_timediff(now, data->progress.ul_limit_start) >=
|
||||
MIN_RATE_LIMIT_PERIOD) {
|
||||
data->progress.ul_limit_start = now;
|
||||
data->progress.ul_limit_size = data->progress.uploaded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the number of uploaded bytes so far.
|
||||
*/
|
||||
void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size)
|
||||
{
|
||||
struct curltime now = Curl_now();
|
||||
|
||||
data->progress.uploaded = size;
|
||||
|
||||
/* upload speed limit */
|
||||
if((data->set.max_send_speed > 0) &&
|
||||
(Curl_pgrsLimitWaitTime(data->progress.uploaded,
|
||||
data->progress.ul_limit_size,
|
||||
data->set.max_send_speed,
|
||||
data->progress.ul_limit_start,
|
||||
now) == 0)) {
|
||||
data->progress.ul_limit_start = now;
|
||||
data->progress.ul_limit_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size)
|
||||
@ -461,22 +480,26 @@ int Curl_pgrsUpdate(struct connectdata *conn)
|
||||
|
||||
if(data->set.fxferinfo) {
|
||||
/* There's a callback set, call that */
|
||||
Curl_set_in_callback(data, true);
|
||||
result = data->set.fxferinfo(data->set.progress_client,
|
||||
data->progress.size_dl,
|
||||
data->progress.downloaded,
|
||||
data->progress.size_ul,
|
||||
data->progress.uploaded);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(result)
|
||||
failf(data, "Callback aborted");
|
||||
return result;
|
||||
}
|
||||
if(data->set.fprogress) {
|
||||
/* The older deprecated callback is set, call that */
|
||||
Curl_set_in_callback(data, true);
|
||||
result = data->set.fprogress(data->set.progress_client,
|
||||
(double)data->progress.size_dl,
|
||||
(double)data->progress.downloaded,
|
||||
(double)data->progress.size_ul,
|
||||
(double)data->progress.uploaded);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(result)
|
||||
failf(data, "Callback aborted");
|
||||
return result;
|
||||
|
@ -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
|
||||
@ -46,14 +46,15 @@ void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size);
|
||||
void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size);
|
||||
void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size);
|
||||
void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
|
||||
void Curl_ratelimit(struct Curl_easy *data, struct curltime now);
|
||||
int Curl_pgrsUpdate(struct connectdata *);
|
||||
void Curl_pgrsResetTransferSizes(struct Curl_easy *data);
|
||||
void Curl_pgrsTime(struct Curl_easy *data, timerid timer);
|
||||
long Curl_pgrsLimitWaitTime(curl_off_t cursize,
|
||||
curl_off_t startsize,
|
||||
curl_off_t limit,
|
||||
struct curltime start,
|
||||
struct curltime now);
|
||||
timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
|
||||
curl_off_t startsize,
|
||||
curl_off_t limit,
|
||||
struct curltime start,
|
||||
struct curltime now);
|
||||
|
||||
/* Don't show progress for sizes smaller than: */
|
||||
#define LEAST_SIZE_PROGRESS BUFSIZE
|
||||
|
@ -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
|
||||
@ -47,7 +47,7 @@
|
||||
* -incoming server requests
|
||||
* -server CSeq counter
|
||||
* -digest authentication
|
||||
* -connect thru proxy
|
||||
* -connect through proxy
|
||||
* -pipelining?
|
||||
*/
|
||||
|
||||
@ -357,7 +357,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
|
||||
}
|
||||
|
||||
/* Transport Header for SETUP requests */
|
||||
p_transport = Curl_checkheaders(conn, "Transport:");
|
||||
p_transport = Curl_checkheaders(conn, "Transport");
|
||||
if(rtspreq == RTSPREQ_SETUP && !p_transport) {
|
||||
/* New Transport: setting? */
|
||||
if(data->set.str[STRING_RTSP_TRANSPORT]) {
|
||||
@ -381,11 +381,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
|
||||
/* Accept Headers for DESCRIBE requests */
|
||||
if(rtspreq == RTSPREQ_DESCRIBE) {
|
||||
/* Accept Header */
|
||||
p_accept = Curl_checkheaders(conn, "Accept:")?
|
||||
p_accept = Curl_checkheaders(conn, "Accept")?
|
||||
NULL:"Accept: application/sdp\r\n";
|
||||
|
||||
/* Accept-Encoding header */
|
||||
if(!Curl_checkheaders(conn, "Accept-Encoding:") &&
|
||||
if(!Curl_checkheaders(conn, "Accept-Encoding") &&
|
||||
data->set.str[STRING_ENCODING]) {
|
||||
Curl_safefree(conn->allocptr.accept_encoding);
|
||||
conn->allocptr.accept_encoding =
|
||||
@ -402,11 +402,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
|
||||
it might have been used in the proxy connect, but if we have got a header
|
||||
with the user-agent string specified, we erase the previously made string
|
||||
here. */
|
||||
if(Curl_checkheaders(conn, "User-Agent:") && conn->allocptr.uagent) {
|
||||
if(Curl_checkheaders(conn, "User-Agent") && conn->allocptr.uagent) {
|
||||
Curl_safefree(conn->allocptr.uagent);
|
||||
conn->allocptr.uagent = NULL;
|
||||
}
|
||||
else if(!Curl_checkheaders(conn, "User-Agent:") &&
|
||||
else if(!Curl_checkheaders(conn, "User-Agent") &&
|
||||
data->set.str[STRING_USERAGENT]) {
|
||||
p_uagent = conn->allocptr.uagent;
|
||||
}
|
||||
@ -421,7 +421,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
|
||||
|
||||
/* Referrer */
|
||||
Curl_safefree(conn->allocptr.ref);
|
||||
if(data->change.referer && !Curl_checkheaders(conn, "Referer:"))
|
||||
if(data->change.referer && !Curl_checkheaders(conn, "Referer"))
|
||||
conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
|
||||
else
|
||||
conn->allocptr.ref = NULL;
|
||||
@ -438,7 +438,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
|
||||
(rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) {
|
||||
|
||||
/* Check to see if there is a range set in the custom headers */
|
||||
if(!Curl_checkheaders(conn, "Range:") && data->state.range) {
|
||||
if(!Curl_checkheaders(conn, "Range") && data->state.range) {
|
||||
Curl_safefree(conn->allocptr.rangeline);
|
||||
conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
|
||||
p_range = conn->allocptr.rangeline;
|
||||
@ -448,11 +448,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
|
||||
/*
|
||||
* Sanity check the custom headers
|
||||
*/
|
||||
if(Curl_checkheaders(conn, "CSeq:")) {
|
||||
if(Curl_checkheaders(conn, "CSeq")) {
|
||||
failf(data, "CSeq cannot be set as a custom header.");
|
||||
return CURLE_RTSP_CSEQ_ERROR;
|
||||
}
|
||||
if(Curl_checkheaders(conn, "Session:")) {
|
||||
if(Curl_checkheaders(conn, "Session")) {
|
||||
failf(data, "Session ID cannot be set as a custom header.");
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
@ -542,7 +542,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
|
||||
if(putsize > 0 || postsize > 0) {
|
||||
/* 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:")) {
|
||||
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));
|
||||
@ -552,7 +552,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
|
||||
|
||||
if(rtspreq == RTSPREQ_SET_PARAMETER ||
|
||||
rtspreq == RTSPREQ_GET_PARAMETER) {
|
||||
if(!Curl_checkheaders(conn, "Content-Type:")) {
|
||||
if(!Curl_checkheaders(conn, "Content-Type")) {
|
||||
result = Curl_add_bufferf(req_buffer,
|
||||
"Content-Type: text/parameters\r\n");
|
||||
if(result)
|
||||
@ -561,7 +561,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
|
||||
}
|
||||
|
||||
if(rtspreq == RTSPREQ_ANNOUNCE) {
|
||||
if(!Curl_checkheaders(conn, "Content-Type:")) {
|
||||
if(!Curl_checkheaders(conn, "Content-Type")) {
|
||||
result = Curl_add_bufferf(req_buffer,
|
||||
"Content-Type: application/sdp\r\n");
|
||||
if(result)
|
||||
@ -764,13 +764,14 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
|
||||
writeit = data->set.fwrite_rtp;
|
||||
user_ptr = data->set.rtp_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
writeit = data->set.fwrite_func;
|
||||
user_ptr = data->set.out;
|
||||
}
|
||||
|
||||
Curl_set_in_callback(data, true);
|
||||
wrote = writeit(ptr, 1, len, user_ptr);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
if(CURL_WRITEFUNC_PAUSE == wrote) {
|
||||
failf(data, "Cannot pause RTP");
|
||||
|
@ -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
|
||||
@ -37,6 +37,7 @@
|
||||
#include "connect.h"
|
||||
#include "vtls/vtls.h"
|
||||
#include "ssh.h"
|
||||
#include "easyif.h"
|
||||
#include "multiif.h"
|
||||
#include "non-ascii.h"
|
||||
#include "strerror.h"
|
||||
@ -388,7 +389,7 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
|
||||
(WSAEWOULDBLOCK == err)
|
||||
#else
|
||||
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
|
||||
due to its inability to send off data without blocking. We therefor
|
||||
due to its inability to send off data without blocking. We therefore
|
||||
treat both error codes the same here */
|
||||
(EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) ||
|
||||
(EINPROGRESS == err)
|
||||
@ -455,7 +456,7 @@ ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
|
||||
(WSAEWOULDBLOCK == err)
|
||||
#else
|
||||
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
|
||||
due to its inability to send off data without blocking. We therefor
|
||||
due to its inability to send off data without blocking. We therefore
|
||||
treat both error codes the same here */
|
||||
(EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
|
||||
#endif
|
||||
@ -540,18 +541,20 @@ static CURLcode pausewrite(struct Curl_easy *data,
|
||||
}
|
||||
|
||||
|
||||
/* Curl_client_chop_write() writes chunks of data not larger than
|
||||
* CURL_MAX_WRITE_SIZE via client write callback(s) and
|
||||
* takes care of pause requests from the callbacks.
|
||||
/* chop_write() writes chunks of data not larger than CURL_MAX_WRITE_SIZE via
|
||||
* client write callback(s) and takes care of pause requests from the
|
||||
* callbacks.
|
||||
*/
|
||||
CURLcode Curl_client_chop_write(struct connectdata *conn,
|
||||
int type,
|
||||
char *ptr,
|
||||
size_t len)
|
||||
static CURLcode chop_write(struct connectdata *conn,
|
||||
int type,
|
||||
char *optr,
|
||||
size_t olen)
|
||||
{
|
||||
struct Curl_easy *data = conn->data;
|
||||
curl_write_callback writeheader = NULL;
|
||||
curl_write_callback writebody = NULL;
|
||||
char *ptr = optr;
|
||||
size_t len = olen;
|
||||
|
||||
if(!len)
|
||||
return CURLE_OK;
|
||||
@ -597,25 +600,30 @@ CURLcode Curl_client_chop_write(struct connectdata *conn,
|
||||
}
|
||||
}
|
||||
|
||||
if(writeheader) {
|
||||
size_t wrote = writeheader(ptr, 1, chunklen, data->set.writeheader);
|
||||
|
||||
if(CURL_WRITEFUNC_PAUSE == wrote)
|
||||
/* here we pass in the HEADER bit only since if this was body as well
|
||||
then it was passed already and clearly that didn't trigger the
|
||||
pause, so this is saved for later with the HEADER bit only */
|
||||
return pausewrite(data, CLIENTWRITE_HEADER, ptr, len);
|
||||
|
||||
if(wrote != chunklen) {
|
||||
failf(data, "Failed writing header");
|
||||
return CURLE_WRITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ptr += chunklen;
|
||||
len -= chunklen;
|
||||
}
|
||||
|
||||
if(writeheader) {
|
||||
size_t wrote;
|
||||
ptr = optr;
|
||||
len = olen;
|
||||
Curl_set_in_callback(data, true);
|
||||
wrote = writeheader(ptr, 1, len, data->set.writeheader);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
if(CURL_WRITEFUNC_PAUSE == wrote)
|
||||
/* here we pass in the HEADER bit only since if this was body as well
|
||||
then it was passed already and clearly that didn't trigger the
|
||||
pause, so this is saved for later with the HEADER bit only */
|
||||
return pausewrite(data, CLIENTWRITE_HEADER, ptr, len);
|
||||
|
||||
if(wrote != len) {
|
||||
failf(data, "Failed writing header");
|
||||
return CURLE_WRITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@ -657,7 +665,7 @@ CURLcode Curl_client_write(struct connectdata *conn,
|
||||
#endif /* CURL_DO_LINEEND_CONV */
|
||||
}
|
||||
|
||||
return Curl_client_chop_write(conn, type, ptr, len);
|
||||
return chop_write(conn, type, ptr, len);
|
||||
}
|
||||
|
||||
CURLcode Curl_read_plain(curl_socket_t sockfd,
|
||||
@ -798,8 +806,11 @@ static int showit(struct Curl_easy *data, curl_infotype type,
|
||||
}
|
||||
#endif /* CURL_DOES_CONVERSIONS */
|
||||
|
||||
if(data->set.fdebug)
|
||||
if(data->set.fdebug) {
|
||||
Curl_set_in_callback(data, true);
|
||||
rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
else {
|
||||
switch(type) {
|
||||
case CURLINFO_TEXT:
|
||||
|
@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2014, 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
|
||||
@ -51,8 +51,6 @@ void Curl_failf(struct Curl_easy *, const char *fmt, ...);
|
||||
#define CLIENTWRITE_HEADER (1<<1)
|
||||
#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
|
||||
|
||||
CURLcode Curl_client_chop_write(struct connectdata *conn, int type, char *ptr,
|
||||
size_t len) WARN_UNUSED_RESULT;
|
||||
CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,
|
||||
size_t len) WARN_UNUSED_RESULT;
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "sendf.h"
|
||||
#include "http2.h"
|
||||
#include "setopt.h"
|
||||
#include "multiif.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
@ -361,6 +362,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
data->set.timevalue = (time_t)va_arg(param, long);
|
||||
break;
|
||||
|
||||
case CURLOPT_TIMEVALUE_LARGE:
|
||||
/*
|
||||
* This is the value to compare with the remote document with the
|
||||
* method set with CURLOPT_TIMECONDITION
|
||||
*/
|
||||
data->set.timevalue = (time_t)va_arg(param, curl_off_t);
|
||||
break;
|
||||
|
||||
case CURLOPT_SSLVERSION:
|
||||
case CURLOPT_PROXY_SSLVERSION:
|
||||
/*
|
||||
@ -772,11 +781,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
|
||||
if(checkprefix("Set-Cookie:", argptr))
|
||||
/* HTTP Header format line */
|
||||
Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL);
|
||||
Curl_cookie_add(data, data->cookies, TRUE, FALSE, argptr + 11, NULL,
|
||||
NULL);
|
||||
|
||||
else
|
||||
/* Netscape format line */
|
||||
Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL);
|
||||
Curl_cookie_add(data, data->cookies, FALSE, FALSE, argptr, NULL,
|
||||
NULL);
|
||||
|
||||
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
|
||||
free(argptr);
|
||||
@ -1028,6 +1039,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
*/
|
||||
data->set.socks5_gssapi_nec = (0 != va_arg(param, long)) ? TRUE : FALSE;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case CURLOPT_SOCKS5_GSSAPI_SERVICE:
|
||||
case CURLOPT_PROXY_SERVICE_NAME:
|
||||
@ -1037,10 +1049,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
result = Curl_setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME],
|
||||
va_arg(param, char *));
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
|
||||
defined(USE_SPNEGO)
|
||||
case CURLOPT_SERVICE_NAME:
|
||||
/*
|
||||
* Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
|
||||
@ -1049,8 +1058,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
va_arg(param, char *));
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
case CURLOPT_HEADERDATA:
|
||||
/*
|
||||
* Custom pointer to pass the header write callback function
|
||||
@ -1594,6 +1601,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE;
|
||||
break;
|
||||
|
||||
case CURLOPT_HAPROXYPROTOCOL:
|
||||
/*
|
||||
* Set to send the HAProxy Proxy Protocol header
|
||||
*/
|
||||
data->set.haproxyprotocol = (0 != va_arg(param, long)) ? TRUE : FALSE;
|
||||
break;
|
||||
|
||||
case CURLOPT_INTERFACE:
|
||||
/*
|
||||
* Set what interface or address/hostname to bind the socket to when
|
||||
@ -1734,7 +1748,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
* Set a SSL_CTX callback
|
||||
*/
|
||||
#ifdef USE_SSL
|
||||
if(Curl_ssl->have_ssl_ctx)
|
||||
if(Curl_ssl->supports & SSLSUPP_SSL_CTX)
|
||||
data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
|
||||
else
|
||||
#endif
|
||||
@ -1745,7 +1759,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
* Set a SSL_CTX callback parameter pointer
|
||||
*/
|
||||
#ifdef USE_SSL
|
||||
if(Curl_ssl->have_ssl_ctx)
|
||||
if(Curl_ssl->supports & SSLSUPP_SSL_CTX)
|
||||
data->set.ssl.fsslctxp = va_arg(param, void *);
|
||||
else
|
||||
#endif
|
||||
@ -1764,7 +1778,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
break;
|
||||
case CURLOPT_CERTINFO:
|
||||
#ifdef USE_SSL
|
||||
if(Curl_ssl->have_certinfo)
|
||||
if(Curl_ssl->supports & SSLSUPP_CERTINFO)
|
||||
data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE;
|
||||
else
|
||||
#endif
|
||||
@ -1776,7 +1790,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
* Specify file name of the public key in DER format.
|
||||
*/
|
||||
#ifdef USE_SSL
|
||||
if(Curl_ssl->have_pinnedpubkey)
|
||||
if(Curl_ssl->supports & SSLSUPP_PINNEDPUBKEY)
|
||||
result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG],
|
||||
va_arg(param, char *));
|
||||
else
|
||||
@ -1789,7 +1803,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
* Specify file name of the public key in DER format.
|
||||
*/
|
||||
#ifdef USE_SSL
|
||||
if(Curl_ssl->have_pinnedpubkey)
|
||||
if(Curl_ssl->supports & SSLSUPP_PINNEDPUBKEY)
|
||||
result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
|
||||
va_arg(param, char *));
|
||||
else
|
||||
@ -1817,7 +1831,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
* certificates which have been prepared using openssl c_rehash utility.
|
||||
*/
|
||||
#ifdef USE_SSL
|
||||
if(Curl_ssl->have_ca_path)
|
||||
if(Curl_ssl->supports & SSLSUPP_CA_PATH)
|
||||
/* This does not work on windows. */
|
||||
result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG],
|
||||
va_arg(param, char *));
|
||||
@ -1831,7 +1845,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
* CA certificates which have been prepared using openssl c_rehash utility.
|
||||
*/
|
||||
#ifdef USE_SSL
|
||||
if(Curl_ssl->have_ca_path)
|
||||
if(Curl_ssl->supports & SSLSUPP_CA_PATH)
|
||||
/* This does not work on windows. */
|
||||
result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY],
|
||||
va_arg(param, char *));
|
||||
@ -2101,6 +2115,21 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
data->set.fclosesocket = va_arg(param, curl_closesocket_callback);
|
||||
break;
|
||||
|
||||
case CURLOPT_RESOLVER_START_FUNCTION:
|
||||
/*
|
||||
* resolver start callback function: called before a new resolver request
|
||||
* is started
|
||||
*/
|
||||
data->set.resolver_start = va_arg(param, curl_resolver_start_callback);
|
||||
break;
|
||||
|
||||
case CURLOPT_RESOLVER_START_DATA:
|
||||
/*
|
||||
* resolver start callback data pointer. Might be NULL.
|
||||
*/
|
||||
data->set.resolver_start_client = va_arg(param, void *);
|
||||
break;
|
||||
|
||||
case CURLOPT_CLOSESOCKETDATA:
|
||||
/*
|
||||
* socket callback data pointer. Might be NULL.
|
||||
@ -2524,6 +2553,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
case CURLOPT_SSH_COMPRESSION:
|
||||
data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE;
|
||||
break;
|
||||
case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS:
|
||||
arg = va_arg(param, long);
|
||||
if(arg < 0)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
data->set.happy_eyeballs_timeout = arg;
|
||||
break;
|
||||
case CURLOPT_DNS_SHUFFLE_ADDRESSES:
|
||||
data->set.dns_shuffle_addresses = (0 != va_arg(param, long)) ? TRUE:FALSE;
|
||||
break;
|
||||
default:
|
||||
/* unknown tag and its companion, just ignore: */
|
||||
result = CURLE_UNKNOWN_OPTION;
|
||||
@ -2536,6 +2574,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
/*
|
||||
* curl_easy_setopt() is the external interface for setting options on an
|
||||
* easy handle.
|
||||
*
|
||||
* NOTE: This is one of few API functions that are allowed to be called from
|
||||
* within a callback.
|
||||
*/
|
||||
|
||||
#undef curl_easy_setopt
|
||||
|
@ -29,9 +29,17 @@
|
||||
|
||||
#if defined(USE_OPENSSL)
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
|
||||
#define USE_OPENSSL_SHA256
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPENSSL_SHA256
|
||||
/* When OpenSSL is available we use the SHA256-function from OpenSSL */
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#else
|
||||
|
||||
/* When no other crypto library is available we use this code segment */
|
||||
@ -234,7 +242,7 @@ static int SHA256_Final(unsigned char *out,
|
||||
sha256_compress(md, md->buf);
|
||||
md->curlen = 0;
|
||||
}
|
||||
/* pad upto 56 bytes of zeroes */
|
||||
/* pad up to 56 bytes of zeroes */
|
||||
while(md->curlen < 56) {
|
||||
md->buf[md->curlen++] = (unsigned char)0;
|
||||
}
|
||||
|
@ -709,14 +709,21 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a timestamp from the Windows world (100 nsec units from
|
||||
* 1 Jan 1601) to Posix time.
|
||||
* Convert a timestamp from the Windows world (100 nsec units from 1 Jan 1601)
|
||||
* to Posix time. Cap the output to fit within a time_t.
|
||||
*/
|
||||
static void get_posix_time(long *out, curl_off_t timestamp)
|
||||
static void get_posix_time(time_t *out, curl_off_t timestamp)
|
||||
{
|
||||
timestamp -= 116444736000000000;
|
||||
timestamp /= 10000000;
|
||||
*out = (long) timestamp;
|
||||
#if SIZEOF_TIME_T < SIZEOF_CURL_OFF_T
|
||||
if(timestamp > TIME_T_MAX)
|
||||
*out = TIME_T_MAX;
|
||||
else if(timestamp < TIME_T_MIN)
|
||||
*out = TIME_T_MIN;
|
||||
else
|
||||
#endif
|
||||
*out = (time_t) timestamp;
|
||||
}
|
||||
|
||||
static CURLcode smb_request_state(struct connectdata *conn, bool *done)
|
||||
@ -783,10 +790,16 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
|
||||
else {
|
||||
smb_m = (const struct smb_nt_create_response*) msg;
|
||||
conn->data->req.size = smb_swap64(smb_m->end_of_file);
|
||||
Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size);
|
||||
if(conn->data->set.get_filetime)
|
||||
get_posix_time(&conn->data->info.filetime, smb_m->last_change_time);
|
||||
next_state = SMB_DOWNLOAD;
|
||||
if(conn->data->req.size < 0) {
|
||||
req->result = CURLE_WEIRD_SERVER_REPLY;
|
||||
next_state = SMB_CLOSE;
|
||||
}
|
||||
else {
|
||||
Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size);
|
||||
if(conn->data->set.get_filetime)
|
||||
get_posix_time(&conn->data->info.filetime, smb_m->last_change_time);
|
||||
next_state = SMB_DOWNLOAD;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1289,6 +1289,11 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
|
||||
/* Store the first recipient (or NULL if not specified) */
|
||||
smtp->rcpt = data->set.mail_rcpt;
|
||||
|
||||
/* Initial data character is the first character in line: it is implicitly
|
||||
preceded by a virtual CRLF. */
|
||||
smtp->trailing_crlf = TRUE;
|
||||
smtp->eob = 2;
|
||||
|
||||
/* Start the first command in the DO phase */
|
||||
if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt)
|
||||
/* MAIL transfer */
|
||||
|
@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
* Copyright (C) 2017 - 2018 Red Hat, Inc.
|
||||
*
|
||||
* Authors: Nikos Mavrogiannopoulos, Tomas Mraz, Stanislav Zidek,
|
||||
* Robert Kolcun, Andreas Schneider
|
||||
@ -383,8 +383,10 @@ static int myssh_is_known(struct connectdata *conn)
|
||||
}
|
||||
|
||||
/* we don't have anything equivalent to knownkey. Always NULL */
|
||||
Curl_set_in_callback(data, true);
|
||||
rc = func(data, NULL, &foundkey, /* from the remote host */
|
||||
keymatch, data->set.ssh_keyfunc_userp);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
switch(rc) {
|
||||
case CURLKHSTAT_FINE_ADD_TO_FILE:
|
||||
@ -1046,7 +1048,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
|
||||
attrs = sftp_stat(sshc->sftp_session, protop->path);
|
||||
if(attrs != 0) {
|
||||
data->info.filetime = (long)attrs->mtime;
|
||||
data->info.filetime = attrs->mtime;
|
||||
sftp_attributes_free(attrs);
|
||||
}
|
||||
|
||||
@ -1128,8 +1130,10 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
if(data->state.resume_from > 0) {
|
||||
/* Let's read off the proper amount of bytes from the input. */
|
||||
if(conn->seek_func) {
|
||||
Curl_set_in_callback(data, true);
|
||||
seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
|
||||
SEEK_SET);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
|
||||
if(seekerr != CURL_SEEKFUNC_OK) {
|
||||
@ -2421,8 +2425,7 @@ static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
|
||||
ssize_t nread;
|
||||
(void)sockindex;
|
||||
|
||||
if(len >= (size_t)1<<32)
|
||||
len = (size_t)(1<<31)-1;
|
||||
DEBUGASSERT(len < CURL_MAX_READ_SIZE);
|
||||
|
||||
switch(conn->proto.sshc.sftp_recv_state) {
|
||||
case 0:
|
||||
|
@ -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
|
||||
@ -342,6 +342,7 @@ static void state(struct connectdata *conn, sshstate nowstate)
|
||||
"SSH_AUTH_HOST",
|
||||
"SSH_AUTH_KEY_INIT",
|
||||
"SSH_AUTH_KEY",
|
||||
"SSH_AUTH_GSSAPI",
|
||||
"SSH_AUTH_DONE",
|
||||
"SSH_SFTP_INIT",
|
||||
"SSH_SFTP_REALPATH",
|
||||
@ -376,6 +377,7 @@ static void state(struct connectdata *conn, sshstate nowstate)
|
||||
"SSH_SCP_TRANS_INIT",
|
||||
"SSH_SCP_UPLOAD_INIT",
|
||||
"SSH_SCP_DOWNLOAD_INIT",
|
||||
"SSH_SCP_DOWNLOAD",
|
||||
"SSH_SCP_DONE",
|
||||
"SSH_SCP_SEND_EOF",
|
||||
"SSH_SCP_WAIT_EOF",
|
||||
@ -386,6 +388,9 @@ static void state(struct connectdata *conn, sshstate nowstate)
|
||||
"QUIT"
|
||||
};
|
||||
|
||||
/* a precaution to make sure the lists are in sync */
|
||||
DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
|
||||
|
||||
if(sshc->state != nowstate) {
|
||||
infof(conn->data, "SFTP %p state change from %s to %s\n",
|
||||
(void *)sshc, names[sshc->state], names[nowstate]);
|
||||
@ -523,9 +528,11 @@ static CURLcode ssh_knownhost(struct connectdata *conn)
|
||||
keymatch = (enum curl_khmatch)keycheck;
|
||||
|
||||
/* Ask the callback how to behave */
|
||||
Curl_set_in_callback(data, true);
|
||||
rc = func(data, knownkeyp, /* from the knownhosts file */
|
||||
&foundkey, /* from the remote host */
|
||||
keymatch, data->set.ssh_keyfunc_userp);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
else
|
||||
/* no remotekey means failure! */
|
||||
@ -777,8 +784,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
* This is done by simply passing sshc->rsa_pub = NULL.
|
||||
*/
|
||||
if(data->set.str[STRING_SSH_PUBLIC_KEY]
|
||||
/* treat empty string the same way as NULL */
|
||||
&& data->set.str[STRING_SSH_PUBLIC_KEY][0]) {
|
||||
/* treat empty string the same way as NULL */
|
||||
&& data->set.str[STRING_SSH_PUBLIC_KEY][0]) {
|
||||
sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]);
|
||||
if(!sshc->rsa_pub)
|
||||
out_of_memory = TRUE;
|
||||
@ -832,7 +839,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
state(conn, SSH_AUTH_DONE);
|
||||
}
|
||||
else {
|
||||
char *err_msg;
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session,
|
||||
&err_msg, NULL, 0);
|
||||
infof(data, "SSH public key authentication failed: %s\n", err_msg);
|
||||
@ -1039,7 +1046,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
*/
|
||||
sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session);
|
||||
if(!sshc->sftp_session) {
|
||||
char *err_msg;
|
||||
char *err_msg = NULL;
|
||||
if(libssh2_session_last_errno(sshc->ssh_session) ==
|
||||
LIBSSH2_ERROR_EAGAIN) {
|
||||
rc = LIBSSH2_ERROR_EAGAIN;
|
||||
@ -1246,7 +1253,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(strncasecompare(cmd, "ln ", 3) ||
|
||||
strncasecompare(cmd, "symlink ", 8)) {
|
||||
strncasecompare(cmd, "symlink ", 8)) {
|
||||
/* symbolic linking */
|
||||
/* sshc->quote_path1 is the source */
|
||||
/* get the destination */
|
||||
@ -1627,7 +1634,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(rc == 0) {
|
||||
data->info.filetime = (long)attrs.mtime;
|
||||
data->info.filetime = attrs.mtime;
|
||||
}
|
||||
|
||||
state(conn, SSH_SFTP_TRANS_INIT);
|
||||
@ -1747,8 +1754,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
if(data->state.resume_from > 0) {
|
||||
/* Let's read off the proper amount of bytes from the input. */
|
||||
if(conn->seek_func) {
|
||||
Curl_set_in_callback(data, true);
|
||||
seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
|
||||
SEEK_SET);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
|
||||
if(seekerr != CURL_SEEKFUNC_OK) {
|
||||
@ -1765,9 +1774,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
(size_t)data->set.buffer_size :
|
||||
curlx_sotouz(data->state.resume_from - passed);
|
||||
|
||||
size_t actuallyread =
|
||||
data->state.fread_func(data->state.buffer, 1,
|
||||
readthisamountnow, data->state.in);
|
||||
size_t actuallyread;
|
||||
Curl_set_in_callback(data, true);
|
||||
actuallyread = data->state.fread_func(data->state.buffer, 1,
|
||||
readthisamountnow,
|
||||
data->state.in);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
passed += actuallyread;
|
||||
if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
|
||||
@ -2131,8 +2143,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(rc ||
|
||||
!(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) ||
|
||||
(attrs.filesize == 0)) {
|
||||
!(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) ||
|
||||
(attrs.filesize == 0)) {
|
||||
/*
|
||||
* libssh2_sftp_open() didn't return an error, so maybe the server
|
||||
* just doesn't support stat()
|
||||
@ -2264,7 +2276,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(rc < 0) {
|
||||
infof(data, "Failed to close libssh2 file\n");
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session,
|
||||
&err_msg, NULL, 0);
|
||||
infof(data, "Failed to close libssh2 file: %d %s\n", rc, err_msg);
|
||||
}
|
||||
sshc->sftp_handle = NULL;
|
||||
}
|
||||
@ -2298,7 +2313,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(rc < 0) {
|
||||
infof(data, "Failed to close libssh2 file\n");
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg,
|
||||
NULL, 0);
|
||||
infof(data, "Failed to close libssh2 file: %d %s\n", rc, err_msg);
|
||||
}
|
||||
sshc->sftp_handle = NULL;
|
||||
}
|
||||
@ -2353,7 +2371,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
data->state.infilesize);
|
||||
if(!sshc->ssh_channel) {
|
||||
int ssh_err;
|
||||
char *err_msg;
|
||||
char *err_msg = NULL;
|
||||
|
||||
if(libssh2_session_last_errno(sshc->ssh_session) ==
|
||||
LIBSSH2_ERROR_EAGAIN) {
|
||||
@ -2407,9 +2425,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
* be set in sb
|
||||
*/
|
||||
|
||||
/*
|
||||
* If support for >2GB files exists, use it.
|
||||
*/
|
||||
/*
|
||||
* If support for >2GB files exists, use it.
|
||||
*/
|
||||
|
||||
/* get a fresh new channel from the ssh layer */
|
||||
#if LIBSSH2_VERSION_NUM < 0x010700
|
||||
@ -2426,7 +2444,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
|
||||
if(!sshc->ssh_channel) {
|
||||
int ssh_err;
|
||||
char *err_msg;
|
||||
char *err_msg = NULL;
|
||||
|
||||
if(libssh2_session_last_errno(sshc->ssh_session) ==
|
||||
LIBSSH2_ERROR_EAGAIN) {
|
||||
@ -2479,7 +2497,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(rc) {
|
||||
infof(data, "Failed to send libssh2 channel EOF\n");
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session,
|
||||
&err_msg, NULL, 0);
|
||||
infof(data, "Failed to send libssh2 channel EOF: %d %s\n",
|
||||
rc, err_msg);
|
||||
}
|
||||
}
|
||||
state(conn, SSH_SCP_WAIT_EOF);
|
||||
@ -2492,7 +2514,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(rc) {
|
||||
infof(data, "Failed to get channel EOF: %d\n", rc);
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session,
|
||||
&err_msg, NULL, 0);
|
||||
infof(data, "Failed to get channel EOF: %d %s\n", rc, err_msg);
|
||||
}
|
||||
}
|
||||
state(conn, SSH_SCP_WAIT_CLOSE);
|
||||
@ -2505,7 +2530,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(rc) {
|
||||
infof(data, "Channel failed to close: %d\n", rc);
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session,
|
||||
&err_msg, NULL, 0);
|
||||
infof(data, "Channel failed to close: %d %s\n", rc, err_msg);
|
||||
}
|
||||
}
|
||||
state(conn, SSH_SCP_CHANNEL_FREE);
|
||||
@ -2518,7 +2546,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(rc < 0) {
|
||||
infof(data, "Failed to free libssh2 scp subsystem\n");
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session,
|
||||
&err_msg, NULL, 0);
|
||||
infof(data, "Failed to free libssh2 scp subsystem: %d %s\n",
|
||||
rc, err_msg);
|
||||
}
|
||||
sshc->ssh_channel = NULL;
|
||||
}
|
||||
@ -2540,7 +2572,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(rc < 0) {
|
||||
infof(data, "Failed to free libssh2 scp subsystem\n");
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session,
|
||||
&err_msg, NULL, 0);
|
||||
infof(data, "Failed to free libssh2 scp subsystem: %d %s\n",
|
||||
rc, err_msg);
|
||||
}
|
||||
sshc->ssh_channel = NULL;
|
||||
}
|
||||
@ -2551,7 +2587,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(rc < 0) {
|
||||
infof(data, "Failed to disconnect libssh2 session\n");
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session,
|
||||
&err_msg, NULL, 0);
|
||||
infof(data, "Failed to disconnect libssh2 session: %d %s\n",
|
||||
rc, err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2576,7 +2616,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(rc < 0) {
|
||||
infof(data, "Failed to disconnect from libssh2 agent\n");
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session,
|
||||
&err_msg, NULL, 0);
|
||||
infof(data, "Failed to disconnect from libssh2 agent: %d %s\n",
|
||||
rc, err_msg);
|
||||
}
|
||||
libssh2_agent_free(sshc->ssh_agent);
|
||||
sshc->ssh_agent = NULL;
|
||||
@ -2594,7 +2638,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
break;
|
||||
}
|
||||
if(rc < 0) {
|
||||
infof(data, "Failed to free libssh2 session\n");
|
||||
char *err_msg = NULL;
|
||||
(void)libssh2_session_last_error(sshc->ssh_session,
|
||||
&err_msg, NULL, 0);
|
||||
infof(data, "Failed to free libssh2 session: %d %s\n", rc, err_msg);
|
||||
}
|
||||
sshc->ssh_session = NULL;
|
||||
}
|
||||
|
@ -312,6 +312,9 @@ curl_easy_strerror(CURLcode error)
|
||||
case CURLE_HTTP2_STREAM:
|
||||
return "Stream error in the HTTP/2 framing layer";
|
||||
|
||||
case CURLE_RECURSIVE_API_CALL:
|
||||
return "API function called from within callback";
|
||||
|
||||
/* error codes not used by current libcurl */
|
||||
case CURLE_OBSOLETE20:
|
||||
case CURLE_OBSOLETE24:
|
||||
@ -380,6 +383,9 @@ curl_multi_strerror(CURLMcode error)
|
||||
case CURLM_ADDED_ALREADY:
|
||||
return "The easy handle is already added to a multi handle";
|
||||
|
||||
case CURLM_RECURSIVE_API_CALL:
|
||||
return "API function called from within callback";
|
||||
|
||||
case CURLM_LAST:
|
||||
break;
|
||||
}
|
||||
|
@ -220,8 +220,6 @@ CURLofft curlx_strtoofft(const char *str, char **endp, int base,
|
||||
errno = 0;
|
||||
*num = 0; /* clear by default */
|
||||
|
||||
DEBUGASSERT(str);
|
||||
|
||||
while(*str && ISSPACE(*str))
|
||||
str++;
|
||||
if('-' == *str) {
|
||||
|
@ -1203,8 +1203,7 @@ CURLcode telrcv(struct connectdata *conn,
|
||||
CURL_SB_ACCUM(tn, c);
|
||||
tn->telrcv_state = CURL_TS_SB;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
CURL_SB_ACCUM(tn, CURL_IAC);
|
||||
CURL_SB_ACCUM(tn, CURL_SE);
|
||||
tn->subpointer -= 2;
|
||||
@ -1460,7 +1459,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
|
||||
if(n == 0) /* no bytes */
|
||||
break;
|
||||
|
||||
readfile_read = (DWORD)n; /* fall thru with number of bytes read */
|
||||
/* fall through with number of bytes read */
|
||||
readfile_read = (DWORD)n;
|
||||
}
|
||||
else {
|
||||
/* read from stdin */
|
||||
|
@ -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
|
||||
@ -1010,7 +1010,7 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
|
||||
state->requested_blksize = blksize;
|
||||
|
||||
((struct sockaddr *)&state->local_addr)->sa_family =
|
||||
(unsigned short)(conn->ip_addr->ai_family);
|
||||
(CURL_SA_FAMILY_T)(conn->ip_addr->ai_family);
|
||||
|
||||
tftp_set_timeouts(state);
|
||||
|
||||
|
@ -110,7 +110,7 @@ struct curltime Curl_now(void)
|
||||
usecs /= 1000;
|
||||
|
||||
cnow.tv_sec = usecs / 1000000;
|
||||
cnow.tv_usec = usecs % 1000000;
|
||||
cnow.tv_usec = (int)(usecs % 1000000);
|
||||
|
||||
return cnow;
|
||||
}
|
||||
@ -128,7 +128,7 @@ struct curltime Curl_now(void)
|
||||
struct curltime ret;
|
||||
(void)gettimeofday(&now, NULL);
|
||||
ret.tv_sec = now.tv_sec;
|
||||
ret.tv_usec = now.tv_usec;
|
||||
ret.tv_usec = (int)now.tv_usec;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
@ -85,7 +85,7 @@
|
||||
!defined(CURL_DISABLE_IMAP)
|
||||
/*
|
||||
* checkheaders() checks the linked list of custom headers for a
|
||||
* particular header (prefix).
|
||||
* particular header (prefix). Provide the prefix without colon!
|
||||
*
|
||||
* Returns a pointer to the first matching header or NULL if none matched.
|
||||
*/
|
||||
@ -97,7 +97,8 @@ char *Curl_checkheaders(const struct connectdata *conn,
|
||||
struct Curl_easy *data = conn->data;
|
||||
|
||||
for(head = data->set.headers; head; head = head->next) {
|
||||
if(strncasecompare(head->data, thisheader, thislen))
|
||||
if(strncasecompare(head->data, thisheader, thislen) &&
|
||||
Curl_headersep(head->data[thislen]) )
|
||||
return head->data;
|
||||
}
|
||||
|
||||
@ -135,8 +136,10 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
|
||||
|
||||
/* this function returns a size_t, so we typecast to int to prevent warnings
|
||||
with picky compilers */
|
||||
Curl_set_in_callback(data, true);
|
||||
nread = (int)data->state.fread_func(data->req.upload_fromhere, 1,
|
||||
buffersize, data->state.in);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
if(nread == CURL_READFUNC_ABORT) {
|
||||
failf(data, "operation aborted by callback");
|
||||
@ -302,7 +305,9 @@ CURLcode Curl_readrewind(struct connectdata *conn)
|
||||
if(data->set.seek_func) {
|
||||
int err;
|
||||
|
||||
Curl_set_in_callback(data, true);
|
||||
err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(err) {
|
||||
failf(data, "seek callback returned error %d", (int)err);
|
||||
return CURLE_SEND_FAIL_REWIND;
|
||||
@ -311,8 +316,10 @@ CURLcode Curl_readrewind(struct connectdata *conn)
|
||||
else if(data->set.ioctl_func) {
|
||||
curlioerr err;
|
||||
|
||||
Curl_set_in_callback(data, true);
|
||||
err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
|
||||
data->set.ioctl_client);
|
||||
Curl_set_in_callback(data, false);
|
||||
infof(data, "the ioctl callback returned %d\n", (int)err);
|
||||
|
||||
if(err) {
|
||||
@ -710,7 +717,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
||||
#endif /* CURL_DISABLE_HTTP */
|
||||
|
||||
/* Account for body content stored in the header buffer */
|
||||
if(k->badheader && !k->ignorebody) {
|
||||
if((k->badheader == HEADER_PARTHEADER) && !k->ignorebody) {
|
||||
DEBUGF(infof(data, "Increasing bytecount by %zu from hbuflen\n",
|
||||
k->hbuflen));
|
||||
k->bytecount += k->hbuflen;
|
||||
@ -801,10 +808,15 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
||||
|
||||
} /* if(!header and data to read) */
|
||||
|
||||
if(conn->handler->readwrite &&
|
||||
(excess > 0 && !conn->bits.stream_was_rewound)) {
|
||||
if(conn->handler->readwrite && excess && !conn->bits.stream_was_rewound) {
|
||||
/* Parse the excess data */
|
||||
k->str += nread;
|
||||
|
||||
if(&k->str[excess] > &k->buf[data->set.buffer_size]) {
|
||||
/* the excess amount was too excessive(!), make sure
|
||||
it doesn't read out of buffer */
|
||||
excess = &k->buf[data->set.buffer_size] - k->str;
|
||||
}
|
||||
nread = (ssize_t)excess;
|
||||
|
||||
result = conn->handler->readwrite(data, conn, &nread, &readmore);
|
||||
@ -1434,6 +1446,16 @@ static const char *find_host_sep(const char *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.
|
||||
@ -1462,7 +1484,7 @@ static size_t strlen_url(const char *url, bool relative)
|
||||
left = FALSE;
|
||||
/* fall through */
|
||||
default:
|
||||
if(*ptr >= 0x80)
|
||||
if(urlchar_needs_escaping(*ptr))
|
||||
newlen += 2;
|
||||
newlen++;
|
||||
break;
|
||||
@ -1507,7 +1529,7 @@ static void strcpy_url(char *output, const char *url, bool relative)
|
||||
left = FALSE;
|
||||
/* fall through */
|
||||
default:
|
||||
if(*iptr >= 0x80) {
|
||||
if(urlchar_needs_escaping(*iptr)) {
|
||||
snprintf(optr, 4, "%%%02x", *iptr);
|
||||
optr += 3;
|
||||
}
|
||||
@ -1914,7 +1936,7 @@ CURLcode Curl_retry_request(struct connectdata *conn,
|
||||
char **url)
|
||||
{
|
||||
struct Curl_easy *data = conn->data;
|
||||
|
||||
bool retry = FALSE;
|
||||
*url = NULL;
|
||||
|
||||
/* if we're talking upload, we can't do the checks below, unless the protocol
|
||||
@ -1927,7 +1949,7 @@ CURLcode Curl_retry_request(struct connectdata *conn,
|
||||
conn->bits.reuse &&
|
||||
(!data->set.opt_no_body
|
||||
|| (conn->handler->protocol & PROTO_FAMILY_HTTP)) &&
|
||||
(data->set.rtspreq != RTSPREQ_RECEIVE)) {
|
||||
(data->set.rtspreq != RTSPREQ_RECEIVE))
|
||||
/* We got no data, we attempted to re-use a connection. For HTTP this
|
||||
can be a retry so we try again regardless if we expected a body.
|
||||
For other protocols we only try again only if we expected a body.
|
||||
@ -1935,6 +1957,19 @@ CURLcode Curl_retry_request(struct connectdata *conn,
|
||||
This might happen if the connection was left alive when we were
|
||||
done using it before, but that was closed when we wanted to read from
|
||||
it again. Bad luck. Retry the same request on a fresh connect! */
|
||||
retry = TRUE;
|
||||
else if(data->state.refused_stream &&
|
||||
(data->req.bytecount + data->req.headerbytecount == 0) ) {
|
||||
/* This was sent on a refused stream, safe to rerun. A refused stream
|
||||
error can typically only happen on HTTP/2 level if the stream is safe
|
||||
to issue again, but the nghttp2 API can deliver the message to other
|
||||
streams as well, which is why this adds the check the data counters
|
||||
too. */
|
||||
infof(conn->data, "REFUSED_STREAM, retrying a fresh connect\n");
|
||||
data->state.refused_stream = FALSE; /* clear again */
|
||||
retry = TRUE;
|
||||
}
|
||||
if(retry) {
|
||||
infof(conn->data, "Connection died, retrying a fresh connect\n");
|
||||
*url = strdup(conn->data->change.url);
|
||||
if(!*url)
|
||||
@ -1983,11 +2018,19 @@ Curl_setup_transfer(
|
||||
|
||||
DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
|
||||
|
||||
/* now copy all input parameters */
|
||||
conn->sockfd = sockindex == -1 ?
|
||||
if(conn->bits.multiplex || conn->httpversion == 20) {
|
||||
/* when multiplexing, the read/write sockets need to be the same! */
|
||||
conn->sockfd = sockindex == -1 ?
|
||||
((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) :
|
||||
conn->sock[sockindex];
|
||||
conn->writesockfd = conn->sockfd;
|
||||
}
|
||||
else {
|
||||
conn->sockfd = sockindex == -1 ?
|
||||
CURL_SOCKET_BAD : conn->sock[sockindex];
|
||||
conn->writesockfd = writesockindex == -1 ?
|
||||
conn->writesockfd = writesockindex == -1 ?
|
||||
CURL_SOCKET_BAD:conn->sock[writesockindex];
|
||||
}
|
||||
k->getheader = getheader;
|
||||
|
||||
k->size = size;
|
||||
@ -2006,10 +2049,10 @@ Curl_setup_transfer(
|
||||
/* we want header and/or body, if neither then don't do this! */
|
||||
if(k->getheader || !data->set.opt_no_body) {
|
||||
|
||||
if(conn->sockfd != CURL_SOCKET_BAD)
|
||||
if(sockindex != -1)
|
||||
k->keepon |= KEEP_RECV;
|
||||
|
||||
if(conn->writesockfd != CURL_SOCKET_BAD) {
|
||||
if(writesockindex != -1) {
|
||||
struct HTTP *http = data->req.protop;
|
||||
/* HTTP 1.1 magic:
|
||||
|
||||
@ -2040,7 +2083,7 @@ Curl_setup_transfer(
|
||||
/* enable the write bit when we're not waiting for continue */
|
||||
k->keepon |= KEEP_SEND;
|
||||
}
|
||||
} /* if(conn->writesockfd != CURL_SOCKET_BAD) */
|
||||
} /* if(writesockindex != -1) */
|
||||
} /* if(k->getheader || !data->set.opt_no_body) */
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
@ -22,6 +22,7 @@
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#define Curl_headersep(x) ((((x)==':') || ((x)==';')))
|
||||
char *Curl_checkheaders(const struct connectdata *conn,
|
||||
const char *thisheader);
|
||||
|
||||
|
@ -488,25 +488,33 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
|
||||
set->socks5_gssapi_nec = FALSE;
|
||||
#endif
|
||||
|
||||
/* This is our preferred CA cert bundle/path since install time */
|
||||
/* Set the default CA cert bundle/path detected/specified at build time.
|
||||
*
|
||||
* If Schannel (WinSSL) is the selected SSL backend then these locations
|
||||
* are ignored. We allow setting CA location for schannel only when
|
||||
* explicitly specified by the user via CURLOPT_CAINFO / --cacert.
|
||||
*/
|
||||
if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
|
||||
#if defined(CURL_CA_BUNDLE)
|
||||
result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE);
|
||||
if(result)
|
||||
return result;
|
||||
result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], CURL_CA_BUNDLE);
|
||||
if(result)
|
||||
return result;
|
||||
result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
|
||||
CURL_CA_BUNDLE);
|
||||
if(result)
|
||||
return result;
|
||||
#endif
|
||||
#if defined(CURL_CA_PATH)
|
||||
result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH);
|
||||
if(result)
|
||||
return result;
|
||||
result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
|
||||
if(result)
|
||||
return result;
|
||||
result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
|
||||
if(result)
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
set->wildcard_enabled = FALSE;
|
||||
set->chunk_bgn = ZERO_NULL;
|
||||
@ -527,6 +535,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
|
||||
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->happy_eyeballs_timeout = CURL_HET_DEFAULT;
|
||||
|
||||
Curl_http2_init_userset(set);
|
||||
return result;
|
||||
@ -2066,15 +2075,6 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
|
||||
return CURLE_URL_MALFORMAT;
|
||||
}
|
||||
|
||||
if(url_has_scheme && path[0] == '/' && path[1] == '/' &&
|
||||
path[2] == '/' && path[3] == '/') {
|
||||
/* This appears to be a UNC string (usually indicating a SMB share).
|
||||
* We don't do SMB in file: URLs. (TODO?)
|
||||
*/
|
||||
failf(data, "SMB shares are not supported in file: URLs.");
|
||||
return CURLE_URL_MALFORMAT;
|
||||
}
|
||||
|
||||
/* Extra handling URLs with an authority component (i.e. that start with
|
||||
* "file://")
|
||||
*
|
||||
@ -2113,25 +2113,6 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
|
||||
ptr += 9; /* now points to the slash after the host */
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 8089, Appendix D, Section D.1, says:
|
||||
*
|
||||
* > In a POSIX file system, the root of the file system is represented
|
||||
* > as a directory with a zero-length name, usually written as "/"; the
|
||||
* > presence of this root in a file URI can be taken as given by the
|
||||
* > initial slash in the "path-absolute" rule.
|
||||
*
|
||||
* i.e. the first slash is part of the path.
|
||||
*
|
||||
* However in RFC 1738 the "/" between the host (or port) and the
|
||||
* URL-path was NOT part of the URL-path. Any agent that followed the
|
||||
* older spec strictly, and wanted to refer to a file with an absolute
|
||||
* path, would have included a second slash. So if there are two
|
||||
* slashes, swallow one.
|
||||
*/
|
||||
if('/' == ptr[1]) /* note: the only way ptr[0]!='/' is if ptr[1]==':' */
|
||||
ptr++;
|
||||
|
||||
/* This cannot be done with strcpy, as the memory chunks overlap! */
|
||||
memmove(path, ptr, strlen(ptr) + 1);
|
||||
}
|
||||
@ -2573,7 +2554,15 @@ static bool check_noproxy(const char *name, const char *no_proxy)
|
||||
/* NO_PROXY was specified and it wasn't just an asterisk */
|
||||
|
||||
no_proxy_len = strlen(no_proxy);
|
||||
endptr = strchr(name, ':');
|
||||
if(name[0] == '[') {
|
||||
/* IPv6 numerical address */
|
||||
endptr = strchr(name, ']');
|
||||
if(!endptr)
|
||||
return FALSE;
|
||||
name++;
|
||||
}
|
||||
else
|
||||
endptr = strchr(name, ':');
|
||||
if(endptr)
|
||||
namelen = endptr - name;
|
||||
else
|
||||
@ -2681,13 +2670,20 @@ static char *detect_proxy(struct connectdata *conn)
|
||||
prox = curl_getenv(proxy_env);
|
||||
}
|
||||
|
||||
if(prox)
|
||||
envp = proxy_env;
|
||||
if(prox) {
|
||||
proxy = prox; /* use this */
|
||||
else {
|
||||
proxy = curl_getenv("all_proxy"); /* default proxy to use */
|
||||
if(!proxy)
|
||||
proxy = curl_getenv("ALL_PROXY");
|
||||
}
|
||||
else {
|
||||
envp = (char *)"all_proxy";
|
||||
proxy = curl_getenv(envp); /* default proxy to use */
|
||||
if(!proxy) {
|
||||
envp = (char *)"ALL_PROXY";
|
||||
proxy = curl_getenv(envp);
|
||||
}
|
||||
}
|
||||
if(proxy)
|
||||
infof(conn->data, "Uses proxy env variable %s == '%s'\n", envp, proxy);
|
||||
|
||||
return proxy;
|
||||
}
|
||||
@ -2744,7 +2740,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
|
||||
proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */
|
||||
|
||||
#ifdef USE_SSL
|
||||
if(!Curl_ssl->support_https_proxy)
|
||||
if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY))
|
||||
#endif
|
||||
if(proxytype == CURLPROXY_HTTPS) {
|
||||
failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
|
||||
@ -2972,9 +2968,15 @@ static CURLcode create_conn_helper_init_proxy(struct connectdata *conn)
|
||||
}
|
||||
|
||||
if(!data->set.str[STRING_NOPROXY]) {
|
||||
no_proxy = curl_getenv("no_proxy");
|
||||
if(!no_proxy)
|
||||
no_proxy = curl_getenv("NO_PROXY");
|
||||
const char *p = "no_proxy";
|
||||
no_proxy = curl_getenv(p);
|
||||
if(!no_proxy) {
|
||||
p = "NO_PROXY";
|
||||
no_proxy = curl_getenv(p);
|
||||
}
|
||||
if(no_proxy) {
|
||||
infof(conn->data, "Uses proxy env variable %s == '%s'\n", p, no_proxy);
|
||||
}
|
||||
}
|
||||
|
||||
if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
|
||||
@ -3417,7 +3419,7 @@ static CURLcode parse_remote_port(struct Curl_easy *data,
|
||||
* 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:%hu%s%s%s", conn->given->scheme,
|
||||
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,
|
||||
@ -4116,7 +4118,7 @@ static CURLcode create_conn(struct Curl_easy *data,
|
||||
*************************************************************/
|
||||
if(prot_missing) {
|
||||
/* We're guessing prefixes here and if we're told to use a proxy or if
|
||||
we're gonna follow a Location: later or... then we need the protocol
|
||||
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;
|
||||
|
@ -98,6 +98,20 @@
|
||||
#include "hash.h"
|
||||
#include "splay.h"
|
||||
|
||||
/* return the count of bytes sent, or -1 on error */
|
||||
typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */
|
||||
int sockindex, /* socketindex */
|
||||
const void *buf, /* data to write */
|
||||
size_t len, /* max amount to write */
|
||||
CURLcode *err); /* error to return */
|
||||
|
||||
/* return the count of bytes read, or -1 on error */
|
||||
typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
|
||||
int sockindex, /* socketindex */
|
||||
char *buf, /* store data here */
|
||||
size_t len, /* max amount to read */
|
||||
CURLcode *err); /* error to return */
|
||||
|
||||
#include "mime.h"
|
||||
#include "imap.h"
|
||||
#include "pop3.h"
|
||||
@ -328,6 +342,7 @@ struct ntlmdata {
|
||||
BYTE *output_token;
|
||||
BYTE *input_token;
|
||||
size_t input_token_len;
|
||||
TCHAR *spn;
|
||||
#else
|
||||
unsigned int flags;
|
||||
unsigned char nonce[8];
|
||||
@ -703,20 +718,6 @@ struct Curl_handler {
|
||||
#define CONNRESULT_NONE 0 /* No extra information. */
|
||||
#define CONNRESULT_DEAD (1<<0) /* The connection is dead. */
|
||||
|
||||
/* return the count of bytes sent, or -1 on error */
|
||||
typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */
|
||||
int sockindex, /* socketindex */
|
||||
const void *buf, /* data to write */
|
||||
size_t len, /* max amount to write */
|
||||
CURLcode *err); /* error to return */
|
||||
|
||||
/* return the count of bytes read, or -1 on error */
|
||||
typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
|
||||
int sockindex, /* socketindex */
|
||||
char *buf, /* store data here */
|
||||
size_t len, /* max amount to read */
|
||||
CURLcode *err); /* error to return */
|
||||
|
||||
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
|
||||
struct postponed_data {
|
||||
char *buffer; /* Temporal store for received data during
|
||||
@ -895,7 +896,7 @@ struct connectdata {
|
||||
well be the same we read from.
|
||||
CURL_SOCKET_BAD disables */
|
||||
|
||||
/** Dynamicly allocated strings, MUST be freed before this **/
|
||||
/** Dynamically allocated strings, MUST be freed before this **/
|
||||
/** struct is killed. **/
|
||||
struct dynamically_allocated_data {
|
||||
char *proxyuserpwd;
|
||||
@ -1024,10 +1025,8 @@ struct PureInfo {
|
||||
int httpcode; /* Recent HTTP, FTP, RTSP or SMTP response code */
|
||||
int httpproxycode; /* response code from proxy when received separate */
|
||||
int httpversion; /* the http version number X.Y = X*10+Y */
|
||||
long filetime; /* If requested, this is might get set. Set to -1 if the time
|
||||
was unretrievable. We cannot have this of type time_t,
|
||||
since time_t is unsigned on several platforms such as
|
||||
OpenVMS. */
|
||||
time_t filetime; /* If requested, this is might get set. Set to -1 if the
|
||||
time was unretrievable. */
|
||||
bool timecond; /* set to TRUE if the time condition didn't match, which
|
||||
thus made the document NOT get fetched */
|
||||
long header_size; /* size of read header(s) in bytes */
|
||||
@ -1168,7 +1167,7 @@ struct Curl_http2_dep {
|
||||
};
|
||||
|
||||
/*
|
||||
* This struct is for holding data that was attemped to get sent to the user's
|
||||
* This struct is for holding data that was attempted to get sent to the user's
|
||||
* callback but is held due to pausing. One instance per type (BOTH, HEADER,
|
||||
* BODY).
|
||||
*/
|
||||
@ -1227,7 +1226,7 @@ struct UrlState {
|
||||
curl_off_t current_speed; /* the ProgressShow() function sets this,
|
||||
bytes / second */
|
||||
bool this_is_a_follow; /* this is a followed Location: request */
|
||||
|
||||
bool refused_stream; /* this was refused, try again */
|
||||
char *first_host; /* host name of the first (not followed) request.
|
||||
if set, this should be the host name that we will
|
||||
sent authorization to, no else. Used to make Location:
|
||||
@ -1424,13 +1423,8 @@ enum dupstring {
|
||||
STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
|
||||
STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */
|
||||
#endif
|
||||
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
|
||||
STRING_PROXY_SERVICE_NAME, /* Proxy service name */
|
||||
#endif
|
||||
#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
|
||||
defined(USE_SPNEGO) || defined(HAVE_GSSAPI)
|
||||
STRING_SERVICE_NAME, /* Service name */
|
||||
#endif
|
||||
STRING_MAIL_FROM,
|
||||
STRING_MAIL_AUTH,
|
||||
|
||||
@ -1522,6 +1516,7 @@ struct UserDefined {
|
||||
long timeout; /* in milliseconds, 0 means no timeout */
|
||||
long connecttimeout; /* in milliseconds, 0 means no timeout */
|
||||
long accepttimeout; /* in milliseconds, 0 means no timeout */
|
||||
long happy_eyeballs_timeout; /* in milliseconds, 0 is a valid value */
|
||||
long server_response_timeout; /* in milliseconds, 0 means no timeout */
|
||||
long tftp_blksize; /* in bytes, 0 means use default */
|
||||
bool tftp_no_options; /* do not send TFTP options requests */
|
||||
@ -1675,13 +1670,21 @@ struct UserDefined {
|
||||
bool suppress_connect_headers; /* suppress proxy CONNECT response headers
|
||||
from user callbacks */
|
||||
|
||||
bool dns_shuffle_addresses; /* whether to shuffle addresses before use */
|
||||
|
||||
struct Curl_easy *stream_depends_on;
|
||||
bool stream_depends_e; /* set or don't set the Exclusive bit */
|
||||
int stream_weight;
|
||||
|
||||
bool haproxyprotocol; /* whether to send HAProxy PROXY protocol header */
|
||||
|
||||
struct Curl_http2_dep *stream_dependents;
|
||||
|
||||
bool abstract_unix_socket;
|
||||
|
||||
curl_resolver_start_callback resolver_start; /* optional callback called
|
||||
before resolver start */
|
||||
void *resolver_start_client; /* pointer to pass to resolver start callback */
|
||||
};
|
||||
|
||||
struct Names {
|
||||
|
@ -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
|
||||
@ -73,16 +73,10 @@ CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
|
||||
ulen = strlen(userp);
|
||||
plen = strlen(passwdp);
|
||||
|
||||
/* Compute binary message length, checking for overflows. */
|
||||
plainlen = 2 * ulen;
|
||||
if(plainlen < ulen)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
plainlen += plen;
|
||||
if(plainlen < plen)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
plainlen += 2;
|
||||
if(plainlen < 2)
|
||||
/* Compute binary message length. Check for overflows. */
|
||||
if((ulen > SIZE_T_MAX/2) || (plen > (SIZE_T_MAX/2 - 2)))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
plainlen = 2 * ulen + plen + 2;
|
||||
|
||||
plainauth = malloc(plainlen);
|
||||
if(!plainauth)
|
||||
|
@ -135,7 +135,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
|
||||
}
|
||||
|
||||
if(!krb5->credentials) {
|
||||
/* Do we have credientials to use or are we using single sign-on? */
|
||||
/* Do we have credentials to use or are we using single sign-on? */
|
||||
if(userp && *userp) {
|
||||
/* Populate our identity structure */
|
||||
result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity);
|
||||
@ -150,12 +150,10 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
|
||||
krb5->p_identity = NULL;
|
||||
|
||||
/* Allocate our credentials handle */
|
||||
krb5->credentials = malloc(sizeof(CredHandle));
|
||||
krb5->credentials = calloc(1, sizeof(CredHandle));
|
||||
if(!krb5->credentials)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
memset(krb5->credentials, 0, sizeof(CredHandle));
|
||||
|
||||
/* Acquire our credentials handle */
|
||||
status = s_pSecFn->AcquireCredentialsHandle(NULL,
|
||||
(TCHAR *)
|
||||
@ -167,11 +165,9 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
|
||||
return CURLE_LOGIN_DENIED;
|
||||
|
||||
/* Allocate our new context handle */
|
||||
krb5->context = malloc(sizeof(CtxtHandle));
|
||||
krb5->context = calloc(1, sizeof(CtxtHandle));
|
||||
if(!krb5->context)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
memset(krb5->context, 0, sizeof(CtxtHandle));
|
||||
}
|
||||
|
||||
if(chlg64 && *chlg64) {
|
||||
|
@ -63,9 +63,9 @@
|
||||
/* "NTLMSSP" signature is always in ASCII regardless of the platform */
|
||||
#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
|
||||
|
||||
#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
|
||||
#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \
|
||||
(((x) >> 16) & 0xff), (((x) >> 24) & 0xff)
|
||||
#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
|
||||
#define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
|
||||
((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff))
|
||||
|
||||
#if DEBUG_ME
|
||||
# define DEBUG_OUT(x) x
|
||||
@ -355,6 +355,8 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length)
|
||||
* data [in] - The session handle.
|
||||
* userp [in] - The user name in the format User or Domain\User.
|
||||
* passdwp [in] - The user's password.
|
||||
* service [in] - The service type such as http, smtp, pop or imap.
|
||||
* host [in] - The host name.
|
||||
* ntlm [in/out] - The NTLM data struct being used and modified.
|
||||
* outptr [in/out] - The address where a pointer to newly allocated memory
|
||||
* holding the result will be stored upon completion.
|
||||
@ -365,6 +367,8 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length)
|
||||
CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
|
||||
const char *userp,
|
||||
const char *passwdp,
|
||||
const char *service,
|
||||
const char *hostname,
|
||||
struct ntlmdata *ntlm,
|
||||
char **outptr, size_t *outlen)
|
||||
{
|
||||
@ -394,6 +398,8 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
|
||||
domain are empty */
|
||||
(void)userp;
|
||||
(void)passwdp;
|
||||
(void)service,
|
||||
(void)hostname,
|
||||
|
||||
/* Clean up any former leftovers and initialise to defaults */
|
||||
Curl_auth_ntlm_cleanup(ntlm);
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef HEADER_CURL_NTLM_H
|
||||
#define HEADER_CURL_NTLM_H
|
||||
#ifndef HEADER_VAUTH_NTLM_H
|
||||
#define HEADER_VAUTH_NTLM_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
@ -7,7 +7,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
|
||||
@ -140,4 +140,4 @@
|
||||
|
||||
#endif /* USE_NTLM */
|
||||
|
||||
#endif /* HEADER_CURL_NTLM_H */
|
||||
#endif /* HEADER_VAUTH_NTLM_H */
|
||||
|
@ -70,6 +70,8 @@ bool Curl_auth_is_ntlm_supported(void)
|
||||
* data [in] - The session handle.
|
||||
* userp [in] - The user name in the format User or Domain\User.
|
||||
* passdwp [in] - The user's password.
|
||||
* service [in] - The service type such as http, smtp, pop or imap.
|
||||
* host [in] - The host name.
|
||||
* ntlm [in/out] - The NTLM data struct being used and modified.
|
||||
* outptr [in/out] - The address where a pointer to newly allocated memory
|
||||
* holding the result will be stored upon completion.
|
||||
@ -80,6 +82,8 @@ bool Curl_auth_is_ntlm_supported(void)
|
||||
CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
|
||||
const char *userp,
|
||||
const char *passwdp,
|
||||
const char *service,
|
||||
const char *host,
|
||||
struct ntlmdata *ntlm,
|
||||
char **outptr, size_t *outlen)
|
||||
{
|
||||
@ -125,12 +129,10 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
|
||||
ntlm->p_identity = NULL;
|
||||
|
||||
/* Allocate our credentials handle */
|
||||
ntlm->credentials = malloc(sizeof(CredHandle));
|
||||
ntlm->credentials = calloc(1, sizeof(CredHandle));
|
||||
if(!ntlm->credentials)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
memset(ntlm->credentials, 0, sizeof(CredHandle));
|
||||
|
||||
/* Acquire our credentials handle */
|
||||
status = s_pSecFn->AcquireCredentialsHandle(NULL,
|
||||
(TCHAR *) TEXT(SP_NAME_NTLM),
|
||||
@ -141,11 +143,13 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
|
||||
return CURLE_LOGIN_DENIED;
|
||||
|
||||
/* Allocate our new context handle */
|
||||
ntlm->context = malloc(sizeof(CtxtHandle));
|
||||
ntlm->context = calloc(1, sizeof(CtxtHandle));
|
||||
if(!ntlm->context)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
memset(ntlm->context, 0, sizeof(CtxtHandle));
|
||||
ntlm->spn = Curl_auth_build_spn(service, host, NULL);
|
||||
if(!ntlm->spn)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Setup the type-1 "output" security buffer */
|
||||
type_1_desc.ulVersion = SECBUFFER_VERSION;
|
||||
@ -157,7 +161,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
|
||||
|
||||
/* Generate our type-1 message */
|
||||
status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL,
|
||||
(TCHAR *) TEXT(""),
|
||||
ntlm->spn,
|
||||
0, 0, SECURITY_NETWORK_DREP,
|
||||
NULL, 0,
|
||||
ntlm->context, &type_1_desc,
|
||||
@ -275,7 +279,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
|
||||
/* Generate our type-3 message */
|
||||
status = s_pSecFn->InitializeSecurityContext(ntlm->credentials,
|
||||
ntlm->context,
|
||||
(TCHAR *) TEXT(""),
|
||||
ntlm->spn,
|
||||
0, 0, SECURITY_NETWORK_DREP,
|
||||
&type_2_desc,
|
||||
0, ntlm->context,
|
||||
@ -333,6 +337,8 @@ void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm)
|
||||
|
||||
/* Reset any variables */
|
||||
ntlm->token_max = 0;
|
||||
|
||||
Curl_safefree(ntlm->spn);
|
||||
}
|
||||
|
||||
#endif /* USE_WINDOWS_SSPI && USE_NTLM */
|
||||
|
@ -138,7 +138,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
|
||||
}
|
||||
|
||||
if(!nego->credentials) {
|
||||
/* Do we have credientials to use or are we using single sign-on? */
|
||||
/* Do we have credentials to use or are we using single sign-on? */
|
||||
if(user && *user) {
|
||||
/* Populate our identity structure */
|
||||
result = Curl_create_sspi_identity(user, password, &nego->identity);
|
||||
@ -153,12 +153,10 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
|
||||
nego->p_identity = NULL;
|
||||
|
||||
/* Allocate our credentials handle */
|
||||
nego->credentials = malloc(sizeof(CredHandle));
|
||||
nego->credentials = calloc(1, sizeof(CredHandle));
|
||||
if(!nego->credentials)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
memset(nego->credentials, 0, sizeof(CredHandle));
|
||||
|
||||
/* Acquire our credentials handle */
|
||||
nego->status =
|
||||
s_pSecFn->AcquireCredentialsHandle(NULL,
|
||||
@ -170,11 +168,9 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
|
||||
return CURLE_LOGIN_DENIED;
|
||||
|
||||
/* Allocate our new context handle */
|
||||
nego->context = malloc(sizeof(CtxtHandle));
|
||||
nego->context = calloc(1, sizeof(CtxtHandle));
|
||||
if(!nego->context)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
memset(nego->context, 0, sizeof(CtxtHandle));
|
||||
}
|
||||
|
||||
if(chlg64 && *chlg64) {
|
||||
|
@ -115,8 +115,8 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host,
|
||||
* User@Domain (User Principal Name)
|
||||
*
|
||||
* Note: The user name may be empty when using a GSS-API library or Windows SSPI
|
||||
* as the user and domain are either obtained from the credientals cache when
|
||||
* using GSS-API or via the currently logged in user's credientals when using
|
||||
* as the user and domain are either obtained from the credentials cache when
|
||||
* using GSS-API or via the currently logged in user's credentials when using
|
||||
* Windows SSPI.
|
||||
*
|
||||
* Parameters:
|
||||
@ -138,7 +138,7 @@ bool Curl_auth_user_contains_domain(const char *user)
|
||||
}
|
||||
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
|
||||
else
|
||||
/* User and domain are obtained from the GSS-API credientials cache or the
|
||||
/* User and domain are obtained from the GSS-API credentials cache or the
|
||||
currently logged in user from Windows */
|
||||
valid = TRUE;
|
||||
#endif
|
||||
|
@ -122,6 +122,8 @@ bool Curl_auth_is_ntlm_supported(void);
|
||||
CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
|
||||
const char *userp,
|
||||
const char *passwdp,
|
||||
const char *service,
|
||||
const char *host,
|
||||
struct ntlmdata *ntlm,
|
||||
char **outptr,
|
||||
size_t *outlen);
|
||||
|
@ -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
|
||||
@ -399,7 +399,7 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
|
||||
#ifdef USE_SSL
|
||||
Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
|
||||
version_info.ssl_version = ssl_buffer;
|
||||
if(Curl_ssl->support_https_proxy)
|
||||
if(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY)
|
||||
version_info.features |= CURL_VERSION_HTTPS_PROXY;
|
||||
else
|
||||
version_info.features &= ~CURL_VERSION_HTTPS_PROXY;
|
||||
|
@ -6,7 +6,7 @@
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2010, DirecTV, Contact: Eric Hu, <ehu@directv.com>.
|
||||
* Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2010 - 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
|
||||
@ -703,13 +703,7 @@ static void *Curl_axtls_get_internals(struct ssl_connect_data *connssl,
|
||||
|
||||
const struct Curl_ssl Curl_ssl_axtls = {
|
||||
{ CURLSSLBACKEND_AXTLS, "axtls" }, /* info */
|
||||
|
||||
0, /* have_ca_path */
|
||||
0, /* have_certinfo */
|
||||
0, /* have_pinnedpubkey */
|
||||
0, /* have_ssl_ctx */
|
||||
0, /* support_https_proxy */
|
||||
|
||||
0, /* no fancy stuff */
|
||||
sizeof(struct ssl_backend_data),
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
@ -187,8 +187,13 @@ cyassl_connect_step1(struct connectdata *conn,
|
||||
use_sni(TRUE);
|
||||
break;
|
||||
case CURL_SSLVERSION_TLSv1_0:
|
||||
#ifdef WOLFSSL_ALLOW_TLSV10
|
||||
req_method = TLSv1_client_method();
|
||||
use_sni(TRUE);
|
||||
#else
|
||||
failf(data, "CyaSSL does not support TLS 1.0");
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
break;
|
||||
case CURL_SSLVERSION_TLSv1_1:
|
||||
req_method = TLSv1_1_client_method();
|
||||
@ -199,8 +204,14 @@ cyassl_connect_step1(struct connectdata *conn,
|
||||
use_sni(TRUE);
|
||||
break;
|
||||
case CURL_SSLVERSION_TLSv1_3:
|
||||
#ifdef WOLFSSL_TLS13
|
||||
req_method = wolfTLSv1_3_client_method();
|
||||
use_sni(TRUE);
|
||||
break;
|
||||
#else
|
||||
failf(data, "CyaSSL: TLS 1.3 is not yet supported");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
#endif
|
||||
case CURL_SSLVERSION_SSLv3:
|
||||
#ifdef WOLFSSL_ALLOW_SSLV3
|
||||
req_method = SSLv3_client_method();
|
||||
@ -245,7 +256,11 @@ cyassl_connect_step1(struct connectdata *conn,
|
||||
*/
|
||||
if((wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1) != 1) &&
|
||||
(wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_1) != 1) &&
|
||||
(wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1)) {
|
||||
(wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1)
|
||||
#ifdef WOLFSSL_TLS13
|
||||
&& (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_3) != 1)
|
||||
#endif
|
||||
) {
|
||||
failf(data, "SSL: couldn't set the minimum protocol version");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
@ -956,7 +971,7 @@ static CURLcode Curl_cyassl_random(struct Curl_easy *data,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
|
||||
static CURLcode Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
|
||||
size_t tmplen,
|
||||
unsigned char *sha256sum /* output */,
|
||||
size_t unused)
|
||||
@ -966,6 +981,7 @@ static void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
|
||||
InitSha256(&SHA256pw);
|
||||
Sha256Update(&SHA256pw, tmp, (word32)tmplen);
|
||||
Sha256Final(&SHA256pw, sha256sum);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void *Curl_cyassl_get_internals(struct ssl_connect_data *connssl,
|
||||
@ -978,15 +994,10 @@ static void *Curl_cyassl_get_internals(struct ssl_connect_data *connssl,
|
||||
const struct Curl_ssl Curl_ssl_cyassl = {
|
||||
{ CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */
|
||||
|
||||
0, /* have_ca_path */
|
||||
0, /* have_certinfo */
|
||||
#ifdef KEEP_PEER_CERT
|
||||
1, /* have_pinnedpubkey */
|
||||
#else
|
||||
0, /* have_pinnedpubkey */
|
||||
SSLSUPP_PINNEDPUBKEY |
|
||||
#endif
|
||||
1, /* have_ssl_ctx */
|
||||
0, /* support_https_proxy */
|
||||
SSLSUPP_SSL_CTX,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2012 - 2017, Nick Zitzmann, <nickzman@gmail.com>.
|
||||
* Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2012 - 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
|
||||
@ -1135,28 +1135,79 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
|
||||
raise linker errors when used on that cat for some reason. */
|
||||
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
|
||||
if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data,
|
||||
NULL, NULL, &status)) {
|
||||
NULL, NULL, &status)) {
|
||||
CFArrayRef items = NULL;
|
||||
|
||||
/* On iOS SecPKCS12Import will never add the client certificate to the
|
||||
* Keychain.
|
||||
*
|
||||
* It gives us back a SecIdentityRef that we can use directly. */
|
||||
#if CURL_BUILD_IOS
|
||||
const void *cKeys[] = {kSecImportExportPassphrase};
|
||||
const void *cValues[] = {password};
|
||||
CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
|
||||
password ? 1L : 0L, NULL, NULL);
|
||||
CFArrayRef items = NULL;
|
||||
|
||||
/* Here we go: */
|
||||
status = SecPKCS12Import(pkcs_data, options, &items);
|
||||
if(options != NULL) {
|
||||
status = SecPKCS12Import(pkcs_data, options, &items);
|
||||
CFRelease(options);
|
||||
}
|
||||
|
||||
|
||||
/* On macOS SecPKCS12Import will always add the client certificate to
|
||||
* the Keychain.
|
||||
*
|
||||
* As this doesn't match iOS, and apps may not want to see their client
|
||||
* certificate saved in the the user's keychain, we use SecItemImport
|
||||
* with a NULL keychain to avoid importing it.
|
||||
*
|
||||
* This returns a SecCertificateRef from which we can construct a
|
||||
* SecIdentityRef.
|
||||
*/
|
||||
#elif CURL_BUILD_MAC_10_7
|
||||
SecItemImportExportKeyParameters keyParams;
|
||||
SecExternalFormat inputFormat = kSecFormatPKCS12;
|
||||
SecExternalItemType inputType = kSecItemTypeCertificate;
|
||||
|
||||
memset(&keyParams, 0x00, sizeof(keyParams));
|
||||
keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
|
||||
keyParams.passphrase = password;
|
||||
|
||||
status = SecItemImport(pkcs_data, NULL, &inputFormat, &inputType,
|
||||
0, &keyParams, NULL, &items);
|
||||
#endif
|
||||
|
||||
|
||||
/* Extract the SecIdentityRef */
|
||||
if(status == errSecSuccess && items && CFArrayGetCount(items)) {
|
||||
CFDictionaryRef identity_and_trust = CFArrayGetValueAtIndex(items, 0L);
|
||||
const void *temp_identity = CFDictionaryGetValue(identity_and_trust,
|
||||
kSecImportItemIdentity);
|
||||
CFIndex i, count;
|
||||
count = CFArrayGetCount(items);
|
||||
|
||||
/* Retain the identity; we don't care about any other data... */
|
||||
CFRetain(temp_identity);
|
||||
*out_cert_and_key = (SecIdentityRef)temp_identity;
|
||||
for(i = 0; i < count; i++) {
|
||||
CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(items, i);
|
||||
CFTypeID itemID = CFGetTypeID(item);
|
||||
|
||||
if(itemID == CFDictionaryGetTypeID()) {
|
||||
CFTypeRef identity = (CFTypeRef) CFDictionaryGetValue(
|
||||
(CFDictionaryRef) item,
|
||||
kSecImportItemIdentity);
|
||||
CFRetain(identity);
|
||||
*out_cert_and_key = (SecIdentityRef) identity;
|
||||
break;
|
||||
}
|
||||
#if CURL_BUILD_MAC_10_7
|
||||
else if(itemID == SecCertificateGetTypeID()) {
|
||||
status = SecIdentityCreateWithCertificate(NULL,
|
||||
(SecCertificateRef) item,
|
||||
out_cert_and_key);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if(items)
|
||||
CFRelease(items);
|
||||
CFRelease(options);
|
||||
CFRelease(pkcs_data);
|
||||
}
|
||||
#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
|
||||
@ -1340,7 +1391,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
|
||||
#endif /* CURL_BUILD_MAC */
|
||||
|
||||
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
|
||||
if(SSLCreateContext != NULL) { /* use the newer API if avaialble */
|
||||
if(SSLCreateContext != NULL) { /* use the newer API if available */
|
||||
if(BACKEND->ssl_ctx)
|
||||
CFRelease(BACKEND->ssl_ctx);
|
||||
BACKEND->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
|
||||
@ -2843,13 +2894,14 @@ static CURLcode Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void Curl_darwinssl_sha256sum(const unsigned char *tmp, /* input */
|
||||
static CURLcode Curl_darwinssl_sha256sum(const unsigned char *tmp, /* input */
|
||||
size_t tmplen,
|
||||
unsigned char *sha256sum, /* output */
|
||||
size_t sha256len)
|
||||
{
|
||||
assert(sha256len >= CURL_SHA256_DIGEST_LENGTH);
|
||||
(void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static bool Curl_darwinssl_false_start(void)
|
||||
@ -2977,15 +3029,11 @@ static void *Curl_darwinssl_get_internals(struct ssl_connect_data *connssl,
|
||||
const struct Curl_ssl Curl_ssl_darwinssl = {
|
||||
{ CURLSSLBACKEND_DARWINSSL, "darwinssl" }, /* info */
|
||||
|
||||
0, /* have_ca_path */
|
||||
0, /* have_certinfo */
|
||||
#ifdef DARWIN_SSL_PINNEDPUBKEY
|
||||
1, /* have_pinnedpubkey */
|
||||
SSLSUPP_PINNEDPUBKEY,
|
||||
#else
|
||||
0, /* have_pinnedpubkey */
|
||||
0,
|
||||
#endif /* DARWIN_SSL_PINNEDPUBKEY */
|
||||
0, /* have_ssl_ctx */
|
||||
0, /* support_https_proxy */
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
|
||||
|
@ -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
|
||||
@ -1353,12 +1353,8 @@ static void *Curl_gskit_get_internals(struct ssl_connect_data *connssl,
|
||||
const struct Curl_ssl Curl_ssl_gskit = {
|
||||
{ CURLSSLBACKEND_GSKIT, "gskit" }, /* info */
|
||||
|
||||
0, /* have_ca_path */
|
||||
1, /* have_certinfo */
|
||||
0, /* have_pinnedpubkey */
|
||||
0, /* have_ssl_ctx */
|
||||
/* TODO: convert to 1 and fix test #1014 (if need) */
|
||||
0, /* support_https_proxy */
|
||||
SSLSUPP_CERTINFO |
|
||||
SSLSUPP_PINNEDPUBKEY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
|
||||
|
@ -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
|
||||
@ -60,15 +60,6 @@
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
#ifndef GNUTLS_POINTER_TO_SOCKET_CAST
|
||||
#define GNUTLS_POINTER_TO_SOCKET_CAST(p) \
|
||||
((curl_socket_t) ((char *)(p) - (char *)NULL))
|
||||
#endif
|
||||
#ifndef GNUTLS_SOCKET_TO_POINTER_CAST
|
||||
#define GNUTLS_SOCKET_TO_POINTER_CAST(s) \
|
||||
((void *) ((char *)NULL + (s)))
|
||||
#endif
|
||||
|
||||
/* Enable GnuTLS debugging by defining GTLSDEBUG */
|
||||
/*#define GTLSDEBUG */
|
||||
|
||||
@ -161,7 +152,8 @@ static int gtls_mapped_sockerrno(void)
|
||||
|
||||
static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
|
||||
{
|
||||
ssize_t ret = swrite(GNUTLS_POINTER_TO_SOCKET_CAST(s), buf, len);
|
||||
curl_socket_t sock = *(curl_socket_t *)s;
|
||||
ssize_t ret = swrite(sock, buf, len);
|
||||
#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
|
||||
if(ret < 0)
|
||||
gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
|
||||
@ -171,7 +163,8 @@ static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
|
||||
|
||||
static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
|
||||
{
|
||||
ssize_t ret = sread(GNUTLS_POINTER_TO_SOCKET_CAST(s), buf, len);
|
||||
curl_socket_t sock = *(curl_socket_t *)s;
|
||||
ssize_t ret = sread(sock, buf, len);
|
||||
#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
|
||||
if(ret < 0)
|
||||
gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
|
||||
@ -857,7 +850,7 @@ gtls_connect_step1(struct connectdata *conn,
|
||||
}
|
||||
else {
|
||||
/* file descriptor for the socket */
|
||||
transport_ptr = GNUTLS_SOCKET_TO_POINTER_CAST(conn->sock[sockindex]);
|
||||
transport_ptr = &conn->sock[sockindex];
|
||||
gnutls_transport_push = Curl_gtls_push;
|
||||
gnutls_transport_pull = Curl_gtls_pull;
|
||||
}
|
||||
@ -1770,7 +1763,7 @@ static CURLcode Curl_gtls_md5sum(unsigned char *tmp, /* input */
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
|
||||
static CURLcode Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
|
||||
size_t tmplen,
|
||||
unsigned char *sha256sum, /* output */
|
||||
size_t sha256len)
|
||||
@ -1787,6 +1780,7 @@ static void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
|
||||
memcpy(sha256sum, gcry_md_read(SHA256pw, 0), sha256len);
|
||||
gcry_md_close(SHA256pw);
|
||||
#endif
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static bool Curl_gtls_cert_status_request(void)
|
||||
@ -1808,11 +1802,10 @@ static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl,
|
||||
const struct Curl_ssl Curl_ssl_gnutls = {
|
||||
{ CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */
|
||||
|
||||
1, /* have_ca_path */
|
||||
1, /* have_certinfo */
|
||||
1, /* have_pinnedpubkey */
|
||||
0, /* have_ssl_ctx */
|
||||
1, /* support_https_proxy */
|
||||
SSLSUPP_CA_PATH |
|
||||
SSLSUPP_CERTINFO |
|
||||
SSLSUPP_PINNEDPUBKEY |
|
||||
SSLSUPP_HTTPS_PROXY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
|
||||
* Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2012 - 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
|
||||
@ -815,7 +815,7 @@ static void Curl_mbedtls_session_free(void *ptr)
|
||||
static size_t Curl_mbedtls_version(char *buffer, size_t size)
|
||||
{
|
||||
unsigned int version = mbedtls_version_get_number();
|
||||
return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24,
|
||||
return snprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24,
|
||||
(version>>16)&0xff, (version>>8)&0xff);
|
||||
}
|
||||
|
||||
@ -1023,13 +1023,20 @@ static bool Curl_mbedtls_data_pending(const struct connectdata *conn,
|
||||
return mbedtls_ssl_get_bytes_avail(&BACKEND->ssl) != 0;
|
||||
}
|
||||
|
||||
static void Curl_mbedtls_sha256sum(const unsigned char *input,
|
||||
static CURLcode Curl_mbedtls_sha256sum(const unsigned char *input,
|
||||
size_t inputlen,
|
||||
unsigned char *sha256sum,
|
||||
size_t sha256len UNUSED_PARAM)
|
||||
{
|
||||
(void)sha256len;
|
||||
#if MBEDTLS_VERSION_NUMBER < 0x02070000
|
||||
mbedtls_sha256(input, inputlen, sha256sum, 0);
|
||||
#else
|
||||
/* returns 0 on success, otherwise failure */
|
||||
if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
#endif
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl,
|
||||
@ -1042,11 +1049,9 @@ static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl,
|
||||
const struct Curl_ssl Curl_ssl_mbedtls = {
|
||||
{ CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */
|
||||
|
||||
1, /* have_ca_path */
|
||||
0, /* have_certinfo */
|
||||
1, /* have_pinnedpubkey */
|
||||
1, /* have_ssl_ctx */
|
||||
0, /* support_https_proxy */
|
||||
SSLSUPP_CA_PATH |
|
||||
SSLSUPP_PINNEDPUBKEY |
|
||||
SSLSUPP_SSL_CTX,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
|
||||
|
@ -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
|
||||
@ -440,7 +440,17 @@ static CURLcode nss_create_object(struct ssl_connect_data *connssl,
|
||||
PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
|
||||
}
|
||||
|
||||
obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE);
|
||||
/* PK11_CreateManagedGenericObject() was introduced in NSS 3.34 because
|
||||
* PK11_DestroyGenericObject() does not release resources allocated by
|
||||
* PK11_CreateGenericObject() early enough. */
|
||||
obj =
|
||||
#ifdef HAVE_PK11_CREATEMANAGEDGENERICOBJECT
|
||||
PK11_CreateManagedGenericObject
|
||||
#else
|
||||
PK11_CreateGenericObject
|
||||
#endif
|
||||
(slot, attrs, attr_cnt, PR_FALSE);
|
||||
|
||||
PK11_FreeSlot(slot);
|
||||
if(!obj)
|
||||
return result;
|
||||
@ -2304,7 +2314,7 @@ static CURLcode Curl_nss_md5sum(unsigned char *tmp, /* input */
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void Curl_nss_sha256sum(const unsigned char *tmp, /* input */
|
||||
static CURLcode Curl_nss_sha256sum(const unsigned char *tmp, /* input */
|
||||
size_t tmplen,
|
||||
unsigned char *sha256sum, /* output */
|
||||
size_t sha256len)
|
||||
@ -2315,6 +2325,8 @@ static void Curl_nss_sha256sum(const unsigned char *tmp, /* input */
|
||||
PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen));
|
||||
PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len));
|
||||
PK11_DestroyContext(SHA256pw, PR_TRUE);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static bool Curl_nss_cert_status_request(void)
|
||||
@ -2345,11 +2357,10 @@ static void *Curl_nss_get_internals(struct ssl_connect_data *connssl,
|
||||
const struct Curl_ssl Curl_ssl_nss = {
|
||||
{ CURLSSLBACKEND_NSS, "nss" }, /* info */
|
||||
|
||||
1, /* have_ca_path */
|
||||
1, /* have_certinfo */
|
||||
1, /* have_pinnedpubkey */
|
||||
0, /* have_ssl_ctx */
|
||||
1, /* support_https_proxy */
|
||||
SSLSUPP_CA_PATH |
|
||||
SSLSUPP_CERTINFO |
|
||||
SSLSUPP_PINNEDPUBKEY |
|
||||
SSLSUPP_HTTPS_PROXY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
|
||||
|
@ -104,13 +104,22 @@
|
||||
#endif
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \
|
||||
!defined(LIBRESSL_VERSION_NUMBER)
|
||||
!(defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
LIBRESSL_VERSION_NUMBER < 0x20700000L)
|
||||
#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER
|
||||
#define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */
|
||||
#define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */
|
||||
#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */
|
||||
#define CONST_EXTS const
|
||||
#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1
|
||||
|
||||
/* funny typecast define due to difference in API */
|
||||
#ifdef LIBRESSL_VERSION_NUMBER
|
||||
#define ARG2_X509_signature_print (X509_ALGOR *)
|
||||
#else
|
||||
#define ARG2_X509_signature_print
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* For OpenSSL before 1.1.0 */
|
||||
#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x)
|
||||
@ -128,7 +137,8 @@ static unsigned long OpenSSL_version_num(void)
|
||||
#endif
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \
|
||||
!defined(LIBRESSL_VERSION_NUMBER)
|
||||
!(defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
LIBRESSL_VERSION_NUMBER < 0x20700000L)
|
||||
#define HAVE_X509_GET0_SIGNATURE 1
|
||||
#endif
|
||||
|
||||
@ -147,7 +157,7 @@ static unsigned long OpenSSL_version_num(void)
|
||||
* Whether SSL_CTX_set_keylog_callback is available.
|
||||
* OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287
|
||||
* BoringSSL: supported since d28f59c27bac (committed 2015-11-19)
|
||||
* LibreSSL: unsupported in at least 2.5.1 (explicitly check for it since it
|
||||
* LibreSSL: unsupported in at least 2.7.2 (explicitly check for it since it
|
||||
* lies and pretends to be OpenSSL 2.0.0).
|
||||
*/
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
|
||||
@ -259,7 +269,9 @@ static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state)
|
||||
if(!session || !keylog_file_fp)
|
||||
return;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
|
||||
!(defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
LIBRESSL_VERSION_NUMBER < 0x20700000L)
|
||||
/* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that
|
||||
* we have a valid SSL context if we have a non-NULL session. */
|
||||
SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE);
|
||||
@ -649,18 +661,28 @@ int cert_stuff(struct connectdata *conn,
|
||||
|
||||
case SSL_FILETYPE_PKCS12:
|
||||
{
|
||||
FILE *f;
|
||||
PKCS12 *p12;
|
||||
BIO *fp = NULL;
|
||||
PKCS12 *p12 = NULL;
|
||||
EVP_PKEY *pri;
|
||||
STACK_OF(X509) *ca = NULL;
|
||||
|
||||
f = fopen(cert_file, "rb");
|
||||
if(!f) {
|
||||
failf(data, "could not open PKCS12 file '%s'", cert_file);
|
||||
fp = BIO_new(BIO_s_file());
|
||||
if(fp == NULL) {
|
||||
failf(data,
|
||||
"BIO_new return NULL, " OSSL_PACKAGE
|
||||
" error %s",
|
||||
ossl_strerror(ERR_get_error(), error_buffer,
|
||||
sizeof(error_buffer)) );
|
||||
return 0;
|
||||
}
|
||||
p12 = d2i_PKCS12_fp(f, NULL);
|
||||
fclose(f);
|
||||
|
||||
if(BIO_read_filename(fp, cert_file) <= 0) {
|
||||
failf(data, "could not open PKCS12 file '%s'", cert_file);
|
||||
BIO_free(fp);
|
||||
return 0;
|
||||
}
|
||||
p12 = d2i_PKCS12_bio(fp, NULL);
|
||||
BIO_free(fp);
|
||||
|
||||
if(!p12) {
|
||||
failf(data, "error reading PKCS12 file '%s'", cert_file);
|
||||
@ -1311,6 +1333,51 @@ static void Curl_ossl_close_all(struct Curl_easy *data)
|
||||
|
||||
/* ====================================================== */
|
||||
|
||||
/*
|
||||
* Match subjectAltName against the host name. This requires a conversion
|
||||
* in CURL_DOES_CONVERSIONS builds.
|
||||
*/
|
||||
static bool subj_alt_hostcheck(struct Curl_easy *data,
|
||||
const char *match_pattern, const char *hostname,
|
||||
const char *dispname)
|
||||
#ifdef CURL_DOES_CONVERSIONS
|
||||
{
|
||||
bool res = FALSE;
|
||||
|
||||
/* Curl_cert_hostcheck uses host encoding, but we get ASCII from
|
||||
OpenSSl.
|
||||
*/
|
||||
char *match_pattern2 = strdup(match_pattern);
|
||||
|
||||
if(match_pattern2) {
|
||||
if(Curl_convert_from_network(data, match_pattern2,
|
||||
strlen(match_pattern2)) == CURLE_OK) {
|
||||
if(Curl_cert_hostcheck(match_pattern2, hostname)) {
|
||||
res = TRUE;
|
||||
infof(data,
|
||||
" subjectAltName: host \"%s\" matched cert's \"%s\"\n",
|
||||
dispname, match_pattern2);
|
||||
}
|
||||
}
|
||||
free(match_pattern2);
|
||||
}
|
||||
else {
|
||||
failf(data,
|
||||
"SSL: out of memory when allocating temporary for subjectAltName");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
{
|
||||
if(Curl_cert_hostcheck(match_pattern, hostname)) {
|
||||
infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
|
||||
dispname, match_pattern);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Quote from RFC2818 section 3.1 "Server Identity"
|
||||
|
||||
@ -1410,11 +1477,8 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
|
||||
if((altlen == strlen(altptr)) &&
|
||||
/* if this isn't true, there was an embedded zero in the name
|
||||
string and we cannot match it. */
|
||||
Curl_cert_hostcheck(altptr, hostname)) {
|
||||
subj_alt_hostcheck(data, altptr, hostname, dispname)) {
|
||||
dnsmatched = TRUE;
|
||||
infof(data,
|
||||
" subjectAltName: host \"%s\" matched cert's \"%s\"\n",
|
||||
dispname, altptr);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1724,14 +1788,41 @@ static const char *ssl_msg_type(int ssl_ver, int msg)
|
||||
#ifdef SSL3_MT_CERTIFICATE_STATUS
|
||||
case SSL3_MT_CERTIFICATE_STATUS:
|
||||
return "Certificate Status";
|
||||
#endif
|
||||
#ifdef SSL3_MT_ENCRYPTED_EXTENSIONS
|
||||
case SSL3_MT_ENCRYPTED_EXTENSIONS:
|
||||
return "Encrypted Extensions";
|
||||
#endif
|
||||
#ifdef SSL3_MT_END_OF_EARLY_DATA
|
||||
case SSL3_MT_END_OF_EARLY_DATA:
|
||||
return "End of early data";
|
||||
#endif
|
||||
#ifdef SSL3_MT_KEY_UPDATE
|
||||
case SSL3_MT_KEY_UPDATE:
|
||||
return "Key update";
|
||||
#endif
|
||||
#ifdef SSL3_MT_NEXT_PROTO
|
||||
case SSL3_MT_NEXT_PROTO:
|
||||
return "Next protocol";
|
||||
#endif
|
||||
#ifdef SSL3_MT_MESSAGE_HASH
|
||||
case SSL3_MT_MESSAGE_HASH:
|
||||
return "Message hash";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
static const char *tls_rt_type(int type)
|
||||
static const char *tls_rt_type(int type, const void *buf, size_t buflen)
|
||||
{
|
||||
(void)buf;
|
||||
(void)buflen;
|
||||
#ifdef SSL3_RT_INNER_CONTENT_TYPE
|
||||
if(type == SSL3_RT_INNER_CONTENT_TYPE && buf && buflen >= 1)
|
||||
type = *(unsigned char *)buf;
|
||||
#endif
|
||||
|
||||
switch(type) {
|
||||
#ifdef SSL3_RT_HEADER
|
||||
case SSL3_RT_HEADER:
|
||||
@ -1759,10 +1850,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
|
||||
void *userp)
|
||||
{
|
||||
struct Curl_easy *data;
|
||||
const char *msg_name, *tls_rt_name;
|
||||
char ssl_buf[1024];
|
||||
char unknown[32];
|
||||
int msg_type, txt_len;
|
||||
const char *verstr = NULL;
|
||||
struct connectdata *conn = userp;
|
||||
|
||||
@ -1810,6 +1898,10 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
|
||||
}
|
||||
|
||||
if(ssl_ver) {
|
||||
const char *msg_name, *tls_rt_name;
|
||||
char ssl_buf[1024];
|
||||
int msg_type, txt_len;
|
||||
|
||||
/* the info given when the version is zero is not that useful for us */
|
||||
|
||||
ssl_ver >>= 8; /* check the upper 8 bits only below */
|
||||
@ -1819,17 +1911,28 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
|
||||
* is at 'buf[0]'.
|
||||
*/
|
||||
if(ssl_ver == SSL3_VERSION_MAJOR && content_type)
|
||||
tls_rt_name = tls_rt_type(content_type);
|
||||
tls_rt_name = tls_rt_type(content_type, buf, len);
|
||||
else
|
||||
tls_rt_name = "";
|
||||
|
||||
msg_type = *(char *)buf;
|
||||
msg_name = ssl_msg_type(ssl_ver, msg_type);
|
||||
#ifdef SSL3_RT_INNER_CONTENT_TYPE
|
||||
if(content_type == SSL3_RT_INNER_CONTENT_TYPE) {
|
||||
msg_type = 0;
|
||||
msg_name = "[no content]";
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
msg_type = *(char *)buf;
|
||||
msg_name = ssl_msg_type(ssl_ver, msg_type);
|
||||
}
|
||||
|
||||
txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n",
|
||||
verstr, direction?"OUT":"IN",
|
||||
tls_rt_name, msg_name, msg_type);
|
||||
Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL);
|
||||
if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) {
|
||||
Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
|
||||
@ -2082,8 +2185,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
|
||||
case CURL_SSLVERSION_TLSv1_2:
|
||||
case CURL_SSLVERSION_TLSv1_3:
|
||||
/* it will be handled later with the context options */
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
|
||||
!defined(LIBRESSL_VERSION_NUMBER)
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
||||
req_method = TLS_client_method();
|
||||
#else
|
||||
req_method = SSLv23_client_method();
|
||||
@ -2800,7 +2902,7 @@ static CURLcode get_cert_chain(struct connectdata *conn,
|
||||
ASN1_STRING *a = ASN1_STRING_new();
|
||||
if(a) {
|
||||
X509_get0_signature(&psig, &palg, x);
|
||||
X509_signature_print(mem, palg, a);
|
||||
X509_signature_print(mem, ARG2_X509_signature_print palg, a);
|
||||
ASN1_STRING_free(a);
|
||||
|
||||
if(palg) {
|
||||
@ -3035,7 +3137,8 @@ static CURLcode servercert(struct connectdata *conn,
|
||||
long lerr, len;
|
||||
struct Curl_easy *data = conn->data;
|
||||
X509 *issuer;
|
||||
FILE *fp;
|
||||
BIO *fp = NULL;
|
||||
char error_buffer[256]="";
|
||||
char buffer[2048];
|
||||
const char *ptr;
|
||||
long * const certverifyresult = SSL_IS_PROXY() ?
|
||||
@ -3046,8 +3149,20 @@ static CURLcode servercert(struct connectdata *conn,
|
||||
/* we've been asked to gather certificate info! */
|
||||
(void)get_cert_chain(conn, connssl);
|
||||
|
||||
fp = BIO_new(BIO_s_file());
|
||||
if(fp == NULL) {
|
||||
failf(data,
|
||||
"BIO_new return NULL, " OSSL_PACKAGE
|
||||
" error %s",
|
||||
ossl_strerror(ERR_get_error(), error_buffer,
|
||||
sizeof(error_buffer)) );
|
||||
BIO_free(mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle);
|
||||
if(!BACKEND->server_cert) {
|
||||
BIO_free(fp);
|
||||
BIO_free(mem);
|
||||
if(!strict)
|
||||
return CURLE_OK;
|
||||
@ -3077,6 +3192,7 @@ static CURLcode servercert(struct connectdata *conn,
|
||||
if(SSL_CONN_CONFIG(verifyhost)) {
|
||||
result = verifyhost(conn, BACKEND->server_cert);
|
||||
if(result) {
|
||||
BIO_free(fp);
|
||||
X509_free(BACKEND->server_cert);
|
||||
BACKEND->server_cert = NULL;
|
||||
return result;
|
||||
@ -3098,35 +3214,35 @@ static CURLcode servercert(struct connectdata *conn,
|
||||
|
||||
/* e.g. match issuer name with provided issuer certificate */
|
||||
if(SSL_SET_OPTION(issuercert)) {
|
||||
fp = fopen(SSL_SET_OPTION(issuercert), FOPEN_READTEXT);
|
||||
if(!fp) {
|
||||
if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) {
|
||||
if(strict)
|
||||
failf(data, "SSL: Unable to open issuer cert (%s)",
|
||||
SSL_SET_OPTION(issuercert));
|
||||
BIO_free(fp);
|
||||
X509_free(BACKEND->server_cert);
|
||||
BACKEND->server_cert = NULL;
|
||||
return CURLE_SSL_ISSUER_ERROR;
|
||||
}
|
||||
|
||||
issuer = PEM_read_X509(fp, NULL, ZERO_NULL, NULL);
|
||||
issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL);
|
||||
if(!issuer) {
|
||||
if(strict)
|
||||
failf(data, "SSL: Unable to read issuer cert (%s)",
|
||||
SSL_SET_OPTION(issuercert));
|
||||
X509_free(BACKEND->server_cert);
|
||||
BIO_free(fp);
|
||||
X509_free(issuer);
|
||||
fclose(fp);
|
||||
X509_free(BACKEND->server_cert);
|
||||
BACKEND->server_cert = NULL;
|
||||
return CURLE_SSL_ISSUER_ERROR;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if(X509_check_issued(issuer, BACKEND->server_cert) != X509_V_OK) {
|
||||
if(strict)
|
||||
failf(data, "SSL: Certificate issuer check failed (%s)",
|
||||
SSL_SET_OPTION(issuercert));
|
||||
X509_free(BACKEND->server_cert);
|
||||
BIO_free(fp);
|
||||
X509_free(issuer);
|
||||
X509_free(BACKEND->server_cert);
|
||||
BACKEND->server_cert = NULL;
|
||||
return CURLE_SSL_ISSUER_ERROR;
|
||||
}
|
||||
@ -3161,6 +3277,7 @@ static CURLcode servercert(struct connectdata *conn,
|
||||
if(SSL_CONN_CONFIG(verifystatus)) {
|
||||
result = verifystatus(conn, connssl);
|
||||
if(result) {
|
||||
BIO_free(fp);
|
||||
X509_free(BACKEND->server_cert);
|
||||
BACKEND->server_cert = NULL;
|
||||
return result;
|
||||
@ -3180,6 +3297,7 @@ static CURLcode servercert(struct connectdata *conn,
|
||||
failf(data, "SSL: public key does not match pinned public key!");
|
||||
}
|
||||
|
||||
BIO_free(fp);
|
||||
X509_free(BACKEND->server_cert);
|
||||
BACKEND->server_cert = NULL;
|
||||
connssl->connecting_state = ssl_connect_done;
|
||||
@ -3580,25 +3698,34 @@ static CURLcode Curl_ossl_md5sum(unsigned char *tmp, /* input */
|
||||
unsigned char *md5sum /* output */,
|
||||
size_t unused)
|
||||
{
|
||||
MD5_CTX MD5pw;
|
||||
(void)unused;
|
||||
MD5_Init(&MD5pw);
|
||||
MD5_Update(&MD5pw, tmp, tmplen);
|
||||
MD5_Final(md5sum, &MD5pw);
|
||||
EVP_MD_CTX *mdctx;
|
||||
unsigned int len = 0;
|
||||
(void) unused;
|
||||
|
||||
mdctx = EVP_MD_CTX_create();
|
||||
EVP_DigestInit_ex(mdctx, EVP_md5(), NULL);
|
||||
EVP_DigestUpdate(mdctx, tmp, tmplen);
|
||||
EVP_DigestFinal_ex(mdctx, md5sum, &len);
|
||||
EVP_MD_CTX_destroy(mdctx);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
|
||||
static void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
|
||||
static CURLcode Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
|
||||
size_t tmplen,
|
||||
unsigned char *sha256sum /* output */,
|
||||
size_t unused)
|
||||
{
|
||||
SHA256_CTX SHA256pw;
|
||||
(void)unused;
|
||||
SHA256_Init(&SHA256pw);
|
||||
SHA256_Update(&SHA256pw, tmp, tmplen);
|
||||
SHA256_Final(sha256sum, &SHA256pw);
|
||||
EVP_MD_CTX *mdctx;
|
||||
unsigned int len = 0;
|
||||
(void) unused;
|
||||
|
||||
mdctx = EVP_MD_CTX_create();
|
||||
EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL);
|
||||
EVP_DigestUpdate(mdctx, tmp, tmplen);
|
||||
EVP_DigestFinal_ex(mdctx, sha256sum, &len);
|
||||
EVP_MD_CTX_destroy(mdctx);
|
||||
return CURLE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -3623,11 +3750,11 @@ static void *Curl_ossl_get_internals(struct ssl_connect_data *connssl,
|
||||
const struct Curl_ssl Curl_ssl_openssl = {
|
||||
{ CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */
|
||||
|
||||
1, /* have_ca_path */
|
||||
1, /* have_certinfo */
|
||||
1, /* have_pinnedpubkey */
|
||||
1, /* have_ssl_ctx */
|
||||
1, /* support_https_proxy */
|
||||
SSLSUPP_CA_PATH |
|
||||
SSLSUPP_CERTINFO |
|
||||
SSLSUPP_PINNEDPUBKEY |
|
||||
SSLSUPP_SSL_CTX |
|
||||
SSLSUPP_HTTPS_PROXY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
@ -620,12 +620,10 @@ polarssl_connect_step3(struct connectdata *conn,
|
||||
ssl_session *our_ssl_sessionid;
|
||||
void *old_ssl_sessionid = NULL;
|
||||
|
||||
our_ssl_sessionid = malloc(sizeof(ssl_session));
|
||||
our_ssl_sessionid = calloc(1, sizeof(ssl_session));
|
||||
if(!our_ssl_sessionid)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
memset(our_ssl_sessionid, 0, sizeof(ssl_session));
|
||||
|
||||
ret = ssl_get_session(&BACKEND->ssl, our_ssl_sessionid);
|
||||
if(ret) {
|
||||
failf(data, "ssl_get_session returned -0x%x", -ret);
|
||||
@ -882,13 +880,14 @@ static bool Curl_polarssl_data_pending(const struct connectdata *conn,
|
||||
return ssl_get_bytes_avail(&BACKEND->ssl) != 0;
|
||||
}
|
||||
|
||||
static void Curl_polarssl_sha256sum(const unsigned char *input,
|
||||
static CURLcode Curl_polarssl_sha256sum(const unsigned char *input,
|
||||
size_t inputlen,
|
||||
unsigned char *sha256sum,
|
||||
size_t sha256len UNUSED_PARAM)
|
||||
{
|
||||
(void)sha256len;
|
||||
sha256(input, inputlen, sha256sum, 0);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void *Curl_polarssl_get_internals(struct ssl_connect_data *connssl,
|
||||
@ -901,11 +900,8 @@ static void *Curl_polarssl_get_internals(struct ssl_connect_data *connssl,
|
||||
const struct Curl_ssl Curl_ssl_polarssl = {
|
||||
{ CURLSSLBACKEND_POLARSSL, "polarssl" }, /* info */
|
||||
|
||||
1, /* have_ca_path */
|
||||
0, /* have_certinfo */
|
||||
1, /* have_pinnedpubkey */
|
||||
0, /* have_ssl_ctx */
|
||||
0, /* support_https_proxy */
|
||||
SSLSUPP_CA_PATH |
|
||||
SSLSUPP_PINNEDPUBKEY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
* Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
|
||||
* Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
|
||||
* Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2012 - 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
|
||||
@ -42,13 +42,12 @@
|
||||
|
||||
#ifdef USE_SCHANNEL
|
||||
|
||||
#define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
|
||||
|
||||
#ifndef USE_WINDOWS_SSPI
|
||||
# error "Can't compile SCHANNEL support without SSPI."
|
||||
#endif
|
||||
|
||||
#include <schnlsp.h>
|
||||
#include <schannel.h>
|
||||
#include "curl_sspi.h"
|
||||
#include "schannel.h"
|
||||
#include "vtls.h"
|
||||
#include "sendf.h"
|
||||
@ -61,7 +60,6 @@
|
||||
#include "x509asn1.h"
|
||||
#include "curl_printf.h"
|
||||
#include "system_win32.h"
|
||||
#include "hostcheck.h"
|
||||
|
||||
/* The last #include file should be: */
|
||||
#include "curl_memory.h"
|
||||
@ -92,6 +90,12 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef UNICODE
|
||||
#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W
|
||||
#else
|
||||
#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_SSL2_CLIENT
|
||||
#define SP_PROT_SSL2_CLIENT 0x00000008
|
||||
#endif
|
||||
@ -124,50 +128,25 @@
|
||||
#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
|
||||
#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
|
||||
|
||||
#define CERT_THUMBPRINT_STR_LEN 40
|
||||
#define CERT_THUMBPRINT_DATA_LEN 20
|
||||
|
||||
/* Uncomment to force verbose output
|
||||
* #define infof(x, y, ...) printf(y, __VA_ARGS__)
|
||||
* #define failf(x, y, ...) printf(y, __VA_ARGS__)
|
||||
*/
|
||||
|
||||
/* Structs to store Schannel handles */
|
||||
struct curl_schannel_cred {
|
||||
CredHandle cred_handle;
|
||||
TimeStamp time_stamp;
|
||||
int refcount;
|
||||
};
|
||||
|
||||
struct curl_schannel_ctxt {
|
||||
CtxtHandle ctxt_handle;
|
||||
TimeStamp time_stamp;
|
||||
};
|
||||
|
||||
struct ssl_backend_data {
|
||||
struct curl_schannel_cred *cred;
|
||||
struct curl_schannel_ctxt *ctxt;
|
||||
SecPkgContext_StreamSizes stream_sizes;
|
||||
size_t encdata_length, decdata_length;
|
||||
size_t encdata_offset, decdata_offset;
|
||||
unsigned char *encdata_buffer, *decdata_buffer;
|
||||
/* encdata_is_incomplete: if encdata contains only a partial record that
|
||||
can't be decrypted without another Curl_read_plain (that is, status is
|
||||
SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes
|
||||
more bytes into encdata then set this back to false. */
|
||||
bool encdata_is_incomplete;
|
||||
unsigned long req_flags, ret_flags;
|
||||
CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
|
||||
bool recv_sspi_close_notify; /* true if connection closed by close_notify */
|
||||
bool recv_connection_closed; /* true if connection closed, regardless how */
|
||||
bool use_alpn; /* true if ALPN is used for this connection */
|
||||
};
|
||||
#ifndef CALG_SHA_256
|
||||
# define CALG_SHA_256 0x0000800c
|
||||
#endif
|
||||
|
||||
#define BACKEND connssl->backend
|
||||
|
||||
static Curl_recv schannel_recv;
|
||||
static Curl_send schannel_send;
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
|
||||
#endif
|
||||
static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
|
||||
const char *pinnedpubkey);
|
||||
|
||||
static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
|
||||
void *BufDataPtr, unsigned long BufByteSize)
|
||||
@ -220,6 +199,56 @@ set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
|
||||
TCHAR **thumbprint)
|
||||
{
|
||||
TCHAR *sep;
|
||||
size_t store_name_len;
|
||||
|
||||
sep = _tcschr(path, TEXT('\\'));
|
||||
if(sep == NULL)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
||||
store_name_len = sep - path;
|
||||
|
||||
if(_tcsnccmp(path, TEXT("CurrentUser"), store_name_len) == 0)
|
||||
*store_name = CERT_SYSTEM_STORE_CURRENT_USER;
|
||||
else if(_tcsnccmp(path, TEXT("LocalMachine"), store_name_len) == 0)
|
||||
*store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE;
|
||||
else if(_tcsnccmp(path, TEXT("CurrentService"), store_name_len) == 0)
|
||||
*store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE;
|
||||
else if(_tcsnccmp(path, TEXT("Services"), store_name_len) == 0)
|
||||
*store_name = CERT_SYSTEM_STORE_SERVICES;
|
||||
else if(_tcsnccmp(path, TEXT("Users"), store_name_len) == 0)
|
||||
*store_name = CERT_SYSTEM_STORE_USERS;
|
||||
else if(_tcsnccmp(path, TEXT("CurrentUserGroupPolicy"),
|
||||
store_name_len) == 0)
|
||||
*store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
|
||||
else if(_tcsnccmp(path, TEXT("LocalMachineGroupPolicy"),
|
||||
store_name_len) == 0)
|
||||
*store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
|
||||
else if(_tcsnccmp(path, TEXT("LocalMachineEnterprise"),
|
||||
store_name_len) == 0)
|
||||
*store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
|
||||
else
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
||||
*store_path = sep + 1;
|
||||
|
||||
sep = _tcschr(*store_path, TEXT('\\'));
|
||||
if(sep == NULL)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
||||
*sep = 0;
|
||||
|
||||
*thumbprint = sep + 1;
|
||||
if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
schannel_connect_step1(struct connectdata *conn, int sockindex)
|
||||
{
|
||||
@ -234,6 +263,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
|
||||
unsigned char alpn_buffer[128];
|
||||
#endif
|
||||
SCHANNEL_CRED schannel_cred;
|
||||
PCCERT_CONTEXT client_certs[1] = { NULL };
|
||||
SECURITY_STATUS sspi_status = SEC_E_OK;
|
||||
struct curl_schannel_cred *old_cred = NULL;
|
||||
struct in_addr addr;
|
||||
@ -268,6 +298,26 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
|
||||
BACKEND->use_alpn = false;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
/* certificate validation on CE doesn't seem to work right; we'll
|
||||
* do it following a more manual process. */
|
||||
BACKEND->use_manual_cred_validation = true;
|
||||
#else
|
||||
if(SSL_CONN_CONFIG(CAfile)) {
|
||||
if(Curl_verify_windows_version(6, 1, PLATFORM_WINNT,
|
||||
VERSION_GREATER_THAN_EQUAL)) {
|
||||
BACKEND->use_manual_cred_validation = true;
|
||||
}
|
||||
else {
|
||||
failf(data, "schannel: this version of Windows is too old to support "
|
||||
"certificate verification via CA bundle file.");
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
}
|
||||
else
|
||||
BACKEND->use_manual_cred_validation = false;
|
||||
#endif
|
||||
|
||||
BACKEND->cred = NULL;
|
||||
|
||||
/* check for an existing re-usable credential handle */
|
||||
@ -291,26 +341,23 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
|
||||
schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
|
||||
|
||||
if(conn->ssl_config.verifypeer) {
|
||||
#ifdef _WIN32_WCE
|
||||
/* certificate validation on CE doesn't seem to work right; we'll
|
||||
do it following a more manual process. */
|
||||
schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
|
||||
SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
|
||||
SCH_CRED_IGNORE_REVOCATION_OFFLINE;
|
||||
#else
|
||||
schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
|
||||
/* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */
|
||||
if(data->set.ssl.no_revoke)
|
||||
schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
|
||||
SCH_CRED_IGNORE_REVOCATION_OFFLINE;
|
||||
if(BACKEND->use_manual_cred_validation)
|
||||
schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
|
||||
else
|
||||
schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
|
||||
#endif
|
||||
if(data->set.ssl.no_revoke)
|
||||
schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
|
||||
|
||||
/* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */
|
||||
if(data->set.ssl.no_revoke) {
|
||||
schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
|
||||
SCH_CRED_IGNORE_REVOCATION_OFFLINE;
|
||||
|
||||
infof(data, "schannel: disabled server certificate revocation "
|
||||
"checks\n");
|
||||
else
|
||||
}
|
||||
else {
|
||||
schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
|
||||
infof(data, "schannel: checking server certificate revocation\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
|
||||
@ -354,14 +401,70 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
/* client certificate */
|
||||
if(data->set.ssl.cert) {
|
||||
DWORD cert_store_name;
|
||||
TCHAR *cert_store_path;
|
||||
TCHAR *cert_thumbprint_str;
|
||||
CRYPT_HASH_BLOB cert_thumbprint;
|
||||
BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
|
||||
HCERTSTORE cert_store;
|
||||
|
||||
TCHAR *cert_path = Curl_convert_UTF8_to_tchar(data->set.ssl.cert);
|
||||
if(!cert_path)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
result = get_cert_location(cert_path, &cert_store_name,
|
||||
&cert_store_path, &cert_thumbprint_str);
|
||||
if(result != CURLE_OK) {
|
||||
Curl_unicodefree(cert_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
cert_store = CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
|
||||
(HCRYPTPROV)NULL,
|
||||
cert_store_name, cert_store_path);
|
||||
if(!cert_store) {
|
||||
Curl_unicodefree(cert_path);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
cert_thumbprint.pbData = cert_thumbprint_data;
|
||||
cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
|
||||
|
||||
if(!CryptStringToBinary(cert_thumbprint_str, CERT_THUMBPRINT_STR_LEN,
|
||||
CRYPT_STRING_HEX,
|
||||
cert_thumbprint_data, &cert_thumbprint.cbData,
|
||||
NULL, NULL)) {
|
||||
Curl_unicodefree(cert_path);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
client_certs[0] = CertFindCertificateInStore(
|
||||
cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
|
||||
CERT_FIND_HASH, &cert_thumbprint, NULL);
|
||||
|
||||
Curl_unicodefree(cert_path);
|
||||
|
||||
if(client_certs[0]) {
|
||||
schannel_cred.cCreds = 1;
|
||||
schannel_cred.paCred = client_certs;
|
||||
}
|
||||
|
||||
CertCloseStore(cert_store, 0);
|
||||
}
|
||||
|
||||
/* allocate memory for the re-usable credential handle */
|
||||
BACKEND->cred = (struct curl_schannel_cred *)
|
||||
malloc(sizeof(struct curl_schannel_cred));
|
||||
calloc(1, sizeof(struct curl_schannel_cred));
|
||||
if(!BACKEND->cred) {
|
||||
failf(data, "schannel: unable to allocate memory");
|
||||
|
||||
if(client_certs[0])
|
||||
CertFreeCertificateContext(client_certs[0]);
|
||||
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
memset(BACKEND->cred, 0, sizeof(struct curl_schannel_cred));
|
||||
BACKEND->cred->refcount = 1;
|
||||
|
||||
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
|
||||
@ -373,6 +476,9 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
|
||||
&BACKEND->cred->cred_handle,
|
||||
&BACKEND->cred->time_stamp);
|
||||
|
||||
if(client_certs[0])
|
||||
CertFreeCertificateContext(client_certs[0]);
|
||||
|
||||
if(sspi_status != SEC_E_OK) {
|
||||
if(sspi_status == SEC_E_WRONG_PRINCIPAL)
|
||||
failf(data, "schannel: SNI or certificate check failed: %s",
|
||||
@ -438,8 +544,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
|
||||
InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
|
||||
InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
|
||||
InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
|
||||
}
|
||||
@ -459,12 +564,11 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
|
||||
|
||||
/* allocate memory for the security context handle */
|
||||
BACKEND->ctxt = (struct curl_schannel_ctxt *)
|
||||
malloc(sizeof(struct curl_schannel_ctxt));
|
||||
calloc(1, sizeof(struct curl_schannel_ctxt));
|
||||
if(!BACKEND->ctxt) {
|
||||
failf(data, "schannel: unable to allocate memory");
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
memset(BACKEND->ctxt, 0, sizeof(struct curl_schannel_ctxt));
|
||||
|
||||
host_name = Curl_convert_UTF8_to_tchar(hostname);
|
||||
if(!host_name)
|
||||
@ -542,6 +646,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
|
||||
bool doread;
|
||||
char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
|
||||
conn->host.name;
|
||||
const char *pubkey_ptr;
|
||||
|
||||
doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
|
||||
|
||||
@ -761,12 +866,20 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
|
||||
infof(data, "schannel: SSL/TLS handshake complete\n");
|
||||
}
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
/* Windows CE doesn't do any server certificate validation.
|
||||
We have to do it manually. */
|
||||
if(conn->ssl_config.verifypeer)
|
||||
pubkey_ptr = SSL_IS_PROXY() ?
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
|
||||
if(pubkey_ptr) {
|
||||
result = pkp_pin_peer_pubkey(conn, sockindex, pubkey_ptr);
|
||||
if(result) {
|
||||
failf(data, "SSL: public key does not match pinned public key!");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) {
|
||||
return verify_certificate(conn, sockindex);
|
||||
#endif
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
@ -1669,145 +1782,136 @@ static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
|
||||
static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
|
||||
const char *pinnedpubkey)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
struct Curl_easy *data = conn->data;
|
||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||
CURLcode result = CURLE_OK;
|
||||
CERT_CONTEXT *pCertContextServer = NULL;
|
||||
const CERT_CHAIN_CONTEXT *pChainContext = NULL;
|
||||
const char * const conn_hostname = SSL_IS_PROXY() ?
|
||||
conn->http_proxy.host.name :
|
||||
conn->host.name;
|
||||
const char *x509_der;
|
||||
DWORD x509_der_len;
|
||||
curl_X509certificate x509_parsed;
|
||||
curl_asn1Element *pubkey;
|
||||
|
||||
status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
|
||||
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
|
||||
&pCertContextServer);
|
||||
/* Result is returned to caller */
|
||||
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
|
||||
|
||||
if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
|
||||
failf(data, "schannel: Failed to read remote certificate context: %s",
|
||||
Curl_sspi_strerror(conn, status));
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
/* if a path wasn't specified, don't pin */
|
||||
if(!pinnedpubkey)
|
||||
return CURLE_OK;
|
||||
|
||||
if(result == CURLE_OK) {
|
||||
CERT_CHAIN_PARA ChainPara;
|
||||
memset(&ChainPara, 0, sizeof(ChainPara));
|
||||
ChainPara.cbSize = sizeof(ChainPara);
|
||||
do {
|
||||
status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
|
||||
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
|
||||
&pCertContextServer);
|
||||
|
||||
if(!CertGetCertificateChain(NULL,
|
||||
pCertContextServer,
|
||||
NULL,
|
||||
pCertContextServer->hCertStore,
|
||||
&ChainPara,
|
||||
(data->set.ssl.no_revoke ? 0 :
|
||||
CERT_CHAIN_REVOCATION_CHECK_CHAIN),
|
||||
NULL,
|
||||
&pChainContext)) {
|
||||
failf(data, "schannel: CertGetCertificateChain failed: %s",
|
||||
Curl_sspi_strerror(conn, GetLastError()));
|
||||
pChainContext = NULL;
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
|
||||
failf(data, "schannel: Failed to read remote certificate context: %s",
|
||||
Curl_sspi_strerror(conn, status));
|
||||
break; /* failed */
|
||||
}
|
||||
|
||||
if(result == CURLE_OK) {
|
||||
CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
|
||||
DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
|
||||
dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
|
||||
if(dwTrustErrorMask) {
|
||||
if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
|
||||
failf(data, "schannel: CertGetCertificateChain trust error"
|
||||
" CERT_TRUST_IS_REVOKED");
|
||||
else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
|
||||
failf(data, "schannel: CertGetCertificateChain trust error"
|
||||
" CERT_TRUST_IS_PARTIAL_CHAIN");
|
||||
else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
|
||||
failf(data, "schannel: CertGetCertificateChain trust error"
|
||||
" CERT_TRUST_IS_UNTRUSTED_ROOT");
|
||||
else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
|
||||
failf(data, "schannel: CertGetCertificateChain trust error"
|
||||
" CERT_TRUST_IS_NOT_TIME_VALID");
|
||||
else
|
||||
failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
|
||||
dwTrustErrorMask);
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
|
||||
if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
|
||||
(pCertContextServer->cbCertEncoded > 0)))
|
||||
break;
|
||||
|
||||
x509_der = (const char *)pCertContextServer->pbCertEncoded;
|
||||
x509_der_len = pCertContextServer->cbCertEncoded;
|
||||
memset(&x509_parsed, 0, sizeof x509_parsed);
|
||||
if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
|
||||
break;
|
||||
|
||||
pubkey = &x509_parsed.subjectPublicKeyInfo;
|
||||
if(!pubkey->header || pubkey->end <= pubkey->header) {
|
||||
failf(data, "SSL: failed retrieving public key from server certificate");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(result == CURLE_OK) {
|
||||
if(conn->ssl_config.verifyhost) {
|
||||
TCHAR cert_hostname_buff[256];
|
||||
DWORD len;
|
||||
|
||||
/* TODO: Fix this for certificates with multiple alternative names.
|
||||
Right now we're only asking for the first preferred alternative name.
|
||||
Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG
|
||||
(if WinCE supports that?) and run this section in a loop for each.
|
||||
https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx
|
||||
curl: (51) schannel: CertGetNameString() certificate hostname
|
||||
(.google.com) did not match connection (google.com)
|
||||
*/
|
||||
len = CertGetNameString(pCertContextServer,
|
||||
CERT_NAME_DNS_TYPE,
|
||||
CERT_NAME_DISABLE_IE4_UTF8_FLAG,
|
||||
NULL,
|
||||
cert_hostname_buff,
|
||||
256);
|
||||
if(len > 0) {
|
||||
const char *cert_hostname;
|
||||
|
||||
/* Comparing the cert name and the connection hostname encoded as UTF-8
|
||||
* is acceptable since both values are assumed to use ASCII
|
||||
* (or some equivalent) encoding
|
||||
*/
|
||||
cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname_buff);
|
||||
if(!cert_hostname) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
else{
|
||||
int match_result;
|
||||
|
||||
match_result = Curl_cert_hostcheck(cert_hostname, conn->host.name);
|
||||
if(match_result == CURL_HOST_MATCH) {
|
||||
infof(data,
|
||||
"schannel: connection hostname (%s) validated "
|
||||
"against certificate name (%s)\n",
|
||||
conn->host.name,
|
||||
cert_hostname);
|
||||
result = CURLE_OK;
|
||||
}
|
||||
else{
|
||||
failf(data,
|
||||
"schannel: connection hostname (%s) "
|
||||
"does not match certificate name (%s)",
|
||||
conn->host.name,
|
||||
cert_hostname);
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
Curl_unicodefree(cert_hostname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
failf(data,
|
||||
"schannel: CertGetNameString did not provide any "
|
||||
"certificate name information");
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
result = Curl_pin_peer_pubkey(data,
|
||||
pinnedpubkey,
|
||||
(const unsigned char *)pubkey->header,
|
||||
(size_t)(pubkey->end - pubkey->header));
|
||||
if(result) {
|
||||
failf(data, "SSL: public key does not match pinned public key!");
|
||||
}
|
||||
}
|
||||
|
||||
if(pChainContext)
|
||||
CertFreeCertificateChain(pChainContext);
|
||||
} while(0);
|
||||
|
||||
if(pCertContextServer)
|
||||
CertFreeCertificateContext(pCertContextServer);
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif /* _WIN32_WCE */
|
||||
|
||||
static void Curl_schannel_checksum(const unsigned char *input,
|
||||
size_t inputlen,
|
||||
unsigned char *checksum,
|
||||
size_t checksumlen,
|
||||
DWORD provType,
|
||||
const unsigned int algId)
|
||||
{
|
||||
HCRYPTPROV hProv = 0;
|
||||
HCRYPTHASH hHash = 0;
|
||||
DWORD cbHashSize = 0;
|
||||
DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
|
||||
DWORD dwChecksumLen = (DWORD)checksumlen;
|
||||
|
||||
/* since this can fail in multiple ways, zero memory first so we never
|
||||
* return old data
|
||||
*/
|
||||
memset(checksum, 0, checksumlen);
|
||||
|
||||
if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
|
||||
CRYPT_VERIFYCONTEXT))
|
||||
return; /* failed */
|
||||
|
||||
do {
|
||||
if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
|
||||
break; /* failed */
|
||||
|
||||
if(!CryptHashData(hHash, (const BYTE*)input, (DWORD)inputlen, 0))
|
||||
break; /* failed */
|
||||
|
||||
/* get hash size */
|
||||
if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
|
||||
&dwHashSizeLen, 0))
|
||||
break; /* failed */
|
||||
|
||||
/* check hash size */
|
||||
if(checksumlen < cbHashSize)
|
||||
break; /* failed */
|
||||
|
||||
if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
|
||||
break; /* failed */
|
||||
} while(0);
|
||||
|
||||
if(hHash)
|
||||
CryptDestroyHash(hHash);
|
||||
|
||||
if(hProv)
|
||||
CryptReleaseContext(hProv, 0);
|
||||
}
|
||||
|
||||
static CURLcode Curl_schannel_md5sum(unsigned char *input,
|
||||
size_t inputlen,
|
||||
unsigned char *md5sum,
|
||||
size_t md5len)
|
||||
{
|
||||
Curl_schannel_checksum(input, inputlen, md5sum, md5len,
|
||||
PROV_RSA_FULL, CALG_MD5);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
|
||||
size_t inputlen,
|
||||
unsigned char *sha256sum,
|
||||
size_t sha256len)
|
||||
{
|
||||
Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
|
||||
PROV_RSA_AES, CALG_SHA_256);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
|
||||
CURLINFO info UNUSED_PARAM)
|
||||
@ -1819,11 +1923,8 @@ static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
|
||||
const struct Curl_ssl Curl_ssl_schannel = {
|
||||
{ CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
|
||||
|
||||
0, /* have_ca_path */
|
||||
1, /* have_certinfo */
|
||||
0, /* have_pinnedpubkey */
|
||||
0, /* have_ssl_ctx */
|
||||
0, /* support_https_proxy */
|
||||
SSLSUPP_CERTINFO |
|
||||
SSLSUPP_PINNEDPUBKEY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
|
||||
@ -1845,8 +1946,8 @@ const struct Curl_ssl Curl_ssl_schannel = {
|
||||
Curl_none_set_engine_default, /* set_engine_default */
|
||||
Curl_none_engines_list, /* engines_list */
|
||||
Curl_none_false_start, /* false_start */
|
||||
Curl_none_md5sum, /* md5sum */
|
||||
NULL /* sha256sum */
|
||||
Curl_schannel_md5sum, /* md5sum */
|
||||
Curl_schannel_sha256sum /* sha256sum */
|
||||
};
|
||||
|
||||
#endif /* USE_SCHANNEL */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user