mirror of
https://github.com/Kitware/CMake.git
synced 2026-04-28 18:09:42 -05:00
Merge branch 'upstream-curl' into update-curl
* upstream-curl: curl 2023-07-26 (50490c06)
This commit is contained in:
@@ -31,7 +31,7 @@ Find the ngtcp2 library
|
||||
This module accepts optional COMPONENTS to control the crypto library (these are
|
||||
mutually exclusive)::
|
||||
|
||||
OpenSSL: Use libngtcp2_crypto_openssl
|
||||
OpenSSL: Use libngtcp2_crypto_quictls
|
||||
GnuTLS: Use libngtcp2_crypto_gnutls
|
||||
|
||||
Result Variables
|
||||
@@ -71,7 +71,7 @@ endif()
|
||||
if(NGTCP2_FIND_COMPONENTS)
|
||||
set(NGTCP2_CRYPTO_BACKEND "")
|
||||
foreach(component IN LISTS NGTCP2_FIND_COMPONENTS)
|
||||
if(component MATCHES "^(BoringSSL|OpenSSL|wolfSSL|GnuTLS)")
|
||||
if(component MATCHES "^(BoringSSL|quictls|wolfSSL|GnuTLS)")
|
||||
if(NGTCP2_CRYPTO_BACKEND)
|
||||
message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected")
|
||||
endif()
|
||||
|
||||
@@ -242,6 +242,8 @@ endif()
|
||||
|
||||
include_directories(${CURL_SOURCE_DIR}/include)
|
||||
|
||||
set(CMAKE_UNITY_BUILD_BATCH_SIZE 0)
|
||||
|
||||
option(CURL_WERROR "Turn compiler warnings into errors" OFF)
|
||||
option(PICKY_COMPILER "Enable picky compiler options" ON)
|
||||
option(BUILD_CURL_EXE "Set to ON to build curl executable." ON)
|
||||
@@ -689,7 +691,7 @@ endif()
|
||||
option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF)
|
||||
set(HAVE_BROTLI OFF)
|
||||
if(CURL_BROTLI)
|
||||
find_package(Brotli QUIET)
|
||||
find_package(Brotli REQUIRED)
|
||||
if(BROTLI_FOUND)
|
||||
set(HAVE_BROTLI ON)
|
||||
list(APPEND CURL_LIBS ${BROTLI_LIBRARIES})
|
||||
@@ -768,7 +770,7 @@ if(USE_NGTCP2)
|
||||
elseif(HAVE_BORINGSSL)
|
||||
find_package(NGTCP2 REQUIRED BoringSSL)
|
||||
else()
|
||||
find_package(NGTCP2 REQUIRED OpenSSL)
|
||||
find_package(NGTCP2 REQUIRED quictls)
|
||||
endif()
|
||||
CheckQuicSupportInOpenSSL()
|
||||
elseif(USE_GNUTLS)
|
||||
@@ -839,9 +841,7 @@ if(NOT CURL_DISABLE_LDAP)
|
||||
endif()
|
||||
|
||||
# Now that we know, we're not using windows LDAP...
|
||||
if(USE_WIN32_LDAP)
|
||||
check_include_file_concat("winldap.h" HAVE_WINLDAP_H)
|
||||
else()
|
||||
if(NOT USE_WIN32_LDAP)
|
||||
# Check for LDAP
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES})
|
||||
check_library_exists_concat(${CMAKE_LDAP_LIB} ldap_init HAVE_LIBLDAP)
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \
|
||||
(defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \
|
||||
(defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000)) || \
|
||||
defined(__sun__) || defined(__serenity__)
|
||||
defined(__sun__) || defined(__serenity__) || defined(__vxworks__)
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
@@ -781,7 +781,7 @@ typedef enum {
|
||||
CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT
|
||||
HTTP/1.0 */
|
||||
CURLPROXY_HTTPS = 2, /* HTTPS but stick to HTTP/1 added in 7.52.0 */
|
||||
CURLPROXY_HTTPS2 = 3, /* HTTPS and attempt HTTP/2 added in 8.1.0 */
|
||||
CURLPROXY_HTTPS2 = 3, /* HTTPS and attempt HTTP/2 added in 8.2.0 */
|
||||
CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already
|
||||
in 7.10 */
|
||||
CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
|
||||
@@ -2113,7 +2113,7 @@ typedef enum {
|
||||
CURLOPT(CURLOPT_SASL_AUTHZID, CURLOPTTYPE_STRINGPOINT, 289),
|
||||
|
||||
/* allow RCPT TO command to fail for some recipients */
|
||||
CURLOPT(CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOPTTYPE_LONG, 290),
|
||||
CURLOPT(CURLOPT_MAIL_RCPT_ALLOWFAILS, CURLOPTTYPE_LONG, 290),
|
||||
|
||||
/* the private SSL-certificate as a "blob" */
|
||||
CURLOPT(CURLOPT_SSLCERT_BLOB, CURLOPTTYPE_BLOB, 291),
|
||||
@@ -2207,6 +2207,9 @@ typedef enum {
|
||||
/* Can leak things, gonna exit() soon */
|
||||
CURLOPT(CURLOPT_QUICK_EXIT, CURLOPTTYPE_LONG, 322),
|
||||
|
||||
/* set a specific client IP for HAProxy PROXY protocol header? */
|
||||
CURLOPT(CURLOPT_HAPROXY_CLIENT_IP, CURLOPTTYPE_STRINGPOINT, 323),
|
||||
|
||||
CURLOPT_LASTENTRY /* the last unused */
|
||||
} CURLoption;
|
||||
|
||||
@@ -2235,6 +2238,9 @@ typedef enum {
|
||||
/* */
|
||||
#define CURLOPT_FTP_RESPONSE_TIMEOUT CURLOPT_SERVER_RESPONSE_TIMEOUT
|
||||
|
||||
/* Added in 8.2.0 */
|
||||
#define CURLOPT_MAIL_RCPT_ALLLOWFAILS CURLOPT_MAIL_RCPT_ALLOWFAILS
|
||||
|
||||
#else
|
||||
/* This is set if CURL_NO_OLDIES is defined at compile-time */
|
||||
#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
|
||||
@@ -2918,7 +2924,9 @@ typedef enum {
|
||||
CURLINFO_REFERER = CURLINFO_STRING + 60,
|
||||
CURLINFO_CAINFO = CURLINFO_STRING + 61,
|
||||
CURLINFO_CAPATH = CURLINFO_STRING + 62,
|
||||
CURLINFO_LASTONE = 62
|
||||
CURLINFO_XFER_ID = CURLINFO_OFF_T + 63,
|
||||
CURLINFO_CONN_ID = CURLINFO_OFF_T + 64,
|
||||
CURLINFO_LASTONE = 64
|
||||
} CURLINFO;
|
||||
|
||||
/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
|
||||
/* This is the version number of the libcurl package from which this header
|
||||
file origins: */
|
||||
#define LIBCURL_VERSION "8.1.2"
|
||||
#define LIBCURL_VERSION "8.2.1"
|
||||
|
||||
/* The numeric version number is also available "in parts" by using these
|
||||
defines: */
|
||||
#define LIBCURL_VERSION_MAJOR 8
|
||||
#define LIBCURL_VERSION_MINOR 1
|
||||
#define LIBCURL_VERSION_PATCH 2
|
||||
#define LIBCURL_VERSION_MINOR 2
|
||||
#define LIBCURL_VERSION_PATCH 1
|
||||
|
||||
/* This is the numeric version of the libcurl version number, meant for easier
|
||||
parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
|
||||
@@ -59,7 +59,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 0x080102
|
||||
#define LIBCURL_VERSION_NUM 0x080201
|
||||
|
||||
/*
|
||||
* This is the date and time when the full source package was created. The
|
||||
|
||||
@@ -237,33 +237,28 @@
|
||||
# define CURL_PULL_SYS_SOCKET_H 1
|
||||
|
||||
#elif defined(__MVS__)
|
||||
# if defined(__IBMC__) || defined(__IBMCPP__)
|
||||
# if defined(_ILP32)
|
||||
# elif defined(_LP64)
|
||||
# endif
|
||||
# if defined(_LONG_LONG)
|
||||
# define CURL_TYPEOF_CURL_OFF_T long long
|
||||
# define CURL_FORMAT_CURL_OFF_T "lld"
|
||||
# define CURL_FORMAT_CURL_OFF_TU "llu"
|
||||
# define CURL_SUFFIX_CURL_OFF_T LL
|
||||
# define CURL_SUFFIX_CURL_OFF_TU ULL
|
||||
# elif defined(_LP64)
|
||||
# define CURL_TYPEOF_CURL_OFF_T long
|
||||
# define CURL_FORMAT_CURL_OFF_T "ld"
|
||||
# define CURL_FORMAT_CURL_OFF_TU "lu"
|
||||
# define CURL_SUFFIX_CURL_OFF_T L
|
||||
# define CURL_SUFFIX_CURL_OFF_TU UL
|
||||
# else
|
||||
# define CURL_TYPEOF_CURL_OFF_T long
|
||||
# define CURL_FORMAT_CURL_OFF_T "ld"
|
||||
# define CURL_FORMAT_CURL_OFF_TU "lu"
|
||||
# define CURL_SUFFIX_CURL_OFF_T L
|
||||
# define CURL_SUFFIX_CURL_OFF_TU UL
|
||||
# endif
|
||||
# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
|
||||
# define CURL_PULL_SYS_TYPES_H 1
|
||||
# define CURL_PULL_SYS_SOCKET_H 1
|
||||
# if defined(_LONG_LONG)
|
||||
# define CURL_TYPEOF_CURL_OFF_T long long
|
||||
# define CURL_FORMAT_CURL_OFF_T "lld"
|
||||
# define CURL_FORMAT_CURL_OFF_TU "llu"
|
||||
# define CURL_SUFFIX_CURL_OFF_T LL
|
||||
# define CURL_SUFFIX_CURL_OFF_TU ULL
|
||||
# elif defined(_LP64)
|
||||
# define CURL_TYPEOF_CURL_OFF_T long
|
||||
# define CURL_FORMAT_CURL_OFF_T "ld"
|
||||
# define CURL_FORMAT_CURL_OFF_TU "lu"
|
||||
# define CURL_SUFFIX_CURL_OFF_T L
|
||||
# define CURL_SUFFIX_CURL_OFF_TU UL
|
||||
# else
|
||||
# define CURL_TYPEOF_CURL_OFF_T long
|
||||
# define CURL_FORMAT_CURL_OFF_T "ld"
|
||||
# define CURL_FORMAT_CURL_OFF_TU "lu"
|
||||
# define CURL_SUFFIX_CURL_OFF_T L
|
||||
# define CURL_SUFFIX_CURL_OFF_TU UL
|
||||
# endif
|
||||
# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
|
||||
# define CURL_PULL_SYS_TYPES_H 1
|
||||
# define CURL_PULL_SYS_SOCKET_H 1
|
||||
|
||||
#elif defined(__370__)
|
||||
# if defined(__IBMC__) || defined(__IBMCPP__)
|
||||
|
||||
@@ -280,6 +280,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
|
||||
(option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \
|
||||
(option) == CURLOPT_FTPPORT || \
|
||||
(option) == CURLOPT_HSTS || \
|
||||
(option) == CURLOPT_HAPROXY_CLIENT_IP || \
|
||||
(option) == CURLOPT_INTERFACE || \
|
||||
(option) == CURLOPT_ISSUERCERT || \
|
||||
(option) == CURLOPT_KEYPASSWD || \
|
||||
|
||||
@@ -54,13 +54,13 @@ struct curl_ws_frame {
|
||||
*/
|
||||
CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
|
||||
size_t *recv,
|
||||
struct curl_ws_frame **metap);
|
||||
const struct curl_ws_frame **metap);
|
||||
|
||||
/* sendflags for curl_ws_send() */
|
||||
/* flags for curl_ws_send() */
|
||||
#define CURLWS_PONG (1<<6)
|
||||
|
||||
/*
|
||||
* NAME curl_easy_send()
|
||||
* NAME curl_ws_send()
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
@@ -69,13 +69,13 @@ CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
|
||||
*/
|
||||
CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer,
|
||||
size_t buflen, size_t *sent,
|
||||
curl_off_t framesize,
|
||||
unsigned int sendflags);
|
||||
curl_off_t fragsize,
|
||||
unsigned int flags);
|
||||
|
||||
/* bits for the CURLOPT_WS_OPTIONS bitmask: */
|
||||
#define CURLWS_RAW_MODE (1<<0)
|
||||
|
||||
CURL_EXTERN struct curl_ws_frame *curl_ws_meta(CURL *curl);
|
||||
CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *curl);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -89,16 +89,31 @@ add_library(
|
||||
${CMAKE_CURL_SSL_DLLS}
|
||||
)
|
||||
|
||||
add_library(
|
||||
curlu # special libcurlu library just for unittests
|
||||
STATIC
|
||||
EXCLUDE_FROM_ALL
|
||||
${HHEADERS} ${CSOURCES}
|
||||
)
|
||||
target_compile_definitions(curlu PUBLIC UNITTESTS CURL_STATICLIB)
|
||||
|
||||
add_library(
|
||||
${PROJECT_NAME}::${LIB_NAME}
|
||||
ALIAS ${LIB_NAME}
|
||||
)
|
||||
|
||||
if(ENABLE_CURLDEBUG)
|
||||
# We must compile memdebug.c separately to avoid memdebug.h redefinitions
|
||||
# being applied to memdebug.c itself.
|
||||
set_source_files_properties(memdebug.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
|
||||
endif()
|
||||
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
set_target_properties(${LIB_NAME} PROPERTIES INTERFACE_COMPILE_DEFINITIONS CURL_STATICLIB)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${LIB_NAME} PRIVATE ${CURL_LIBS})
|
||||
target_link_libraries(curlu PRIVATE ${CURL_LIBS})
|
||||
|
||||
if(0) # This code not needed for building within CMake.
|
||||
transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
|
||||
|
||||
@@ -72,6 +72,7 @@ LIB_VTLS_HFILES = \
|
||||
vtls/openssl.h \
|
||||
vtls/rustls.h \
|
||||
vtls/schannel.h \
|
||||
vtls/schannel_int.h \
|
||||
vtls/sectransp.h \
|
||||
vtls/vtls.h \
|
||||
vtls/vtls_int.h \
|
||||
@@ -179,6 +180,7 @@ LIB_CFILES = \
|
||||
krb5.c \
|
||||
ldap.c \
|
||||
llist.c \
|
||||
macos.c \
|
||||
md4.c \
|
||||
md5.c \
|
||||
memdebug.c \
|
||||
@@ -315,6 +317,7 @@ LIB_HFILES = \
|
||||
inet_ntop.h \
|
||||
inet_pton.h \
|
||||
llist.h \
|
||||
macos.h \
|
||||
memdebug.h \
|
||||
mime.h \
|
||||
mqtt.h \
|
||||
|
||||
@@ -424,7 +424,7 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
|
||||
#ifdef DEBUGBUILD
|
||||
/* to play well with debug builds, we can *set* a fixed time this will
|
||||
return */
|
||||
static time_t debugtime(void *unused)
|
||||
static time_t altsvc_debugtime(void *unused)
|
||||
{
|
||||
char *timestr = getenv("CURL_TIME");
|
||||
(void)unused;
|
||||
@@ -434,7 +434,8 @@ static time_t debugtime(void *unused)
|
||||
}
|
||||
return time(NULL);
|
||||
}
|
||||
#define time(x) debugtime(x)
|
||||
#undef time
|
||||
#define time(x) altsvc_debugtime(x)
|
||||
#endif
|
||||
|
||||
#define ISNEWLINE(x) (((x) == '\n') || (x) == '\r')
|
||||
|
||||
@@ -178,6 +178,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
|
||||
#endif /* CURLRES_AMIGA */
|
||||
|
||||
#ifdef USE_AMISSL
|
||||
#include <signal.h>
|
||||
int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *errorfds, struct timeval *timeout)
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
/* ---- Base64 Encoding/Decoding Table --- */
|
||||
/* Padding character string starts at offset 64. */
|
||||
static const char base64[]=
|
||||
static const char base64encdec[]=
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
|
||||
/* The Base 64 encoding with a URL and filename safe alphabet, RFC 4648
|
||||
@@ -120,7 +120,7 @@ CURLcode Curl_base64_decode(const char *src,
|
||||
/* replaces
|
||||
{
|
||||
unsigned char c;
|
||||
const unsigned char *p = (const unsigned char *)base64;
|
||||
const unsigned char *p = (const unsigned char *)base64encdec;
|
||||
for(c = 0; *p; c++, p++)
|
||||
lookup[*p] = c;
|
||||
}
|
||||
@@ -264,7 +264,7 @@ static CURLcode base64_encode(const char *table64,
|
||||
CURLcode Curl_base64_encode(const char *inputbuff, size_t insize,
|
||||
char **outptr, size_t *outlen)
|
||||
{
|
||||
return base64_encode(base64, inputbuff, insize, outptr, outlen);
|
||||
return base64_encode(base64encdec, inputbuff, insize, outptr, outlen);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -418,7 +418,8 @@ ssize_t Curl_bufq_write(struct bufq *q,
|
||||
break;
|
||||
}
|
||||
n = chunk_append(tail, buf, len);
|
||||
DEBUGASSERT(n);
|
||||
if(!n)
|
||||
break;
|
||||
nwritten += n;
|
||||
buf += n;
|
||||
len -= n;
|
||||
@@ -528,6 +529,14 @@ ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(!chunk_written) {
|
||||
if(!nwritten) {
|
||||
/* treat as blocked */
|
||||
*err = CURLE_AGAIN;
|
||||
nwritten = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Curl_bufq_skip(q, (size_t)chunk_written);
|
||||
nwritten += chunk_written;
|
||||
}
|
||||
@@ -551,7 +560,8 @@ ssize_t Curl_bufq_write_pass(struct bufq *q,
|
||||
/* real error, fail */
|
||||
return -1;
|
||||
}
|
||||
/* would block */
|
||||
/* would block, bufq is full, give up */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,16 +572,25 @@ ssize_t Curl_bufq_write_pass(struct bufq *q,
|
||||
/* real error, fail */
|
||||
return -1;
|
||||
}
|
||||
/* no room in bufq, bail out */
|
||||
goto out;
|
||||
/* no room in bufq */
|
||||
break;
|
||||
}
|
||||
/* edge case of writer returning 0 (and len is >0)
|
||||
* break or we might enter an infinite loop here */
|
||||
if(n == 0)
|
||||
break;
|
||||
|
||||
/* Maybe only part of `data` has been added, continue to loop */
|
||||
buf += (size_t)n;
|
||||
len -= (size_t)n;
|
||||
nwritten += (size_t)n;
|
||||
}
|
||||
|
||||
out:
|
||||
if(!nwritten && len) {
|
||||
*err = CURLE_AGAIN;
|
||||
return -1;
|
||||
}
|
||||
*err = CURLE_OK;
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,9 +71,11 @@ size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
|
||||
DEBUGASSERT(conn);
|
||||
(void)ctx;
|
||||
|
||||
DEBUGF(infof(data, "Curl_hyper_recv(%zu)", buflen));
|
||||
result = Curl_read(data, conn->sockfd, (char *)buf, buflen, &nread);
|
||||
if(result == CURLE_AGAIN) {
|
||||
/* would block, register interest */
|
||||
DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> EAGAIN", buflen));
|
||||
if(data->hyp.read_waker)
|
||||
hyper_waker_free(data->hyp.read_waker);
|
||||
data->hyp.read_waker = hyper_context_waker(ctx);
|
||||
@@ -87,6 +89,7 @@ size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
|
||||
failf(data, "Curl_read failed");
|
||||
return HYPER_IO_ERROR;
|
||||
}
|
||||
DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> %zd", buflen, nread));
|
||||
return (size_t)nread;
|
||||
}
|
||||
|
||||
@@ -98,8 +101,12 @@ size_t Curl_hyper_send(void *userp, hyper_context *ctx,
|
||||
CURLcode result;
|
||||
ssize_t nwrote;
|
||||
|
||||
DEBUGF(infof(data, "Curl_hyper_send(%zu)", buflen));
|
||||
result = Curl_write(data, conn->sockfd, (void *)buf, buflen, &nwrote);
|
||||
if(!result && !nwrote)
|
||||
result = CURLE_AGAIN;
|
||||
if(result == CURLE_AGAIN) {
|
||||
DEBUGF(infof(data, "Curl_hyper_send(%zu) -> EAGAIN", buflen));
|
||||
/* would block, register interest */
|
||||
if(data->hyp.write_waker)
|
||||
hyper_waker_free(data->hyp.write_waker);
|
||||
@@ -114,6 +121,7 @@ size_t Curl_hyper_send(void *userp, hyper_context *ctx,
|
||||
failf(data, "Curl_write failed");
|
||||
return HYPER_IO_ERROR;
|
||||
}
|
||||
DEBUGF(infof(data, "Curl_hyper_send(%zu) -> %zd", buflen, nwrote));
|
||||
return (size_t)nwrote;
|
||||
}
|
||||
|
||||
@@ -433,8 +441,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
|
||||
break;
|
||||
}
|
||||
else if(t != HYPER_TASK_RESPONSE) {
|
||||
*didwhat = KEEP_RECV;
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
/* HYPER_TASK_RESPONSE */
|
||||
|
||||
|
||||
@@ -54,16 +54,16 @@
|
||||
|
||||
|
||||
typedef enum {
|
||||
TUNNEL_INIT, /* init/default/no tunnel state */
|
||||
TUNNEL_CONNECT, /* CONNECT request is being send */
|
||||
TUNNEL_RECEIVE, /* CONNECT answer is being received */
|
||||
TUNNEL_RESPONSE, /* CONNECT response received completely */
|
||||
TUNNEL_ESTABLISHED,
|
||||
TUNNEL_FAILED
|
||||
} tunnel_state;
|
||||
H1_TUNNEL_INIT, /* init/default/no tunnel state */
|
||||
H1_TUNNEL_CONNECT, /* CONNECT request is being send */
|
||||
H1_TUNNEL_RECEIVE, /* CONNECT answer is being received */
|
||||
H1_TUNNEL_RESPONSE, /* CONNECT response received completely */
|
||||
H1_TUNNEL_ESTABLISHED,
|
||||
H1_TUNNEL_FAILED
|
||||
} h1_tunnel_state;
|
||||
|
||||
/* struct for HTTP CONNECT tunneling */
|
||||
struct tunnel_state {
|
||||
struct h1_tunnel_state {
|
||||
int sockindex;
|
||||
const char *hostname;
|
||||
int remote_port;
|
||||
@@ -78,23 +78,23 @@ struct tunnel_state {
|
||||
KEEPON_IGNORE
|
||||
} keepon;
|
||||
curl_off_t cl; /* size of content to read and ignore */
|
||||
tunnel_state tunnel_state;
|
||||
h1_tunnel_state tunnel_state;
|
||||
BIT(chunked_encoding);
|
||||
BIT(close_connection);
|
||||
};
|
||||
|
||||
|
||||
static bool tunnel_is_established(struct tunnel_state *ts)
|
||||
static bool tunnel_is_established(struct h1_tunnel_state *ts)
|
||||
{
|
||||
return ts && (ts->tunnel_state == TUNNEL_ESTABLISHED);
|
||||
return ts && (ts->tunnel_state == H1_TUNNEL_ESTABLISHED);
|
||||
}
|
||||
|
||||
static bool tunnel_is_failed(struct tunnel_state *ts)
|
||||
static bool tunnel_is_failed(struct h1_tunnel_state *ts)
|
||||
{
|
||||
return ts && (ts->tunnel_state == TUNNEL_FAILED);
|
||||
return ts && (ts->tunnel_state == H1_TUNNEL_FAILED);
|
||||
}
|
||||
|
||||
static CURLcode tunnel_reinit(struct tunnel_state *ts,
|
||||
static CURLcode tunnel_reinit(struct h1_tunnel_state *ts,
|
||||
struct connectdata *conn,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
@@ -102,7 +102,7 @@ static CURLcode tunnel_reinit(struct tunnel_state *ts,
|
||||
DEBUGASSERT(ts);
|
||||
Curl_dyn_reset(&ts->rcvbuf);
|
||||
Curl_dyn_reset(&ts->req);
|
||||
ts->tunnel_state = TUNNEL_INIT;
|
||||
ts->tunnel_state = H1_TUNNEL_INIT;
|
||||
ts->keepon = KEEPON_CONNECT;
|
||||
ts->cl = 0;
|
||||
ts->close_connection = FALSE;
|
||||
@@ -124,12 +124,12 @@ static CURLcode tunnel_reinit(struct tunnel_state *ts,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode tunnel_init(struct tunnel_state **pts,
|
||||
static CURLcode tunnel_init(struct h1_tunnel_state **pts,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex)
|
||||
{
|
||||
struct tunnel_state *ts;
|
||||
struct h1_tunnel_state *ts;
|
||||
CURLcode result;
|
||||
|
||||
if(conn->handler->flags & PROTOPT_NOTCPPROXY) {
|
||||
@@ -157,16 +157,16 @@ static CURLcode tunnel_init(struct tunnel_state **pts,
|
||||
return tunnel_reinit(ts, conn, data);
|
||||
}
|
||||
|
||||
static void tunnel_go_state(struct Curl_cfilter *cf,
|
||||
struct tunnel_state *ts,
|
||||
tunnel_state new_state,
|
||||
struct Curl_easy *data)
|
||||
static void h1_tunnel_go_state(struct Curl_cfilter *cf,
|
||||
struct h1_tunnel_state *ts,
|
||||
h1_tunnel_state new_state,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
if(ts->tunnel_state == new_state)
|
||||
return;
|
||||
/* leaving this one */
|
||||
switch(ts->tunnel_state) {
|
||||
case TUNNEL_CONNECT:
|
||||
case H1_TUNNEL_CONNECT:
|
||||
data->req.ignorebody = FALSE;
|
||||
break;
|
||||
default:
|
||||
@@ -174,36 +174,36 @@ static void tunnel_go_state(struct Curl_cfilter *cf,
|
||||
}
|
||||
/* entering this one */
|
||||
switch(new_state) {
|
||||
case TUNNEL_INIT:
|
||||
case H1_TUNNEL_INIT:
|
||||
DEBUGF(LOG_CF(data, cf, "new tunnel state 'init'"));
|
||||
tunnel_reinit(ts, cf->conn, data);
|
||||
break;
|
||||
|
||||
case TUNNEL_CONNECT:
|
||||
case H1_TUNNEL_CONNECT:
|
||||
DEBUGF(LOG_CF(data, cf, "new tunnel state 'connect'"));
|
||||
ts->tunnel_state = TUNNEL_CONNECT;
|
||||
ts->tunnel_state = H1_TUNNEL_CONNECT;
|
||||
ts->keepon = KEEPON_CONNECT;
|
||||
Curl_dyn_reset(&ts->rcvbuf);
|
||||
break;
|
||||
|
||||
case TUNNEL_RECEIVE:
|
||||
case H1_TUNNEL_RECEIVE:
|
||||
DEBUGF(LOG_CF(data, cf, "new tunnel state 'receive'"));
|
||||
ts->tunnel_state = TUNNEL_RECEIVE;
|
||||
ts->tunnel_state = H1_TUNNEL_RECEIVE;
|
||||
break;
|
||||
|
||||
case TUNNEL_RESPONSE:
|
||||
case H1_TUNNEL_RESPONSE:
|
||||
DEBUGF(LOG_CF(data, cf, "new tunnel state 'response'"));
|
||||
ts->tunnel_state = TUNNEL_RESPONSE;
|
||||
ts->tunnel_state = H1_TUNNEL_RESPONSE;
|
||||
break;
|
||||
|
||||
case TUNNEL_ESTABLISHED:
|
||||
case H1_TUNNEL_ESTABLISHED:
|
||||
DEBUGF(LOG_CF(data, cf, "new tunnel state 'established'"));
|
||||
infof(data, "CONNECT phase completed");
|
||||
data->state.authproxy.done = TRUE;
|
||||
data->state.authproxy.multipass = FALSE;
|
||||
/* FALLTHROUGH */
|
||||
case TUNNEL_FAILED:
|
||||
if(new_state == TUNNEL_FAILED)
|
||||
case H1_TUNNEL_FAILED:
|
||||
if(new_state == H1_TUNNEL_FAILED)
|
||||
DEBUGF(LOG_CF(data, cf, "new tunnel state 'failed'"));
|
||||
ts->tunnel_state = new_state;
|
||||
Curl_dyn_reset(&ts->rcvbuf);
|
||||
@@ -225,9 +225,9 @@ static void tunnel_go_state(struct Curl_cfilter *cf,
|
||||
static void tunnel_free(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct tunnel_state *ts = cf->ctx;
|
||||
struct h1_tunnel_state *ts = cf->ctx;
|
||||
if(ts) {
|
||||
tunnel_go_state(cf, ts, TUNNEL_FAILED, data);
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
|
||||
Curl_dyn_free(&ts->rcvbuf);
|
||||
Curl_dyn_free(&ts->req);
|
||||
free(ts);
|
||||
@@ -270,7 +270,7 @@ static CURLcode CONNECT_host(struct Curl_easy *data,
|
||||
#ifndef USE_HYPER
|
||||
static CURLcode start_CONNECT(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct tunnel_state *ts)
|
||||
struct h1_tunnel_state *ts)
|
||||
{
|
||||
struct connectdata *conn = cf->conn;
|
||||
char *hostheader = NULL;
|
||||
@@ -351,7 +351,7 @@ out:
|
||||
|
||||
static CURLcode send_CONNECT(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
struct tunnel_state *ts,
|
||||
struct h1_tunnel_state *ts,
|
||||
bool *done)
|
||||
{
|
||||
struct SingleRequest *k = &data->req;
|
||||
@@ -399,7 +399,7 @@ out:
|
||||
|
||||
static CURLcode on_resp_header(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct tunnel_state *ts,
|
||||
struct h1_tunnel_state *ts,
|
||||
const char *header)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
@@ -475,7 +475,7 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf,
|
||||
|
||||
static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct tunnel_state *ts,
|
||||
struct h1_tunnel_state *ts,
|
||||
bool *done)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
@@ -671,7 +671,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
|
||||
/* The Hyper version of CONNECT */
|
||||
static CURLcode start_CONNECT(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct tunnel_state *ts)
|
||||
struct h1_tunnel_state *ts)
|
||||
{
|
||||
struct connectdata *conn = cf->conn;
|
||||
struct hyptransfer *h = &data->hyp;
|
||||
@@ -882,7 +882,7 @@ error:
|
||||
|
||||
static CURLcode send_CONNECT(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
struct tunnel_state *ts,
|
||||
struct h1_tunnel_state *ts,
|
||||
bool *done)
|
||||
{
|
||||
struct hyptransfer *h = &data->hyp;
|
||||
@@ -919,7 +919,7 @@ error:
|
||||
|
||||
static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct tunnel_state *ts,
|
||||
struct h1_tunnel_state *ts,
|
||||
bool *done)
|
||||
{
|
||||
struct hyptransfer *h = &data->hyp;
|
||||
@@ -949,9 +949,9 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
|
||||
|
||||
#endif /* USE_HYPER */
|
||||
|
||||
static CURLcode CONNECT(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct tunnel_state *ts)
|
||||
static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct h1_tunnel_state *ts)
|
||||
{
|
||||
struct connectdata *conn = cf->conn;
|
||||
CURLcode result;
|
||||
@@ -973,25 +973,25 @@ static CURLcode CONNECT(struct Curl_cfilter *cf,
|
||||
}
|
||||
|
||||
switch(ts->tunnel_state) {
|
||||
case TUNNEL_INIT:
|
||||
case H1_TUNNEL_INIT:
|
||||
/* Prepare the CONNECT request and make a first attempt to send. */
|
||||
DEBUGF(LOG_CF(data, cf, "CONNECT start"));
|
||||
result = start_CONNECT(cf, data, ts);
|
||||
if(result)
|
||||
goto out;
|
||||
tunnel_go_state(cf, ts, TUNNEL_CONNECT, data);
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_CONNECT, data);
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case TUNNEL_CONNECT:
|
||||
case H1_TUNNEL_CONNECT:
|
||||
/* see that the request is completely sent */
|
||||
DEBUGF(LOG_CF(data, cf, "CONNECT send"));
|
||||
result = send_CONNECT(data, cf->conn, ts, &done);
|
||||
if(result || !done)
|
||||
goto out;
|
||||
tunnel_go_state(cf, ts, TUNNEL_RECEIVE, data);
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_RECEIVE, data);
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case TUNNEL_RECEIVE:
|
||||
case H1_TUNNEL_RECEIVE:
|
||||
/* read what is there */
|
||||
DEBUGF(LOG_CF(data, cf, "CONNECT receive"));
|
||||
result = recv_CONNECT_resp(cf, data, ts, &done);
|
||||
@@ -1003,10 +1003,10 @@ static CURLcode CONNECT(struct Curl_cfilter *cf,
|
||||
if(result || !done)
|
||||
goto out;
|
||||
/* got it */
|
||||
tunnel_go_state(cf, ts, TUNNEL_RESPONSE, data);
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_RESPONSE, data);
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case TUNNEL_RESPONSE:
|
||||
case H1_TUNNEL_RESPONSE:
|
||||
DEBUGF(LOG_CF(data, cf, "CONNECT response"));
|
||||
if(data->req.newurl) {
|
||||
/* not the "final" response, we need to do a follow up request.
|
||||
@@ -1028,7 +1028,7 @@ static CURLcode CONNECT(struct Curl_cfilter *cf,
|
||||
}
|
||||
else {
|
||||
/* staying on this connection, reset state */
|
||||
tunnel_go_state(cf, ts, TUNNEL_INIT, data);
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_INIT, data);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1039,25 +1039,25 @@ static CURLcode CONNECT(struct Curl_cfilter *cf,
|
||||
|
||||
} while(data->req.newurl);
|
||||
|
||||
DEBUGASSERT(ts->tunnel_state == TUNNEL_RESPONSE);
|
||||
DEBUGASSERT(ts->tunnel_state == H1_TUNNEL_RESPONSE);
|
||||
if(data->info.httpproxycode/100 != 2) {
|
||||
/* a non-2xx response and we have no next url to try. */
|
||||
Curl_safefree(data->req.newurl);
|
||||
/* failure, close this connection to avoid re-use */
|
||||
streamclose(conn, "proxy CONNECT failure");
|
||||
tunnel_go_state(cf, ts, TUNNEL_FAILED, data);
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
|
||||
failf(data, "CONNECT tunnel failed, response %d", data->req.httpcode);
|
||||
return CURLE_RECV_ERROR;
|
||||
}
|
||||
/* 2xx response, SUCCESS! */
|
||||
tunnel_go_state(cf, ts, TUNNEL_ESTABLISHED, data);
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_ESTABLISHED, data);
|
||||
infof(data, "CONNECT tunnel established, response %d",
|
||||
data->info.httpproxycode);
|
||||
result = CURLE_OK;
|
||||
|
||||
out:
|
||||
if(result)
|
||||
tunnel_go_state(cf, ts, TUNNEL_FAILED, data);
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1066,7 +1066,7 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
|
||||
bool blocking, bool *done)
|
||||
{
|
||||
CURLcode result;
|
||||
struct tunnel_state *ts = cf->ctx;
|
||||
struct h1_tunnel_state *ts = cf->ctx;
|
||||
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
@@ -1074,7 +1074,7 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
|
||||
}
|
||||
|
||||
DEBUGF(LOG_CF(data, cf, "connect"));
|
||||
result = cf->next->cft->connect(cf->next, data, blocking, done);
|
||||
result = cf->next->cft->do_connect(cf->next, data, blocking, done);
|
||||
if(result || !*done)
|
||||
return result;
|
||||
|
||||
@@ -1089,7 +1089,7 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
|
||||
/* TODO: can we do blocking? */
|
||||
/* We want "seamless" operations through HTTP proxy tunnel */
|
||||
|
||||
result = CONNECT(cf, data, ts);
|
||||
result = H1_CONNECT(cf, data, ts);
|
||||
if(result)
|
||||
goto out;
|
||||
Curl_safefree(data->state.aptr.proxyuserpwd);
|
||||
@@ -1107,7 +1107,7 @@ static int cf_h1_proxy_get_select_socks(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
curl_socket_t *socks)
|
||||
{
|
||||
struct tunnel_state *ts = cf->ctx;
|
||||
struct h1_tunnel_state *ts = cf->ctx;
|
||||
int fds;
|
||||
|
||||
fds = cf->next->cft->get_select_socks(cf->next, data, socks);
|
||||
@@ -1143,10 +1143,10 @@ static void cf_h1_proxy_close(struct Curl_cfilter *cf,
|
||||
DEBUGF(LOG_CF(data, cf, "close"));
|
||||
cf->connected = FALSE;
|
||||
if(cf->ctx) {
|
||||
tunnel_go_state(cf, cf->ctx, TUNNEL_INIT, data);
|
||||
h1_tunnel_go_state(cf, cf->ctx, H1_TUNNEL_INIT, data);
|
||||
}
|
||||
if(cf->next)
|
||||
cf->next->cft->close(cf->next, data);
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+329
-202
@@ -44,26 +44,25 @@
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#define H2_NW_CHUNK_SIZE (128*1024)
|
||||
#define H2_NW_RECV_CHUNKS 1
|
||||
#define H2_NW_SEND_CHUNKS 1
|
||||
#define H2_CHUNK_SIZE (16*1024)
|
||||
|
||||
#define HTTP2_HUGE_WINDOW_SIZE (32 * 1024 * 1024) /* 32 MB */
|
||||
#define PROXY_HTTP2_HUGE_WINDOW_SIZE (100 * 1024 * 1024)
|
||||
#define H2_TUNNEL_WINDOW_SIZE (10 * 1024 * 1024)
|
||||
|
||||
#define PROXY_H2_NW_RECV_CHUNKS (H2_TUNNEL_WINDOW_SIZE / H2_CHUNK_SIZE)
|
||||
#define PROXY_H2_NW_SEND_CHUNKS 1
|
||||
|
||||
#define H2_TUNNEL_RECV_CHUNKS (H2_TUNNEL_WINDOW_SIZE / H2_CHUNK_SIZE)
|
||||
#define H2_TUNNEL_SEND_CHUNKS ((128 * 1024) / H2_CHUNK_SIZE)
|
||||
|
||||
#define H2_TUNNEL_WINDOW_SIZE (1024 * 1024)
|
||||
#define H2_TUNNEL_CHUNK_SIZE (32 * 1024)
|
||||
#define H2_TUNNEL_RECV_CHUNKS \
|
||||
(H2_TUNNEL_WINDOW_SIZE / H2_TUNNEL_CHUNK_SIZE)
|
||||
#define H2_TUNNEL_SEND_CHUNKS \
|
||||
(H2_TUNNEL_WINDOW_SIZE / H2_TUNNEL_CHUNK_SIZE)
|
||||
|
||||
typedef enum {
|
||||
TUNNEL_INIT, /* init/default/no tunnel state */
|
||||
TUNNEL_CONNECT, /* CONNECT request is being send */
|
||||
TUNNEL_RESPONSE, /* CONNECT response received completely */
|
||||
TUNNEL_ESTABLISHED,
|
||||
TUNNEL_FAILED
|
||||
} tunnel_state;
|
||||
H2_TUNNEL_INIT, /* init/default/no tunnel state */
|
||||
H2_TUNNEL_CONNECT, /* CONNECT request is being send */
|
||||
H2_TUNNEL_RESPONSE, /* CONNECT response received completely */
|
||||
H2_TUNNEL_ESTABLISHED,
|
||||
H2_TUNNEL_FAILED
|
||||
} h2_tunnel_state;
|
||||
|
||||
struct tunnel_stream {
|
||||
struct http_resp *resp;
|
||||
@@ -72,10 +71,11 @@ struct tunnel_stream {
|
||||
char *authority;
|
||||
int32_t stream_id;
|
||||
uint32_t error;
|
||||
tunnel_state state;
|
||||
bool has_final_response;
|
||||
bool closed;
|
||||
bool reset;
|
||||
size_t upload_blocked_len;
|
||||
h2_tunnel_state state;
|
||||
BIT(has_final_response);
|
||||
BIT(closed);
|
||||
BIT(reset);
|
||||
};
|
||||
|
||||
static CURLcode tunnel_stream_init(struct Curl_cfilter *cf,
|
||||
@@ -85,11 +85,11 @@ static CURLcode tunnel_stream_init(struct Curl_cfilter *cf,
|
||||
int port;
|
||||
bool ipv6_ip = cf->conn->bits.ipv6_ip;
|
||||
|
||||
ts->state = TUNNEL_INIT;
|
||||
ts->state = H2_TUNNEL_INIT;
|
||||
ts->stream_id = -1;
|
||||
Curl_bufq_init2(&ts->recvbuf, H2_TUNNEL_CHUNK_SIZE, H2_TUNNEL_RECV_CHUNKS,
|
||||
Curl_bufq_init2(&ts->recvbuf, H2_CHUNK_SIZE, H2_TUNNEL_RECV_CHUNKS,
|
||||
BUFQ_OPT_SOFT_LIMIT);
|
||||
Curl_bufq_init(&ts->sendbuf, H2_TUNNEL_CHUNK_SIZE, H2_TUNNEL_SEND_CHUNKS);
|
||||
Curl_bufq_init(&ts->sendbuf, H2_CHUNK_SIZE, H2_TUNNEL_SEND_CHUNKS);
|
||||
|
||||
if(cf->conn->bits.conn_to_host)
|
||||
hostname = cf->conn->conn_to_host.name;
|
||||
@@ -123,13 +123,13 @@ static void tunnel_stream_clear(struct tunnel_stream *ts)
|
||||
Curl_bufq_free(&ts->sendbuf);
|
||||
Curl_safefree(ts->authority);
|
||||
memset(ts, 0, sizeof(*ts));
|
||||
ts->state = TUNNEL_INIT;
|
||||
ts->state = H2_TUNNEL_INIT;
|
||||
}
|
||||
|
||||
static void tunnel_go_state(struct Curl_cfilter *cf,
|
||||
struct tunnel_stream *ts,
|
||||
tunnel_state new_state,
|
||||
struct Curl_easy *data)
|
||||
static void h2_tunnel_go_state(struct Curl_cfilter *cf,
|
||||
struct tunnel_stream *ts,
|
||||
h2_tunnel_state new_state,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
(void)cf;
|
||||
|
||||
@@ -137,7 +137,7 @@ static void tunnel_go_state(struct Curl_cfilter *cf,
|
||||
return;
|
||||
/* leaving this one */
|
||||
switch(ts->state) {
|
||||
case TUNNEL_CONNECT:
|
||||
case H2_TUNNEL_CONNECT:
|
||||
data->req.ignorebody = FALSE;
|
||||
break;
|
||||
default:
|
||||
@@ -145,29 +145,29 @@ static void tunnel_go_state(struct Curl_cfilter *cf,
|
||||
}
|
||||
/* entering this one */
|
||||
switch(new_state) {
|
||||
case TUNNEL_INIT:
|
||||
case H2_TUNNEL_INIT:
|
||||
DEBUGF(LOG_CF(data, cf, "new tunnel state 'init'"));
|
||||
tunnel_stream_clear(ts);
|
||||
break;
|
||||
|
||||
case TUNNEL_CONNECT:
|
||||
case H2_TUNNEL_CONNECT:
|
||||
DEBUGF(LOG_CF(data, cf, "new tunnel state 'connect'"));
|
||||
ts->state = TUNNEL_CONNECT;
|
||||
ts->state = H2_TUNNEL_CONNECT;
|
||||
break;
|
||||
|
||||
case TUNNEL_RESPONSE:
|
||||
case H2_TUNNEL_RESPONSE:
|
||||
DEBUGF(LOG_CF(data, cf, "new tunnel state 'response'"));
|
||||
ts->state = TUNNEL_RESPONSE;
|
||||
ts->state = H2_TUNNEL_RESPONSE;
|
||||
break;
|
||||
|
||||
case TUNNEL_ESTABLISHED:
|
||||
case H2_TUNNEL_ESTABLISHED:
|
||||
DEBUGF(LOG_CF(data, cf, "new tunnel state 'established'"));
|
||||
infof(data, "CONNECT phase completed");
|
||||
data->state.authproxy.done = TRUE;
|
||||
data->state.authproxy.multipass = FALSE;
|
||||
/* FALLTHROUGH */
|
||||
case TUNNEL_FAILED:
|
||||
if(new_state == TUNNEL_FAILED)
|
||||
case H2_TUNNEL_FAILED:
|
||||
if(new_state == H2_TUNNEL_FAILED)
|
||||
DEBUGF(LOG_CF(data, cf, "new tunnel state 'failed'"));
|
||||
ts->state = new_state;
|
||||
/* If a proxy-authorization header was used for the proxy, then we should
|
||||
@@ -191,9 +191,11 @@ struct cf_h2_proxy_ctx {
|
||||
int32_t last_stream_id;
|
||||
BIT(conn_closed);
|
||||
BIT(goaway);
|
||||
BIT(nw_out_blocked);
|
||||
};
|
||||
|
||||
/* How to access `call_data` from a cf_h2 filter */
|
||||
#undef CF_CTX_CALL_DATA
|
||||
#define CF_CTX_CALL_DATA(cf) \
|
||||
((struct cf_h2_proxy_ctx *)(cf)->ctx)->call_data
|
||||
|
||||
@@ -219,35 +221,54 @@ static void cf_h2_proxy_ctx_free(struct cf_h2_proxy_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t nw_in_reader(void *reader_ctx,
|
||||
unsigned char *buf, size_t buflen,
|
||||
CURLcode *err)
|
||||
static void drain_tunnel(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct tunnel_stream *tunnel)
|
||||
{
|
||||
unsigned char bits;
|
||||
|
||||
(void)cf;
|
||||
bits = CURL_CSELECT_IN;
|
||||
if(!tunnel->closed && !tunnel->reset && tunnel->upload_blocked_len)
|
||||
bits |= CURL_CSELECT_OUT;
|
||||
if(data->state.dselect_bits != bits) {
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] DRAIN dselect_bits=%x",
|
||||
tunnel->stream_id, bits));
|
||||
data->state.dselect_bits = bits;
|
||||
Curl_expire(data, 0, EXPIRE_RUN_NOW);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t proxy_nw_in_reader(void *reader_ctx,
|
||||
unsigned char *buf, size_t buflen,
|
||||
CURLcode *err)
|
||||
{
|
||||
struct Curl_cfilter *cf = reader_ctx;
|
||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||
ssize_t nread;
|
||||
|
||||
nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err);
|
||||
DEBUGF(LOG_CF(data, cf, "nw_in recv(len=%zu) -> %zd, %d",
|
||||
DEBUGF(LOG_CF(data, cf, "nw_in_reader(len=%zu) -> %zd, %d",
|
||||
buflen, nread, *err));
|
||||
return nread;
|
||||
}
|
||||
|
||||
static ssize_t nw_out_writer(void *writer_ctx,
|
||||
const unsigned char *buf, size_t buflen,
|
||||
CURLcode *err)
|
||||
static ssize_t proxy_h2_nw_out_writer(void *writer_ctx,
|
||||
const unsigned char *buf, size_t buflen,
|
||||
CURLcode *err)
|
||||
{
|
||||
struct Curl_cfilter *cf = writer_ctx;
|
||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||
ssize_t nwritten;
|
||||
|
||||
nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen, err);
|
||||
DEBUGF(LOG_CF(data, cf, "nw_out send(len=%zu) -> %zd", buflen, nwritten));
|
||||
DEBUGF(LOG_CF(data, cf, "nw_out_writer(len=%zu) -> %zd, %d",
|
||||
buflen, nwritten, *err));
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
static int h2_client_new(struct Curl_cfilter *cf,
|
||||
nghttp2_session_callbacks *cbs)
|
||||
static int proxy_h2_client_new(struct Curl_cfilter *cf,
|
||||
nghttp2_session_callbacks *cbs)
|
||||
{
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
nghttp2_option *o;
|
||||
@@ -271,15 +292,18 @@ static int h2_client_new(struct Curl_cfilter *cf,
|
||||
static ssize_t on_session_send(nghttp2_session *h2,
|
||||
const uint8_t *buf, size_t blen,
|
||||
int flags, void *userp);
|
||||
static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
void *userp);
|
||||
static int on_stream_close(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code, void *userp);
|
||||
static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags,
|
||||
void *userp);
|
||||
static int proxy_h2_on_frame_recv(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *userp);
|
||||
static int proxy_h2_on_stream_close(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
uint32_t error_code, void *userp);
|
||||
static int proxy_h2_on_header(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags,
|
||||
void *userp);
|
||||
static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const uint8_t *mem, size_t len, void *userp);
|
||||
@@ -298,8 +322,8 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
|
||||
DEBUGASSERT(!ctx->h2);
|
||||
memset(&ctx->tunnel, 0, sizeof(ctx->tunnel));
|
||||
|
||||
Curl_bufq_init(&ctx->inbufq, H2_NW_CHUNK_SIZE, H2_NW_RECV_CHUNKS);
|
||||
Curl_bufq_init(&ctx->outbufq, H2_NW_CHUNK_SIZE, H2_NW_SEND_CHUNKS);
|
||||
Curl_bufq_init(&ctx->inbufq, H2_CHUNK_SIZE, PROXY_H2_NW_RECV_CHUNKS);
|
||||
Curl_bufq_init(&ctx->outbufq, H2_CHUNK_SIZE, PROXY_H2_NW_SEND_CHUNKS);
|
||||
|
||||
if(tunnel_stream_init(cf, &ctx->tunnel))
|
||||
goto out;
|
||||
@@ -311,14 +335,16 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
|
||||
}
|
||||
|
||||
nghttp2_session_callbacks_set_send_callback(cbs, on_session_send);
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback(cbs, on_frame_recv);
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback(
|
||||
cbs, proxy_h2_on_frame_recv);
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
cbs, tunnel_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(cbs, on_stream_close);
|
||||
nghttp2_session_callbacks_set_on_header_callback(cbs, on_header);
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
cbs, proxy_h2_on_stream_close);
|
||||
nghttp2_session_callbacks_set_on_header_callback(cbs, proxy_h2_on_header);
|
||||
|
||||
/* The nghttp2 session is not yet setup, do it */
|
||||
rc = h2_client_new(cf, cbs);
|
||||
rc = proxy_h2_client_new(cf, cbs);
|
||||
if(rc) {
|
||||
failf(data, "Couldn't initialize nghttp2");
|
||||
goto out;
|
||||
@@ -343,7 +369,7 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
|
||||
}
|
||||
|
||||
rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0,
|
||||
HTTP2_HUGE_WINDOW_SIZE);
|
||||
PROXY_HTTP2_HUGE_WINDOW_SIZE);
|
||||
if(rc) {
|
||||
failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
|
||||
nghttp2_strerror(rc), rc);
|
||||
@@ -362,27 +388,35 @@ out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode nw_out_flush(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
static int should_close_session(struct cf_h2_proxy_ctx *ctx)
|
||||
{
|
||||
return !nghttp2_session_want_read(ctx->h2) &&
|
||||
!nghttp2_session_want_write(ctx->h2);
|
||||
}
|
||||
|
||||
static CURLcode proxy_h2_nw_out_flush(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
size_t buflen = Curl_bufq_len(&ctx->outbufq);
|
||||
ssize_t nwritten;
|
||||
CURLcode result;
|
||||
|
||||
(void)data;
|
||||
if(!buflen)
|
||||
if(Curl_bufq_is_empty(&ctx->outbufq))
|
||||
return CURLE_OK;
|
||||
|
||||
DEBUGF(LOG_CF(data, cf, "h2 conn flush %zu bytes", buflen));
|
||||
nwritten = Curl_bufq_pass(&ctx->outbufq, nw_out_writer, cf, &result);
|
||||
nwritten = Curl_bufq_pass(&ctx->outbufq, proxy_h2_nw_out_writer, cf,
|
||||
&result);
|
||||
if(nwritten < 0) {
|
||||
if(result == CURLE_AGAIN) {
|
||||
DEBUGF(LOG_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN",
|
||||
Curl_bufq_len(&ctx->outbufq)));
|
||||
ctx->nw_out_blocked = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if((size_t)nwritten < buflen) {
|
||||
return CURLE_AGAIN;
|
||||
}
|
||||
return CURLE_OK;
|
||||
DEBUGF(LOG_CF(data, cf, "nw send buffer flushed"));
|
||||
return Curl_bufq_is_empty(&ctx->outbufq)? CURLE_OK: CURLE_AGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -390,9 +424,9 @@ static CURLcode nw_out_flush(struct Curl_cfilter *cf,
|
||||
* 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_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
CURLcode *err)
|
||||
static int proxy_h2_process_pending_input(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
CURLcode *err)
|
||||
{
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
const unsigned char *buf;
|
||||
@@ -422,19 +456,11 @@ static int h2_process_pending_input(struct Curl_cfilter *cf,
|
||||
}
|
||||
}
|
||||
|
||||
if(nghttp2_session_check_request_allowed(ctx->h2) == 0) {
|
||||
/* No more requests are allowed in the current session, so
|
||||
the connection may not be reused. This is set when a
|
||||
GOAWAY frame has been received or when the limit of stream
|
||||
identifiers has been reached. */
|
||||
connclose(cf->conn, "http/2: No new requests allowed");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
@@ -442,9 +468,9 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
|
||||
|
||||
/* Process network input buffer fist */
|
||||
if(!Curl_bufq_is_empty(&ctx->inbufq)) {
|
||||
DEBUGF(LOG_CF(data, cf, "Process %zd bytes in connection buffer",
|
||||
DEBUGF(LOG_CF(data, cf, "Process %zu bytes in connection buffer",
|
||||
Curl_bufq_len(&ctx->inbufq)));
|
||||
if(h2_process_pending_input(cf, data, &result) < 0)
|
||||
if(proxy_h2_process_pending_input(cf, data, &result) < 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -455,8 +481,8 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
|
||||
Curl_bufq_is_empty(&ctx->inbufq) && /* and we consumed our input */
|
||||
!Curl_bufq_is_full(&ctx->tunnel.recvbuf)) {
|
||||
|
||||
nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result);
|
||||
DEBUGF(LOG_CF(data, cf, "read %zd bytes nw data -> %zd, %d",
|
||||
nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
|
||||
DEBUGF(LOG_CF(data, cf, "read %zu bytes nw data -> %zd, %d",
|
||||
Curl_bufq_len(&ctx->inbufq), nread, result));
|
||||
if(nread < 0) {
|
||||
if(result != CURLE_AGAIN) {
|
||||
@@ -470,7 +496,7 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
|
||||
break;
|
||||
}
|
||||
|
||||
if(h2_process_pending_input(cf, data, &result))
|
||||
if(proxy_h2_process_pending_input(cf, data, &result))
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -481,25 +507,22 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if there's been an update in the priority /
|
||||
* dependency settings and if so it submits a PRIORITY frame with the updated
|
||||
* info.
|
||||
* Flush any out data pending in the network buffer.
|
||||
*/
|
||||
static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
static CURLcode proxy_h2_progress_egress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
int rv = 0;
|
||||
|
||||
rv = nghttp2_session_send(ctx->h2);
|
||||
ctx->nw_out_blocked = 0;
|
||||
while(!rv && !ctx->nw_out_blocked && nghttp2_session_want_write(ctx->h2))
|
||||
rv = nghttp2_session_send(ctx->h2);
|
||||
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
DEBUGF(LOG_CF(data, cf, "nghttp2_session_send error (%s)%d",
|
||||
nghttp2_strerror(rv), rv));
|
||||
return CURLE_SEND_ERROR;
|
||||
}
|
||||
return nw_out_flush(cf, data);
|
||||
return proxy_h2_nw_out_flush(cf, data);
|
||||
}
|
||||
|
||||
static ssize_t on_session_send(nghttp2_session *h2,
|
||||
@@ -517,7 +540,7 @@ static ssize_t on_session_send(nghttp2_session *h2,
|
||||
DEBUGASSERT(data);
|
||||
|
||||
nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
|
||||
nw_out_writer, cf, &result);
|
||||
proxy_h2_nw_out_writer, cf, &result);
|
||||
if(nwritten < 0) {
|
||||
if(result == CURLE_AGAIN) {
|
||||
return NGHTTP2_ERR_WOULDBLOCK;
|
||||
@@ -532,8 +555,9 @@ static ssize_t on_session_send(nghttp2_session *h2,
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
void *userp)
|
||||
static int proxy_h2_on_frame_recv(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *userp)
|
||||
{
|
||||
struct Curl_cfilter *cf = userp;
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
@@ -616,11 +640,12 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags,
|
||||
void *userp)
|
||||
static int proxy_h2_on_header(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags,
|
||||
void *userp)
|
||||
{
|
||||
struct Curl_cfilter *cf = userp;
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
@@ -752,8 +777,9 @@ static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_stream_close(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code, void *userp)
|
||||
static int proxy_h2_on_stream_close(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
uint32_t error_code, void *userp)
|
||||
{
|
||||
struct Curl_cfilter *cf = userp;
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
@@ -765,7 +791,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
|
||||
if(stream_id != ctx->tunnel.stream_id)
|
||||
return 0;
|
||||
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%u] on_stream_close, %s (err %d)",
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%u] proxy_h2_on_stream_close, %s (err %d)",
|
||||
stream_id, nghttp2_http2_strerror(error_code), error_code));
|
||||
ctx->tunnel.closed = TRUE;
|
||||
ctx->tunnel.error = error_code;
|
||||
@@ -773,15 +799,15 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static CURLcode h2_submit(int32_t *pstream_id,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
nghttp2_session *h2,
|
||||
struct httpreq *req,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
void *stream_user_data,
|
||||
nghttp2_data_source_read_callback read_callback,
|
||||
void *read_ctx)
|
||||
static CURLcode proxy_h2_submit(int32_t *pstream_id,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
nghttp2_session *h2,
|
||||
struct httpreq *req,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
void *stream_user_data,
|
||||
nghttp2_data_source_read_callback read_callback,
|
||||
void *read_ctx)
|
||||
{
|
||||
struct dynhds h2_headers;
|
||||
nghttp2_nv *nva = NULL;
|
||||
@@ -881,8 +907,8 @@ static CURLcode submit_CONNECT(struct Curl_cfilter *cf,
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
result = h2_submit(&ts->stream_id, cf, data, ctx->h2, req,
|
||||
NULL, ts, tunnel_send_callback, cf);
|
||||
result = proxy_h2_submit(&ts->stream_id, cf, data, ctx->h2, req,
|
||||
NULL, ts, tunnel_send_callback, cf);
|
||||
if(result) {
|
||||
DEBUGF(LOG_CF(data, cf, "send: nghttp2_submit_request error (%s)%u",
|
||||
nghttp2_strerror(ts->stream_id), ts->stream_id));
|
||||
@@ -907,7 +933,7 @@ static CURLcode inspect_response(struct Curl_cfilter *cf,
|
||||
DEBUGASSERT(ts->resp);
|
||||
if(ts->resp->status/100 == 2) {
|
||||
infof(data, "CONNECT tunnel established, response %d", ts->resp->status);
|
||||
tunnel_go_state(cf, ts, TUNNEL_ESTABLISHED, data);
|
||||
h2_tunnel_go_state(cf, ts, H2_TUNNEL_ESTABLISHED, data);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@@ -928,7 +954,7 @@ static CURLcode inspect_response(struct Curl_cfilter *cf,
|
||||
if(data->req.newurl) {
|
||||
/* Inidicator that we should try again */
|
||||
Curl_safefree(data->req.newurl);
|
||||
tunnel_go_state(cf, ts, TUNNEL_INIT, data);
|
||||
h2_tunnel_go_state(cf, ts, H2_TUNNEL_INIT, data);
|
||||
return CURLE_OK;
|
||||
}
|
||||
}
|
||||
@@ -937,9 +963,9 @@ static CURLcode inspect_response(struct Curl_cfilter *cf,
|
||||
return CURLE_RECV_ERROR;
|
||||
}
|
||||
|
||||
static CURLcode CONNECT(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct tunnel_stream *ts)
|
||||
static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct tunnel_stream *ts)
|
||||
{
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
@@ -948,27 +974,27 @@ static CURLcode CONNECT(struct Curl_cfilter *cf,
|
||||
DEBUGASSERT(ts->authority);
|
||||
do {
|
||||
switch(ts->state) {
|
||||
case TUNNEL_INIT:
|
||||
case H2_TUNNEL_INIT:
|
||||
/* Prepare the CONNECT request and make a first attempt to send. */
|
||||
DEBUGF(LOG_CF(data, cf, "CONNECT start for %s", ts->authority));
|
||||
result = submit_CONNECT(cf, data, ts);
|
||||
if(result)
|
||||
goto out;
|
||||
tunnel_go_state(cf, ts, TUNNEL_CONNECT, data);
|
||||
h2_tunnel_go_state(cf, ts, H2_TUNNEL_CONNECT, data);
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case TUNNEL_CONNECT:
|
||||
case H2_TUNNEL_CONNECT:
|
||||
/* see that the request is completely sent */
|
||||
result = h2_progress_ingress(cf, data);
|
||||
result = proxy_h2_progress_ingress(cf, data);
|
||||
if(!result)
|
||||
result = h2_progress_egress(cf, data);
|
||||
if(result) {
|
||||
tunnel_go_state(cf, ts, TUNNEL_FAILED, data);
|
||||
result = proxy_h2_progress_egress(cf, data);
|
||||
if(result && result != CURLE_AGAIN) {
|
||||
h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data);
|
||||
break;
|
||||
}
|
||||
|
||||
if(ts->has_final_response) {
|
||||
tunnel_go_state(cf, ts, TUNNEL_RESPONSE, data);
|
||||
h2_tunnel_go_state(cf, ts, H2_TUNNEL_RESPONSE, data);
|
||||
}
|
||||
else {
|
||||
result = CURLE_OK;
|
||||
@@ -976,28 +1002,28 @@ static CURLcode CONNECT(struct Curl_cfilter *cf,
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case TUNNEL_RESPONSE:
|
||||
case H2_TUNNEL_RESPONSE:
|
||||
DEBUGASSERT(ts->has_final_response);
|
||||
result = inspect_response(cf, data, ts);
|
||||
if(result)
|
||||
goto out;
|
||||
break;
|
||||
|
||||
case TUNNEL_ESTABLISHED:
|
||||
case H2_TUNNEL_ESTABLISHED:
|
||||
return CURLE_OK;
|
||||
|
||||
case TUNNEL_FAILED:
|
||||
case H2_TUNNEL_FAILED:
|
||||
return CURLE_RECV_ERROR;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} while(ts->state == TUNNEL_INIT);
|
||||
} while(ts->state == H2_TUNNEL_INIT);
|
||||
|
||||
out:
|
||||
if(result || ctx->tunnel.closed)
|
||||
tunnel_go_state(cf, ts, TUNNEL_FAILED, data);
|
||||
h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1043,10 +1069,10 @@ static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf,
|
||||
/* for the secondary socket (FTP), use the "connect to host"
|
||||
* but ignore the "connect to port" (use the secondary port)
|
||||
*/
|
||||
result = CONNECT(cf, data, ts);
|
||||
result = H2_CONNECT(cf, data, ts);
|
||||
|
||||
out:
|
||||
*done = (result == CURLE_OK) && (ts->state == TUNNEL_ESTABLISHED);
|
||||
*done = (result == CURLE_OK) && (ts->state == H2_TUNNEL_ESTABLISHED);
|
||||
cf->connected = *done;
|
||||
CF_DATA_RESTORE(cf, save);
|
||||
return result;
|
||||
@@ -1082,7 +1108,7 @@ static bool cf_h2_proxy_data_pending(struct Curl_cfilter *cf,
|
||||
{
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
if((ctx && !Curl_bufq_is_empty(&ctx->inbufq)) ||
|
||||
(ctx && ctx->tunnel.state == TUNNEL_ESTABLISHED &&
|
||||
(ctx && ctx->tunnel.state == H2_TUNNEL_ESTABLISHED &&
|
||||
!Curl_bufq_is_empty(&ctx->tunnel.recvbuf)))
|
||||
return TRUE;
|
||||
return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
|
||||
@@ -1188,14 +1214,14 @@ static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf,
|
||||
struct cf_call_data save;
|
||||
CURLcode result;
|
||||
|
||||
if(ctx->tunnel.state != TUNNEL_ESTABLISHED) {
|
||||
if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
|
||||
*err = CURLE_RECV_ERROR;
|
||||
return -1;
|
||||
}
|
||||
CF_DATA_SAVE(save, cf, data);
|
||||
|
||||
if(Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) {
|
||||
*err = h2_progress_ingress(cf, data);
|
||||
*err = proxy_h2_progress_ingress(cf, data);
|
||||
if(*err)
|
||||
goto out;
|
||||
}
|
||||
@@ -1208,13 +1234,19 @@ static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf,
|
||||
nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, (size_t)nread);
|
||||
}
|
||||
|
||||
result = h2_progress_egress(cf, data);
|
||||
if(result) {
|
||||
result = proxy_h2_progress_egress(cf, data);
|
||||
if(result && result != CURLE_AGAIN) {
|
||||
*err = result;
|
||||
nread = -1;
|
||||
}
|
||||
|
||||
out:
|
||||
if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) &&
|
||||
(nread >= 0 || *err == CURLE_AGAIN)) {
|
||||
/* data pending and no fatal error to report. Need to trigger
|
||||
* draining to avoid stalling when no socket events happen. */
|
||||
drain_tunnel(cf, data, &ctx->tunnel);
|
||||
}
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_recv(len=%zu) -> %zd %d",
|
||||
ctx->tunnel.stream_id, len, nread, *err));
|
||||
CF_DATA_RESTORE(cf, save);
|
||||
@@ -1223,93 +1255,188 @@ out:
|
||||
|
||||
static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const void *mem, size_t len, CURLcode *err)
|
||||
const void *buf, size_t len, CURLcode *err)
|
||||
{
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
struct cf_call_data save;
|
||||
ssize_t nwritten = -1;
|
||||
const unsigned char *buf = mem;
|
||||
size_t start_len = len;
|
||||
int rv;
|
||||
ssize_t nwritten;
|
||||
CURLcode result;
|
||||
int blocked = 0;
|
||||
|
||||
if(ctx->tunnel.state != TUNNEL_ESTABLISHED) {
|
||||
if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
|
||||
*err = CURLE_SEND_ERROR;
|
||||
return -1;
|
||||
}
|
||||
CF_DATA_SAVE(save, cf, data);
|
||||
|
||||
while(len) {
|
||||
if(ctx->tunnel.closed) {
|
||||
nwritten = -1;
|
||||
*err = CURLE_SEND_ERROR;
|
||||
goto out;
|
||||
}
|
||||
else if(ctx->tunnel.upload_blocked_len) {
|
||||
/* the data in `buf` has alread been submitted or added to the
|
||||
* buffers, but have been EAGAINed on the last invocation. */
|
||||
DEBUGASSERT(len >= ctx->tunnel.upload_blocked_len);
|
||||
if(len < ctx->tunnel.upload_blocked_len) {
|
||||
/* Did we get called again with a smaller `len`? This should not
|
||||
* happend. We are not prepared to handle that. */
|
||||
failf(data, "HTTP/2 proxy, send again with decreased length");
|
||||
*err = CURLE_HTTP2;
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
}
|
||||
nwritten = (ssize_t)ctx->tunnel.upload_blocked_len;
|
||||
ctx->tunnel.upload_blocked_len = 0;
|
||||
}
|
||||
else {
|
||||
nwritten = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, err);
|
||||
if(nwritten <= 0) {
|
||||
if(*err && *err != CURLE_AGAIN) {
|
||||
DEBUGF(LOG_CF(data, cf, "error adding data to tunnel sendbuf: %d",
|
||||
*err));
|
||||
nwritten = -1;
|
||||
if(nwritten < 0) {
|
||||
if(*err != CURLE_AGAIN)
|
||||
goto out;
|
||||
}
|
||||
/* blocked */
|
||||
nwritten = 0;
|
||||
}
|
||||
else {
|
||||
DEBUGASSERT((size_t)nwritten <= len);
|
||||
buf += (size_t)nwritten;
|
||||
len -= (size_t)nwritten;
|
||||
}
|
||||
}
|
||||
|
||||
/* resume the tunnel stream and let the h2 session send, which
|
||||
* triggers reading from tunnel.sendbuf */
|
||||
if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
|
||||
/* req body data is buffered, resume the potentially suspended stream */
|
||||
rv = nghttp2_session_resume_data(ctx->h2, ctx->tunnel.stream_id);
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
*err = CURLE_SEND_ERROR;
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
}
|
||||
*err = h2_progress_egress(cf, data);
|
||||
if(*err) {
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(!nwritten && Curl_bufq_is_full(&ctx->tunnel.sendbuf)) {
|
||||
size_t rwin;
|
||||
/* we could not add to the buffer and after session processing,
|
||||
* it is still full. */
|
||||
rwin = nghttp2_session_get_stream_remote_window_size(
|
||||
ctx->h2, ctx->tunnel.stream_id);
|
||||
DEBUGF(LOG_CF(data, cf, "cf_send: tunnel win %u/%zu",
|
||||
nghttp2_session_get_remote_window_size(ctx->h2), rwin));
|
||||
if(rwin == 0) {
|
||||
/* We cannot upload more as the stream's remote window size
|
||||
* is 0. We need to receive WIN_UPDATEs before we can continue.
|
||||
*/
|
||||
data->req.keepon |= KEEP_SEND_HOLD;
|
||||
DEBUGF(LOG_CF(data, cf, "pausing send as remote flow "
|
||||
"window is exhausted"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nwritten = start_len - len;
|
||||
if(nwritten > 0) {
|
||||
*err = CURLE_OK;
|
||||
/* Call the nghttp2 send loop and flush to write ALL buffered data,
|
||||
* headers and/or request body completely out to the network */
|
||||
result = proxy_h2_progress_egress(cf, data);
|
||||
if(result == CURLE_AGAIN) {
|
||||
blocked = 1;
|
||||
}
|
||||
else if(ctx->tunnel.closed) {
|
||||
else if(result) {
|
||||
*err = result;
|
||||
nwritten = -1;
|
||||
*err = CURLE_SEND_ERROR;
|
||||
goto out;
|
||||
}
|
||||
else {
|
||||
nwritten = -1;
|
||||
else if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
|
||||
/* although we wrote everything that nghttp2 wants to send now,
|
||||
* there is data left in our stream send buffer unwritten. This may
|
||||
* be due to the stream's HTTP/2 flow window being exhausted. */
|
||||
blocked = 1;
|
||||
}
|
||||
|
||||
if(blocked) {
|
||||
/* Unable to send all data, due to connection blocked or H2 window
|
||||
* exhaustion. Data is left in our stream buffer, or nghttp2's internal
|
||||
* frame buffer or our network out buffer. */
|
||||
size_t rwin = nghttp2_session_get_stream_remote_window_size(
|
||||
ctx->h2, ctx->tunnel.stream_id);
|
||||
if(rwin == 0) {
|
||||
/* H2 flow window exhaustion.
|
||||
* FIXME: there is no way to HOLD all transfers that use this
|
||||
* proxy connection AND to UNHOLD all of them again when the
|
||||
* window increases.
|
||||
* We *could* iterate over all data on this conn maybe? */
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] remote flow "
|
||||
"window is exhausted", ctx->tunnel.stream_id));
|
||||
}
|
||||
|
||||
/* Whatever the cause, we need to return CURL_EAGAIN for this call.
|
||||
* We have unwritten state that needs us being invoked again and EAGAIN
|
||||
* is the only way to ensure that. */
|
||||
ctx->tunnel.upload_blocked_len = nwritten;
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) BLOCK: win %u/%zu "
|
||||
"blocked_len=%zu",
|
||||
ctx->tunnel.stream_id, len,
|
||||
nghttp2_session_get_remote_window_size(ctx->h2), rwin,
|
||||
nwritten));
|
||||
*err = CURLE_AGAIN;
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
}
|
||||
else if(should_close_session(ctx)) {
|
||||
/* nghttp2 thinks this session is done. If the stream has not been
|
||||
* closed, this is an error state for out transfer */
|
||||
if(ctx->tunnel.closed) {
|
||||
*err = CURLE_SEND_ERROR;
|
||||
nwritten = -1;
|
||||
}
|
||||
else {
|
||||
DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session"));
|
||||
*err = CURLE_HTTP2;
|
||||
nwritten = -1;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
DEBUGF(LOG_CF(data, cf, "cf_send(len=%zu) -> %zd, %d ",
|
||||
start_len, nwritten, *err));
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) -> %zd, %d, "
|
||||
"h2 windows %d-%d (stream-conn), "
|
||||
"buffers %zu-%zu (stream-conn)",
|
||||
ctx->tunnel.stream_id, len, nwritten, *err,
|
||||
nghttp2_session_get_stream_remote_window_size(
|
||||
ctx->h2, ctx->tunnel.stream_id),
|
||||
nghttp2_session_get_remote_window_size(ctx->h2),
|
||||
Curl_bufq_len(&ctx->tunnel.sendbuf),
|
||||
Curl_bufq_len(&ctx->outbufq)));
|
||||
CF_DATA_RESTORE(cf, save);
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
static bool proxy_h2_connisalive(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *input_pending)
|
||||
{
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
bool alive = TRUE;
|
||||
|
||||
*input_pending = FALSE;
|
||||
if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
|
||||
return FALSE;
|
||||
|
||||
if(*input_pending) {
|
||||
/* This happens before we've sent off a request and the connection is
|
||||
not in use by any other transfer, there shouldn't be any data here,
|
||||
only "protocol frames" */
|
||||
CURLcode result;
|
||||
ssize_t nread = -1;
|
||||
|
||||
*input_pending = FALSE;
|
||||
nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
|
||||
if(nread != -1) {
|
||||
if(proxy_h2_process_pending_input(cf, data, &result) < 0)
|
||||
/* immediate error, considered dead */
|
||||
alive = FALSE;
|
||||
else {
|
||||
alive = !should_close_session(ctx);
|
||||
}
|
||||
}
|
||||
else if(result != CURLE_AGAIN) {
|
||||
/* the read failed so let's say this is dead anyway */
|
||||
alive = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return alive;
|
||||
}
|
||||
|
||||
static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *input_pending)
|
||||
{
|
||||
struct cf_h2_proxy_ctx *ctx = cf->ctx;
|
||||
CURLcode result;
|
||||
struct cf_call_data save;
|
||||
|
||||
CF_DATA_SAVE(save, cf, data);
|
||||
result = (ctx && ctx->h2 && proxy_h2_connisalive(cf, data, input_pending));
|
||||
DEBUGF(LOG_CF(data, cf, "conn alive -> %d, input_pending=%d",
|
||||
result, *input_pending));
|
||||
CF_DATA_RESTORE(cf, save);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct Curl_cftype Curl_cft_h2_proxy = {
|
||||
"H2-PROXY",
|
||||
CF_TYPE_IP_CONNECT,
|
||||
@@ -1323,7 +1450,7 @@ struct Curl_cftype Curl_cft_h2_proxy = {
|
||||
cf_h2_proxy_send,
|
||||
cf_h2_proxy_recv,
|
||||
Curl_cf_def_cntrl,
|
||||
Curl_cf_def_conn_is_alive,
|
||||
cf_h2_proxy_is_alive,
|
||||
Curl_cf_def_conn_keep_alive,
|
||||
Curl_cf_def_query,
|
||||
};
|
||||
|
||||
@@ -71,6 +71,7 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
|
||||
struct cf_haproxy_ctx *ctx = cf->ctx;
|
||||
CURLcode result;
|
||||
const char *tcp_version;
|
||||
const char *client_ip;
|
||||
|
||||
DEBUGASSERT(ctx);
|
||||
DEBUGASSERT(ctx->state == HAPROXY_INIT);
|
||||
@@ -82,11 +83,15 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
|
||||
#endif /* USE_UNIX_SOCKETS */
|
||||
/* Emit the correct prefix for IPv6 */
|
||||
tcp_version = cf->conn->bits.ipv6 ? "TCP6" : "TCP4";
|
||||
if(data->set.str[STRING_HAPROXY_CLIENT_IP])
|
||||
client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP];
|
||||
else
|
||||
client_ip = data->info.conn_primary_ip;
|
||||
|
||||
result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
|
||||
tcp_version,
|
||||
data->info.conn_local_ip,
|
||||
data->info.conn_primary_ip,
|
||||
client_ip,
|
||||
data->info.conn_local_port,
|
||||
data->info.conn_primary_port);
|
||||
|
||||
@@ -110,7 +115,7 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
result = cf->next->cft->connect(cf->next, data, blocking, done);
|
||||
result = cf->next->cft->do_connect(cf->next, data, blocking, done);
|
||||
if(result || !*done)
|
||||
return result;
|
||||
|
||||
@@ -163,7 +168,7 @@ static void cf_haproxy_close(struct Curl_cfilter *cf,
|
||||
cf->connected = FALSE;
|
||||
cf_haproxy_ctx_reset(cf->ctx);
|
||||
if(cf->next)
|
||||
cf->next->cft->close(cf->next, data);
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
}
|
||||
|
||||
static int cf_haproxy_get_select_socks(struct Curl_cfilter *cf,
|
||||
|
||||
@@ -376,9 +376,9 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf,
|
||||
|| cf_hc_baller_data_pending(&ctx->h21_baller, data);
|
||||
}
|
||||
|
||||
static struct curltime get_max_baller_time(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int query)
|
||||
static struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int query)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
struct Curl_cfilter *cfb;
|
||||
@@ -408,12 +408,12 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
|
||||
switch(query) {
|
||||
case CF_QUERY_TIMER_CONNECT: {
|
||||
struct curltime *when = pres2;
|
||||
*when = get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT);
|
||||
*when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT);
|
||||
return CURLE_OK;
|
||||
}
|
||||
case CF_QUERY_TIMER_APPCONNECT: {
|
||||
struct curltime *when = pres2;
|
||||
*when = get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT);
|
||||
*when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT);
|
||||
return CURLE_OK;
|
||||
}
|
||||
default:
|
||||
@@ -432,7 +432,7 @@ static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
cf->connected = FALSE;
|
||||
|
||||
if(cf->next) {
|
||||
cf->next->cft->close(cf->next, data);
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
Curl_conn_cf_discard_chain(&cf->next, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -871,7 +871,7 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
/* this is our local socket, we did never publish it */
|
||||
DEBUGF(LOG_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
|
||||
", not active)", ctx->sock));
|
||||
sclose(ctx->sock);
|
||||
socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
|
||||
ctx->sock = CURL_SOCKET_BAD;
|
||||
}
|
||||
Curl_bufq_reset(&ctx->recvbuf);
|
||||
@@ -901,22 +901,26 @@ static CURLcode set_local_ip(struct Curl_cfilter *cf,
|
||||
struct cf_socket_ctx *ctx = cf->ctx;
|
||||
|
||||
#ifdef HAVE_GETSOCKNAME
|
||||
char buffer[STRERROR_LEN];
|
||||
struct Curl_sockaddr_storage ssloc;
|
||||
curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage);
|
||||
if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) {
|
||||
/* TFTP does not connect, so it cannot get the IP like this */
|
||||
|
||||
memset(&ssloc, 0, sizeof(ssloc));
|
||||
if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) {
|
||||
int error = SOCKERRNO;
|
||||
failf(data, "getsockname() failed with errno %d: %s",
|
||||
error, Curl_strerror(error, buffer, sizeof(buffer)));
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
|
||||
ctx->l_ip, &ctx->l_port)) {
|
||||
failf(data, "ssloc inet_ntop() failed with errno %d: %s",
|
||||
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
|
||||
return CURLE_FAILED_INIT;
|
||||
char buffer[STRERROR_LEN];
|
||||
struct Curl_sockaddr_storage ssloc;
|
||||
curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage);
|
||||
|
||||
memset(&ssloc, 0, sizeof(ssloc));
|
||||
if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) {
|
||||
int error = SOCKERRNO;
|
||||
failf(data, "getsockname() failed with errno %d: %s",
|
||||
error, Curl_strerror(error, buffer, sizeof(buffer)));
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
|
||||
ctx->l_ip, &ctx->l_port)) {
|
||||
failf(data, "ssloc inet_ntop() failed with errno %d: %s",
|
||||
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)data;
|
||||
@@ -1356,26 +1360,31 @@ out:
|
||||
static void conn_set_primary_ip(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_socket_ctx *ctx = cf->ctx;
|
||||
#ifdef HAVE_GETPEERNAME
|
||||
char buffer[STRERROR_LEN];
|
||||
struct Curl_sockaddr_storage ssrem;
|
||||
curl_socklen_t plen;
|
||||
int port;
|
||||
struct cf_socket_ctx *ctx = cf->ctx;
|
||||
if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) {
|
||||
/* TFTP does not connect the endpoint: getpeername() failed with errno
|
||||
107: Transport endpoint is not connected */
|
||||
|
||||
plen = sizeof(ssrem);
|
||||
memset(&ssrem, 0, plen);
|
||||
if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
|
||||
int error = SOCKERRNO;
|
||||
failf(data, "getpeername() failed with errno %d: %s",
|
||||
error, Curl_strerror(error, buffer, sizeof(buffer)));
|
||||
return;
|
||||
}
|
||||
if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
|
||||
cf->conn->primary_ip, &port)) {
|
||||
failf(data, "ssrem inet_ntop() failed with errno %d: %s",
|
||||
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
|
||||
return;
|
||||
char buffer[STRERROR_LEN];
|
||||
struct Curl_sockaddr_storage ssrem;
|
||||
curl_socklen_t plen;
|
||||
int port;
|
||||
|
||||
plen = sizeof(ssrem);
|
||||
memset(&ssrem, 0, plen);
|
||||
if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
|
||||
int error = SOCKERRNO;
|
||||
failf(data, "getpeername() failed with errno %d: %s",
|
||||
error, Curl_strerror(error, buffer, sizeof(buffer)));
|
||||
return;
|
||||
}
|
||||
if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
|
||||
cf->conn->primary_ip, &port)) {
|
||||
failf(data, "ssrem inet_ntop() failed with errno %d: %s",
|
||||
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
cf->conn->primary_ip[0] = 0;
|
||||
|
||||
@@ -50,7 +50,7 @@ void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
cf->connected = FALSE;
|
||||
if(cf->next)
|
||||
cf->next->cft->close(cf->next, data);
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -161,7 +161,7 @@ void Curl_conn_close(struct Curl_easy *data, int index)
|
||||
/* it is valid to call that without filters being present */
|
||||
cf = data->conn->cfilter[index];
|
||||
if(cf) {
|
||||
cf->cft->close(cf, data);
|
||||
cf->cft->do_close(cf, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ ssize_t Curl_conn_recv(struct Curl_easy *data, int num, char *buf,
|
||||
if(cf) {
|
||||
return cf->cft->do_recv(cf, data, buf, len, code);
|
||||
}
|
||||
failf(data, CMSGI(data->conn, num, "recv: no filter connected"));
|
||||
failf(data, "recv: no filter connected");
|
||||
*code = CURLE_FAILED_INIT;
|
||||
return -1;
|
||||
}
|
||||
@@ -198,7 +198,7 @@ ssize_t Curl_conn_send(struct Curl_easy *data, int num,
|
||||
if(cf) {
|
||||
return cf->cft->do_send(cf, data, mem, len, code);
|
||||
}
|
||||
failf(data, CMSGI(data->conn, num, "send: no filter connected"));
|
||||
failf(data, "send: no filter connected");
|
||||
DEBUGASSERT(0);
|
||||
*code = CURLE_FAILED_INIT;
|
||||
return -1;
|
||||
@@ -293,14 +293,14 @@ CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
|
||||
bool blocking, bool *done)
|
||||
{
|
||||
if(cf)
|
||||
return cf->cft->connect(cf, data, blocking, done);
|
||||
return cf->cft->do_connect(cf, data, blocking, done);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
if(cf)
|
||||
cf->cft->close(cf, data);
|
||||
cf->cft->do_close(cf, data);
|
||||
}
|
||||
|
||||
int Curl_conn_cf_get_select_socks(struct Curl_cfilter *cf,
|
||||
@@ -348,7 +348,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
|
||||
|
||||
*done = cf->connected;
|
||||
if(!*done) {
|
||||
result = cf->cft->connect(cf, data, blocking, done);
|
||||
result = cf->cft->do_connect(cf, data, blocking, done);
|
||||
if(!result && *done) {
|
||||
Curl_conn_ev_update_info(data, data->conn);
|
||||
conn_report_connect_stats(data, data->conn);
|
||||
|
||||
@@ -168,8 +168,8 @@ struct Curl_cftype {
|
||||
int flags; /* flags of filter type */
|
||||
int log_level; /* log level for such filters */
|
||||
Curl_cft_destroy_this *destroy; /* destroy resources of this cf */
|
||||
Curl_cft_connect *connect; /* establish connection */
|
||||
Curl_cft_close *close; /* close conn */
|
||||
Curl_cft_connect *do_connect; /* establish connection */
|
||||
Curl_cft_close *do_close; /* close conn */
|
||||
Curl_cft_get_host *get_host; /* host filter talks to */
|
||||
Curl_cft_get_select_socks *get_select_socks;/* sockets to select on */
|
||||
Curl_cft_data_pending *has_data_pending;/* conn has data pending */
|
||||
|
||||
@@ -39,7 +39,8 @@ struct connectdata;
|
||||
struct conncache {
|
||||
struct Curl_hash hash;
|
||||
size_t num_conn;
|
||||
long next_connection_id;
|
||||
curl_off_t next_connection_id;
|
||||
curl_off_t next_easy_id;
|
||||
struct curltime last_cleanup;
|
||||
/* handle used for closing cached connections */
|
||||
struct Curl_easy *closure_handle;
|
||||
|
||||
@@ -253,7 +253,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
|
||||
}
|
||||
|
||||
struct connfind {
|
||||
long id_tofind;
|
||||
curl_off_t id_tofind;
|
||||
struct connectdata *found;
|
||||
};
|
||||
|
||||
@@ -937,7 +937,7 @@ static void cf_he_close(struct Curl_cfilter *cf,
|
||||
ctx->state = SCFST_INIT;
|
||||
|
||||
if(cf->next) {
|
||||
cf->next->cft->close(cf->next, data);
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
Curl_conn_cf_discard_chain(&cf->next, data);
|
||||
}
|
||||
}
|
||||
@@ -1291,7 +1291,7 @@ static void cf_setup_close(struct Curl_cfilter *cf,
|
||||
ctx->state = CF_SETUP_INIT;
|
||||
|
||||
if(cf->next) {
|
||||
cf->next->cft->close(cf->next, data);
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
Curl_conn_cf_discard_chain(&cf->next, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,8 +123,9 @@ static void freecookie(struct Cookie *co)
|
||||
free(co);
|
||||
}
|
||||
|
||||
static bool tailmatch(const char *cookie_domain, size_t cookie_domain_len,
|
||||
const char *hostname)
|
||||
static bool cookie_tailmatch(const char *cookie_domain,
|
||||
size_t cookie_domain_len,
|
||||
const char *hostname)
|
||||
{
|
||||
size_t hostname_len = strlen(hostname);
|
||||
|
||||
@@ -696,7 +697,7 @@ Curl_cookie_add(struct Curl_easy *data,
|
||||
if(!domain
|
||||
|| (is_ip && !strncmp(valuep, domain, vlen) &&
|
||||
(vlen == strlen(domain)))
|
||||
|| (!is_ip && tailmatch(valuep, vlen, domain))) {
|
||||
|| (!is_ip && cookie_tailmatch(valuep, vlen, domain))) {
|
||||
strstore(&co->domain, valuep, vlen);
|
||||
if(!co->domain) {
|
||||
badcookie = TRUE;
|
||||
@@ -1431,7 +1432,7 @@ struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
|
||||
/* now check if the domain is correct */
|
||||
if(!co->domain ||
|
||||
(co->tailmatch && !is_ip &&
|
||||
tailmatch(co->domain, strlen(co->domain), host)) ||
|
||||
cookie_tailmatch(co->domain, strlen(co->domain), host)) ||
|
||||
((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
|
||||
/*
|
||||
* the right part of the host matches the domain stuff in the
|
||||
|
||||
@@ -443,6 +443,9 @@
|
||||
/* Define to 1 if you have the sigsetjmp function or macro. */
|
||||
#cmakedefine HAVE_SIGSETJMP 1
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#cmakedefine HAVE_SNPRINTF
|
||||
|
||||
/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
|
||||
#cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
|
||||
|
||||
@@ -572,9 +575,6 @@
|
||||
/* Define to 1 if you have the windows.h header file. */
|
||||
#cmakedefine HAVE_WINDOWS_H 1
|
||||
|
||||
/* Define to 1 if you have the winldap.h header file. */
|
||||
#cmakedefine HAVE_WINLDAP_H 1
|
||||
|
||||
/* Define to 1 if you have the winsock2.h header file. */
|
||||
#cmakedefine HAVE_WINSOCK2_H 1
|
||||
|
||||
|
||||
@@ -130,13 +130,11 @@ void Curl_log_cf_debug(struct Curl_easy *data, struct Curl_cfilter *cf,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
DEBUGASSERT(cf);
|
||||
if(data && Curl_log_cf_is_debug(cf)) {
|
||||
if(data && Curl_log_cf_is_debug(cf, data)) {
|
||||
va_list ap;
|
||||
int len;
|
||||
char buffer[MAXINFO + 2];
|
||||
len = msnprintf(buffer, MAXINFO, "[CONN-%ld%s-%s] ",
|
||||
cf->conn->connection_id, cf->sockindex? "/2" : "",
|
||||
cf->cft->name);
|
||||
len = msnprintf(buffer, MAXINFO, "[%s] ", cf->cft->name);
|
||||
va_start(ap, fmt);
|
||||
len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
@@ -74,7 +74,7 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type,
|
||||
defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
||||
|
||||
#define LOG_CF(data, cf, ...) \
|
||||
do { if(Curl_log_cf_is_debug(cf)) \
|
||||
do { if(Curl_log_cf_is_debug(cf, data)) \
|
||||
Curl_log_cf_debug(data, cf, __VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOG_CF Curl_log_cf_debug
|
||||
@@ -90,8 +90,10 @@ void Curl_log_cf_debug(struct Curl_easy *data, struct Curl_cfilter *cf,
|
||||
const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
#define Curl_log_cf_is_debug(cf) \
|
||||
((cf) && (cf)->cft->log_level >= CURL_LOG_DEBUG)
|
||||
#define Curl_log_cf_is_debug(cf, data) \
|
||||
((data) && (data)->set.verbose && \
|
||||
(cf) && (cf)->cft->log_level >= CURL_LOG_DEBUG)
|
||||
|
||||
|
||||
#else /* !DEBUGBUILD */
|
||||
|
||||
@@ -110,29 +112,10 @@ void Curl_log_cf_debug(struct Curl_easy *data, struct Curl_cfilter *cf,
|
||||
const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
#define Curl_log_cf_is_debug(x) ((void)(x), FALSE)
|
||||
#define Curl_log_cf_is_debug(x,y) ((void)(x), (void)(y), FALSE)
|
||||
|
||||
#endif /* !DEBUGBUILD */
|
||||
|
||||
#define LOG_CF_IS_DEBUG(x) Curl_log_cf_is_debug(x)
|
||||
|
||||
/* Macros intended for DEBUGF logging, use like:
|
||||
* DEBUGF(infof(data, CFMSG(cf, "this filter %s rocks"), "very much"));
|
||||
* and it will output:
|
||||
* [CONN-1-0][CF-SSL] this filter very much rocks
|
||||
* on connection #1 with sockindex 0 for filter of type "SSL". */
|
||||
#define DMSG(d,msg) \
|
||||
"[CONN-%ld] "msg, (d)->conn->connection_id
|
||||
#define DMSGI(d,i,msg) \
|
||||
"[CONN-%ld-%d] "msg, (d)->conn->connection_id, (i)
|
||||
#define CMSG(c,msg) \
|
||||
"[CONN-%ld] "msg, (c)->connection_id
|
||||
#define CMSGI(c,i,msg) \
|
||||
"[CONN-%ld-%d] "msg, (c)->connection_id, (i)
|
||||
#define CFMSG(cf,msg) \
|
||||
"[CONN-%ld-%d][CF-%s] "msg, (cf)->conn->connection_id, \
|
||||
(cf)->sockindex, (cf)->cft->name
|
||||
|
||||
|
||||
#define LOG_CF_IS_DEBUG(cf, data) Curl_log_cf_is_debug(cf, data)
|
||||
|
||||
#endif /* HEADER_CURL_LOG_H */
|
||||
|
||||
@@ -55,9 +55,65 @@
|
||||
*/
|
||||
|
||||
#ifdef HEADER_CURL_MEMDEBUG_H
|
||||
#error "Header memdebug.h shall not be included before curl_memory.h"
|
||||
/* cleanup after memdebug.h */
|
||||
|
||||
#ifdef MEMDEBUG_NODEFINES
|
||||
#ifdef CURLDEBUG
|
||||
|
||||
#undef strdup
|
||||
#undef malloc
|
||||
#undef calloc
|
||||
#undef realloc
|
||||
#undef free
|
||||
#undef send
|
||||
#undef recv
|
||||
|
||||
#ifdef WIN32
|
||||
# ifdef UNICODE
|
||||
# undef wcsdup
|
||||
# undef _wcsdup
|
||||
# undef _tcsdup
|
||||
# else
|
||||
# undef _tcsdup
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#undef socket
|
||||
#undef accept
|
||||
#ifdef HAVE_SOCKETPAIR
|
||||
#undef socketpair
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
#if defined(getaddrinfo) && defined(__osf__)
|
||||
#undef ogetaddrinfo
|
||||
#else
|
||||
#undef getaddrinfo
|
||||
#endif
|
||||
#endif /* HAVE_GETADDRINFO */
|
||||
|
||||
#ifdef HAVE_FREEADDRINFO
|
||||
#undef freeaddrinfo
|
||||
#endif /* HAVE_FREEADDRINFO */
|
||||
|
||||
/* sclose is probably already defined, redefine it! */
|
||||
#undef sclose
|
||||
#undef fopen
|
||||
#undef fdopen
|
||||
#undef fclose
|
||||
|
||||
#endif /* MEMDEBUG_NODEFINES */
|
||||
#endif /* CURLDEBUG */
|
||||
|
||||
#undef HEADER_CURL_MEMDEBUG_H
|
||||
#endif /* HEADER_CURL_MEMDEBUG_H */
|
||||
|
||||
/*
|
||||
** Following section applies even when CURLDEBUG is not defined.
|
||||
*/
|
||||
|
||||
#undef fake_sclose
|
||||
|
||||
#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */
|
||||
/*
|
||||
* The following memory function replacement typedef's are COPIED from
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
# undef vprintf
|
||||
# undef vfprintf
|
||||
# undef vsnprintf
|
||||
# undef mvsnprintf
|
||||
# undef aprintf
|
||||
# undef vaprintf
|
||||
# define printf curl_mprintf
|
||||
|
||||
@@ -221,12 +221,12 @@ void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
|
||||
}
|
||||
|
||||
/*
|
||||
* state()
|
||||
* sasl_state()
|
||||
*
|
||||
* This is the ONLY way to change SASL state!
|
||||
*/
|
||||
static void state(struct SASL *sasl, struct Curl_easy *data,
|
||||
saslstate newstate)
|
||||
static void sasl_state(struct SASL *sasl, struct Curl_easy *data,
|
||||
saslstate newstate)
|
||||
{
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
/* for debug purposes */
|
||||
@@ -508,7 +508,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
|
||||
|
||||
if(!result) {
|
||||
*progress = SASL_INPROGRESS;
|
||||
state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1);
|
||||
sasl_state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,14 +548,14 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
|
||||
if(code != sasl->params->finalcode)
|
||||
result = CURLE_LOGIN_DENIED;
|
||||
*progress = SASL_DONE;
|
||||
state(sasl, data, SASL_STOP);
|
||||
sasl_state(sasl, data, SASL_STOP);
|
||||
return result;
|
||||
}
|
||||
|
||||
if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
|
||||
code != sasl->params->contcode) {
|
||||
*progress = SASL_DONE;
|
||||
state(sasl, data, SASL_STOP);
|
||||
sasl_state(sasl, data, SASL_STOP);
|
||||
return CURLE_LOGIN_DENIED;
|
||||
}
|
||||
|
||||
@@ -698,7 +698,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
|
||||
if(code == sasl->params->finalcode) {
|
||||
/* Final response was received so we are done */
|
||||
*progress = SASL_DONE;
|
||||
state(sasl, data, SASL_STOP);
|
||||
sasl_state(sasl, data, SASL_STOP);
|
||||
return result;
|
||||
}
|
||||
else if(code == sasl->params->contcode) {
|
||||
@@ -708,7 +708,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
|
||||
}
|
||||
else {
|
||||
*progress = SASL_DONE;
|
||||
state(sasl, data, SASL_STOP);
|
||||
sasl_state(sasl, data, SASL_STOP);
|
||||
return CURLE_LOGIN_DENIED;
|
||||
}
|
||||
|
||||
@@ -745,7 +745,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
|
||||
|
||||
Curl_bufref_free(&resp);
|
||||
|
||||
state(sasl, data, newstate);
|
||||
sasl_state(sasl, data, newstate);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@
|
||||
#if defined(__APPLE__) && !defined(USE_ARES)
|
||||
#include <TargetConditionals.h>
|
||||
#define USE_RESOLVE_ON_IPS 1
|
||||
# if defined(TARGET_OS_OSX) && TARGET_OS_OSX
|
||||
# if !defined(TARGET_OS_OSX) || TARGET_OS_OSX
|
||||
# define CURL_OSX_CALL_COPYPROXIES 1
|
||||
# endif
|
||||
#endif
|
||||
@@ -302,6 +302,7 @@
|
||||
# if defined(HAVE_PROTO_BSDSOCKET_H) && \
|
||||
(!defined(__amigaos4__) || defined(USE_AMISSL))
|
||||
/* use bsdsocket.library directly, instead of libc networking functions */
|
||||
# define _SYS_MBUF_H /* m_len define clashes with curl */
|
||||
# include <proto/bsdsocket.h>
|
||||
# ifdef __amigaos4__
|
||||
int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
|
||||
@@ -77,6 +77,12 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_SCHANNEL
|
||||
/* Must set this before <schannel.h> is included directly or indirectly by
|
||||
another Windows header. */
|
||||
# define SCHANNEL_USE_BLACKLISTS 1
|
||||
#endif
|
||||
|
||||
#ifdef __hpux
|
||||
# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
|
||||
# ifdef _APP32_64BIT_OFF_T
|
||||
|
||||
@@ -81,8 +81,6 @@ int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save);
|
||||
#define DYN_PAUSE_BUFFER (64 * 1024 * 1024)
|
||||
#define DYN_HAXPROXY 2048
|
||||
#define DYN_HTTP_REQUEST (1024*1024)
|
||||
#define DYN_H2_HEADERS (128*1024)
|
||||
#define DYN_H2_TRAILERS (128*1024)
|
||||
#define DYN_APRINTF 8000000
|
||||
#define DYN_RTSP_REQ_HEADER (64*1024)
|
||||
#define DYN_TRAILERS (64*1024)
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
#include "slist.h"
|
||||
#include "mime.h"
|
||||
#include "amigaos.h"
|
||||
#include "macos.h"
|
||||
#include "warnless.h"
|
||||
#include "sigpipe.h"
|
||||
#include "vssh/ssh.h"
|
||||
@@ -83,7 +84,7 @@
|
||||
|
||||
/* true globals -- for curl_global_init() and curl_global_cleanup() */
|
||||
static unsigned int initialized;
|
||||
static long init_flags;
|
||||
static long easy_init_flags;
|
||||
|
||||
#ifdef GLOBAL_INIT_IS_THREADSAFE
|
||||
|
||||
@@ -181,6 +182,11 @@ static CURLcode global_init(long flags, bool memoryfuncs)
|
||||
}
|
||||
#endif
|
||||
|
||||
if(Curl_macos_init()) {
|
||||
DEBUGF(fprintf(stderr, "Error: Curl_macos_init failed\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(Curl_resolver_global_init()) {
|
||||
DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n"));
|
||||
goto fail;
|
||||
@@ -199,7 +205,7 @@ static CURLcode global_init(long flags, bool memoryfuncs)
|
||||
}
|
||||
#endif
|
||||
|
||||
init_flags = flags;
|
||||
easy_init_flags = flags;
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
if(getenv("CURL_GLOBAL_INIT"))
|
||||
@@ -274,7 +280,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
|
||||
|
||||
/**
|
||||
* curl_global_cleanup() globally cleanups curl, uses the value of
|
||||
* "init_flags" to determine what needs to be cleaned up and what doesn't.
|
||||
* "easy_init_flags" to determine what needs to be cleaned up and what doesn't.
|
||||
*/
|
||||
void curl_global_cleanup(void)
|
||||
{
|
||||
@@ -294,7 +300,7 @@ void curl_global_cleanup(void)
|
||||
Curl_resolver_global_cleanup();
|
||||
|
||||
#ifdef WIN32
|
||||
Curl_win32_cleanup(init_flags);
|
||||
Curl_win32_cleanup(easy_init_flags);
|
||||
#endif
|
||||
|
||||
Curl_amiga_cleanup();
|
||||
@@ -308,7 +314,7 @@ void curl_global_cleanup(void)
|
||||
free(leakpointer);
|
||||
#endif
|
||||
|
||||
init_flags = 0;
|
||||
easy_init_flags = 0;
|
||||
|
||||
global_init_unlock();
|
||||
}
|
||||
@@ -893,6 +899,8 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
|
||||
/* the connection cache is setup on demand */
|
||||
outcurl->state.conn_cache = NULL;
|
||||
outcurl->state.lastconnect_id = -1;
|
||||
outcurl->state.recent_conn_id = -1;
|
||||
outcurl->id = -1;
|
||||
|
||||
outcurl->progress.flags = data->progress.flags;
|
||||
outcurl->progress.callback = data->progress.callback;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#ifndef HEADER_CURL_EASY_LOCK_H
|
||||
#define HEADER_CURL_EASY_LOCK_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
@@ -103,3 +105,5 @@ static inline void curl_simple_lock_unlock(curl_simple_lock *lock)
|
||||
#undef GLOBAL_INIT_IS_THREADSAFE
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_EASY_LOCK_H */
|
||||
|
||||
@@ -120,6 +120,7 @@ struct curl_easyoption Curl_easyopts[] = {
|
||||
{"HAPPY_EYEBALLS_TIMEOUT_MS", CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS,
|
||||
CURLOT_LONG, 0},
|
||||
{"HAPROXYPROTOCOL", CURLOPT_HAPROXYPROTOCOL, CURLOT_LONG, 0},
|
||||
{"HAPROXY_CLIENT_IP", CURLOPT_HAPROXY_CLIENT_IP, CURLOT_STRING, 0},
|
||||
{"HEADER", CURLOPT_HEADER, CURLOT_LONG, 0},
|
||||
{"HEADERDATA", CURLOPT_HEADERDATA, CURLOT_CBPTR, 0},
|
||||
{"HEADERFUNCTION", CURLOPT_HEADERFUNCTION, CURLOT_FUNCTION, 0},
|
||||
@@ -164,7 +165,9 @@ struct curl_easyoption Curl_easyopts[] = {
|
||||
{"MAIL_AUTH", CURLOPT_MAIL_AUTH, CURLOT_STRING, 0},
|
||||
{"MAIL_FROM", CURLOPT_MAIL_FROM, CURLOT_STRING, 0},
|
||||
{"MAIL_RCPT", CURLOPT_MAIL_RCPT, CURLOT_SLIST, 0},
|
||||
{"MAIL_RCPT_ALLLOWFAILS", CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOT_LONG, 0},
|
||||
{"MAIL_RCPT_ALLLOWFAILS", CURLOPT_MAIL_RCPT_ALLOWFAILS,
|
||||
CURLOT_LONG, CURLOT_FLAG_ALIAS},
|
||||
{"MAIL_RCPT_ALLOWFAILS", CURLOPT_MAIL_RCPT_ALLOWFAILS, CURLOT_LONG, 0},
|
||||
{"MAXAGE_CONN", CURLOPT_MAXAGE_CONN, CURLOT_LONG, 0},
|
||||
{"MAXCONNECTS", CURLOPT_MAXCONNECTS, CURLOT_LONG, 0},
|
||||
{"MAXFILESIZE", CURLOPT_MAXFILESIZE, CURLOT_LONG, 0},
|
||||
@@ -370,6 +373,6 @@ struct curl_easyoption Curl_easyopts[] = {
|
||||
*/
|
||||
int Curl_easyopts_check(void)
|
||||
{
|
||||
return ((CURLOPT_LASTENTRY%10000) != (322 + 1));
|
||||
return ((CURLOPT_LASTENTRY%10000) != (323 + 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -56,13 +56,13 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
|
||||
int fd = -1;
|
||||
*tempname = NULL;
|
||||
|
||||
if(stat(filename, &sb) == -1 || !S_ISREG(sb.st_mode)) {
|
||||
/* a non-regular file, fallback to direct fopen() */
|
||||
*fh = fopen(filename, FOPEN_WRITETEXT);
|
||||
if(*fh)
|
||||
return CURLE_OK;
|
||||
*fh = fopen(filename, FOPEN_WRITETEXT);
|
||||
if(!*fh)
|
||||
goto fail;
|
||||
}
|
||||
if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode))
|
||||
return CURLE_OK;
|
||||
fclose(*fh);
|
||||
*fh = NULL;
|
||||
|
||||
result = Curl_rand_hex(data, randsuffix, sizeof(randsuffix));
|
||||
if(result)
|
||||
@@ -85,7 +85,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
|
||||
if((fstat(fd, &nsb) != -1) &&
|
||||
(nsb.st_uid == sb.st_uid) && (nsb.st_gid == sb.st_gid)) {
|
||||
/* if the user and group are the same, clone the original mode */
|
||||
if(fchmod(fd, sb.st_mode) == -1)
|
||||
if(fchmod(fd, (mode_t)sb.st_mode) == -1)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
+65
-65
@@ -93,14 +93,14 @@
|
||||
|
||||
/* Local API functions */
|
||||
#ifndef DEBUGBUILD
|
||||
static void _state(struct Curl_easy *data,
|
||||
ftpstate newstate);
|
||||
#define state(x,y) _state(x,y)
|
||||
static void _ftp_state(struct Curl_easy *data,
|
||||
ftpstate newstate);
|
||||
#define ftp_state(x,y) _ftp_state(x,y)
|
||||
#else
|
||||
static void _state(struct Curl_easy *data,
|
||||
ftpstate newstate,
|
||||
int lineno);
|
||||
#define state(x,y) _state(x,y,__LINE__)
|
||||
static void _ftp_state(struct Curl_easy *data,
|
||||
ftpstate newstate,
|
||||
int lineno);
|
||||
#define ftp_state(x,y) _ftp_state(x,y,__LINE__)
|
||||
#endif
|
||||
|
||||
static CURLcode ftp_sendquote(struct Curl_easy *data,
|
||||
@@ -463,7 +463,7 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
|
||||
}
|
||||
|
||||
conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
|
||||
state(data, FTP_STOP);
|
||||
ftp_state(data, FTP_STOP);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
@@ -591,7 +591,7 @@ static CURLcode ftp_readresp(struct Curl_easy *data,
|
||||
* generically is a good idea.
|
||||
*/
|
||||
infof(data, "We got a 421 - timeout");
|
||||
state(data, FTP_STOP);
|
||||
ftp_state(data, FTP_STOP);
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
|
||||
@@ -750,10 +750,10 @@ static const char * const ftp_state_names[]={
|
||||
#endif
|
||||
|
||||
/* This is the ONLY way to change FTP state! */
|
||||
static void _state(struct Curl_easy *data,
|
||||
ftpstate newstate
|
||||
static void _ftp_state(struct Curl_easy *data,
|
||||
ftpstate newstate
|
||||
#ifdef DEBUGBUILD
|
||||
, int lineno
|
||||
, int lineno
|
||||
#endif
|
||||
)
|
||||
{
|
||||
@@ -784,7 +784,7 @@ static CURLcode ftp_state_user(struct Curl_easy *data,
|
||||
if(!result) {
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
ftpc->ftp_trying_alternative = FALSE;
|
||||
state(data, FTP_USER);
|
||||
ftp_state(data, FTP_USER);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -794,7 +794,7 @@ static CURLcode ftp_state_pwd(struct Curl_easy *data,
|
||||
{
|
||||
CURLcode result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PWD");
|
||||
if(!result)
|
||||
state(data, FTP_PWD);
|
||||
ftp_state(data, FTP_PWD);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -872,7 +872,7 @@ static CURLcode ftp_state_cwd(struct Curl_easy *data,
|
||||
for all upcoming ones in the ftp->dirs[] array */
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->entrypath);
|
||||
if(!result)
|
||||
state(data, FTP_CWD);
|
||||
ftp_state(data, FTP_CWD);
|
||||
}
|
||||
else {
|
||||
if(ftpc->dirdepth) {
|
||||
@@ -882,7 +882,7 @@ static CURLcode ftp_state_cwd(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
|
||||
ftpc->dirs[ftpc->cwdcount -1]);
|
||||
if(!result)
|
||||
state(data, FTP_CWD);
|
||||
ftp_state(data, FTP_CWD);
|
||||
}
|
||||
else {
|
||||
/* No CWD necessary */
|
||||
@@ -1261,11 +1261,11 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
|
||||
if(result)
|
||||
goto out;
|
||||
portsock = CURL_SOCKET_BAD; /* now held in filter */
|
||||
state(data, FTP_PORT);
|
||||
ftp_state(data, FTP_PORT);
|
||||
|
||||
out:
|
||||
if(result) {
|
||||
state(data, FTP_STOP);
|
||||
ftp_state(data, FTP_STOP);
|
||||
}
|
||||
if(portsock != CURL_SOCKET_BAD)
|
||||
Curl_socket_close(data, conn, portsock);
|
||||
@@ -1307,7 +1307,7 @@ static CURLcode ftp_state_use_pasv(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "%s", mode[modeoff]);
|
||||
if(!result) {
|
||||
ftpc->count1 = modeoff;
|
||||
state(data, FTP_PASV);
|
||||
ftp_state(data, FTP_PASV);
|
||||
infof(data, "Connect data stream passively");
|
||||
}
|
||||
return result;
|
||||
@@ -1330,7 +1330,7 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
|
||||
/* doesn't transfer any data */
|
||||
|
||||
/* still possibly do PRE QUOTE jobs */
|
||||
state(data, FTP_RETR_PREQUOTE);
|
||||
ftp_state(data, FTP_RETR_PREQUOTE);
|
||||
result = ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
|
||||
}
|
||||
else if(data->set.ftp_use_port) {
|
||||
@@ -1355,7 +1355,7 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "PRET RETR %s",
|
||||
conn->proto.ftpc.file);
|
||||
if(!result)
|
||||
state(data, FTP_PRET);
|
||||
ftp_state(data, FTP_PRET);
|
||||
}
|
||||
else
|
||||
result = ftp_state_use_pasv(data, conn);
|
||||
@@ -1377,7 +1377,7 @@ static CURLcode ftp_state_rest(struct Curl_easy *data,
|
||||
whether it supports range */
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "REST %d", 0);
|
||||
if(!result)
|
||||
state(data, FTP_REST);
|
||||
ftp_state(data, FTP_REST);
|
||||
}
|
||||
else
|
||||
result = ftp_state_prepare_transfer(data);
|
||||
@@ -1398,7 +1398,7 @@ static CURLcode ftp_state_size(struct Curl_easy *data,
|
||||
/* we know ftpc->file is a valid pointer to a file name */
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
|
||||
if(!result)
|
||||
state(data, FTP_SIZE);
|
||||
ftp_state(data, FTP_SIZE);
|
||||
}
|
||||
else
|
||||
result = ftp_state_rest(data, conn);
|
||||
@@ -1466,7 +1466,7 @@ static CURLcode ftp_state_list(struct Curl_easy *data)
|
||||
free(cmd);
|
||||
|
||||
if(!result)
|
||||
state(data, FTP_LIST);
|
||||
ftp_state(data, FTP_LIST);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1530,7 +1530,7 @@ static CURLcode ftp_state_mdtm(struct Curl_easy *data)
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "MDTM %s", ftpc->file);
|
||||
|
||||
if(!result)
|
||||
state(data, FTP_MDTM);
|
||||
ftp_state(data, FTP_MDTM);
|
||||
}
|
||||
else
|
||||
result = ftp_state_type(data);
|
||||
@@ -1569,7 +1569,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
|
||||
/* Got no given size to start from, figure it out */
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
|
||||
if(!result)
|
||||
state(data, FTP_STOR_SIZE);
|
||||
ftp_state(data, FTP_STOR_SIZE);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1624,7 +1624,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
|
||||
* ftp_done() because we didn't transfer anything! */
|
||||
ftp->transfer = PPTRANSFER_NONE;
|
||||
|
||||
state(data, FTP_STOP);
|
||||
ftp_state(data, FTP_STOP);
|
||||
return CURLE_OK;
|
||||
}
|
||||
}
|
||||
@@ -1634,7 +1634,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s",
|
||||
ftpc->file);
|
||||
if(!result)
|
||||
state(data, FTP_STOR);
|
||||
ftp_state(data, FTP_STOR);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1695,7 +1695,7 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd);
|
||||
if(result)
|
||||
return result;
|
||||
state(data, instate);
|
||||
ftp_state(data, instate);
|
||||
quote = TRUE;
|
||||
}
|
||||
}
|
||||
@@ -1709,7 +1709,7 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
|
||||
break;
|
||||
case FTP_RETR_PREQUOTE:
|
||||
if(ftp->transfer != PPTRANSFER_BODY)
|
||||
state(data, FTP_STOP);
|
||||
ftp_state(data, FTP_STOP);
|
||||
else {
|
||||
if(ftpc->known_filesize != -1) {
|
||||
Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
|
||||
@@ -1731,12 +1731,12 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
|
||||
*/
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
|
||||
if(!result)
|
||||
state(data, FTP_RETR);
|
||||
ftp_state(data, FTP_RETR);
|
||||
}
|
||||
else {
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
|
||||
if(!result)
|
||||
state(data, FTP_RETR_SIZE);
|
||||
ftp_state(data, FTP_RETR_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1780,7 +1780,7 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data,
|
||||
if(!result) {
|
||||
conn->proto.ftpc.count1++;
|
||||
/* remain in/go to the FTP_PASV state */
|
||||
state(data, FTP_PASV);
|
||||
ftp_state(data, FTP_PASV);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -2005,7 +2005,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
conn->bits.do_more = TRUE;
|
||||
state(data, FTP_STOP); /* this phase is completed */
|
||||
ftp_state(data, FTP_STOP); /* this phase is completed */
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -2039,7 +2039,7 @@ static CURLcode ftp_state_port_resp(struct Curl_easy *data,
|
||||
}
|
||||
else {
|
||||
infof(data, "Connect data stream actively");
|
||||
state(data, FTP_STOP); /* end of DO phase */
|
||||
ftp_state(data, FTP_STOP); /* end of DO phase */
|
||||
result = ftp_dophase_done(data, FALSE);
|
||||
}
|
||||
|
||||
@@ -2151,7 +2151,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
|
||||
infof(data, "The requested document is not new enough");
|
||||
ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
|
||||
data->info.timecond = TRUE;
|
||||
state(data, FTP_STOP);
|
||||
ftp_state(data, FTP_STOP);
|
||||
return CURLE_OK;
|
||||
}
|
||||
break;
|
||||
@@ -2160,7 +2160,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
|
||||
infof(data, "The requested document is not old enough");
|
||||
ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
|
||||
data->info.timecond = TRUE;
|
||||
state(data, FTP_STOP);
|
||||
ftp_state(data, FTP_STOP);
|
||||
return CURLE_OK;
|
||||
}
|
||||
break;
|
||||
@@ -2268,7 +2268,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
|
||||
/* Set ->transfer so that we won't get any error in ftp_done()
|
||||
* because we didn't transfer the any file */
|
||||
ftp->transfer = PPTRANSFER_NONE;
|
||||
state(data, FTP_STOP);
|
||||
ftp_state(data, FTP_STOP);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@@ -2279,13 +2279,13 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
|
||||
data->state.resume_from);
|
||||
if(!result)
|
||||
state(data, FTP_RETR_REST);
|
||||
ftp_state(data, FTP_RETR_REST);
|
||||
}
|
||||
else {
|
||||
/* no resume */
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
|
||||
if(!result)
|
||||
state(data, FTP_RETR);
|
||||
ftp_state(data, FTP_RETR);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -2385,7 +2385,7 @@ static CURLcode ftp_state_rest_resp(struct Curl_easy *data,
|
||||
else {
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
|
||||
if(!result)
|
||||
state(data, FTP_RETR);
|
||||
ftp_state(data, FTP_RETR);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2401,7 +2401,7 @@ static CURLcode ftp_state_stor_resp(struct Curl_easy *data,
|
||||
|
||||
if(ftpcode >= 400) {
|
||||
failf(data, "Failed FTP upload: %0d", ftpcode);
|
||||
state(data, FTP_STOP);
|
||||
ftp_state(data, FTP_STOP);
|
||||
/* oops, we never close the sockets! */
|
||||
return CURLE_UPLOAD_FAILED;
|
||||
}
|
||||
@@ -2412,7 +2412,7 @@ static CURLcode ftp_state_stor_resp(struct Curl_easy *data,
|
||||
if(data->set.ftp_use_port) {
|
||||
bool connected;
|
||||
|
||||
state(data, FTP_STOP); /* no longer in STOR state */
|
||||
ftp_state(data, FTP_STOP); /* no longer in STOR state */
|
||||
|
||||
result = AllowServerConnect(data, &connected);
|
||||
if(result)
|
||||
@@ -2535,7 +2535,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
|
||||
if(!connected) {
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
infof(data, "Data conn was not available immediately");
|
||||
state(data, FTP_STOP);
|
||||
ftp_state(data, FTP_STOP);
|
||||
ftpc->wait_data_conn = TRUE;
|
||||
}
|
||||
}
|
||||
@@ -2546,7 +2546,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
|
||||
if((instate == FTP_LIST) && (ftpcode == 450)) {
|
||||
/* simply no matching files in the dir listing */
|
||||
ftp->transfer = PPTRANSFER_NONE; /* don't download anything */
|
||||
state(data, FTP_STOP); /* this phase is over */
|
||||
ftp_state(data, FTP_STOP); /* this phase is over */
|
||||
}
|
||||
else {
|
||||
failf(data, "RETR response: %03d", ftpcode);
|
||||
@@ -2582,7 +2582,7 @@ static CURLcode ftp_state_loggedin(struct Curl_easy *data)
|
||||
*/
|
||||
result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "PBSZ %d", 0);
|
||||
if(!result)
|
||||
state(data, FTP_PBSZ);
|
||||
ftp_state(data, FTP_PBSZ);
|
||||
}
|
||||
else {
|
||||
result = ftp_state_pwd(data, conn);
|
||||
@@ -2605,7 +2605,7 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s",
|
||||
conn->passwd?conn->passwd:"");
|
||||
if(!result)
|
||||
state(data, FTP_PASS);
|
||||
ftp_state(data, FTP_PASS);
|
||||
}
|
||||
else if(ftpcode/100 == 2) {
|
||||
/* 230 User ... logged in.
|
||||
@@ -2617,7 +2617,7 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "ACCT %s",
|
||||
data->set.str[STRING_FTP_ACCOUNT]);
|
||||
if(!result)
|
||||
state(data, FTP_ACCT);
|
||||
ftp_state(data, FTP_ACCT);
|
||||
}
|
||||
else {
|
||||
failf(data, "ACCT requested but none available");
|
||||
@@ -2638,7 +2638,7 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data,
|
||||
data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
|
||||
if(!result) {
|
||||
ftpc->ftp_trying_alternative = TRUE;
|
||||
state(data, FTP_USER);
|
||||
ftp_state(data, FTP_USER);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -2741,7 +2741,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
|
||||
ftpauth[ftpc->count1]);
|
||||
if(!result)
|
||||
state(data, FTP_AUTH);
|
||||
ftp_state(data, FTP_AUTH);
|
||||
}
|
||||
else
|
||||
result = ftp_state_user(data, conn);
|
||||
@@ -2808,7 +2808,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
|
||||
Curl_pp_sendf(data, &ftpc->pp, "PROT %c",
|
||||
data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
|
||||
if(!result)
|
||||
state(data, FTP_PROT);
|
||||
ftp_state(data, FTP_PROT);
|
||||
break;
|
||||
|
||||
case FTP_PROT:
|
||||
@@ -2827,7 +2827,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
|
||||
*/
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC");
|
||||
if(!result)
|
||||
state(data, FTP_CCC);
|
||||
ftp_state(data, FTP_CCC);
|
||||
}
|
||||
else
|
||||
result = ftp_state_pwd(data, conn);
|
||||
@@ -2919,7 +2919,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
|
||||
infof(data, "Entry path is '%s'", ftpc->entrypath);
|
||||
/* also save it where getinfo can access it: */
|
||||
data->state.most_recent_ftp_entrypath = ftpc->entrypath;
|
||||
state(data, FTP_SYST);
|
||||
ftp_state(data, FTP_SYST);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2935,7 +2935,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
|
||||
infof(data, "Failed to figure out path");
|
||||
}
|
||||
}
|
||||
state(data, FTP_STOP); /* we are done with the CONNECT phase! */
|
||||
ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
|
||||
DEBUGF(infof(data, "protocol connect phase DONE"));
|
||||
break;
|
||||
|
||||
@@ -2970,7 +2970,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
|
||||
/* remember target server OS */
|
||||
Curl_safefree(ftpc->server_os);
|
||||
ftpc->server_os = os;
|
||||
state(data, FTP_NAMEFMT);
|
||||
ftp_state(data, FTP_NAMEFMT);
|
||||
break;
|
||||
}
|
||||
/* Nothing special for the target server. */
|
||||
@@ -2982,7 +2982,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
|
||||
/* Cannot identify server OS. Continue anyway and cross fingers. */
|
||||
}
|
||||
|
||||
state(data, FTP_STOP); /* we are done with the CONNECT phase! */
|
||||
ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
|
||||
DEBUGF(infof(data, "protocol connect phase DONE"));
|
||||
break;
|
||||
|
||||
@@ -2993,7 +2993,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
|
||||
break;
|
||||
}
|
||||
|
||||
state(data, FTP_STOP); /* we are done with the CONNECT phase! */
|
||||
ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
|
||||
DEBUGF(infof(data, "protocol connect phase DONE"));
|
||||
break;
|
||||
|
||||
@@ -3026,7 +3026,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s",
|
||||
ftpc->dirs[ftpc->cwdcount - 1]);
|
||||
if(!result)
|
||||
state(data, FTP_MKD);
|
||||
ftp_state(data, FTP_MKD);
|
||||
}
|
||||
else {
|
||||
/* return failure */
|
||||
@@ -3055,7 +3055,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
|
||||
result = CURLE_REMOTE_ACCESS_DENIED;
|
||||
}
|
||||
else {
|
||||
state(data, FTP_CWD);
|
||||
ftp_state(data, FTP_CWD);
|
||||
/* send CWD */
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
|
||||
ftpc->dirs[ftpc->cwdcount - 1]);
|
||||
@@ -3114,7 +3114,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
|
||||
/* fallthrough, just stop! */
|
||||
default:
|
||||
/* internal error */
|
||||
state(data, FTP_STOP);
|
||||
ftp_state(data, FTP_STOP);
|
||||
break;
|
||||
}
|
||||
} /* if(ftpcode) */
|
||||
@@ -3191,7 +3191,7 @@ static CURLcode ftp_connect(struct Curl_easy *data,
|
||||
|
||||
/* When we connect, we start in the state where we await the 220
|
||||
response */
|
||||
state(data, FTP_WAIT220);
|
||||
ftp_state(data, FTP_WAIT220);
|
||||
|
||||
result = ftp_multi_statemach(data, done);
|
||||
|
||||
@@ -3516,13 +3516,13 @@ static CURLcode ftp_nb_type(struct Curl_easy *data,
|
||||
char want = (char)(ascii?'A':'I');
|
||||
|
||||
if(ftpc->transfertype == want) {
|
||||
state(data, newstate);
|
||||
ftp_state(data, newstate);
|
||||
return ftp_state_type_resp(data, 200, newstate);
|
||||
}
|
||||
|
||||
result = Curl_pp_sendf(data, &ftpc->pp, "TYPE %c", want);
|
||||
if(!result) {
|
||||
state(data, newstate);
|
||||
ftp_state(data, newstate);
|
||||
|
||||
/* keep track of our current transfer type */
|
||||
ftpc->transfertype = want;
|
||||
@@ -4040,11 +4040,11 @@ static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn)
|
||||
curl_easy_strerror(result));
|
||||
conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
|
||||
connclose(conn, "QUIT command failed"); /* mark for connection closure */
|
||||
state(data, FTP_STOP);
|
||||
ftp_state(data, FTP_STOP);
|
||||
return result;
|
||||
}
|
||||
|
||||
state(data, FTP_QUIT);
|
||||
ftp_state(data, FTP_QUIT);
|
||||
|
||||
result = ftp_block_statemach(data, conn);
|
||||
}
|
||||
|
||||
@@ -415,6 +415,13 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
|
||||
case CURLINFO_RETRY_AFTER:
|
||||
*param_offt = data->info.retry_after;
|
||||
break;
|
||||
case CURLINFO_XFER_ID:
|
||||
*param_offt = data->id;
|
||||
break;
|
||||
case CURLINFO_CONN_ID:
|
||||
*param_offt = data->conn?
|
||||
data->conn->connection_id : data->state.recent_conn_id;
|
||||
break;
|
||||
default:
|
||||
return CURLE_UNKNOWN_OPTION;
|
||||
}
|
||||
|
||||
@@ -67,10 +67,6 @@
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES)
|
||||
#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
|
||||
#endif
|
||||
|
||||
#if defined(CURLRES_SYNCH) && \
|
||||
defined(HAVE_ALARM) && \
|
||||
defined(SIGALRM) && \
|
||||
@@ -561,6 +557,7 @@ static struct Curl_addrinfo *get_localhost6(int port, const char *name)
|
||||
static struct Curl_addrinfo *get_localhost(int port, const char *name)
|
||||
{
|
||||
struct Curl_addrinfo *ca;
|
||||
struct Curl_addrinfo *ca6;
|
||||
const size_t ss_size = sizeof(struct sockaddr_in);
|
||||
const size_t hostlen = strlen(name);
|
||||
struct sockaddr_in sa;
|
||||
@@ -587,8 +584,12 @@ static struct Curl_addrinfo *get_localhost(int port, const char *name)
|
||||
memcpy(ca->ai_addr, &sa, ss_size);
|
||||
ca->ai_canonname = (char *)ca->ai_addr + ss_size;
|
||||
strcpy(ca->ai_canonname, name);
|
||||
ca->ai_next = get_localhost6(port, name);
|
||||
return ca;
|
||||
|
||||
ca6 = get_localhost6(port, name);
|
||||
if(!ca6)
|
||||
return ca;
|
||||
ca6->ai_next = ca;
|
||||
return ca6;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
@@ -743,23 +744,6 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
|
||||
return CURLRESOLV_ERROR;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES)
|
||||
{
|
||||
/*
|
||||
* The automagic conversion from IPv4 literals to IPv6 literals only
|
||||
* works if the SCDynamicStoreCopyProxies system function gets called
|
||||
* first. As Curl currently doesn't support system-wide HTTP proxies, we
|
||||
* therefore don't use any value this function might return.
|
||||
*
|
||||
* This function is only available on a macOS and is not needed for
|
||||
* IPv4-only builds, hence the conditions above.
|
||||
*/
|
||||
CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
|
||||
if(dict)
|
||||
CFRelease(dict);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef USE_RESOLVE_ON_IPS
|
||||
/* First check if this is an IPv4 address string */
|
||||
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
/* to play well with debug builds, we can *set* a fixed time this will
|
||||
return */
|
||||
time_t deltatime; /* allow for "adjustments" for unit test purposes */
|
||||
static time_t debugtime(void *unused)
|
||||
static time_t hsts_debugtime(void *unused)
|
||||
{
|
||||
char *timestr = getenv("CURL_TIME");
|
||||
(void)unused;
|
||||
@@ -70,7 +70,8 @@ static time_t debugtime(void *unused)
|
||||
}
|
||||
return time(NULL);
|
||||
}
|
||||
#define time(x) debugtime(x)
|
||||
#undef time
|
||||
#define time(x) hsts_debugtime(x)
|
||||
#endif
|
||||
|
||||
struct hsts *Curl_hsts_init(void)
|
||||
|
||||
+17
-15
@@ -1308,7 +1308,7 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
|
||||
|| IS_HTTPS_PROXY(conn->http_proxy.proxytype)
|
||||
#endif
|
||||
)
|
||||
&& conn->httpversion != 20) {
|
||||
&& conn->httpversion < 20) {
|
||||
/* Make sure this doesn't send more body bytes than what the max send
|
||||
speed says. The request bytes do not count to the max speed.
|
||||
*/
|
||||
@@ -2667,11 +2667,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
|
||||
#ifndef USE_HYPER
|
||||
/* With Hyper the body is always passed on separately */
|
||||
if(data->set.postfields) {
|
||||
|
||||
/* In HTTP2, we send request body in DATA frame regardless of
|
||||
its size. */
|
||||
if(conn->httpversion < 20 &&
|
||||
!data->state.expect100header &&
|
||||
if(!data->state.expect100header &&
|
||||
(http->postsize < MAX_INITIAL_POST_SIZE)) {
|
||||
/* if we don't use expect: 100 AND
|
||||
postsize is less than MAX_INITIAL_POST_SIZE
|
||||
@@ -2832,16 +2828,18 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
|
||||
}
|
||||
if(co) {
|
||||
struct Cookie *store = co;
|
||||
size_t clen = 8; /* hold the size of the generated Cookie: header */
|
||||
/* now loop through all cookies that matched */
|
||||
while(co) {
|
||||
if(co->value) {
|
||||
if(0 == count) {
|
||||
size_t add;
|
||||
if(!count) {
|
||||
result = Curl_dyn_addn(r, STRCONST("Cookie: "));
|
||||
if(result)
|
||||
break;
|
||||
}
|
||||
if((Curl_dyn_len(r) + strlen(co->name) + strlen(co->value) + 1) >=
|
||||
MAX_COOKIE_HEADER_LEN) {
|
||||
add = strlen(co->name) + strlen(co->value) + 1;
|
||||
if(clen + add >= MAX_COOKIE_HEADER_LEN) {
|
||||
infof(data, "Restricted outgoing cookies due to header size, "
|
||||
"'%s' not sent", co->name);
|
||||
linecap = TRUE;
|
||||
@@ -2851,6 +2849,7 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
|
||||
co->name, co->value);
|
||||
if(result)
|
||||
break;
|
||||
clen += add + (count ? 2 : 0);
|
||||
count++;
|
||||
}
|
||||
co = co->next; /* next cookie please */
|
||||
@@ -3381,6 +3380,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
|
||||
}
|
||||
}
|
||||
|
||||
if(data->req.upload_done)
|
||||
Curl_conn_ev_data_done_send(data);
|
||||
|
||||
if((conn->httpversion >= 20) && data->req.upload_chunky)
|
||||
/* upload_chunky was set above to set up the request in a chunky fashion,
|
||||
but is disabled here again to avoid that the chunked encoded version is
|
||||
@@ -4569,8 +4571,8 @@ CURLcode Curl_http_req_make(struct httpreq **preq,
|
||||
if(!req->path)
|
||||
goto out;
|
||||
}
|
||||
Curl_dynhds_init(&req->headers, 0, DYN_H2_HEADERS);
|
||||
Curl_dynhds_init(&req->trailers, 0, DYN_H2_TRAILERS);
|
||||
Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST);
|
||||
Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST);
|
||||
result = CURLE_OK;
|
||||
|
||||
out:
|
||||
@@ -4727,8 +4729,8 @@ CURLcode Curl_http_req_make2(struct httpreq **preq,
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
Curl_dynhds_init(&req->headers, 0, DYN_H2_HEADERS);
|
||||
Curl_dynhds_init(&req->trailers, 0, DYN_H2_TRAILERS);
|
||||
Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST);
|
||||
Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST);
|
||||
result = CURLE_OK;
|
||||
|
||||
out:
|
||||
@@ -4858,8 +4860,8 @@ CURLcode Curl_http_resp_make(struct http_resp **presp,
|
||||
if(!resp->description)
|
||||
goto out;
|
||||
}
|
||||
Curl_dynhds_init(&resp->headers, 0, DYN_H2_HEADERS);
|
||||
Curl_dynhds_init(&resp->trailers, 0, DYN_H2_TRAILERS);
|
||||
Curl_dynhds_init(&resp->headers, 0, DYN_HTTP_REQUEST);
|
||||
Curl_dynhds_init(&resp->trailers, 0, DYN_HTTP_REQUEST);
|
||||
result = CURLE_OK;
|
||||
|
||||
out:
|
||||
|
||||
@@ -38,124 +38,97 @@
|
||||
#include "memdebug.h"
|
||||
|
||||
|
||||
#define MAX_URL_LEN (4*1024)
|
||||
#define H1_MAX_URL_LEN (8*1024)
|
||||
|
||||
void Curl_h1_req_parse_init(struct h1_req_parser *parser, size_t max_line_len)
|
||||
{
|
||||
memset(parser, 0, sizeof(*parser));
|
||||
parser->max_line_len = max_line_len;
|
||||
Curl_bufq_init(&parser->scratch, max_line_len, 1);
|
||||
Curl_dyn_init(&parser->scratch, max_line_len);
|
||||
}
|
||||
|
||||
void Curl_h1_req_parse_free(struct h1_req_parser *parser)
|
||||
{
|
||||
if(parser) {
|
||||
Curl_http_req_free(parser->req);
|
||||
Curl_bufq_free(&parser->scratch);
|
||||
Curl_dyn_free(&parser->scratch);
|
||||
parser->req = NULL;
|
||||
parser->done = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode trim_line(struct h1_req_parser *parser, int options)
|
||||
{
|
||||
DEBUGASSERT(parser->line);
|
||||
if(parser->line_len) {
|
||||
if(parser->line[parser->line_len - 1] == '\n')
|
||||
--parser->line_len;
|
||||
if(parser->line_len) {
|
||||
if(parser->line[parser->line_len - 1] == '\r')
|
||||
--parser->line_len;
|
||||
else if(options & H1_PARSE_OPT_STRICT)
|
||||
return CURLE_URL_MALFORMAT;
|
||||
}
|
||||
else if(options & H1_PARSE_OPT_STRICT)
|
||||
return CURLE_URL_MALFORMAT;
|
||||
}
|
||||
else if(options & H1_PARSE_OPT_STRICT)
|
||||
return CURLE_URL_MALFORMAT;
|
||||
|
||||
if(parser->line_len > parser->max_line_len) {
|
||||
return CURLE_URL_MALFORMAT;
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static ssize_t detect_line(struct h1_req_parser *parser,
|
||||
const char *buf, const size_t buflen, int options,
|
||||
const char *buf, const size_t buflen,
|
||||
CURLcode *err)
|
||||
{
|
||||
const char *line_end;
|
||||
size_t len;
|
||||
|
||||
DEBUGASSERT(!parser->line);
|
||||
line_end = memchr(buf, '\n', buflen);
|
||||
if(!line_end) {
|
||||
*err = (buflen > parser->max_line_len)? CURLE_URL_MALFORMAT : CURLE_AGAIN;
|
||||
*err = CURLE_AGAIN;
|
||||
return -1;
|
||||
}
|
||||
len = line_end - buf + 1;
|
||||
if(len > parser->max_line_len) {
|
||||
*err = CURLE_URL_MALFORMAT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(options & H1_PARSE_OPT_STRICT) {
|
||||
if((len == 1) || (buf[len - 2] != '\r')) {
|
||||
*err = CURLE_URL_MALFORMAT;
|
||||
return -1;
|
||||
}
|
||||
parser->line = buf;
|
||||
parser->line_len = len - 2;
|
||||
}
|
||||
else {
|
||||
parser->line = buf;
|
||||
parser->line_len = len - (((len == 1) || (buf[len - 2] != '\r'))? 1 : 2);
|
||||
}
|
||||
parser->line = buf;
|
||||
parser->line_len = line_end - buf + 1;
|
||||
*err = CURLE_OK;
|
||||
return (ssize_t)len;
|
||||
return (ssize_t)parser->line_len;
|
||||
}
|
||||
|
||||
static ssize_t next_line(struct h1_req_parser *parser,
|
||||
const char *buf, const size_t buflen, int options,
|
||||
CURLcode *err)
|
||||
{
|
||||
ssize_t nread = 0, n;
|
||||
ssize_t nread = 0;
|
||||
|
||||
if(parser->line) {
|
||||
if(parser->scratch_skip) {
|
||||
/* last line was from scratch. Remove it now, since we are done
|
||||
* with it and look for the next one. */
|
||||
Curl_bufq_skip_and_shift(&parser->scratch, parser->scratch_skip);
|
||||
parser->scratch_skip = 0;
|
||||
}
|
||||
parser->line = NULL;
|
||||
parser->line_len = 0;
|
||||
Curl_dyn_reset(&parser->scratch);
|
||||
}
|
||||
|
||||
if(Curl_bufq_is_empty(&parser->scratch)) {
|
||||
nread = detect_line(parser, buf, buflen, options, err);
|
||||
if(nread < 0) {
|
||||
if(*err != CURLE_AGAIN)
|
||||
nread = detect_line(parser, buf, buflen, err);
|
||||
if(nread >= 0) {
|
||||
if(Curl_dyn_len(&parser->scratch)) {
|
||||
/* append detected line to scratch to have the complete line */
|
||||
*err = Curl_dyn_addn(&parser->scratch, parser->line, parser->line_len);
|
||||
if(*err)
|
||||
return -1;
|
||||
/* not a complete line, add to scratch for later revisit */
|
||||
nread = Curl_bufq_write(&parser->scratch,
|
||||
(const unsigned char *)buf, buflen, err);
|
||||
return nread;
|
||||
parser->line = Curl_dyn_ptr(&parser->scratch);
|
||||
parser->line_len = Curl_dyn_len(&parser->scratch);
|
||||
}
|
||||
/* found one */
|
||||
*err = trim_line(parser, options);
|
||||
if(*err)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
const char *sbuf;
|
||||
size_t sbuflen;
|
||||
|
||||
/* scratch contains bytes from last attempt, add more to it */
|
||||
if(buflen) {
|
||||
const char *line_end;
|
||||
size_t add_len;
|
||||
ssize_t pos;
|
||||
|
||||
line_end = memchr(buf, '\n', buflen);
|
||||
pos = line_end? (line_end - buf + 1) : -1;
|
||||
add_len = (pos >= 0)? (size_t)pos : buflen;
|
||||
nread = Curl_bufq_write(&parser->scratch,
|
||||
(const unsigned char *)buf, add_len, err);
|
||||
if(nread < 0) {
|
||||
/* Unable to add anything to scratch is an error, since we should
|
||||
* have seen a line there then before. */
|
||||
if(*err == CURLE_AGAIN)
|
||||
*err = CURLE_URL_MALFORMAT;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(Curl_bufq_peek(&parser->scratch,
|
||||
(const unsigned char **)&sbuf, &sbuflen)) {
|
||||
n = detect_line(parser, sbuf, sbuflen, options, err);
|
||||
if(n < 0 && *err != CURLE_AGAIN)
|
||||
return -1; /* real error */
|
||||
parser->scratch_skip = (size_t)n;
|
||||
}
|
||||
else {
|
||||
/* we SHOULD be able to peek at scratch data */
|
||||
DEBUGASSERT(0);
|
||||
}
|
||||
else if(*err == CURLE_AGAIN) {
|
||||
/* no line end in `buf`, add it to our scratch */
|
||||
*err = Curl_dyn_addn(&parser->scratch, (const unsigned char *)buf, buflen);
|
||||
nread = (*err)? -1 : (ssize_t)buflen;
|
||||
}
|
||||
return nread;
|
||||
}
|
||||
@@ -231,7 +204,7 @@ static CURLcode start_req(struct h1_req_parser *parser,
|
||||
else {
|
||||
/* origin-form OR absolute-form */
|
||||
CURLUcode uc;
|
||||
char tmp[MAX_URL_LEN];
|
||||
char tmp[H1_MAX_URL_LEN];
|
||||
|
||||
/* default, unless we see an absolute URL */
|
||||
path = target;
|
||||
@@ -328,7 +301,7 @@ ssize_t Curl_h1_req_parse_read(struct h1_req_parser *parser,
|
||||
goto out;
|
||||
}
|
||||
parser->done = TRUE;
|
||||
Curl_bufq_free(&parser->scratch);
|
||||
Curl_dyn_reset(&parser->scratch);
|
||||
/* last chance adjustments */
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -33,11 +33,11 @@
|
||||
#define H1_PARSE_OPT_NONE (0)
|
||||
#define H1_PARSE_OPT_STRICT (1 << 0)
|
||||
|
||||
#define H1_PARSE_DEFAULT_MAX_LINE_LEN (8 * 1024)
|
||||
#define H1_PARSE_DEFAULT_MAX_LINE_LEN DYN_HTTP_REQUEST
|
||||
|
||||
struct h1_req_parser {
|
||||
struct httpreq *req;
|
||||
struct bufq scratch;
|
||||
struct dynbuf scratch;
|
||||
size_t scratch_skip;
|
||||
const char *line;
|
||||
size_t max_line_len;
|
||||
|
||||
+203
-127
@@ -134,9 +134,11 @@ struct cf_h2_ctx {
|
||||
BIT(conn_closed);
|
||||
BIT(goaway);
|
||||
BIT(enable_push);
|
||||
BIT(nw_out_blocked);
|
||||
};
|
||||
|
||||
/* How to access `call_data` from a cf_h2 filter */
|
||||
#undef CF_CTX_CALL_DATA
|
||||
#define CF_CTX_CALL_DATA(cf) \
|
||||
((struct cf_h2_ctx *)(cf)->ctx)->call_data
|
||||
|
||||
@@ -175,6 +177,7 @@ struct stream_ctx {
|
||||
struct bufq sendbuf; /* request buffer */
|
||||
struct dynhds resp_trailers; /* response trailer fields */
|
||||
size_t resp_hds_len; /* amount of response header bytes in recvbuf */
|
||||
size_t upload_blocked_len;
|
||||
curl_off_t upload_left; /* number of request bytes left to upload */
|
||||
|
||||
char **push_headers; /* allocated array */
|
||||
@@ -183,6 +186,7 @@ struct stream_ctx {
|
||||
|
||||
int status_code; /* HTTP response status code */
|
||||
uint32_t error; /* stream error code */
|
||||
uint32_t local_window_size; /* the local recv window size */
|
||||
bool closed; /* TRUE on stream close */
|
||||
bool reset; /* TRUE on stream reset */
|
||||
bool close_handled; /* TRUE if stream closure is handled by libcurl */
|
||||
@@ -209,9 +213,12 @@ static void drain_stream(struct Curl_cfilter *cf,
|
||||
|
||||
(void)cf;
|
||||
bits = CURL_CSELECT_IN;
|
||||
if(!stream->send_closed && stream->upload_left)
|
||||
if(!stream->send_closed &&
|
||||
(stream->upload_left || stream->upload_blocked_len))
|
||||
bits |= CURL_CSELECT_OUT;
|
||||
if(data->state.dselect_bits != bits) {
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] DRAIN dselect_bits=%x",
|
||||
stream->id, bits));
|
||||
data->state.dselect_bits = bits;
|
||||
Curl_expire(data, 0, EXPIRE_RUN_NOW);
|
||||
}
|
||||
@@ -245,13 +252,14 @@ static CURLcode http2_data_setup(struct Curl_cfilter *cf,
|
||||
H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
|
||||
Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
|
||||
H2_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
|
||||
Curl_dynhds_init(&stream->resp_trailers, 0, DYN_H2_TRAILERS);
|
||||
Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST);
|
||||
stream->resp_hds_len = 0;
|
||||
stream->bodystarted = FALSE;
|
||||
stream->status_code = -1;
|
||||
stream->closed = FALSE;
|
||||
stream->close_handled = FALSE;
|
||||
stream->error = NGHTTP2_NO_ERROR;
|
||||
stream->local_window_size = H2_STREAM_WINDOW_SIZE;
|
||||
stream->upload_left = 0;
|
||||
|
||||
H2_STREAM_LCTX(data) = stream;
|
||||
@@ -580,7 +588,6 @@ static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
ssize_t nread = -1;
|
||||
|
||||
*input_pending = FALSE;
|
||||
Curl_attach_connection(data, cf->conn);
|
||||
nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result);
|
||||
if(nread != -1) {
|
||||
DEBUGF(LOG_CF(data, cf, "%zd bytes stray data read before trying "
|
||||
@@ -592,11 +599,10 @@ static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
alive = !should_close_session(ctx);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if(result != CURLE_AGAIN) {
|
||||
/* the read failed so let's say this is dead anyway */
|
||||
alive = FALSE;
|
||||
}
|
||||
Curl_detach_connection(data);
|
||||
}
|
||||
|
||||
return alive;
|
||||
@@ -644,13 +650,17 @@ static CURLcode nw_out_flush(struct Curl_cfilter *cf,
|
||||
if(Curl_bufq_is_empty(&ctx->outbufq))
|
||||
return CURLE_OK;
|
||||
|
||||
DEBUGF(LOG_CF(data, cf, "h2 conn flush %zu bytes",
|
||||
Curl_bufq_len(&ctx->outbufq)));
|
||||
nwritten = Curl_bufq_pass(&ctx->outbufq, nw_out_writer, cf, &result);
|
||||
if(nwritten < 0 && result != CURLE_AGAIN) {
|
||||
if(nwritten < 0) {
|
||||
if(result == CURLE_AGAIN) {
|
||||
DEBUGF(LOG_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN",
|
||||
Curl_bufq_len(&ctx->outbufq)));
|
||||
ctx->nw_out_blocked = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return CURLE_OK;
|
||||
DEBUGF(LOG_CF(data, cf, "nw send buffer flushed"));
|
||||
return Curl_bufq_is_empty(&ctx->outbufq)? CURLE_OK: CURLE_AGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -676,15 +686,17 @@ static ssize_t send_callback(nghttp2_session *h2,
|
||||
nw_out_writer, cf, &result);
|
||||
if(nwritten < 0) {
|
||||
if(result == CURLE_AGAIN) {
|
||||
ctx->nw_out_blocked = 1;
|
||||
return NGHTTP2_ERR_WOULDBLOCK;
|
||||
}
|
||||
failf(data, "Failed sending HTTP2 data");
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
if(!nwritten)
|
||||
if(!nwritten) {
|
||||
ctx->nw_out_blocked = 1;
|
||||
return NGHTTP2_ERR_WOULDBLOCK;
|
||||
|
||||
}
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
@@ -964,6 +976,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
|
||||
struct stream_ctx *stream = H2_STREAM_CTX(data);
|
||||
int32_t stream_id = frame->hd.stream_id;
|
||||
CURLcode result;
|
||||
size_t rbuflen;
|
||||
int rv;
|
||||
|
||||
if(!stream) {
|
||||
@@ -973,10 +986,10 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
|
||||
|
||||
switch(frame->hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
rbuflen = Curl_bufq_len(&stream->recvbuf);
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] FRAME[DATA len=%zu pad=%zu], "
|
||||
"buffered=%zu, window=%d/%d",
|
||||
stream_id, frame->hd.length, frame->data.padlen,
|
||||
Curl_bufq_len(&stream->recvbuf),
|
||||
stream_id, frame->hd.length, frame->data.padlen, rbuflen,
|
||||
nghttp2_session_get_stream_effective_recv_data_length(
|
||||
ctx->h2, stream->id),
|
||||
nghttp2_session_get_stream_effective_local_window_size(
|
||||
@@ -993,6 +1006,20 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
drain_stream(cf, data, stream);
|
||||
}
|
||||
else if(rbuflen > stream->local_window_size) {
|
||||
int32_t wsize = nghttp2_session_get_stream_local_window_size(
|
||||
ctx->h2, stream->id);
|
||||
if(wsize > 0 && (uint32_t)wsize != stream->local_window_size) {
|
||||
/* H2 flow control is not absolute, as the server might not have the
|
||||
* same view, yet. When we recieve more than we want, we enforce
|
||||
* the local window size again to make nghttp2 send WINDOW_UPATEs
|
||||
* accordingly. */
|
||||
nghttp2_session_set_local_window_size(ctx->h2,
|
||||
NGHTTP2_FLAG_NONE,
|
||||
stream->id,
|
||||
stream->local_window_size);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_HEADERS:
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] FRAME[HEADERS]", stream_id));
|
||||
@@ -1095,6 +1122,21 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
ctx->max_concurrent_streams));
|
||||
multi_connchanged(data->multi);
|
||||
}
|
||||
/* Since the initial stream window is 64K, a request might be on HOLD,
|
||||
* due to exhaustion. The (initial) SETTINGS may announce a much larger
|
||||
* window and *assume* that we treat this like a WINDOW_UPDATE. Some
|
||||
* servers send an explicit WINDOW_UPDATE, but not all seem to do that.
|
||||
* To be safe, we UNHOLD a stream in order not to stall. */
|
||||
if((data->req.keepon & KEEP_SEND_HOLD) &&
|
||||
(data->req.keepon & KEEP_SEND)) {
|
||||
struct stream_ctx *stream = H2_STREAM_CTX(data);
|
||||
data->req.keepon &= ~KEEP_SEND_HOLD;
|
||||
if(stream) {
|
||||
drain_stream(cf, data, stream);
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] un-holding after SETTINGS",
|
||||
stream_id));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_GOAWAY:
|
||||
@@ -1448,8 +1490,8 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
|
||||
if(nread > 0 && stream->upload_left != -1)
|
||||
stream->upload_left -= nread;
|
||||
|
||||
DEBUGF(LOG_CF(data_s, cf, "[h2sid=%d] req_body_read(len=%zu) left=%zd"
|
||||
" -> %zd, %d",
|
||||
DEBUGF(LOG_CF(data_s, cf, "[h2sid=%d] req_body_read(len=%zu) left=%"
|
||||
CURL_FORMAT_CURL_OFF_T " -> %zd, %d",
|
||||
stream_id, length, stream->upload_left, nread, result));
|
||||
|
||||
if(stream->upload_left == 0)
|
||||
@@ -1555,11 +1597,6 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
|
||||
*err = CURLE_SEND_ERROR; /* trigger Curl_retry_request() later */
|
||||
return -1;
|
||||
}
|
||||
else if(stream->reset) {
|
||||
failf(data, "HTTP/2 stream %u was reset", stream->id);
|
||||
*err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
|
||||
return -1;
|
||||
}
|
||||
else if(stream->error != NGHTTP2_NO_ERROR) {
|
||||
failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
|
||||
stream->id, nghttp2_http2_strerror(stream->error),
|
||||
@@ -1567,6 +1604,11 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
|
||||
*err = CURLE_HTTP2_STREAM;
|
||||
return -1;
|
||||
}
|
||||
else if(stream->reset) {
|
||||
failf(data, "HTTP/2 stream %u was reset", stream->id);
|
||||
*err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!stream->bodystarted) {
|
||||
failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
|
||||
@@ -1659,9 +1701,10 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
|
||||
struct stream_ctx *stream = H2_STREAM_CTX(data);
|
||||
int rv = 0;
|
||||
|
||||
if((sweight_wanted(data) != sweight_in_effect(data)) ||
|
||||
(data->set.priority.exclusive != data->state.priority.exclusive) ||
|
||||
(data->set.priority.parent != data->state.priority.parent) ) {
|
||||
if(stream && stream->id > 0 &&
|
||||
((sweight_wanted(data) != sweight_in_effect(data)) ||
|
||||
(data->set.priority.exclusive != data->state.priority.exclusive) ||
|
||||
(data->set.priority.parent != data->state.priority.parent)) ) {
|
||||
/* send new weight and/or dependency */
|
||||
nghttp2_priority_spec pri_spec;
|
||||
|
||||
@@ -1675,7 +1718,8 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
|
||||
goto out;
|
||||
}
|
||||
|
||||
while(!rv && nghttp2_session_want_write(ctx->h2))
|
||||
ctx->nw_out_blocked = 0;
|
||||
while(!rv && !ctx->nw_out_blocked && nghttp2_session_want_write(ctx->h2))
|
||||
rv = nghttp2_session_send(ctx->h2);
|
||||
|
||||
out:
|
||||
@@ -1739,7 +1783,7 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
|
||||
|
||||
/* Process network input buffer fist */
|
||||
if(!Curl_bufq_is_empty(&ctx->inbufq)) {
|
||||
DEBUGF(LOG_CF(data, cf, "Process %zd bytes in connection buffer",
|
||||
DEBUGF(LOG_CF(data, cf, "Process %zu bytes in connection buffer",
|
||||
Curl_bufq_len(&ctx->inbufq)));
|
||||
if(h2_process_pending_input(cf, data, &result) < 0)
|
||||
return result;
|
||||
@@ -1760,7 +1804,7 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
|
||||
}
|
||||
|
||||
nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result);
|
||||
/* DEBUGF(LOG_CF(data, cf, "read %zd bytes nw data -> %zd, %d",
|
||||
/* DEBUGF(LOG_CF(data, cf, "read %zu bytes nw data -> %zd, %d",
|
||||
Curl_bufq_len(&ctx->inbufq), nread, result)); */
|
||||
if(nread < 0) {
|
||||
if(result != CURLE_AGAIN) {
|
||||
@@ -1836,7 +1880,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
|
||||
out:
|
||||
result = h2_progress_egress(cf, data);
|
||||
if(result) {
|
||||
if(result && result != CURLE_AGAIN) {
|
||||
*err = result;
|
||||
nread = -1;
|
||||
}
|
||||
@@ -1864,7 +1908,8 @@ static ssize_t h2_submit(struct stream_ctx **pstream,
|
||||
struct h1_req_parser h1;
|
||||
struct dynhds h2_headers;
|
||||
nghttp2_nv *nva = NULL;
|
||||
size_t nheader, i;
|
||||
const void *body = NULL;
|
||||
size_t nheader, bodylen, i;
|
||||
nghttp2_data_provider data_prd;
|
||||
int32_t stream_id;
|
||||
nghttp2_priority_spec pri_spec;
|
||||
@@ -1929,8 +1974,8 @@ static ssize_t h2_submit(struct stream_ctx **pstream,
|
||||
|
||||
h2_pri_spec(data, &pri_spec);
|
||||
|
||||
DEBUGF(LOG_CF(data, cf, "send request allowed %d (easy handle %p)",
|
||||
nghttp2_session_check_request_allowed(ctx->h2), (void *)data));
|
||||
DEBUGF(LOG_CF(data, cf, "send request allowed %d",
|
||||
nghttp2_session_check_request_allowed(ctx->h2)));
|
||||
|
||||
switch(data->state.httpreq) {
|
||||
case HTTPREQ_POST:
|
||||
@@ -1966,9 +2011,35 @@ static ssize_t h2_submit(struct stream_ctx **pstream,
|
||||
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) submit %s",
|
||||
stream_id, len, data->state.url));
|
||||
infof(data, "Using Stream ID: %u (easy handle %p)",
|
||||
stream_id, (void *)data);
|
||||
infof(data, "Using Stream ID: %u", stream_id);
|
||||
stream->id = stream_id;
|
||||
stream->local_window_size = H2_STREAM_WINDOW_SIZE;
|
||||
if(data->set.max_recv_speed) {
|
||||
/* We are asked to only receive `max_recv_speed` bytes per second.
|
||||
* Let's limit our stream window size around that, otherwise the server
|
||||
* will send in large bursts only. We make the window 50% larger to
|
||||
* allow for data in flight and avoid stalling. */
|
||||
curl_off_t n = (((data->set.max_recv_speed - 1) / H2_CHUNK_SIZE) + 1);
|
||||
n += CURLMAX((n/2), 1);
|
||||
if(n < (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE) &&
|
||||
n < (UINT_MAX / H2_CHUNK_SIZE)) {
|
||||
stream->local_window_size = (uint32_t)n * H2_CHUNK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
body = (const char *)buf + nwritten;
|
||||
bodylen = len - nwritten;
|
||||
|
||||
if(bodylen) {
|
||||
/* We have request body to send in DATA frame */
|
||||
ssize_t n = Curl_bufq_write(&stream->sendbuf, body, bodylen, err);
|
||||
if(n < 0) {
|
||||
*err = CURLE_SEND_ERROR;
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
}
|
||||
nwritten += n;
|
||||
}
|
||||
|
||||
out:
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] submit -> %zd, %d",
|
||||
@@ -1982,17 +2053,13 @@ out:
|
||||
static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *buf, size_t len, CURLcode *err)
|
||||
{
|
||||
/*
|
||||
* Currently, we send request in this function, but this function is also
|
||||
* used to send request body. It would be nice to add dedicated function for
|
||||
* request.
|
||||
*/
|
||||
struct cf_h2_ctx *ctx = cf->ctx;
|
||||
struct stream_ctx *stream = H2_STREAM_CTX(data);
|
||||
struct cf_call_data save;
|
||||
int rv;
|
||||
ssize_t nwritten;
|
||||
CURLcode result;
|
||||
int blocked = 0;
|
||||
|
||||
CF_DATA_SAVE(save, cf, data);
|
||||
|
||||
@@ -2007,18 +2074,35 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
nwritten = http2_handle_stream_close(cf, data, stream, err);
|
||||
goto out;
|
||||
}
|
||||
/* If stream_id != -1, we have dispatched request HEADERS, and now
|
||||
are going to send or sending request body in DATA frame */
|
||||
nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err);
|
||||
if(nwritten < 0) {
|
||||
if(*err != CURLE_AGAIN)
|
||||
else if(stream->upload_blocked_len) {
|
||||
/* the data in `buf` has alread been submitted or added to the
|
||||
* buffers, but have been EAGAINed on the last invocation. */
|
||||
DEBUGASSERT(len >= stream->upload_blocked_len);
|
||||
if(len < stream->upload_blocked_len) {
|
||||
/* Did we get called again with a smaller `len`? This should not
|
||||
* happend. We are not prepared to handle that. */
|
||||
failf(data, "HTTP/2 send again with decreased length");
|
||||
*err = CURLE_HTTP2;
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
nwritten = 0;
|
||||
}
|
||||
nwritten = (ssize_t)stream->upload_blocked_len;
|
||||
stream->upload_blocked_len = 0;
|
||||
}
|
||||
else {
|
||||
/* If stream_id != -1, we have dispatched request HEADERS and
|
||||
* optionally request body, and now are going to send or sending
|
||||
* more request body in DATA frame */
|
||||
nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err);
|
||||
if(nwritten < 0) {
|
||||
if(*err != CURLE_AGAIN)
|
||||
goto out;
|
||||
nwritten = 0;
|
||||
}
|
||||
}
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%u] bufq_write(len=%zu) -> %zd, %d",
|
||||
stream->id, len, nwritten, *err));
|
||||
|
||||
if(!Curl_bufq_is_empty(&stream->sendbuf)) {
|
||||
/* req body data is buffered, resume the potentially suspended stream */
|
||||
rv = nghttp2_session_resume_data(ctx->h2, stream->id);
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
*err = CURLE_SEND_ERROR;
|
||||
@@ -2026,104 +2110,99 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
result = h2_progress_ingress(cf, data);
|
||||
if(result) {
|
||||
*err = result;
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = h2_progress_egress(cf, data);
|
||||
if(result) {
|
||||
*err = result;
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(should_close_session(ctx)) {
|
||||
if(stream->closed) {
|
||||
nwritten = http2_handle_stream_close(cf, data, stream, err);
|
||||
}
|
||||
else {
|
||||
DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session"));
|
||||
*err = CURLE_HTTP2;
|
||||
nwritten = -1;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(!nwritten) {
|
||||
size_t rwin = nghttp2_session_get_stream_remote_window_size(ctx->h2,
|
||||
stream->id);
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send: win %u/%zu",
|
||||
stream->id,
|
||||
nghttp2_session_get_remote_window_size(ctx->h2), rwin));
|
||||
if(rwin == 0) {
|
||||
/* We cannot upload more as the stream's remote window size
|
||||
* is 0. We need to receive WIN_UPDATEs before we can continue.
|
||||
*/
|
||||
data->req.keepon |= KEEP_SEND_HOLD;
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] holding send as remote flow "
|
||||
"window is exhausted", stream->id));
|
||||
}
|
||||
nwritten = -1;
|
||||
*err = CURLE_AGAIN;
|
||||
}
|
||||
/* handled writing BODY for open stream. */
|
||||
goto out;
|
||||
}
|
||||
else {
|
||||
nwritten = h2_submit(&stream, cf, data, buf, len, err);
|
||||
if(nwritten < 0) {
|
||||
goto out;
|
||||
}
|
||||
DEBUGASSERT(stream);
|
||||
}
|
||||
|
||||
result = h2_progress_ingress(cf, data);
|
||||
if(result) {
|
||||
*err = result;
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
/* Call the nghttp2 send loop and flush to write ALL buffered data,
|
||||
* headers and/or request body completely out to the network */
|
||||
result = h2_progress_egress(cf, data);
|
||||
/* if the stream has been closed in egress handling (nghttp2 does that
|
||||
* when it does not like the headers, for example */
|
||||
if(stream && stream->closed) {
|
||||
nwritten = http2_handle_stream_close(cf, data, stream, err);
|
||||
goto out;
|
||||
}
|
||||
else if(result == CURLE_AGAIN) {
|
||||
blocked = 1;
|
||||
}
|
||||
else if(result) {
|
||||
*err = result;
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
}
|
||||
else if(stream && !Curl_bufq_is_empty(&stream->sendbuf)) {
|
||||
/* although we wrote everything that nghttp2 wants to send now,
|
||||
* there is data left in our stream send buffer unwritten. This may
|
||||
* be due to the stream's HTTP/2 flow window being exhausted. */
|
||||
blocked = 1;
|
||||
}
|
||||
|
||||
if(stream && blocked) {
|
||||
/* Unable to send all data, due to connection blocked or H2 window
|
||||
* exhaustion. Data is left in our stream buffer, or nghttp2's internal
|
||||
* frame buffer or our network out buffer. */
|
||||
size_t rwin = nghttp2_session_get_stream_remote_window_size(ctx->h2,
|
||||
stream->id);
|
||||
if(rwin == 0) {
|
||||
/* H2 flow window exhaustion. We need to HOLD upload until we get
|
||||
* a WINDOW_UPDATE from the server. */
|
||||
data->req.keepon |= KEEP_SEND_HOLD;
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] holding send as remote flow "
|
||||
"window is exhausted", stream->id));
|
||||
}
|
||||
|
||||
result = h2_progress_egress(cf, data);
|
||||
if(result) {
|
||||
*err = result;
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
/* Whatever the cause, we need to return CURL_EAGAIN for this call.
|
||||
* We have unwritten state that needs us being invoked again and EAGAIN
|
||||
* is the only way to ensure that. */
|
||||
stream->upload_blocked_len = nwritten;
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) BLOCK: win %u/%zu "
|
||||
"blocked_len=%zu",
|
||||
stream->id, len,
|
||||
nghttp2_session_get_remote_window_size(ctx->h2), rwin,
|
||||
nwritten));
|
||||
*err = CURLE_AGAIN;
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
}
|
||||
else if(should_close_session(ctx)) {
|
||||
/* nghttp2 thinks this session is done. If the stream has not been
|
||||
* closed, this is an error state for out transfer */
|
||||
if(stream->closed) {
|
||||
nwritten = http2_handle_stream_close(cf, data, stream, err);
|
||||
}
|
||||
|
||||
if(should_close_session(ctx)) {
|
||||
if(stream->closed) {
|
||||
nwritten = http2_handle_stream_close(cf, data, stream, err);
|
||||
}
|
||||
else {
|
||||
DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session"));
|
||||
*err = CURLE_HTTP2;
|
||||
nwritten = -1;
|
||||
}
|
||||
goto out;
|
||||
else {
|
||||
DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session"));
|
||||
*err = CURLE_HTTP2;
|
||||
nwritten = -1;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if(stream) {
|
||||
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) -> %zd, %d, "
|
||||
"buffered=%zu, upload_left=%zu, stream-window=%d, "
|
||||
"connection-window=%d",
|
||||
"upload_left=%" CURL_FORMAT_CURL_OFF_T ", "
|
||||
"h2 windows %d-%d (stream-conn), "
|
||||
"buffers %zu-%zu (stream-conn)",
|
||||
stream->id, len, nwritten, *err,
|
||||
Curl_bufq_len(&stream->sendbuf),
|
||||
(ssize_t)stream->upload_left,
|
||||
nghttp2_session_get_stream_remote_window_size(
|
||||
ctx->h2, stream->id),
|
||||
nghttp2_session_get_remote_window_size(ctx->h2)));
|
||||
drain_stream(cf, data, stream);
|
||||
nghttp2_session_get_remote_window_size(ctx->h2),
|
||||
Curl_bufq_len(&stream->sendbuf),
|
||||
Curl_bufq_len(&ctx->outbufq)));
|
||||
}
|
||||
else {
|
||||
DEBUGF(LOG_CF(data, cf, "cf_send(len=%zu) -> %zd, %d, "
|
||||
"connection-window=%d",
|
||||
"connection-window=%d, nw_send_buffer(%zu)",
|
||||
len, nwritten, *err,
|
||||
nghttp2_session_get_remote_window_size(ctx->h2)));
|
||||
nghttp2_session_get_remote_window_size(ctx->h2),
|
||||
Curl_bufq_len(&ctx->outbufq)));
|
||||
}
|
||||
CF_DATA_RESTORE(cf, save);
|
||||
return nwritten;
|
||||
@@ -2241,8 +2320,7 @@ static CURLcode http2_data_pause(struct Curl_cfilter *cf,
|
||||
|
||||
DEBUGASSERT(data);
|
||||
if(ctx && ctx->h2 && stream) {
|
||||
uint32_t window = !pause * H2_STREAM_WINDOW_SIZE;
|
||||
CURLcode result;
|
||||
uint32_t window = pause? 0 : stream->local_window_size;
|
||||
|
||||
int rv = nghttp2_session_set_local_window_size(ctx->h2,
|
||||
NGHTTP2_FLAG_NONE,
|
||||
@@ -2257,10 +2335,8 @@ static CURLcode http2_data_pause(struct Curl_cfilter *cf,
|
||||
if(!pause)
|
||||
drain_stream(cf, data, stream);
|
||||
|
||||
/* make sure the window update gets sent */
|
||||
result = h2_progress_egress(cf, data);
|
||||
if(result)
|
||||
return result;
|
||||
/* attempt to send the window update */
|
||||
(void)h2_progress_egress(cf, data);
|
||||
|
||||
if(!pause) {
|
||||
/* Unpausing a h2 transfer, requires it to be run again. The server
|
||||
@@ -2510,7 +2586,7 @@ CURLcode Curl_http2_switch(struct Curl_easy *data,
|
||||
CURLcode result;
|
||||
|
||||
DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex));
|
||||
DEBUGF(infof(data, DMSGI(data, sockindex, "switching to HTTP/2")));
|
||||
DEBUGF(infof(data, "switching to HTTP/2"));
|
||||
|
||||
result = http2_cfilter_add(&cf, data, conn, sockindex);
|
||||
if(result)
|
||||
@@ -2569,7 +2645,7 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data,
|
||||
CURLcode result;
|
||||
|
||||
DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex));
|
||||
DEBUGF(infof(data, DMSGI(data, sockindex, "upgrading to HTTP/2")));
|
||||
DEBUGF(infof(data, "upgrading to HTTP/2"));
|
||||
DEBUGASSERT(data->req.upgr101 == UPGR101_RECEIVED);
|
||||
|
||||
result = http2_cfilter_add(&cf, data, conn, sockindex);
|
||||
|
||||
@@ -71,7 +71,7 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf,
|
||||
|
||||
DEBUGF(LOG_CF(data, cf, "connect"));
|
||||
connect_sub:
|
||||
result = cf->next->cft->connect(cf->next, data, blocking, done);
|
||||
result = cf->next->cft->do_connect(cf->next, data, blocking, done);
|
||||
if(result || !*done)
|
||||
return result;
|
||||
|
||||
@@ -181,7 +181,7 @@ static void http_proxy_cf_close(struct Curl_cfilter *cf,
|
||||
ctx->cf_protocol = NULL;
|
||||
}
|
||||
if(cf->next)
|
||||
cf->next->cft->close(cf->next, data);
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+55
-41
@@ -385,11 +385,11 @@ static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out)
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* state()
|
||||
* imap_state()
|
||||
*
|
||||
* This is the ONLY way to change IMAP state!
|
||||
*/
|
||||
static void state(struct Curl_easy *data, imapstate newstate)
|
||||
static void imap_state(struct Curl_easy *data, imapstate newstate)
|
||||
{
|
||||
struct imap_conn *imapc = &data->conn->proto.imapc;
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
@@ -441,7 +441,7 @@ static CURLcode imap_perform_capability(struct Curl_easy *data,
|
||||
result = imap_sendf(data, "CAPABILITY");
|
||||
|
||||
if(!result)
|
||||
state(data, IMAP_CAPABILITY);
|
||||
imap_state(data, IMAP_CAPABILITY);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -458,7 +458,7 @@ static CURLcode imap_perform_starttls(struct Curl_easy *data)
|
||||
CURLcode result = imap_sendf(data, "STARTTLS");
|
||||
|
||||
if(!result)
|
||||
state(data, IMAP_STARTTLS);
|
||||
imap_state(data, IMAP_STARTTLS);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -487,7 +487,7 @@ static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data,
|
||||
if(!result) {
|
||||
imapc->ssldone = ssldone;
|
||||
if(imapc->state != IMAP_UPGRADETLS)
|
||||
state(data, IMAP_UPGRADETLS);
|
||||
imap_state(data, IMAP_UPGRADETLS);
|
||||
|
||||
if(imapc->ssldone) {
|
||||
imap_to_imaps(conn);
|
||||
@@ -514,7 +514,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
|
||||
/* Check we have a username and password to authenticate with and end the
|
||||
connect phase if we don't */
|
||||
if(!data->state.aptr.user) {
|
||||
state(data, IMAP_STOP);
|
||||
imap_state(data, IMAP_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -531,7 +531,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
|
||||
free(passwd);
|
||||
|
||||
if(!result)
|
||||
state(data, IMAP_LOGIN);
|
||||
imap_state(data, IMAP_LOGIN);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -615,7 +615,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
|
||||
with and end the connect phase if we don't */
|
||||
if(imapc->preauth ||
|
||||
!Curl_sasl_can_authenticate(&imapc->sasl, data)) {
|
||||
state(data, IMAP_STOP);
|
||||
imap_state(data, IMAP_STOP);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -624,7 +624,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
|
||||
|
||||
if(!result) {
|
||||
if(progress == SASL_INPROGRESS)
|
||||
state(data, IMAP_AUTHENTICATE);
|
||||
imap_state(data, IMAP_AUTHENTICATE);
|
||||
else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
|
||||
/* Perform clear text authentication */
|
||||
result = imap_perform_login(data, conn);
|
||||
@@ -667,7 +667,7 @@ static CURLcode imap_perform_list(struct Curl_easy *data)
|
||||
}
|
||||
|
||||
if(!result)
|
||||
state(data, IMAP_LIST);
|
||||
imap_state(data, IMAP_LIST);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -707,7 +707,7 @@ static CURLcode imap_perform_select(struct Curl_easy *data)
|
||||
free(mailbox);
|
||||
|
||||
if(!result)
|
||||
state(data, IMAP_SELECT);
|
||||
imap_state(data, IMAP_SELECT);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -749,7 +749,7 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data)
|
||||
return CURLE_URL_MALFORMAT;
|
||||
}
|
||||
if(!result)
|
||||
state(data, IMAP_FETCH);
|
||||
imap_state(data, IMAP_FETCH);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -820,7 +820,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
|
||||
free(mailbox);
|
||||
|
||||
if(!result)
|
||||
state(data, IMAP_APPEND);
|
||||
imap_state(data, IMAP_APPEND);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -846,7 +846,7 @@ static CURLcode imap_perform_search(struct Curl_easy *data)
|
||||
result = imap_sendf(data, "SEARCH %s", imap->query);
|
||||
|
||||
if(!result)
|
||||
state(data, IMAP_SEARCH);
|
||||
imap_state(data, IMAP_SEARCH);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -863,7 +863,7 @@ static CURLcode imap_perform_logout(struct Curl_easy *data)
|
||||
CURLcode result = imap_sendf(data, "LOGOUT");
|
||||
|
||||
if(!result)
|
||||
state(data, IMAP_LOGOUT);
|
||||
imap_state(data, IMAP_LOGOUT);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1017,7 +1017,7 @@ static CURLcode imap_state_auth_resp(struct Curl_easy *data,
|
||||
if(!result)
|
||||
switch(progress) {
|
||||
case SASL_DONE:
|
||||
state(data, IMAP_STOP); /* Authenticated */
|
||||
imap_state(data, IMAP_STOP); /* Authenticated */
|
||||
break;
|
||||
case SASL_IDLE: /* No mechanism left after cancellation */
|
||||
if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
|
||||
@@ -1049,7 +1049,7 @@ static CURLcode imap_state_login_resp(struct Curl_easy *data,
|
||||
}
|
||||
else
|
||||
/* End of connect phase */
|
||||
state(data, IMAP_STOP);
|
||||
imap_state(data, IMAP_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1075,7 +1075,7 @@ static CURLcode imap_state_listsearch_resp(struct Curl_easy *data,
|
||||
result = CURLE_QUOTE_ERROR;
|
||||
else
|
||||
/* End of DO phase */
|
||||
state(data, IMAP_STOP);
|
||||
imap_state(data, IMAP_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1143,7 +1143,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
|
||||
|
||||
if(imapcode != '*') {
|
||||
Curl_pgrsSetDownloadSize(data, -1);
|
||||
state(data, IMAP_STOP);
|
||||
imap_state(data, IMAP_STOP);
|
||||
return CURLE_REMOTE_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -1178,7 +1178,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
|
||||
|
||||
if(!chunk) {
|
||||
/* no size, we're done with the data */
|
||||
state(data, IMAP_STOP);
|
||||
imap_state(data, IMAP_STOP);
|
||||
return CURLE_OK;
|
||||
}
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY, pp->cache, chunk);
|
||||
@@ -1224,7 +1224,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
|
||||
}
|
||||
|
||||
/* End of DO phase */
|
||||
state(data, IMAP_STOP);
|
||||
imap_state(data, IMAP_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1242,7 +1242,7 @@ static CURLcode imap_state_fetch_final_resp(struct Curl_easy *data,
|
||||
result = CURLE_WEIRD_SERVER_REPLY;
|
||||
else
|
||||
/* End of DONE phase */
|
||||
state(data, IMAP_STOP);
|
||||
imap_state(data, IMAP_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1265,7 +1265,7 @@ static CURLcode imap_state_append_resp(struct Curl_easy *data, int imapcode,
|
||||
Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
|
||||
|
||||
/* End of DO phase */
|
||||
state(data, IMAP_STOP);
|
||||
imap_state(data, IMAP_STOP);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1284,7 +1284,7 @@ static CURLcode imap_state_append_final_resp(struct Curl_easy *data,
|
||||
result = CURLE_UPLOAD_FAILED;
|
||||
else
|
||||
/* End of DONE phase */
|
||||
state(data, IMAP_STOP);
|
||||
imap_state(data, IMAP_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1372,7 +1372,7 @@ static CURLcode imap_statemachine(struct Curl_easy *data,
|
||||
/* fallthrough, just stop! */
|
||||
default:
|
||||
/* internal error */
|
||||
state(data, IMAP_STOP);
|
||||
imap_state(data, IMAP_STOP);
|
||||
break;
|
||||
}
|
||||
} while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp));
|
||||
@@ -1475,7 +1475,7 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done)
|
||||
return result;
|
||||
|
||||
/* Start off waiting for the server greeting response */
|
||||
state(data, IMAP_SERVERGREET);
|
||||
imap_state(data, IMAP_SERVERGREET);
|
||||
|
||||
/* Start off with an response id of '*' */
|
||||
strcpy(imapc->resptag, "*");
|
||||
@@ -1516,12 +1516,12 @@ static CURLcode imap_done(struct Curl_easy *data, CURLcode status,
|
||||
/* Handle responses after FETCH or APPEND transfer has finished */
|
||||
|
||||
if(!data->state.upload && data->set.mimepost.kind == MIMEKIND_NONE)
|
||||
state(data, IMAP_FETCH_FINAL);
|
||||
imap_state(data, IMAP_FETCH_FINAL);
|
||||
else {
|
||||
/* End the APPEND command first by sending an empty line */
|
||||
result = Curl_pp_sendf(data, &conn->proto.imapc.pp, "%s", "");
|
||||
if(!result)
|
||||
state(data, IMAP_APPEND_FINAL);
|
||||
imap_state(data, IMAP_APPEND_FINAL);
|
||||
}
|
||||
|
||||
/* Run the state-machine */
|
||||
@@ -1777,7 +1777,7 @@ static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
|
||||
|
||||
/* Calculate the tag based on the connection ID and command ID */
|
||||
msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
|
||||
'A' + curlx_sltosi(data->conn->connection_id % 26),
|
||||
'A' + curlx_sltosi((long)(data->conn->connection_id % 26)),
|
||||
++imapc->cmdid);
|
||||
|
||||
/* start with a blank buffer */
|
||||
@@ -1925,6 +1925,7 @@ static CURLcode imap_parse_url_options(struct connectdata *conn)
|
||||
CURLcode result = CURLE_OK;
|
||||
struct imap_conn *imapc = &conn->proto.imapc;
|
||||
const char *ptr = conn->options;
|
||||
bool prefer_login = false;
|
||||
|
||||
while(!result && ptr && *ptr) {
|
||||
const char *key = ptr;
|
||||
@@ -1938,26 +1939,39 @@ static CURLcode imap_parse_url_options(struct connectdata *conn)
|
||||
while(*ptr && *ptr != ';')
|
||||
ptr++;
|
||||
|
||||
if(strncasecompare(key, "AUTH=", 5))
|
||||
if(strncasecompare(key, "AUTH=+LOGIN", 11)) {
|
||||
/* User prefers plaintext LOGIN over any SASL, including SASL LOGIN */
|
||||
prefer_login = true;
|
||||
imapc->sasl.prefmech = SASL_AUTH_NONE;
|
||||
}
|
||||
else if(strncasecompare(key, "AUTH=", 5)) {
|
||||
prefer_login = false;
|
||||
result = Curl_sasl_parse_url_auth_option(&imapc->sasl,
|
||||
value, ptr - value);
|
||||
else
|
||||
}
|
||||
else {
|
||||
prefer_login = false;
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
}
|
||||
|
||||
if(*ptr == ';')
|
||||
ptr++;
|
||||
}
|
||||
|
||||
switch(imapc->sasl.prefmech) {
|
||||
case SASL_AUTH_NONE:
|
||||
imapc->preftype = IMAP_TYPE_NONE;
|
||||
break;
|
||||
case SASL_AUTH_DEFAULT:
|
||||
imapc->preftype = IMAP_TYPE_ANY;
|
||||
break;
|
||||
default:
|
||||
imapc->preftype = IMAP_TYPE_SASL;
|
||||
break;
|
||||
if(prefer_login)
|
||||
imapc->preftype = IMAP_TYPE_CLEARTEXT;
|
||||
else {
|
||||
switch(imapc->sasl.prefmech) {
|
||||
case SASL_AUTH_NONE:
|
||||
imapc->preftype = IMAP_TYPE_NONE;
|
||||
break;
|
||||
case SASL_AUTH_DEFAULT:
|
||||
imapc->preftype = IMAP_TYPE_ANY;
|
||||
break;
|
||||
default:
|
||||
imapc->preftype = IMAP_TYPE_SASL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -261,7 +261,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
|
||||
}
|
||||
/* We pass NULL as |output_name_type| to avoid a leak. */
|
||||
gss_display_name(&min, gssname, &output_buffer, NULL);
|
||||
infof(data, "Trying against %s", output_buffer.value);
|
||||
infof(data, "Trying against %s", (char *)output_buffer.value);
|
||||
gssresp = GSS_C_NO_BUFFER;
|
||||
*context = GSS_C_NO_CONTEXT;
|
||||
|
||||
|
||||
@@ -50,6 +50,14 @@
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIN32_LDAP /* Use Windows LDAP implementation. */
|
||||
# ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4201)
|
||||
# endif
|
||||
# include <subauth.h> /* for [P]UNICODE_STRING */
|
||||
# ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
# endif
|
||||
# include <winldap.h>
|
||||
# ifndef LDAP_VENDOR_NAME
|
||||
# error Your Platform SDK is NOT sufficient for LDAP support! \
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
#if !defined(TARGET_OS_OSX) || TARGET_OS_OSX
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "macos.h"
|
||||
|
||||
#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES)
|
||||
#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
|
||||
#endif
|
||||
|
||||
CURLcode Curl_macos_init(void)
|
||||
{
|
||||
#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES)
|
||||
{
|
||||
/*
|
||||
* The automagic conversion from IPv4 literals to IPv6 literals only
|
||||
* works if the SCDynamicStoreCopyProxies system function gets called
|
||||
* first. As Curl currently doesn't support system-wide HTTP proxies, we
|
||||
* therefore don't use any value this function might return.
|
||||
*
|
||||
* This function is only available on a macOS and is not needed for
|
||||
* IPv4-only builds, hence the conditions above.
|
||||
*/
|
||||
CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
|
||||
if(dict)
|
||||
CFRelease(dict);
|
||||
}
|
||||
#endif
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#endif /* TARGET_OS_OSX */
|
||||
|
||||
#endif /* __APPLE__ */
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef HEADER_CURL_MACOS_H
|
||||
#define HEADER_CURL_MACOS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if defined(__APPLE__) && (!defined(TARGET_OS_OSX) || TARGET_OS_OSX)
|
||||
|
||||
CURLcode Curl_macos_init(void);
|
||||
|
||||
#else
|
||||
|
||||
#define Curl_macos_init() CURLE_OK
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_MACOS_H */
|
||||
@@ -84,7 +84,7 @@ static const struct mime_encoder encoders[] = {
|
||||
};
|
||||
|
||||
/* Base64 encoding table */
|
||||
static const char base64[] =
|
||||
static const char base64enc[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
/* Quoted-printable character class table.
|
||||
@@ -469,10 +469,10 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
|
||||
i = st->buf[st->bufbeg++] & 0xFF;
|
||||
i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
|
||||
i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
|
||||
*ptr++ = base64[(i >> 18) & 0x3F];
|
||||
*ptr++ = base64[(i >> 12) & 0x3F];
|
||||
*ptr++ = base64[(i >> 6) & 0x3F];
|
||||
*ptr++ = base64[i & 0x3F];
|
||||
*ptr++ = base64enc[(i >> 18) & 0x3F];
|
||||
*ptr++ = base64enc[(i >> 12) & 0x3F];
|
||||
*ptr++ = base64enc[(i >> 6) & 0x3F];
|
||||
*ptr++ = base64enc[i & 0x3F];
|
||||
cursize += 4;
|
||||
st->pos += 4;
|
||||
size -= 4;
|
||||
@@ -496,10 +496,10 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
|
||||
i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
|
||||
|
||||
i |= (st->buf[st->bufbeg] & 0xFF) << 16;
|
||||
ptr[0] = base64[(i >> 18) & 0x3F];
|
||||
ptr[1] = base64[(i >> 12) & 0x3F];
|
||||
ptr[0] = base64enc[(i >> 18) & 0x3F];
|
||||
ptr[1] = base64enc[(i >> 12) & 0x3F];
|
||||
if(++st->bufbeg != st->bufend) {
|
||||
ptr[2] = base64[(i >> 6) & 0x3F];
|
||||
ptr[2] = base64enc[(i >> 6) & 0x3F];
|
||||
st->bufbeg++;
|
||||
}
|
||||
cursize += 4;
|
||||
|
||||
@@ -636,7 +636,7 @@ MQTT_SUBACK_COMING:
|
||||
|
||||
/* -- switched state -- */
|
||||
remlen = mq->remaining_length;
|
||||
infof(data, "Remaining length: %zd bytes", remlen);
|
||||
infof(data, "Remaining length: %zu bytes", remlen);
|
||||
if(data->set.max_filesize &&
|
||||
(curl_off_t)remlen > data->set.max_filesize) {
|
||||
failf(data, "Maximum file size exceeded");
|
||||
|
||||
@@ -112,7 +112,7 @@ static CURLMcode multi_timeout(struct Curl_multi *multi,
|
||||
static void process_pending_handles(struct Curl_multi *multi);
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
static const char * const statename[]={
|
||||
static const char * const multi_statename[]={
|
||||
"INIT",
|
||||
"PENDING",
|
||||
"CONNECT",
|
||||
@@ -194,15 +194,10 @@ static void mstate(struct Curl_easy *data, CURLMstate state
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
if(data->mstate >= MSTATE_PENDING &&
|
||||
data->mstate < MSTATE_COMPLETED) {
|
||||
long connection_id = -5000;
|
||||
|
||||
if(data->conn)
|
||||
connection_id = data->conn->connection_id;
|
||||
|
||||
infof(data,
|
||||
"STATE: %s => %s handle %p; line %d (connection #%ld)",
|
||||
statename[oldstate], statename[data->mstate],
|
||||
(void *)data, lineno, connection_id);
|
||||
"STATE: %s => %s handle %p; line %d",
|
||||
multi_statename[oldstate], multi_statename[data->mstate],
|
||||
(void *)data, lineno);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -464,6 +459,20 @@ struct Curl_multi *curl_multi_init(void)
|
||||
CURL_DNS_HASH_SIZE);
|
||||
}
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
static void multi_warn_debug(struct Curl_multi *multi, struct Curl_easy *data)
|
||||
{
|
||||
if(!multi->warned) {
|
||||
infof(data, "!!! WARNING !!!");
|
||||
infof(data, "This is a debug build of libcurl, "
|
||||
"do not use in production.");
|
||||
multi->warned = true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define multi_warn_debug(x,y) Curl_nop_stmt
|
||||
#endif
|
||||
|
||||
/* returns TRUE if the easy handle is supposed to be present in the main link
|
||||
list */
|
||||
static bool in_main_list(struct Curl_easy *data)
|
||||
@@ -623,8 +632,14 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
|
||||
data->set.server_response_timeout;
|
||||
data->state.conn_cache->closure_handle->set.no_signal =
|
||||
data->set.no_signal;
|
||||
data->id = data->state.conn_cache->next_easy_id++;
|
||||
if(data->state.conn_cache->next_easy_id <= 0)
|
||||
data->state.conn_cache->next_easy_id = 0;
|
||||
CONNCACHE_UNLOCK(data);
|
||||
|
||||
multi_warn_debug(multi, data);
|
||||
infof(data, "processing: %s", data->state.url);
|
||||
|
||||
return CURLM_OK;
|
||||
}
|
||||
|
||||
@@ -742,6 +757,7 @@ static CURLcode multi_done(struct Curl_easy *data,
|
||||
but currently we have no such detail knowledge.
|
||||
*/
|
||||
|
||||
data->state.recent_conn_id = conn->connection_id;
|
||||
if((data->set.reuse_forbid
|
||||
#if defined(USE_NTLM)
|
||||
&& !(conn->http_ntlm_state == NTLMSTATE_TYPE2 ||
|
||||
@@ -753,8 +769,9 @@ static CURLcode multi_done(struct Curl_easy *data,
|
||||
#endif
|
||||
) || conn->bits.close
|
||||
|| (premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) {
|
||||
DEBUGF(infof(data, "multi_done, not re-using connection=%ld, forbid=%d"
|
||||
", close=%d, premature=%d, conn_multiplex=%d",
|
||||
DEBUGF(infof(data, "multi_done, not re-using connection=%"
|
||||
CURL_FORMAT_CURL_OFF_T ", forbid=%d"
|
||||
", close=%d, premature=%d, conn_multiplex=%d",
|
||||
conn->connection_id,
|
||||
data->set.reuse_forbid, conn->bits.close, premature,
|
||||
Curl_conn_is_multiplex(conn, FIRSTSOCKET)));
|
||||
@@ -774,15 +791,16 @@ static CURLcode multi_done(struct Curl_easy *data,
|
||||
conn->bits.conn_to_host ? conn->conn_to_host.dispname :
|
||||
conn->host.dispname;
|
||||
/* create string before returning the connection */
|
||||
long connection_id = conn->connection_id;
|
||||
curl_off_t connection_id = conn->connection_id;
|
||||
msnprintf(buffer, sizeof(buffer),
|
||||
"Connection #%ld to host %s left intact",
|
||||
"Connection #%" CURL_FORMAT_CURL_OFF_T " to host %s left intact",
|
||||
connection_id, host);
|
||||
/* the connection is no longer in use by this transfer */
|
||||
CONNCACHE_UNLOCK(data);
|
||||
if(Curl_conncache_return_conn(data, conn)) {
|
||||
/* remember the most recently used connection */
|
||||
data->state.lastconnect_id = connection_id;
|
||||
data->state.recent_conn_id = connection_id;
|
||||
infof(data, "%s", buffer);
|
||||
}
|
||||
else
|
||||
@@ -1895,14 +1913,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
multistate(data, MSTATE_COMPLETED);
|
||||
}
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
if(!multi->warned) {
|
||||
infof(data, "!!! WARNING !!!");
|
||||
infof(data, "This is a debug build of libcurl, "
|
||||
"do not use in production.");
|
||||
multi->warned = true;
|
||||
}
|
||||
#endif
|
||||
multi_warn_debug(multi, data);
|
||||
|
||||
do {
|
||||
/* A "stream" here is a logical stream if the protocol can handle that
|
||||
@@ -3690,7 +3701,7 @@ void Curl_expire_clear(struct Curl_easy *data)
|
||||
}
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
infof(data, "Expire cleared (transfer %p)", data);
|
||||
infof(data, "Expire cleared");
|
||||
#endif
|
||||
nowp->tv_sec = 0;
|
||||
nowp->tv_usec = 0;
|
||||
@@ -3798,7 +3809,7 @@ void Curl_multi_dump(struct Curl_multi *multi)
|
||||
/* only display handles that are not completed */
|
||||
fprintf(stderr, "handle %p, state %s, %d sockets\n",
|
||||
(void *)data,
|
||||
statename[data->mstate], data->numsocks);
|
||||
multi_statename[data->mstate], data->numsocks);
|
||||
for(i = 0; i < data->numsocks; i++) {
|
||||
curl_socket_t s = data->sockets[i];
|
||||
struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
|
||||
|
||||
+22
-22
@@ -282,11 +282,11 @@ static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out)
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* state()
|
||||
* pop3_state()
|
||||
*
|
||||
* This is the ONLY way to change POP3 state!
|
||||
*/
|
||||
static void state(struct Curl_easy *data, pop3state newstate)
|
||||
static void pop3_state(struct Curl_easy *data, pop3state newstate)
|
||||
{
|
||||
struct pop3_conn *pop3c = &data->conn->proto.pop3c;
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
@@ -335,7 +335,7 @@ static CURLcode pop3_perform_capa(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &pop3c->pp, "%s", "CAPA");
|
||||
|
||||
if(!result)
|
||||
state(data, POP3_CAPA);
|
||||
pop3_state(data, POP3_CAPA);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -353,7 +353,7 @@ static CURLcode pop3_perform_starttls(struct Curl_easy *data,
|
||||
CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "STLS");
|
||||
|
||||
if(!result)
|
||||
state(data, POP3_STARTTLS);
|
||||
pop3_state(data, POP3_STARTTLS);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -383,7 +383,7 @@ static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data,
|
||||
if(!result) {
|
||||
pop3c->ssldone = ssldone;
|
||||
if(pop3c->state != POP3_UPGRADETLS)
|
||||
state(data, POP3_UPGRADETLS);
|
||||
pop3_state(data, POP3_UPGRADETLS);
|
||||
|
||||
if(pop3c->ssldone) {
|
||||
pop3_to_pop3s(conn);
|
||||
@@ -408,7 +408,7 @@ static CURLcode pop3_perform_user(struct Curl_easy *data,
|
||||
/* Check we have a username and password to authenticate with and end the
|
||||
connect phase if we don't */
|
||||
if(!data->state.aptr.user) {
|
||||
state(data, POP3_STOP);
|
||||
pop3_state(data, POP3_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -417,7 +417,7 @@ static CURLcode pop3_perform_user(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "USER %s",
|
||||
conn->user ? conn->user : "");
|
||||
if(!result)
|
||||
state(data, POP3_USER);
|
||||
pop3_state(data, POP3_USER);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -442,7 +442,7 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data,
|
||||
/* Check we have a username and password to authenticate with and end the
|
||||
connect phase if we don't */
|
||||
if(!data->state.aptr.user) {
|
||||
state(data, POP3_STOP);
|
||||
pop3_state(data, POP3_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -468,7 +468,7 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &pop3c->pp, "APOP %s %s", conn->user, secret);
|
||||
|
||||
if(!result)
|
||||
state(data, POP3_APOP);
|
||||
pop3_state(data, POP3_APOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -552,7 +552,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data,
|
||||
/* Check we have enough data to authenticate with and end the
|
||||
connect phase if we don't */
|
||||
if(!Curl_sasl_can_authenticate(&pop3c->sasl, data)) {
|
||||
state(data, POP3_STOP);
|
||||
pop3_state(data, POP3_STOP);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -562,7 +562,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data,
|
||||
|
||||
if(!result)
|
||||
if(progress == SASL_INPROGRESS)
|
||||
state(data, POP3_AUTH);
|
||||
pop3_state(data, POP3_AUTH);
|
||||
}
|
||||
|
||||
if(!result && progress == SASL_IDLE) {
|
||||
@@ -620,7 +620,7 @@ static CURLcode pop3_perform_command(struct Curl_easy *data)
|
||||
pop3->custom : command));
|
||||
|
||||
if(!result)
|
||||
state(data, POP3_COMMAND);
|
||||
pop3_state(data, POP3_COMMAND);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -638,7 +638,7 @@ static CURLcode pop3_perform_quit(struct Curl_easy *data,
|
||||
CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "QUIT");
|
||||
|
||||
if(!result)
|
||||
state(data, POP3_QUIT);
|
||||
pop3_state(data, POP3_QUIT);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -831,7 +831,7 @@ static CURLcode pop3_state_auth_resp(struct Curl_easy *data,
|
||||
if(!result)
|
||||
switch(progress) {
|
||||
case SASL_DONE:
|
||||
state(data, POP3_STOP); /* Authenticated */
|
||||
pop3_state(data, POP3_STOP); /* Authenticated */
|
||||
break;
|
||||
case SASL_IDLE: /* No mechanism left after cancellation */
|
||||
#ifndef CURL_DISABLE_CRYPTO_AUTH
|
||||
@@ -869,7 +869,7 @@ static CURLcode pop3_state_apop_resp(struct Curl_easy *data, int pop3code,
|
||||
}
|
||||
else
|
||||
/* End of connect phase */
|
||||
state(data, POP3_STOP);
|
||||
pop3_state(data, POP3_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -892,7 +892,7 @@ static CURLcode pop3_state_user_resp(struct Curl_easy *data, int pop3code,
|
||||
result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "PASS %s",
|
||||
conn->passwd ? conn->passwd : "");
|
||||
if(!result)
|
||||
state(data, POP3_PASS);
|
||||
pop3_state(data, POP3_PASS);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -910,7 +910,7 @@ static CURLcode pop3_state_pass_resp(struct Curl_easy *data, int pop3code,
|
||||
}
|
||||
else
|
||||
/* End of connect phase */
|
||||
state(data, POP3_STOP);
|
||||
pop3_state(data, POP3_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -929,7 +929,7 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data,
|
||||
(void)instate; /* no use for this yet */
|
||||
|
||||
if(pop3code != '+') {
|
||||
state(data, POP3_STOP);
|
||||
pop3_state(data, POP3_STOP);
|
||||
return CURLE_WEIRD_SERVER_REPLY;
|
||||
}
|
||||
|
||||
@@ -967,7 +967,7 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data,
|
||||
}
|
||||
|
||||
/* End of DO phase */
|
||||
state(data, POP3_STOP);
|
||||
pop3_state(data, POP3_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1037,12 +1037,12 @@ static CURLcode pop3_statemachine(struct Curl_easy *data,
|
||||
break;
|
||||
|
||||
case POP3_QUIT:
|
||||
state(data, POP3_STOP);
|
||||
pop3_state(data, POP3_STOP);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* internal error */
|
||||
state(data, POP3_STOP);
|
||||
pop3_state(data, POP3_STOP);
|
||||
break;
|
||||
}
|
||||
} while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp));
|
||||
@@ -1143,7 +1143,7 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done)
|
||||
return result;
|
||||
|
||||
/* Start off waiting for the server greeting response */
|
||||
state(data, POP3_SERVERGREET);
|
||||
pop3_state(data, POP3_SERVERGREET);
|
||||
|
||||
result = pop3_multi_statemach(data, done);
|
||||
|
||||
|
||||
@@ -419,8 +419,6 @@ CURLcode Curl_read(struct Curl_easy *data, /* transfer */
|
||||
*n += nread;
|
||||
result = CURLE_OK;
|
||||
out:
|
||||
/* DEBUGF(infof(data, "Curl_read(handle=%p) -> %d, nread=%ld",
|
||||
data, result, nread)); */
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1867,6 +1867,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
||||
*/
|
||||
data->set.haproxyprotocol = (0 != va_arg(param, long)) ? TRUE : FALSE;
|
||||
break;
|
||||
case CURLOPT_HAPROXY_CLIENT_IP:
|
||||
/*
|
||||
* Set the client IP to send through HAProxy PROXY protocol
|
||||
*/
|
||||
result = Curl_setstropt(&data->set.str[STRING_HAPROXY_CLIENT_IP],
|
||||
va_arg(param, char *));
|
||||
/* We enable implicitly the HAProxy protocol if we use this flag. */
|
||||
data->set.haproxyprotocol = TRUE;
|
||||
break;
|
||||
#endif
|
||||
case CURLOPT_INTERFACE:
|
||||
/*
|
||||
@@ -2711,7 +2720,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
||||
/* Set the list of mail recipients */
|
||||
data->set.mail_rcpt = va_arg(param, struct curl_slist *);
|
||||
break;
|
||||
case CURLOPT_MAIL_RCPT_ALLLOWFAILS:
|
||||
case CURLOPT_MAIL_RCPT_ALLOWFAILS:
|
||||
/* allow RCPT TO command to fail for some recipients */
|
||||
data->set.mail_rcpt_allowfails = (0 != va_arg(param, long)) ? TRUE : FALSE;
|
||||
break;
|
||||
|
||||
+193
-2
@@ -27,8 +27,6 @@
|
||||
|
||||
#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE)
|
||||
|
||||
#define BUILDING_CURL_SMB_C
|
||||
|
||||
#ifdef WIN32
|
||||
#define getpid GetCurrentProcessId
|
||||
#endif
|
||||
@@ -50,6 +48,199 @@
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
/*
|
||||
* Definitions for SMB protocol data structures
|
||||
*/
|
||||
#if defined(_MSC_VER) || defined(__ILEC400__)
|
||||
# define PACK
|
||||
# pragma pack(push)
|
||||
# pragma pack(1)
|
||||
#elif defined(__GNUC__)
|
||||
# define PACK __attribute__((packed))
|
||||
#else
|
||||
# define PACK
|
||||
#endif
|
||||
|
||||
#define SMB_COM_CLOSE 0x04
|
||||
#define SMB_COM_READ_ANDX 0x2e
|
||||
#define SMB_COM_WRITE_ANDX 0x2f
|
||||
#define SMB_COM_TREE_DISCONNECT 0x71
|
||||
#define SMB_COM_NEGOTIATE 0x72
|
||||
#define SMB_COM_SETUP_ANDX 0x73
|
||||
#define SMB_COM_TREE_CONNECT_ANDX 0x75
|
||||
#define SMB_COM_NT_CREATE_ANDX 0xa2
|
||||
#define SMB_COM_NO_ANDX_COMMAND 0xff
|
||||
|
||||
#define SMB_WC_CLOSE 0x03
|
||||
#define SMB_WC_READ_ANDX 0x0c
|
||||
#define SMB_WC_WRITE_ANDX 0x0e
|
||||
#define SMB_WC_SETUP_ANDX 0x0d
|
||||
#define SMB_WC_TREE_CONNECT_ANDX 0x04
|
||||
#define SMB_WC_NT_CREATE_ANDX 0x18
|
||||
|
||||
#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10
|
||||
#define SMB_FLAGS_CASELESS_PATHNAMES 0x08
|
||||
#define SMB_FLAGS2_UNICODE_STRINGS 0x8000
|
||||
#define SMB_FLAGS2_IS_LONG_NAME 0x0040
|
||||
#define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001
|
||||
|
||||
#define SMB_CAP_LARGE_FILES 0x08
|
||||
#define SMB_GENERIC_WRITE 0x40000000
|
||||
#define SMB_GENERIC_READ 0x80000000
|
||||
#define SMB_FILE_SHARE_ALL 0x07
|
||||
#define SMB_FILE_OPEN 0x01
|
||||
#define SMB_FILE_OVERWRITE_IF 0x05
|
||||
|
||||
#define SMB_ERR_NOACCESS 0x00050001
|
||||
|
||||
struct smb_header {
|
||||
unsigned char nbt_type;
|
||||
unsigned char nbt_flags;
|
||||
unsigned short nbt_length;
|
||||
unsigned char magic[4];
|
||||
unsigned char command;
|
||||
unsigned int status;
|
||||
unsigned char flags;
|
||||
unsigned short flags2;
|
||||
unsigned short pid_high;
|
||||
unsigned char signature[8];
|
||||
unsigned short pad;
|
||||
unsigned short tid;
|
||||
unsigned short pid;
|
||||
unsigned short uid;
|
||||
unsigned short mid;
|
||||
} PACK;
|
||||
|
||||
struct smb_negotiate_response {
|
||||
struct smb_header h;
|
||||
unsigned char word_count;
|
||||
unsigned short dialect_index;
|
||||
unsigned char security_mode;
|
||||
unsigned short max_mpx_count;
|
||||
unsigned short max_number_vcs;
|
||||
unsigned int max_buffer_size;
|
||||
unsigned int max_raw_size;
|
||||
unsigned int session_key;
|
||||
unsigned int capabilities;
|
||||
unsigned int system_time_low;
|
||||
unsigned int system_time_high;
|
||||
unsigned short server_time_zone;
|
||||
unsigned char encryption_key_length;
|
||||
unsigned short byte_count;
|
||||
char bytes[1];
|
||||
} PACK;
|
||||
|
||||
struct andx {
|
||||
unsigned char command;
|
||||
unsigned char pad;
|
||||
unsigned short offset;
|
||||
} PACK;
|
||||
|
||||
struct smb_setup {
|
||||
unsigned char word_count;
|
||||
struct andx andx;
|
||||
unsigned short max_buffer_size;
|
||||
unsigned short max_mpx_count;
|
||||
unsigned short vc_number;
|
||||
unsigned int session_key;
|
||||
unsigned short lengths[2];
|
||||
unsigned int pad;
|
||||
unsigned int capabilities;
|
||||
unsigned short byte_count;
|
||||
char bytes[1024];
|
||||
} PACK;
|
||||
|
||||
struct smb_tree_connect {
|
||||
unsigned char word_count;
|
||||
struct andx andx;
|
||||
unsigned short flags;
|
||||
unsigned short pw_len;
|
||||
unsigned short byte_count;
|
||||
char bytes[1024];
|
||||
} PACK;
|
||||
|
||||
struct smb_nt_create {
|
||||
unsigned char word_count;
|
||||
struct andx andx;
|
||||
unsigned char pad;
|
||||
unsigned short name_length;
|
||||
unsigned int flags;
|
||||
unsigned int root_fid;
|
||||
unsigned int access;
|
||||
curl_off_t allocation_size;
|
||||
unsigned int ext_file_attributes;
|
||||
unsigned int share_access;
|
||||
unsigned int create_disposition;
|
||||
unsigned int create_options;
|
||||
unsigned int impersonation_level;
|
||||
unsigned char security_flags;
|
||||
unsigned short byte_count;
|
||||
char bytes[1024];
|
||||
} PACK;
|
||||
|
||||
struct smb_nt_create_response {
|
||||
struct smb_header h;
|
||||
unsigned char word_count;
|
||||
struct andx andx;
|
||||
unsigned char op_lock_level;
|
||||
unsigned short fid;
|
||||
unsigned int create_disposition;
|
||||
|
||||
curl_off_t create_time;
|
||||
curl_off_t last_access_time;
|
||||
curl_off_t last_write_time;
|
||||
curl_off_t last_change_time;
|
||||
unsigned int ext_file_attributes;
|
||||
curl_off_t allocation_size;
|
||||
curl_off_t end_of_file;
|
||||
} PACK;
|
||||
|
||||
struct smb_read {
|
||||
unsigned char word_count;
|
||||
struct andx andx;
|
||||
unsigned short fid;
|
||||
unsigned int offset;
|
||||
unsigned short max_bytes;
|
||||
unsigned short min_bytes;
|
||||
unsigned int timeout;
|
||||
unsigned short remaining;
|
||||
unsigned int offset_high;
|
||||
unsigned short byte_count;
|
||||
} PACK;
|
||||
|
||||
struct smb_write {
|
||||
struct smb_header h;
|
||||
unsigned char word_count;
|
||||
struct andx andx;
|
||||
unsigned short fid;
|
||||
unsigned int offset;
|
||||
unsigned int timeout;
|
||||
unsigned short write_mode;
|
||||
unsigned short remaining;
|
||||
unsigned short pad;
|
||||
unsigned short data_length;
|
||||
unsigned short data_offset;
|
||||
unsigned int offset_high;
|
||||
unsigned short byte_count;
|
||||
unsigned char pad2;
|
||||
} PACK;
|
||||
|
||||
struct smb_close {
|
||||
unsigned char word_count;
|
||||
unsigned short fid;
|
||||
unsigned int last_mtime;
|
||||
unsigned short byte_count;
|
||||
} PACK;
|
||||
|
||||
struct smb_tree_disconnect {
|
||||
unsigned char word_count;
|
||||
unsigned short byte_count;
|
||||
} PACK;
|
||||
|
||||
#if defined(_MSC_VER) || defined(__ILEC400__)
|
||||
# pragma pack(pop)
|
||||
#endif
|
||||
|
||||
/* Local API functions */
|
||||
static CURLcode smb_setup_connection(struct Curl_easy *data,
|
||||
struct connectdata *conn);
|
||||
|
||||
@@ -48,203 +48,6 @@ struct smb_conn {
|
||||
size_t got;
|
||||
};
|
||||
|
||||
/*
|
||||
* Definitions for SMB protocol data structures
|
||||
*/
|
||||
#ifdef BUILDING_CURL_SMB_C
|
||||
|
||||
#if defined(_MSC_VER) || defined(__ILEC400__)
|
||||
# define PACK
|
||||
# pragma pack(push)
|
||||
# pragma pack(1)
|
||||
#elif defined(__GNUC__)
|
||||
# define PACK __attribute__((packed))
|
||||
#else
|
||||
# define PACK
|
||||
#endif
|
||||
|
||||
#define SMB_COM_CLOSE 0x04
|
||||
#define SMB_COM_READ_ANDX 0x2e
|
||||
#define SMB_COM_WRITE_ANDX 0x2f
|
||||
#define SMB_COM_TREE_DISCONNECT 0x71
|
||||
#define SMB_COM_NEGOTIATE 0x72
|
||||
#define SMB_COM_SETUP_ANDX 0x73
|
||||
#define SMB_COM_TREE_CONNECT_ANDX 0x75
|
||||
#define SMB_COM_NT_CREATE_ANDX 0xa2
|
||||
#define SMB_COM_NO_ANDX_COMMAND 0xff
|
||||
|
||||
#define SMB_WC_CLOSE 0x03
|
||||
#define SMB_WC_READ_ANDX 0x0c
|
||||
#define SMB_WC_WRITE_ANDX 0x0e
|
||||
#define SMB_WC_SETUP_ANDX 0x0d
|
||||
#define SMB_WC_TREE_CONNECT_ANDX 0x04
|
||||
#define SMB_WC_NT_CREATE_ANDX 0x18
|
||||
|
||||
#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10
|
||||
#define SMB_FLAGS_CASELESS_PATHNAMES 0x08
|
||||
#define SMB_FLAGS2_UNICODE_STRINGS 0x8000
|
||||
#define SMB_FLAGS2_IS_LONG_NAME 0x0040
|
||||
#define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001
|
||||
|
||||
#define SMB_CAP_LARGE_FILES 0x08
|
||||
#define SMB_GENERIC_WRITE 0x40000000
|
||||
#define SMB_GENERIC_READ 0x80000000
|
||||
#define SMB_FILE_SHARE_ALL 0x07
|
||||
#define SMB_FILE_OPEN 0x01
|
||||
#define SMB_FILE_OVERWRITE_IF 0x05
|
||||
|
||||
#define SMB_ERR_NOACCESS 0x00050001
|
||||
|
||||
struct smb_header {
|
||||
unsigned char nbt_type;
|
||||
unsigned char nbt_flags;
|
||||
unsigned short nbt_length;
|
||||
unsigned char magic[4];
|
||||
unsigned char command;
|
||||
unsigned int status;
|
||||
unsigned char flags;
|
||||
unsigned short flags2;
|
||||
unsigned short pid_high;
|
||||
unsigned char signature[8];
|
||||
unsigned short pad;
|
||||
unsigned short tid;
|
||||
unsigned short pid;
|
||||
unsigned short uid;
|
||||
unsigned short mid;
|
||||
} PACK;
|
||||
|
||||
struct smb_negotiate_response {
|
||||
struct smb_header h;
|
||||
unsigned char word_count;
|
||||
unsigned short dialect_index;
|
||||
unsigned char security_mode;
|
||||
unsigned short max_mpx_count;
|
||||
unsigned short max_number_vcs;
|
||||
unsigned int max_buffer_size;
|
||||
unsigned int max_raw_size;
|
||||
unsigned int session_key;
|
||||
unsigned int capabilities;
|
||||
unsigned int system_time_low;
|
||||
unsigned int system_time_high;
|
||||
unsigned short server_time_zone;
|
||||
unsigned char encryption_key_length;
|
||||
unsigned short byte_count;
|
||||
char bytes[1];
|
||||
} PACK;
|
||||
|
||||
struct andx {
|
||||
unsigned char command;
|
||||
unsigned char pad;
|
||||
unsigned short offset;
|
||||
} PACK;
|
||||
|
||||
struct smb_setup {
|
||||
unsigned char word_count;
|
||||
struct andx andx;
|
||||
unsigned short max_buffer_size;
|
||||
unsigned short max_mpx_count;
|
||||
unsigned short vc_number;
|
||||
unsigned int session_key;
|
||||
unsigned short lengths[2];
|
||||
unsigned int pad;
|
||||
unsigned int capabilities;
|
||||
unsigned short byte_count;
|
||||
char bytes[1024];
|
||||
} PACK;
|
||||
|
||||
struct smb_tree_connect {
|
||||
unsigned char word_count;
|
||||
struct andx andx;
|
||||
unsigned short flags;
|
||||
unsigned short pw_len;
|
||||
unsigned short byte_count;
|
||||
char bytes[1024];
|
||||
} PACK;
|
||||
|
||||
struct smb_nt_create {
|
||||
unsigned char word_count;
|
||||
struct andx andx;
|
||||
unsigned char pad;
|
||||
unsigned short name_length;
|
||||
unsigned int flags;
|
||||
unsigned int root_fid;
|
||||
unsigned int access;
|
||||
curl_off_t allocation_size;
|
||||
unsigned int ext_file_attributes;
|
||||
unsigned int share_access;
|
||||
unsigned int create_disposition;
|
||||
unsigned int create_options;
|
||||
unsigned int impersonation_level;
|
||||
unsigned char security_flags;
|
||||
unsigned short byte_count;
|
||||
char bytes[1024];
|
||||
} PACK;
|
||||
|
||||
struct smb_nt_create_response {
|
||||
struct smb_header h;
|
||||
unsigned char word_count;
|
||||
struct andx andx;
|
||||
unsigned char op_lock_level;
|
||||
unsigned short fid;
|
||||
unsigned int create_disposition;
|
||||
|
||||
curl_off_t create_time;
|
||||
curl_off_t last_access_time;
|
||||
curl_off_t last_write_time;
|
||||
curl_off_t last_change_time;
|
||||
unsigned int ext_file_attributes;
|
||||
curl_off_t allocation_size;
|
||||
curl_off_t end_of_file;
|
||||
} PACK;
|
||||
|
||||
struct smb_read {
|
||||
unsigned char word_count;
|
||||
struct andx andx;
|
||||
unsigned short fid;
|
||||
unsigned int offset;
|
||||
unsigned short max_bytes;
|
||||
unsigned short min_bytes;
|
||||
unsigned int timeout;
|
||||
unsigned short remaining;
|
||||
unsigned int offset_high;
|
||||
unsigned short byte_count;
|
||||
} PACK;
|
||||
|
||||
struct smb_write {
|
||||
struct smb_header h;
|
||||
unsigned char word_count;
|
||||
struct andx andx;
|
||||
unsigned short fid;
|
||||
unsigned int offset;
|
||||
unsigned int timeout;
|
||||
unsigned short write_mode;
|
||||
unsigned short remaining;
|
||||
unsigned short pad;
|
||||
unsigned short data_length;
|
||||
unsigned short data_offset;
|
||||
unsigned int offset_high;
|
||||
unsigned short byte_count;
|
||||
unsigned char pad2;
|
||||
} PACK;
|
||||
|
||||
struct smb_close {
|
||||
unsigned char word_count;
|
||||
unsigned short fid;
|
||||
unsigned int last_mtime;
|
||||
unsigned short byte_count;
|
||||
} PACK;
|
||||
|
||||
struct smb_tree_disconnect {
|
||||
unsigned char word_count;
|
||||
unsigned short byte_count;
|
||||
} PACK;
|
||||
|
||||
#if defined(_MSC_VER) || defined(__ILEC400__)
|
||||
# pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#endif /* BUILDING_CURL_SMB_C */
|
||||
|
||||
#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
|
||||
(SIZEOF_CURL_OFF_T > 4)
|
||||
|
||||
|
||||
+22
-22
@@ -281,11 +281,11 @@ static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out)
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* state()
|
||||
* smtp_state()
|
||||
*
|
||||
* This is the ONLY way to change SMTP state!
|
||||
*/
|
||||
static void state(struct Curl_easy *data, smtpstate newstate)
|
||||
static void smtp_state(struct Curl_easy *data, smtpstate newstate)
|
||||
{
|
||||
struct smtp_conn *smtpc = &data->conn->proto.smtpc;
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
@@ -338,7 +338,7 @@ static CURLcode smtp_perform_ehlo(struct Curl_easy *data)
|
||||
result = Curl_pp_sendf(data, &smtpc->pp, "EHLO %s", smtpc->domain);
|
||||
|
||||
if(!result)
|
||||
state(data, SMTP_EHLO);
|
||||
smtp_state(data, SMTP_EHLO);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -362,7 +362,7 @@ static CURLcode smtp_perform_helo(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &smtpc->pp, "HELO %s", smtpc->domain);
|
||||
|
||||
if(!result)
|
||||
state(data, SMTP_HELO);
|
||||
smtp_state(data, SMTP_HELO);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -381,7 +381,7 @@ static CURLcode smtp_perform_starttls(struct Curl_easy *data,
|
||||
"%s", "STARTTLS");
|
||||
|
||||
if(!result)
|
||||
state(data, SMTP_STARTTLS);
|
||||
smtp_state(data, SMTP_STARTTLS);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -410,7 +410,7 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data)
|
||||
if(!result) {
|
||||
smtpc->ssldone = ssldone;
|
||||
if(smtpc->state != SMTP_UPGRADETLS)
|
||||
state(data, SMTP_UPGRADETLS);
|
||||
smtp_state(data, SMTP_UPGRADETLS);
|
||||
|
||||
if(smtpc->ssldone) {
|
||||
smtp_to_smtps(conn);
|
||||
@@ -499,7 +499,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data)
|
||||
server supports authentication, and end the connect phase if not */
|
||||
if(!smtpc->auth_supported ||
|
||||
!Curl_sasl_can_authenticate(&smtpc->sasl, data)) {
|
||||
state(data, SMTP_STOP);
|
||||
smtp_state(data, SMTP_STOP);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -508,7 +508,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data)
|
||||
|
||||
if(!result) {
|
||||
if(progress == SASL_INPROGRESS)
|
||||
state(data, SMTP_AUTH);
|
||||
smtp_state(data, SMTP_AUTH);
|
||||
else {
|
||||
/* Other mechanisms not supported */
|
||||
infof(data, "No known authentication mechanisms supported");
|
||||
@@ -586,7 +586,7 @@ static CURLcode smtp_perform_command(struct Curl_easy *data)
|
||||
smtp->custom : "HELP");
|
||||
|
||||
if(!result)
|
||||
state(data, SMTP_COMMAND);
|
||||
smtp_state(data, SMTP_COMMAND);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -771,7 +771,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
|
||||
free(size);
|
||||
|
||||
if(!result)
|
||||
state(data, SMTP_MAIL);
|
||||
smtp_state(data, SMTP_MAIL);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -812,7 +812,7 @@ static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data)
|
||||
free(address);
|
||||
|
||||
if(!result)
|
||||
state(data, SMTP_RCPT);
|
||||
smtp_state(data, SMTP_RCPT);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -830,7 +830,7 @@ static CURLcode smtp_perform_quit(struct Curl_easy *data,
|
||||
CURLcode result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s", "QUIT");
|
||||
|
||||
if(!result)
|
||||
state(data, SMTP_QUIT);
|
||||
smtp_state(data, SMTP_QUIT);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -996,7 +996,7 @@ static CURLcode smtp_state_helo_resp(struct Curl_easy *data, int smtpcode,
|
||||
}
|
||||
else
|
||||
/* End of connect phase */
|
||||
state(data, SMTP_STOP);
|
||||
smtp_state(data, SMTP_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1017,7 +1017,7 @@ static CURLcode smtp_state_auth_resp(struct Curl_easy *data,
|
||||
if(!result)
|
||||
switch(progress) {
|
||||
case SASL_DONE:
|
||||
state(data, SMTP_STOP); /* Authenticated */
|
||||
smtp_state(data, SMTP_STOP); /* Authenticated */
|
||||
break;
|
||||
case SASL_IDLE: /* No mechanism left after cancellation */
|
||||
failf(data, "Authentication cancelled");
|
||||
@@ -1064,11 +1064,11 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode,
|
||||
}
|
||||
else
|
||||
/* End of DO phase */
|
||||
state(data, SMTP_STOP);
|
||||
smtp_state(data, SMTP_STOP);
|
||||
}
|
||||
else
|
||||
/* End of DO phase */
|
||||
state(data, SMTP_STOP);
|
||||
smtp_state(data, SMTP_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1145,7 +1145,7 @@ static CURLcode smtp_state_rcpt_resp(struct Curl_easy *data,
|
||||
result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s", "DATA");
|
||||
|
||||
if(!result)
|
||||
state(data, SMTP_DATA);
|
||||
smtp_state(data, SMTP_DATA);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1172,7 +1172,7 @@ static CURLcode smtp_state_data_resp(struct Curl_easy *data, int smtpcode,
|
||||
Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
|
||||
|
||||
/* End of DO phase */
|
||||
state(data, SMTP_STOP);
|
||||
smtp_state(data, SMTP_STOP);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1192,7 +1192,7 @@ static CURLcode smtp_state_postdata_resp(struct Curl_easy *data,
|
||||
result = CURLE_WEIRD_SERVER_REPLY;
|
||||
|
||||
/* End of DONE phase */
|
||||
state(data, SMTP_STOP);
|
||||
smtp_state(data, SMTP_STOP);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1274,7 +1274,7 @@ static CURLcode smtp_statemachine(struct Curl_easy *data,
|
||||
/* fallthrough, just stop! */
|
||||
default:
|
||||
/* internal error */
|
||||
state(data, SMTP_STOP);
|
||||
smtp_state(data, SMTP_STOP);
|
||||
break;
|
||||
}
|
||||
} while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp));
|
||||
@@ -1379,7 +1379,7 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done)
|
||||
return result;
|
||||
|
||||
/* Start off waiting for the server greeting response */
|
||||
state(data, SMTP_SERVERGREET);
|
||||
smtp_state(data, SMTP_SERVERGREET);
|
||||
|
||||
result = smtp_multi_statemach(data, done);
|
||||
|
||||
@@ -1461,7 +1461,7 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
|
||||
free(eob);
|
||||
}
|
||||
|
||||
state(data, SMTP_POSTDATA);
|
||||
smtp_state(data, SMTP_POSTDATA);
|
||||
|
||||
/* Run the state-machine */
|
||||
result = smtp_block_statemach(data, conn, FALSE);
|
||||
|
||||
@@ -161,7 +161,7 @@ static void socksstate(struct socks_state *sx, struct Curl_easy *data,
|
||||
enum connect_t oldstate = sx->state;
|
||||
#ifdef DEBUG_AND_VERBOSE
|
||||
/* synced with the state list in urldata.h */
|
||||
static const char * const statename[] = {
|
||||
static const char * const socks_statename[] = {
|
||||
"INIT",
|
||||
"SOCKS_INIT",
|
||||
"SOCKS_SEND",
|
||||
@@ -193,7 +193,7 @@ static void socksstate(struct socks_state *sx, struct Curl_easy *data,
|
||||
#ifdef DEBUG_AND_VERBOSE
|
||||
infof(data,
|
||||
"SXSTATE: %s => %s; line %d",
|
||||
statename[oldstate], statename[sx->state],
|
||||
socks_statename[oldstate], socks_statename[sx->state],
|
||||
lineno);
|
||||
#endif
|
||||
}
|
||||
@@ -567,7 +567,6 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
|
||||
*/
|
||||
struct connectdata *conn = cf->conn;
|
||||
unsigned char *socksreq = (unsigned char *)data->state.buffer;
|
||||
char dest[256] = "unknown"; /* printable hostname:port */
|
||||
int idx;
|
||||
CURLcode result;
|
||||
CURLproxycode presult;
|
||||
@@ -820,8 +819,8 @@ CONNECT_REQ_INIT:
|
||||
/* FALLTHROUGH */
|
||||
CONNECT_RESOLVED:
|
||||
case CONNECT_RESOLVED: {
|
||||
char dest[MAX_IPADR_LEN] = "unknown"; /* printable address */
|
||||
struct Curl_addrinfo *hp = NULL;
|
||||
size_t destlen;
|
||||
if(dns)
|
||||
hp = dns->addr;
|
||||
if(!hp) {
|
||||
@@ -831,8 +830,6 @@ CONNECT_RESOLVED:
|
||||
}
|
||||
|
||||
Curl_printable_address(hp, dest, sizeof(dest));
|
||||
destlen = strlen(dest);
|
||||
msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", sx->remote_port);
|
||||
|
||||
len = 0;
|
||||
socksreq[len++] = 5; /* version (SOCKS5) */
|
||||
@@ -848,7 +845,8 @@ CONNECT_RESOLVED:
|
||||
socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i];
|
||||
}
|
||||
|
||||
infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)", dest);
|
||||
infof(data, "SOCKS5 connect to %s:%d (locally resolved)", dest,
|
||||
sx->remote_port);
|
||||
}
|
||||
#ifdef ENABLE_IPV6
|
||||
else if(hp->ai_family == AF_INET6) {
|
||||
@@ -862,7 +860,8 @@ CONNECT_RESOLVED:
|
||||
((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i];
|
||||
}
|
||||
|
||||
infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)", dest);
|
||||
infof(data, "SOCKS5 connect to [%s]:%d (locally resolved)", dest,
|
||||
sx->remote_port);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
@@ -1115,7 +1114,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
result = cf->next->cft->connect(cf->next, data, blocking, done);
|
||||
result = cf->next->cft->do_connect(cf->next, data, blocking, done);
|
||||
if(result || !*done)
|
||||
return result;
|
||||
|
||||
@@ -1193,7 +1192,7 @@ static void socks_proxy_cf_close(struct Curl_cfilter *cf,
|
||||
DEBUGASSERT(cf->next);
|
||||
cf->connected = FALSE;
|
||||
socks_proxy_cf_free(cf);
|
||||
cf->next->cft->close(cf->next, data);
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
}
|
||||
|
||||
static void socks_proxy_cf_destroy(struct Curl_cfilter *cf,
|
||||
|
||||
@@ -1534,7 +1534,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
|
||||
}
|
||||
|
||||
while(keepon) {
|
||||
DEBUGF(infof(data, "telnet_do(handle=%p), poll %d fds", data, poll_cnt));
|
||||
DEBUGF(infof(data, "telnet_do, poll %d fds", poll_cnt));
|
||||
switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
|
||||
case -1: /* error, stop reading */
|
||||
keepon = FALSE;
|
||||
@@ -1558,8 +1558,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
|
||||
* in a clean way? Seems to be timing related, happens more
|
||||
* on slow debug build */
|
||||
if(data->state.os_errno == ECONNRESET) {
|
||||
DEBUGF(infof(data, "telnet_do(handle=%p), unexpected ECONNRESET"
|
||||
" on recv", data));
|
||||
DEBUGF(infof(data, "telnet_do, unexpected ECONNRESET on recv"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,8 @@ struct curltime Curl_now(void)
|
||||
return now;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
|
||||
#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) || \
|
||||
defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
|
||||
|
||||
struct curltime Curl_now(void)
|
||||
{
|
||||
@@ -87,6 +88,19 @@ struct curltime Curl_now(void)
|
||||
have_clock_gettime = TRUE;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CLOCK_GETTIME_MONOTONIC_RAW
|
||||
if(
|
||||
#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
|
||||
(HAVE_BUILTIN_AVAILABLE == 1)
|
||||
have_clock_gettime &&
|
||||
#endif
|
||||
(0 == clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow))) {
|
||||
cnow.tv_sec = tsnow.tv_sec;
|
||||
cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
if(
|
||||
#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
|
||||
(HAVE_BUILTIN_AVAILABLE == 1)
|
||||
|
||||
@@ -428,6 +428,8 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
||||
size_t excess = 0; /* excess bytes read */
|
||||
bool readmore = FALSE; /* used by RTP to signal for more data */
|
||||
int maxloops = 100;
|
||||
curl_off_t max_recv = data->set.max_recv_speed?
|
||||
data->set.max_recv_speed : CURL_OFF_T_MAX;
|
||||
char *buf = data->state.buffer;
|
||||
DEBUGASSERT(buf);
|
||||
|
||||
@@ -472,7 +474,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
||||
else {
|
||||
/* read nothing but since we wanted nothing we consider this an OK
|
||||
situation to proceed from */
|
||||
DEBUGF(infof(data, DMSG(data, "readwrite_data: we're done")));
|
||||
DEBUGF(infof(data, "readwrite_data: we're done"));
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
@@ -666,6 +668,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
||||
}
|
||||
|
||||
k->bytecount += nread;
|
||||
max_recv -= nread;
|
||||
|
||||
Curl_pgrsSetDownloadCounter(data, k->bytecount);
|
||||
|
||||
@@ -749,9 +752,9 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
||||
break;
|
||||
}
|
||||
|
||||
} while(data_pending(data) && maxloops--);
|
||||
} while((max_recv > 0) && data_pending(data) && maxloops--);
|
||||
|
||||
if(maxloops <= 0) {
|
||||
if(maxloops <= 0 || max_recv <= 0) {
|
||||
/* we mark it as read-again-please */
|
||||
data->state.dselect_bits = CURL_CSELECT_IN;
|
||||
*comeback = TRUE;
|
||||
@@ -768,7 +771,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
|
||||
|
||||
out:
|
||||
if(result)
|
||||
DEBUGF(infof(data, DMSG(data, "readwrite_data() -> %d"), result));
|
||||
DEBUGF(infof(data, "readwrite_data() -> %d", result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1233,7 +1236,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
||||
*done = (0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS))) ? TRUE : FALSE;
|
||||
out:
|
||||
if(result)
|
||||
DEBUGF(infof(data, DMSG(data, "Curl_readwrite() -> %d"), result));
|
||||
DEBUGF(infof(data, "Curl_readwrite() -> %d", result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1551,10 +1554,11 @@ CURLcode Curl_follow(struct Curl_easy *data,
|
||||
|
||||
if((type != FOLLOW_RETRY) &&
|
||||
(data->req.httpcode != 401) && (data->req.httpcode != 407) &&
|
||||
Curl_is_absolute_url(newurl, NULL, 0, FALSE))
|
||||
Curl_is_absolute_url(newurl, NULL, 0, FALSE)) {
|
||||
/* If this is not redirect due to a 401 or 407 response and an absolute
|
||||
URL: don't allow a custom port number */
|
||||
disallowport = TRUE;
|
||||
}
|
||||
|
||||
DEBUGASSERT(data->state.uh);
|
||||
uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl,
|
||||
|
||||
+22
-16
@@ -659,6 +659,9 @@ CURLcode Curl_open(struct Curl_easy **curl)
|
||||
|
||||
/* most recent connection is not yet defined */
|
||||
data->state.lastconnect_id = -1;
|
||||
data->state.recent_conn_id = -1;
|
||||
/* and not assigned an id yet */
|
||||
data->id = -1;
|
||||
|
||||
data->progress.flags |= PGRS_HIDE;
|
||||
data->state.current_speed = -1; /* init to negative == impossible */
|
||||
@@ -680,7 +683,7 @@ CURLcode Curl_open(struct Curl_easy **curl)
|
||||
static void conn_shutdown(struct Curl_easy *data)
|
||||
{
|
||||
DEBUGASSERT(data);
|
||||
infof(data, "Closing connection %ld", data->conn->connection_id);
|
||||
infof(data, "Closing connection");
|
||||
|
||||
/* possible left-overs from the async name resolvers */
|
||||
Curl_resolver_cancel(data);
|
||||
@@ -763,7 +766,8 @@ void Curl_disconnect(struct Curl_easy *data,
|
||||
/* the transfer must be detached from the connection */
|
||||
DEBUGASSERT(!data->conn);
|
||||
|
||||
DEBUGF(infof(data, "Curl_disconnect(conn #%ld, dead=%d)",
|
||||
DEBUGF(infof(data, "Curl_disconnect(conn #%"
|
||||
CURL_FORMAT_CURL_OFF_T ", dead=%d)",
|
||||
conn->connection_id, dead_connection));
|
||||
/*
|
||||
* If this connection isn't marked to force-close, leave it open if there
|
||||
@@ -937,6 +941,7 @@ static bool extract_if_dead(struct connectdata *conn,
|
||||
else {
|
||||
bool input_pending;
|
||||
|
||||
Curl_attach_connection(data, conn);
|
||||
dead = !Curl_conn_is_alive(data, conn, &input_pending);
|
||||
if(input_pending) {
|
||||
/* For reuse, we want a "clean" connection state. The includes
|
||||
@@ -949,10 +954,12 @@ static bool extract_if_dead(struct connectdata *conn,
|
||||
*/
|
||||
dead = TRUE;
|
||||
}
|
||||
Curl_detach_connection(data);
|
||||
}
|
||||
|
||||
if(dead) {
|
||||
infof(data, "Connection %ld seems to be dead", conn->connection_id);
|
||||
infof(data, "Connection %" CURL_FORMAT_CURL_OFF_T " seems to be dead",
|
||||
conn->connection_id);
|
||||
Curl_conncache_remove_conn(data, conn, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1147,8 +1154,8 @@ ConnectionExists(struct Curl_easy *data,
|
||||
/* primary_ip[0] is NUL only if the resolving of the name hasn't
|
||||
completed yet and until then we don't re-use this connection */
|
||||
if(!check->primary_ip[0]) {
|
||||
infof(data,
|
||||
"Connection #%ld is still name resolving, can't reuse",
|
||||
infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T " is still "
|
||||
"name resolving, can't reuse",
|
||||
check->connection_id);
|
||||
continue;
|
||||
}
|
||||
@@ -1158,8 +1165,8 @@ ConnectionExists(struct Curl_easy *data,
|
||||
if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
|
||||
foundPendingCandidate = TRUE;
|
||||
/* Don't pick a connection that hasn't connected yet */
|
||||
infof(data, "Connection #%ld isn't open enough, can't reuse",
|
||||
check->connection_id);
|
||||
infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T
|
||||
"isn't open enough, can't reuse", check->connection_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1335,8 +1342,8 @@ ConnectionExists(struct Curl_easy *data,
|
||||
if(!Curl_ssl_config_matches(&needle->ssl_config,
|
||||
&check->ssl_config)) {
|
||||
DEBUGF(infof(data,
|
||||
"Connection #%ld has different SSL parameters, "
|
||||
"can't reuse",
|
||||
"Connection #%" CURL_FORMAT_CURL_OFF_T
|
||||
" has different SSL parameters, can't reuse",
|
||||
check->connection_id));
|
||||
continue;
|
||||
}
|
||||
@@ -1477,14 +1484,14 @@ void Curl_verboseconnect(struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
if(data->set.verbose)
|
||||
infof(data, "Connected to %s (%s) port %u (#%ld)",
|
||||
infof(data, "Connected to %s (%s) port %u",
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
|
||||
conn->bits.httpproxy ? conn->http_proxy.host.dispname :
|
||||
#endif
|
||||
conn->bits.conn_to_host ? conn->conn_to_host.dispname :
|
||||
conn->host.dispname,
|
||||
conn->primary_ip, conn->port, conn->connection_id);
|
||||
conn->primary_ip, conn->port);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1857,7 +1864,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
|
||||
* User name and password set with their own options override the
|
||||
* credentials possibly set in the URL.
|
||||
*/
|
||||
if(!data->state.aptr.passwd) {
|
||||
if(!data->set.str[STRING_PASSWORD]) {
|
||||
uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
|
||||
if(!uc) {
|
||||
char *decoded;
|
||||
@@ -3678,15 +3685,14 @@ static CURLcode create_conn(struct Curl_easy *data,
|
||||
*in_connect = conn;
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
infof(data, "Re-using existing connection #%ld with %s %s",
|
||||
conn->connection_id,
|
||||
infof(data, "Re-using existing connection with %s %s",
|
||||
conn->bits.proxy?"proxy":"host",
|
||||
conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
|
||||
conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
|
||||
conn->host.dispname);
|
||||
#else
|
||||
infof(data, "Re-using existing connection #%ld with host %s",
|
||||
conn->connection_id, conn->host.dispname);
|
||||
infof(data, "Re-using existing connection with host %s",
|
||||
conn->host.dispname);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -201,7 +201,7 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
|
||||
size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
|
||||
bool guess_scheme)
|
||||
{
|
||||
int i;
|
||||
int i = 0;
|
||||
DEBUGASSERT(!buf || (buflen > MAX_SCHEME_LEN));
|
||||
(void)buflen; /* only used in debug-builds */
|
||||
if(buf)
|
||||
@@ -210,17 +210,18 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
|
||||
if(guess_scheme && STARTS_WITH_DRIVE_PREFIX(url))
|
||||
return 0;
|
||||
#endif
|
||||
for(i = 0; i < MAX_SCHEME_LEN; ++i) {
|
||||
char s = url[i];
|
||||
if(s && (ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') )) {
|
||||
/* RFC 3986 3.1 explains:
|
||||
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
|
||||
*/
|
||||
if(ISALPHA(url[0]))
|
||||
for(i = 1; i < MAX_SCHEME_LEN; ++i) {
|
||||
char s = url[i];
|
||||
if(s && (ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') )) {
|
||||
/* RFC 3986 3.1 explains:
|
||||
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
|
||||
*/
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i && (url[i] == ':') && ((url[i + 1] == '/') || !guess_scheme)) {
|
||||
/* If this does not guess scheme, the scheme always ends with the colon so
|
||||
that this also detects data: URLs etc. In guessing mode, data: could
|
||||
@@ -1546,7 +1547,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
|
||||
}
|
||||
}
|
||||
|
||||
url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
scheme,
|
||||
u->user ? u->user : "",
|
||||
u->password ? ":": "",
|
||||
@@ -1557,7 +1558,6 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
|
||||
allochost ? allochost : u->host,
|
||||
port ? ":": "",
|
||||
port ? port : "",
|
||||
(u->path && (u->path[0] != '/')) ? "/": "",
|
||||
u->path ? u->path : "/",
|
||||
(u->query && u->query[0]) ? "?": "",
|
||||
(u->query && u->query[0]) ? u->query : "",
|
||||
@@ -1639,8 +1639,10 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|
||||
bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0;
|
||||
bool plusencode = FALSE;
|
||||
bool urlskipslash = FALSE;
|
||||
bool leadingslash = FALSE;
|
||||
bool appendquery = FALSE;
|
||||
bool equalsencode = FALSE;
|
||||
size_t nalloc;
|
||||
|
||||
if(!u)
|
||||
return CURLUE_BAD_HANDLE;
|
||||
@@ -1693,6 +1695,11 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|
||||
return CURLUE_OK;
|
||||
}
|
||||
|
||||
nalloc = strlen(part);
|
||||
if(nalloc > CURL_MAX_INPUT_LENGTH)
|
||||
/* excessive input length */
|
||||
return CURLUE_MALFORMED_INPUT;
|
||||
|
||||
switch(what) {
|
||||
case CURLUPART_SCHEME: {
|
||||
size_t plen = strlen(part);
|
||||
@@ -1706,13 +1713,17 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|
||||
return CURLUE_UNSUPPORTED_SCHEME;
|
||||
storep = &u->scheme;
|
||||
urlencode = FALSE; /* never */
|
||||
/* ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */
|
||||
while(plen--) {
|
||||
if(ISALNUM(*s) || (*s == '+') || (*s == '-') || (*s == '.'))
|
||||
s++; /* fine */
|
||||
else
|
||||
return CURLUE_BAD_SCHEME;
|
||||
if(ISALPHA(*s)) {
|
||||
/* ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */
|
||||
while(--plen) {
|
||||
if(ISALNUM(*s) || (*s == '+') || (*s == '-') || (*s == '.'))
|
||||
s++; /* fine */
|
||||
else
|
||||
return CURLUE_BAD_SCHEME;
|
||||
}
|
||||
}
|
||||
else
|
||||
return CURLUE_BAD_SCHEME;
|
||||
break;
|
||||
}
|
||||
case CURLUPART_USER:
|
||||
@@ -1746,6 +1757,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|
||||
break;
|
||||
case CURLUPART_PATH:
|
||||
urlskipslash = TRUE;
|
||||
leadingslash = TRUE; /* enforce */
|
||||
storep = &u->path;
|
||||
break;
|
||||
case CURLUPART_QUERY:
|
||||
@@ -1794,18 +1806,17 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|
||||
}
|
||||
DEBUGASSERT(storep);
|
||||
{
|
||||
const char *newp = part;
|
||||
size_t nalloc = strlen(part);
|
||||
|
||||
if(nalloc > CURL_MAX_INPUT_LENGTH)
|
||||
/* excessive input length */
|
||||
return CURLUE_MALFORMED_INPUT;
|
||||
const char *newp;
|
||||
struct dynbuf enc;
|
||||
Curl_dyn_init(&enc, nalloc * 3 + 1 + leadingslash);
|
||||
|
||||
if(leadingslash && (part[0] != '/')) {
|
||||
CURLcode result = Curl_dyn_addn(&enc, "/", 1);
|
||||
if(result)
|
||||
return CURLUE_OUT_OF_MEMORY;
|
||||
}
|
||||
if(urlencode) {
|
||||
const unsigned char *i;
|
||||
struct dynbuf enc;
|
||||
|
||||
Curl_dyn_init(&enc, nalloc * 3 + 1);
|
||||
|
||||
for(i = (const unsigned char *)part; *i; i++) {
|
||||
CURLcode result;
|
||||
@@ -1833,14 +1844,13 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|
||||
return CURLUE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
newp = Curl_dyn_ptr(&enc);
|
||||
}
|
||||
else {
|
||||
char *p;
|
||||
newp = strdup(part);
|
||||
if(!newp)
|
||||
CURLcode result = Curl_dyn_add(&enc, part);
|
||||
if(result)
|
||||
return CURLUE_OUT_OF_MEMORY;
|
||||
p = (char *)newp;
|
||||
p = Curl_dyn_ptr(&enc);
|
||||
while(*p) {
|
||||
/* make sure percent encoded are lower case */
|
||||
if((*p == '%') && ISXDIGIT(p[1]) && ISXDIGIT(p[2]) &&
|
||||
@@ -1853,6 +1863,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|
||||
p++;
|
||||
}
|
||||
}
|
||||
newp = Curl_dyn_ptr(&enc);
|
||||
|
||||
if(appendquery) {
|
||||
/* Append the 'newp' string onto the old query. Add a '&' separator if
|
||||
@@ -1861,24 +1872,24 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|
||||
size_t querylen = u->query ? strlen(u->query) : 0;
|
||||
bool addamperand = querylen && (u->query[querylen -1] != '&');
|
||||
if(querylen) {
|
||||
struct dynbuf enc;
|
||||
Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
|
||||
struct dynbuf qbuf;
|
||||
Curl_dyn_init(&qbuf, CURL_MAX_INPUT_LENGTH);
|
||||
|
||||
if(Curl_dyn_addn(&enc, u->query, querylen)) /* add original query */
|
||||
if(Curl_dyn_addn(&qbuf, u->query, querylen)) /* add original query */
|
||||
goto nomem;
|
||||
|
||||
if(addamperand) {
|
||||
if(Curl_dyn_addn(&enc, "&", 1))
|
||||
if(Curl_dyn_addn(&qbuf, "&", 1))
|
||||
goto nomem;
|
||||
}
|
||||
if(Curl_dyn_add(&enc, newp))
|
||||
if(Curl_dyn_add(&qbuf, newp))
|
||||
goto nomem;
|
||||
free((char *)newp);
|
||||
Curl_dyn_free(&enc);
|
||||
free(*storep);
|
||||
*storep = Curl_dyn_ptr(&enc);
|
||||
*storep = Curl_dyn_ptr(&qbuf);
|
||||
return CURLUE_OK;
|
||||
nomem:
|
||||
free((char *)newp);
|
||||
Curl_dyn_free(&enc);
|
||||
return CURLUE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
@@ -1890,7 +1901,7 @@ nomem:
|
||||
}
|
||||
else {
|
||||
if(!n || hostname_check(u, (char *)newp, n)) {
|
||||
free((char *)newp);
|
||||
Curl_dyn_free(&enc);
|
||||
return CURLUE_BAD_HOSTNAME;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -882,8 +882,8 @@ struct connectdata {
|
||||
#define CONN_INUSE(c) ((c)->easyq.size)
|
||||
|
||||
/**** Fields set when inited and not modified again */
|
||||
long connection_id; /* Contains a unique number to make it easier to
|
||||
track the connections in the log output */
|
||||
curl_off_t connection_id; /* Contains a unique number to make it easier to
|
||||
track the connections in the log output */
|
||||
|
||||
/* 'dns_entry' is the particular host we use. This points to an entry in the
|
||||
DNS cache and it will not get pruned while locked. It gets unlocked in
|
||||
@@ -1294,7 +1294,9 @@ struct UrlState {
|
||||
/* buffers to store authentication data in, as parsed from input options */
|
||||
struct curltime keeps_speed; /* for the progress meter really */
|
||||
|
||||
long lastconnect_id; /* The last connection, -1 if undefined */
|
||||
curl_off_t lastconnect_id; /* The last connection, -1 if undefined */
|
||||
curl_off_t recent_conn_id; /* The most recent connection used, might no
|
||||
* longer exist */
|
||||
struct dynbuf headerb; /* buffer to store headers in */
|
||||
|
||||
char *buffer; /* download buffer */
|
||||
@@ -1563,6 +1565,7 @@ enum dupstring {
|
||||
STRING_DNS_LOCAL_IP6,
|
||||
STRING_SSL_EC_CURVES,
|
||||
STRING_AWS_SIGV4, /* Parameters for V4 signature */
|
||||
STRING_HAPROXY_CLIENT_IP, /* CURLOPT_HAPROXY_CLIENT_IP */
|
||||
|
||||
/* -- end of null-terminated strings -- */
|
||||
|
||||
@@ -1902,6 +1905,13 @@ struct Curl_easy {
|
||||
/* First a simple identifier to easier detect if a user mix up this easy
|
||||
handle with a multi handle. Set this to CURLEASY_MAGIC_NUMBER */
|
||||
unsigned int magic;
|
||||
/* once an easy handle is tied to a connection cache
|
||||
a non-negative number to distinguish this transfer from
|
||||
other using the same cache. For easier tracking
|
||||
in log output.
|
||||
This may wrap around after LONG_MAX to 0 again, so it
|
||||
has no uniqueness guarantuee for very large processings. */
|
||||
curl_off_t id;
|
||||
|
||||
/* first, two fields for the linked list of these */
|
||||
struct Curl_easy *next;
|
||||
|
||||
@@ -300,7 +300,7 @@ char *curl_version(void)
|
||||
protocol line has its own #if line to make things easier on the eye.
|
||||
*/
|
||||
|
||||
static const char * const protocols[] = {
|
||||
static const char * const supported_protocols[] = {
|
||||
#ifndef CURL_DISABLE_DICT
|
||||
"dict",
|
||||
#endif
|
||||
@@ -535,7 +535,7 @@ static curl_version_info_data version_info = {
|
||||
NULL, /* ssl_version */
|
||||
0, /* ssl_version_num, this is kept at zero */
|
||||
NULL, /* zlib_version */
|
||||
protocols,
|
||||
supported_protocols,
|
||||
NULL, /* c-ares version */
|
||||
0, /* c-ares version numerical */
|
||||
NULL, /* libidn version */
|
||||
|
||||
@@ -123,6 +123,7 @@ struct cf_msh3_ctx {
|
||||
};
|
||||
|
||||
/* How to access `call_data` from a cf_msh3 filter */
|
||||
#undef CF_CTX_CALL_DATA
|
||||
#define CF_CTX_CALL_DATA(cf) \
|
||||
((struct cf_msh3_ctx *)(cf)->ctx)->call_data
|
||||
|
||||
@@ -172,7 +173,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
|
||||
msh3_lock_initialize(&stream->recv_lock);
|
||||
Curl_bufq_init2(&stream->recvbuf, H3_STREAM_CHUNK_SIZE,
|
||||
H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
|
||||
DEBUGF(LOG_CF(data, cf, "data setup (easy %p)", (void *)data));
|
||||
DEBUGF(LOG_CF(data, cf, "data setup"));
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@@ -645,7 +646,7 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
}
|
||||
else {
|
||||
/* request is open */
|
||||
DEBUGF(LOG_CF(data, cf, "req: send %zd body bytes", len));
|
||||
DEBUGF(LOG_CF(data, cf, "req: send %zu body bytes", len));
|
||||
if(len > 0xFFFFFFFF) {
|
||||
len = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
#include <ngtcp2/ngtcp2_crypto_boringssl.h>
|
||||
#else
|
||||
#include <ngtcp2/ngtcp2_crypto_openssl.h>
|
||||
#include <ngtcp2/ngtcp2_crypto_quictls.h>
|
||||
#endif
|
||||
#include "vtls/openssl.h"
|
||||
#elif defined(USE_GNUTLS)
|
||||
@@ -165,17 +165,19 @@ struct cf_ngtcp2_ctx {
|
||||
};
|
||||
|
||||
/* How to access `call_data` from a cf_ngtcp2 filter */
|
||||
#undef CF_CTX_CALL_DATA
|
||||
#define CF_CTX_CALL_DATA(cf) \
|
||||
((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data
|
||||
|
||||
/**
|
||||
* All about the H3 internals of a stream
|
||||
*/
|
||||
struct stream_ctx {
|
||||
struct h3_stream_ctx {
|
||||
int64_t id; /* HTTP/3 protocol identifier */
|
||||
struct bufq sendbuf; /* h3 request body */
|
||||
struct bufq recvbuf; /* h3 response body */
|
||||
size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
|
||||
size_t upload_blocked_len; /* the amount written last and EGAINed */
|
||||
size_t recv_buf_nonflow; /* buffered bytes, not counting for flow control */
|
||||
uint64_t error3; /* HTTP/3 stream error code */
|
||||
curl_off_t upload_left; /* number of request bytes left to upload */
|
||||
@@ -186,18 +188,18 @@ struct stream_ctx {
|
||||
bool send_closed; /* stream is local closed */
|
||||
};
|
||||
|
||||
#define H3_STREAM_CTX(d) ((struct stream_ctx *)(((d) && (d)->req.p.http)? \
|
||||
((struct HTTP *)(d)->req.p.http)->h3_ctx \
|
||||
: NULL))
|
||||
#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx
|
||||
#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \
|
||||
H3_STREAM_CTX(d)->id : -2)
|
||||
#define H3_STREAM_CTX(d) ((struct h3_stream_ctx *)(((d) && (d)->req.p.http)? \
|
||||
((struct HTTP *)(d)->req.p.http)->h3_ctx \
|
||||
: NULL))
|
||||
#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx
|
||||
#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \
|
||||
H3_STREAM_CTX(d)->id : -2)
|
||||
|
||||
static CURLcode h3_data_setup(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
|
||||
if(!data || !data->req.p.http) {
|
||||
failf(data, "initialization failure, transfer not http initialized");
|
||||
@@ -223,13 +225,13 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
|
||||
stream->recv_buf_nonflow = 0;
|
||||
|
||||
H3_STREAM_LCTX(data) = stream;
|
||||
DEBUGF(LOG_CF(data, cf, "data setup (easy %p)", (void *)data));
|
||||
DEBUGF(LOG_CF(data, cf, "data setup"));
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
|
||||
(void)cf;
|
||||
if(stream) {
|
||||
@@ -246,10 +248,37 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
the maximum packet burst to MAX_PKT_BURST packets. */
|
||||
#define MAX_PKT_BURST 10
|
||||
|
||||
static CURLcode cf_process_ingress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
struct pkt_io_ctx {
|
||||
struct Curl_cfilter *cf;
|
||||
struct Curl_easy *data;
|
||||
ngtcp2_tstamp ts;
|
||||
size_t pkt_count;
|
||||
ngtcp2_path_storage ps;
|
||||
};
|
||||
|
||||
static ngtcp2_tstamp timestamp(void)
|
||||
{
|
||||
struct curltime ct = Curl_now();
|
||||
return ct.tv_sec * NGTCP2_SECONDS + ct.tv_usec * NGTCP2_MICROSECONDS;
|
||||
}
|
||||
|
||||
static void pktx_init(struct pkt_io_ctx *pktx,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
pktx->cf = cf;
|
||||
pktx->data = data;
|
||||
pktx->ts = timestamp();
|
||||
pktx->pkt_count = 0;
|
||||
ngtcp2_path_storage_zero(&pktx->ps);
|
||||
}
|
||||
|
||||
static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct pkt_io_ctx *pktx);
|
||||
static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct pkt_io_ctx *pktx);
|
||||
static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
|
||||
uint64_t datalen, void *user_data,
|
||||
void *stream_user_data);
|
||||
@@ -261,12 +290,6 @@ static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref)
|
||||
return ctx->qconn;
|
||||
}
|
||||
|
||||
static ngtcp2_tstamp timestamp(void)
|
||||
{
|
||||
struct curltime ct = Curl_now();
|
||||
return ct.tv_sec * NGTCP2_SECONDS + ct.tv_usec * NGTCP2_MICROSECONDS;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_NGTCP2
|
||||
static void quic_printf(void *user_data, const char *fmt, ...)
|
||||
{
|
||||
@@ -300,7 +323,8 @@ static void qlog_callback(void *user_data, uint32_t flags,
|
||||
}
|
||||
|
||||
static void quic_settings(struct cf_ngtcp2_ctx *ctx,
|
||||
struct Curl_easy *data)
|
||||
struct Curl_easy *data,
|
||||
struct pkt_io_ctx *pktx)
|
||||
{
|
||||
ngtcp2_settings *s = &ctx->settings;
|
||||
ngtcp2_transport_params *t = &ctx->transport_params;
|
||||
@@ -314,7 +338,7 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx,
|
||||
#endif
|
||||
|
||||
(void)data;
|
||||
s->initial_ts = timestamp();
|
||||
s->initial_ts = pktx->ts;
|
||||
s->handshake_timeout = QUIC_HANDSHAKE_TIMEOUT;
|
||||
s->max_window = 100 * ctx->max_stream_window;
|
||||
s->max_stream_window = ctx->max_stream_window;
|
||||
@@ -327,7 +351,7 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx,
|
||||
t->initial_max_streams_uni = QUIC_MAX_STREAMS;
|
||||
t->max_idle_timeout = QUIC_IDLE_TIMEOUT;
|
||||
if(ctx->qlogfd != -1) {
|
||||
s->qlog.write = qlog_callback;
|
||||
s->qlog_write = qlog_callback;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,8 +407,8 @@ static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx,
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
if(ngtcp2_crypto_openssl_configure_client_context(ssl_ctx) != 0) {
|
||||
failf(data, "ngtcp2_crypto_openssl_configure_client_context failed");
|
||||
if(ngtcp2_crypto_quictls_configure_client_context(ssl_ctx) != 0) {
|
||||
failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
@@ -686,7 +710,7 @@ static void report_consumed_data(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
size_t consumed)
|
||||
{
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
|
||||
if(!stream)
|
||||
@@ -902,13 +926,13 @@ static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_crypto_level level,
|
||||
static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_encryption_level level,
|
||||
void *user_data)
|
||||
{
|
||||
struct Curl_cfilter *cf = user_data;
|
||||
(void)tconn;
|
||||
|
||||
if(level != NGTCP2_CRYPTO_LEVEL_APPLICATION) {
|
||||
if(level != NGTCP2_ENCRYPTION_LEVEL_1RTT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -962,6 +986,61 @@ static ngtcp2_callbacks ng_callbacks = {
|
||||
NULL, /* early_data_rejected */
|
||||
};
|
||||
|
||||
/**
|
||||
* Connection maintenance like timeouts on packet ACKs etc. are done by us, not
|
||||
* the OS like for TCP. POLL events on the socket therefore are not
|
||||
* sufficient.
|
||||
* ngtcp2 tells us when it wants to be invoked again. We handle that via
|
||||
* the `Curl_expire()` mechanisms.
|
||||
*/
|
||||
static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct pkt_io_ctx *pktx)
|
||||
{
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
struct pkt_io_ctx local_pktx;
|
||||
ngtcp2_tstamp expiry;
|
||||
|
||||
if(!pktx) {
|
||||
pktx_init(&local_pktx, cf, data);
|
||||
pktx = &local_pktx;
|
||||
}
|
||||
else {
|
||||
pktx->ts = timestamp();
|
||||
}
|
||||
|
||||
expiry = ngtcp2_conn_get_expiry(ctx->qconn);
|
||||
if(expiry != UINT64_MAX) {
|
||||
if(expiry <= pktx->ts) {
|
||||
CURLcode result;
|
||||
int rv = ngtcp2_conn_handle_expiry(ctx->qconn, pktx->ts);
|
||||
if(rv) {
|
||||
failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
|
||||
ngtcp2_strerror(rv));
|
||||
ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0);
|
||||
return CURLE_SEND_ERROR;
|
||||
}
|
||||
result = cf_progress_ingress(cf, data, pktx);
|
||||
if(result)
|
||||
return result;
|
||||
result = cf_progress_egress(cf, data, pktx);
|
||||
if(result)
|
||||
return result;
|
||||
/* ask again, things might have changed */
|
||||
expiry = ngtcp2_conn_get_expiry(ctx->qconn);
|
||||
}
|
||||
|
||||
if(expiry > pktx->ts) {
|
||||
ngtcp2_duration timeout = expiry - pktx->ts;
|
||||
if(timeout % NGTCP2_MILLISECONDS) {
|
||||
timeout += NGTCP2_MILLISECONDS;
|
||||
}
|
||||
Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);
|
||||
}
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static int cf_ngtcp2_get_select_socks(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
curl_socket_t *socks)
|
||||
@@ -969,7 +1048,7 @@ static int cf_ngtcp2_get_select_socks(struct Curl_cfilter *cf,
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
struct SingleRequest *k = &data->req;
|
||||
int rv = GETSOCK_BLANK;
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct cf_call_data save;
|
||||
|
||||
CF_DATA_SAVE(save, cf, data);
|
||||
@@ -991,15 +1070,15 @@ static int cf_ngtcp2_get_select_socks(struct Curl_cfilter *cf,
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void drain_stream(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
static void h3_drain_stream(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
unsigned char bits;
|
||||
|
||||
(void)cf;
|
||||
bits = CURL_CSELECT_IN;
|
||||
if(stream && !stream->send_closed && stream->upload_left)
|
||||
if(stream && stream->upload_left && !stream->send_closed)
|
||||
bits |= CURL_CSELECT_OUT;
|
||||
if(data->state.dselect_bits != bits) {
|
||||
data->state.dselect_bits = bits;
|
||||
@@ -1013,7 +1092,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
|
||||
{
|
||||
struct Curl_cfilter *cf = user_data;
|
||||
struct Curl_easy *data = stream_user_data;
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
(void)conn;
|
||||
(void)stream_id;
|
||||
(void)app_error_code;
|
||||
@@ -1031,7 +1110,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
|
||||
stream->reset = TRUE;
|
||||
stream->send_closed = TRUE;
|
||||
}
|
||||
drain_stream(cf, data);
|
||||
h3_drain_stream(cf, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1045,7 +1124,7 @@ static CURLcode write_resp_raw(struct Curl_cfilter *cf,
|
||||
const void *mem, size_t memlen,
|
||||
bool flow)
|
||||
{
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
CURLcode result = CURLE_OK;
|
||||
ssize_t nwritten;
|
||||
|
||||
@@ -1085,7 +1164,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
|
||||
(void)stream3_id;
|
||||
|
||||
result = write_resp_raw(cf, data, buf, buflen, TRUE);
|
||||
drain_stream(cf, data);
|
||||
h3_drain_stream(cf, data);
|
||||
return result? -1 : 0;
|
||||
}
|
||||
|
||||
@@ -1110,7 +1189,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
|
||||
{
|
||||
struct Curl_cfilter *cf = user_data;
|
||||
struct Curl_easy *data = stream_user_data;
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
CURLcode result = CURLE_OK;
|
||||
(void)conn;
|
||||
(void)stream_id;
|
||||
@@ -1130,7 +1209,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
|
||||
if(stream->status_code / 100 != 1) {
|
||||
stream->resp_hds_complete = TRUE;
|
||||
}
|
||||
drain_stream(cf, data);
|
||||
h3_drain_stream(cf, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1143,7 +1222,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
|
||||
nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
|
||||
nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
|
||||
struct Curl_easy *data = stream_user_data;
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
CURLcode result = CURLE_OK;
|
||||
(void)conn;
|
||||
(void)stream_id;
|
||||
@@ -1207,7 +1286,8 @@ static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id,
|
||||
(void)conn;
|
||||
(void)stream_user_data;
|
||||
|
||||
rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, stream_id, app_error_code);
|
||||
rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, 0, stream_id,
|
||||
app_error_code);
|
||||
if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
@@ -1225,7 +1305,7 @@ static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id,
|
||||
(void)conn;
|
||||
(void)data;
|
||||
|
||||
rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, stream_id,
|
||||
rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, 0, stream_id,
|
||||
app_error_code);
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] reset -> %d", stream_id, rv));
|
||||
if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
|
||||
@@ -1249,7 +1329,8 @@ static nghttp3_callbacks ngh3_callbacks = {
|
||||
cb_h3_stop_sending,
|
||||
NULL, /* end_stream */
|
||||
cb_h3_reset_stream,
|
||||
NULL /* shutdown */
|
||||
NULL, /* shutdown */
|
||||
NULL /* recv_settings */
|
||||
};
|
||||
|
||||
static int init_ngh3_conn(struct Curl_cfilter *cf)
|
||||
@@ -1314,7 +1395,7 @@ fail:
|
||||
|
||||
static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct stream_ctx *stream,
|
||||
struct h3_stream_ctx *stream,
|
||||
CURLcode *err)
|
||||
{
|
||||
ssize_t nread = -1;
|
||||
@@ -1364,9 +1445,10 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
char *buf, size_t len, CURLcode *err)
|
||||
{
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
ssize_t nread = -1;
|
||||
struct cf_call_data save;
|
||||
struct pkt_io_ctx pktx;
|
||||
|
||||
(void)ctx;
|
||||
|
||||
@@ -1377,6 +1459,8 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
DEBUGASSERT(ctx->h3conn);
|
||||
*err = CURLE_OK;
|
||||
|
||||
pktx_init(&pktx, cf, data);
|
||||
|
||||
if(!stream) {
|
||||
*err = CURLE_RECV_ERROR;
|
||||
goto out;
|
||||
@@ -1392,7 +1476,7 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
report_consumed_data(cf, data, nread);
|
||||
}
|
||||
|
||||
if(cf_process_ingress(cf, data)) {
|
||||
if(cf_progress_ingress(cf, data, &pktx)) {
|
||||
*err = CURLE_RECV_ERROR;
|
||||
nread = -1;
|
||||
goto out;
|
||||
@@ -1410,7 +1494,7 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
}
|
||||
|
||||
if(nread > 0) {
|
||||
drain_stream(cf, data);
|
||||
h3_drain_stream(cf, data);
|
||||
}
|
||||
else {
|
||||
if(stream->closed) {
|
||||
@@ -1422,10 +1506,17 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
}
|
||||
|
||||
out:
|
||||
if(cf_flush_egress(cf, data)) {
|
||||
if(cf_progress_egress(cf, data, &pktx)) {
|
||||
*err = CURLE_SEND_ERROR;
|
||||
nread = -1;
|
||||
}
|
||||
else {
|
||||
CURLcode result2 = check_and_set_expiry(cf, data, &pktx);
|
||||
if(result2) {
|
||||
*err = result2;
|
||||
nread = -1;
|
||||
}
|
||||
}
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] cf_recv(len=%zu) -> %zd, %d",
|
||||
stream? stream->id : -1, len, nread, *err));
|
||||
CF_DATA_RESTORE(cf, save);
|
||||
@@ -1438,7 +1529,7 @@ static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
|
||||
{
|
||||
struct Curl_cfilter *cf = user_data;
|
||||
struct Curl_easy *data = stream_user_data;
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
size_t skiplen;
|
||||
|
||||
(void)cf;
|
||||
@@ -1454,10 +1545,8 @@ static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
|
||||
Curl_bufq_skip(&stream->sendbuf, skiplen);
|
||||
stream->sendbuf_len_in_flight -= skiplen;
|
||||
|
||||
/* `sendbuf` *might* now have more room. If so, resume this
|
||||
* possibly paused stream. And also tell our transfer engine that
|
||||
* it may continue KEEP_SEND if told to PAUSE. */
|
||||
if(!Curl_bufq_is_full(&stream->sendbuf)) {
|
||||
/* Everything ACKed, we resume upload processing */
|
||||
if(!stream->sendbuf_len_in_flight) {
|
||||
int rv = nghttp3_conn_resume_stream(conn, stream_id);
|
||||
if(rv) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
@@ -1465,7 +1554,7 @@ static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
|
||||
if((data->req.keepon & KEEP_SEND_HOLD) &&
|
||||
(data->req.keepon & KEEP_SEND)) {
|
||||
data->req.keepon &= ~KEEP_SEND_HOLD;
|
||||
drain_stream(cf, data);
|
||||
h3_drain_stream(cf, data);
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] unpausing acks",
|
||||
stream_id));
|
||||
}
|
||||
@@ -1481,7 +1570,7 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
|
||||
{
|
||||
struct Curl_cfilter *cf = user_data;
|
||||
struct Curl_easy *data = stream_user_data;
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
ssize_t nwritten = 0;
|
||||
size_t nvecs = 0;
|
||||
(void)cf;
|
||||
@@ -1530,8 +1619,10 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
|
||||
}
|
||||
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] read req body -> "
|
||||
"%d vecs%s with %zu (buffered=%zu, left=%zd)", stream->id,
|
||||
(int)nvecs, *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
|
||||
"%d vecs%s with %zu (buffered=%zu, left=%"
|
||||
CURL_FORMAT_CURL_OFF_T ")",
|
||||
stream->id, (int)nvecs,
|
||||
*pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
|
||||
nwritten, Curl_bufq_len(&stream->sendbuf),
|
||||
stream->upload_left));
|
||||
return (nghttp3_ssize)nvecs;
|
||||
@@ -1547,7 +1638,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
|
||||
CURLcode *err)
|
||||
{
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
struct stream_ctx *stream = NULL;
|
||||
struct h3_stream_ctx *stream = NULL;
|
||||
struct h1_req_parser h1;
|
||||
struct dynhds h2_headers;
|
||||
size_t nheader;
|
||||
@@ -1614,16 +1705,19 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
|
||||
else
|
||||
/* data sending without specifying the data amount up front */
|
||||
stream->upload_left = -1; /* unknown */
|
||||
reader.read_data = cb_h3_read_req_body;
|
||||
preader = &reader;
|
||||
break;
|
||||
default:
|
||||
/* there is not request body */
|
||||
stream->upload_left = 0; /* no request body */
|
||||
preader = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
stream->send_closed = (stream->upload_left == 0);
|
||||
if(!stream->send_closed) {
|
||||
reader.read_data = cb_h3_read_req_body;
|
||||
preader = &reader;
|
||||
}
|
||||
|
||||
rc = nghttp3_conn_submit_request(ctx->h3conn, stream->id,
|
||||
nva, nheader, preader, data);
|
||||
if(rc) {
|
||||
@@ -1642,8 +1736,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
|
||||
goto out;
|
||||
}
|
||||
|
||||
infof(data, "Using HTTP/3 Stream ID: %" PRId64 " (easy handle %p)",
|
||||
stream->id, (void *)data);
|
||||
infof(data, "Using HTTP/3 Stream ID: %" PRId64, stream->id);
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] opened for %s",
|
||||
stream->id, data->state.url));
|
||||
|
||||
@@ -1658,20 +1751,23 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *buf, size_t len, CURLcode *err)
|
||||
{
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
ssize_t sent = 0;
|
||||
struct cf_call_data save;
|
||||
struct pkt_io_ctx pktx;
|
||||
CURLcode result;
|
||||
|
||||
CF_DATA_SAVE(save, cf, data);
|
||||
DEBUGASSERT(cf->connected);
|
||||
DEBUGASSERT(ctx->qconn);
|
||||
DEBUGASSERT(ctx->h3conn);
|
||||
pktx_init(&pktx, cf, data);
|
||||
*err = CURLE_OK;
|
||||
|
||||
if(stream && stream->closed) {
|
||||
*err = CURLE_HTTP3;
|
||||
result = cf_progress_ingress(cf, data, &pktx);
|
||||
if(result) {
|
||||
*err = result;
|
||||
sent = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(!stream || stream->id < 0) {
|
||||
@@ -1681,32 +1777,66 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if(stream->upload_blocked_len) {
|
||||
/* the data in `buf` has alread been submitted or added to the
|
||||
* buffers, but have been EAGAINed on the last invocation. */
|
||||
DEBUGASSERT(len >= stream->upload_blocked_len);
|
||||
if(len < stream->upload_blocked_len) {
|
||||
/* Did we get called again with a smaller `len`? This should not
|
||||
* happen. We are not prepared to handle that. */
|
||||
failf(data, "HTTP/3 send again with decreased length");
|
||||
*err = CURLE_HTTP3;
|
||||
sent = -1;
|
||||
goto out;
|
||||
}
|
||||
sent = (ssize_t)stream->upload_blocked_len;
|
||||
stream->upload_blocked_len = 0;
|
||||
}
|
||||
else if(stream->closed) {
|
||||
*err = CURLE_HTTP3;
|
||||
sent = -1;
|
||||
goto out;
|
||||
}
|
||||
else {
|
||||
sent = Curl_bufq_write(&stream->sendbuf, buf, len, err);
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] cf_send, add to "
|
||||
"sendbuf(len=%zu) -> %zd, %d",
|
||||
stream->id, len, sent, *err));
|
||||
if(sent < 0) {
|
||||
if(*err == CURLE_AGAIN) {
|
||||
/* Can't add more to the send buf, needs to drain first.
|
||||
* Pause the sending to avoid a busy loop. */
|
||||
data->req.keepon |= KEEP_SEND_HOLD;
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] pause send",
|
||||
stream->id));
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
(void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
|
||||
}
|
||||
|
||||
if(cf_flush_egress(cf, data)) {
|
||||
*err = CURLE_SEND_ERROR;
|
||||
result = cf_progress_egress(cf, data, &pktx);
|
||||
if(result) {
|
||||
*err = result;
|
||||
sent = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(stream && sent > 0 && stream->sendbuf_len_in_flight) {
|
||||
/* We have unacknowledged DATA and cannot report success to our
|
||||
* caller. Instead we EAGAIN and remember how much we have already
|
||||
* "written" into our various internal connection buffers.
|
||||
* We put the stream upload on HOLD, until this gets ACKed. */
|
||||
stream->upload_blocked_len = sent;
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] cf_send(len=%zu), "
|
||||
"%zu bytes in flight -> EGAIN", stream->id, len,
|
||||
stream->sendbuf_len_in_flight));
|
||||
*err = CURLE_AGAIN;
|
||||
sent = -1;
|
||||
data->req.keepon |= KEEP_SEND_HOLD;
|
||||
}
|
||||
|
||||
out:
|
||||
result = check_and_set_expiry(cf, data, &pktx);
|
||||
if(result) {
|
||||
*err = result;
|
||||
sent = -1;
|
||||
}
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] cf_send(len=%zu) -> %zd, %d",
|
||||
stream? stream->id : -1, len, sent, *err));
|
||||
CF_DATA_RESTORE(cf, save);
|
||||
return sent;
|
||||
}
|
||||
@@ -1763,34 +1893,27 @@ static CURLcode qng_verify_peer(struct Curl_cfilter *cf,
|
||||
return result;
|
||||
}
|
||||
|
||||
struct recv_ctx {
|
||||
struct Curl_cfilter *cf;
|
||||
struct Curl_easy *data;
|
||||
ngtcp2_tstamp ts;
|
||||
size_t pkt_count;
|
||||
};
|
||||
|
||||
static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
|
||||
struct sockaddr_storage *remote_addr,
|
||||
socklen_t remote_addrlen, int ecn,
|
||||
void *userp)
|
||||
{
|
||||
struct recv_ctx *r = userp;
|
||||
struct cf_ngtcp2_ctx *ctx = r->cf->ctx;
|
||||
struct pkt_io_ctx *pktx = userp;
|
||||
struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx;
|
||||
ngtcp2_pkt_info pi;
|
||||
ngtcp2_path path;
|
||||
int rv;
|
||||
|
||||
++r->pkt_count;
|
||||
++pktx->pkt_count;
|
||||
ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr,
|
||||
ctx->q.local_addrlen);
|
||||
ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr,
|
||||
remote_addrlen);
|
||||
pi.ecn = (uint32_t)ecn;
|
||||
|
||||
rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, r->ts);
|
||||
rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts);
|
||||
if(rv) {
|
||||
DEBUGF(LOG_CF(r->data, r->cf, "ingress, read_pkt -> %s",
|
||||
DEBUGF(LOG_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s",
|
||||
ngtcp2_strerror(rv)));
|
||||
if(!ctx->last_error.error_code) {
|
||||
if(rv == NGTCP2_ERR_CRYPTO) {
|
||||
@@ -1813,41 +1936,40 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode cf_process_ingress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct pkt_io_ctx *pktx)
|
||||
{
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
struct recv_ctx rctx;
|
||||
struct pkt_io_ctx local_pktx;
|
||||
size_t pkts_chunk = 128, i;
|
||||
size_t pkts_max = 10 * pkts_chunk;
|
||||
CURLcode result;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
rctx.cf = cf;
|
||||
rctx.data = data;
|
||||
rctx.ts = timestamp();
|
||||
rctx.pkt_count = 0;
|
||||
if(!pktx) {
|
||||
pktx_init(&local_pktx, cf, data);
|
||||
pktx = &local_pktx;
|
||||
}
|
||||
else {
|
||||
pktx->ts = timestamp();
|
||||
}
|
||||
|
||||
for(i = 0; i < pkts_max; i += pkts_chunk) {
|
||||
rctx.pkt_count = 0;
|
||||
pktx->pkt_count = 0;
|
||||
result = vquic_recv_packets(cf, data, &ctx->q, pkts_chunk,
|
||||
recv_pkt, &rctx);
|
||||
recv_pkt, pktx);
|
||||
if(result) /* error */
|
||||
break;
|
||||
if(rctx.pkt_count < pkts_chunk) /* got less than we could */
|
||||
if(pktx->pkt_count < pkts_chunk) /* got less than we could */
|
||||
break;
|
||||
/* give egress a chance before we receive more */
|
||||
result = cf_flush_egress(cf, data);
|
||||
result = cf_progress_egress(cf, data, pktx);
|
||||
if(result) /* error */
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct read_ctx {
|
||||
struct Curl_cfilter *cf;
|
||||
struct Curl_easy *data;
|
||||
ngtcp2_tstamp ts;
|
||||
ngtcp2_path_storage *ps;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read a network packet to send from ngtcp2 into `buf`.
|
||||
* Return number of bytes written or -1 with *err set.
|
||||
@@ -1856,7 +1978,7 @@ static ssize_t read_pkt_to_send(void *userp,
|
||||
unsigned char *buf, size_t buflen,
|
||||
CURLcode *err)
|
||||
{
|
||||
struct read_ctx *x = userp;
|
||||
struct pkt_io_ctx *x = userp;
|
||||
struct cf_ngtcp2_ctx *ctx = x->cf->ctx;
|
||||
nghttp3_vec vec[16];
|
||||
nghttp3_ssize veccnt;
|
||||
@@ -1896,7 +2018,7 @@ static ssize_t read_pkt_to_send(void *userp,
|
||||
|
||||
flags = NGTCP2_WRITE_STREAM_FLAG_MORE |
|
||||
(fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0);
|
||||
n = ngtcp2_conn_writev_stream(ctx->qconn, x->ps? &x->ps->path : NULL,
|
||||
n = ngtcp2_conn_writev_stream(ctx->qconn, &x->ps.path,
|
||||
NULL, buf, buflen,
|
||||
&ndatalen, flags, stream_id,
|
||||
(const ngtcp2_vec *)vec, veccnt, x->ts);
|
||||
@@ -1955,28 +2077,25 @@ out:
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct pkt_io_ctx *pktx)
|
||||
{
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
int rv;
|
||||
ssize_t nread;
|
||||
size_t max_payload_size, path_max_payload_size, max_pktcnt;
|
||||
size_t pktcnt = 0;
|
||||
size_t gsolen = 0; /* this disables gso until we have a clue */
|
||||
ngtcp2_path_storage ps;
|
||||
ngtcp2_tstamp ts = timestamp();
|
||||
ngtcp2_tstamp expiry;
|
||||
ngtcp2_duration timeout;
|
||||
CURLcode curlcode;
|
||||
struct read_ctx readx;
|
||||
struct pkt_io_ctx local_pktx;
|
||||
|
||||
rv = ngtcp2_conn_handle_expiry(ctx->qconn, ts);
|
||||
if(rv) {
|
||||
failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
|
||||
ngtcp2_strerror(rv));
|
||||
ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0);
|
||||
return CURLE_SEND_ERROR;
|
||||
if(!pktx) {
|
||||
pktx_init(&local_pktx, cf, data);
|
||||
pktx = &local_pktx;
|
||||
}
|
||||
else {
|
||||
pktx->ts = timestamp();
|
||||
ngtcp2_path_storage_zero(&pktx->ps);
|
||||
}
|
||||
|
||||
curlcode = vquic_flush(cf, data, &ctx->q);
|
||||
@@ -1988,8 +2107,6 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
|
||||
return curlcode;
|
||||
}
|
||||
|
||||
ngtcp2_path_storage_zero(&ps);
|
||||
|
||||
/* In UDP, there is a maximum theoretical packet paload length and
|
||||
* a minimum payload length that is "guarantueed" to work.
|
||||
* To detect if this minimum payload can be increased, ngtcp2 sends
|
||||
@@ -2008,15 +2125,10 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
|
||||
max_pktcnt = CURLMIN(MAX_PKT_BURST,
|
||||
ctx->q.sendbuf.chunk_size / max_payload_size);
|
||||
|
||||
readx.cf = cf;
|
||||
readx.data = data;
|
||||
readx.ts = ts;
|
||||
readx.ps = &ps;
|
||||
|
||||
for(;;) {
|
||||
/* add the next packet to send, if any, to our buffer */
|
||||
nread = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size,
|
||||
read_pkt_to_send, &readx, &curlcode);
|
||||
read_pkt_to_send, pktx, &curlcode);
|
||||
/* DEBUGF(LOG_CF(data, cf, "sip packet(maxlen=%zu) -> %zd, %d",
|
||||
max_payload_size, nread, curlcode)); */
|
||||
if(nread < 0) {
|
||||
@@ -2076,21 +2188,6 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
|
||||
}
|
||||
|
||||
out:
|
||||
/* non-errored exit. check when we should run again. */
|
||||
expiry = ngtcp2_conn_get_expiry(ctx->qconn);
|
||||
if(expiry != UINT64_MAX) {
|
||||
if(expiry <= ts) {
|
||||
timeout = 0;
|
||||
}
|
||||
else {
|
||||
timeout = expiry - ts;
|
||||
if(timeout % NGTCP2_MILLISECONDS) {
|
||||
timeout += NGTCP2_MILLISECONDS;
|
||||
}
|
||||
}
|
||||
Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@@ -2101,7 +2198,7 @@ out:
|
||||
static bool cf_ngtcp2_data_pending(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
const struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
const struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
(void)cf;
|
||||
return stream && !Curl_bufq_is_empty(&stream->recvbuf);
|
||||
}
|
||||
@@ -2113,7 +2210,7 @@ static CURLcode h3_data_pause(struct Curl_cfilter *cf,
|
||||
/* TODO: there seems right now no API in ngtcp2 to shrink/enlarge
|
||||
* the streams windows. As we do in HTTP/2. */
|
||||
if(!pause) {
|
||||
drain_stream(cf, data);
|
||||
h3_drain_stream(cf, data);
|
||||
Curl_expire(data, 0, EXPIRE_RUN_NOW);
|
||||
}
|
||||
return CURLE_OK;
|
||||
@@ -2141,7 +2238,7 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
|
||||
break;
|
||||
}
|
||||
case CF_CTRL_DATA_DONE_SEND: {
|
||||
struct stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
|
||||
if(stream && !stream->send_closed) {
|
||||
stream->send_closed = TRUE;
|
||||
stream->upload_left = Curl_bufq_len(&stream->sendbuf);
|
||||
@@ -2150,11 +2247,7 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
|
||||
break;
|
||||
}
|
||||
case CF_CTRL_DATA_IDLE:
|
||||
if(timestamp() >= ngtcp2_conn_get_expiry(ctx->qconn)) {
|
||||
if(cf_flush_egress(cf, data)) {
|
||||
result = CURLE_SEND_ERROR;
|
||||
}
|
||||
}
|
||||
result = check_and_set_expiry(cf, data, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -2250,7 +2343,8 @@ static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
* Might be called twice for happy eyeballs.
|
||||
*/
|
||||
static CURLcode cf_connect_start(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
struct Curl_easy *data,
|
||||
struct pkt_io_ctx *pktx)
|
||||
{
|
||||
struct cf_ngtcp2_ctx *ctx = cf->ctx;
|
||||
int rc;
|
||||
@@ -2294,7 +2388,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
|
||||
|
||||
(void)Curl_qlogdir(data, ctx->scid.data, NGTCP2_MAX_CIDLEN, &qfd);
|
||||
ctx->qlogfd = qfd; /* -1 if failure above */
|
||||
quic_settings(ctx, data);
|
||||
quic_settings(ctx, data, pktx);
|
||||
|
||||
result = vquic_ctx_init(&ctx->q);
|
||||
if(result)
|
||||
@@ -2344,6 +2438,7 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
|
||||
CURLcode result = CURLE_OK;
|
||||
struct cf_call_data save;
|
||||
struct curltime now;
|
||||
struct pkt_io_ctx pktx;
|
||||
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
@@ -2359,6 +2454,7 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
|
||||
|
||||
*done = FALSE;
|
||||
now = Curl_now();
|
||||
pktx_init(&pktx, cf, data);
|
||||
|
||||
CF_DATA_SAVE(save, cf, data);
|
||||
|
||||
@@ -2370,19 +2466,19 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
|
||||
|
||||
if(!ctx->qconn) {
|
||||
ctx->started_at = now;
|
||||
result = cf_connect_start(cf, data);
|
||||
result = cf_connect_start(cf, data, &pktx);
|
||||
if(result)
|
||||
goto out;
|
||||
result = cf_flush_egress(cf, data);
|
||||
result = cf_progress_egress(cf, data, &pktx);
|
||||
/* we do not expect to be able to recv anything yet */
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = cf_process_ingress(cf, data);
|
||||
result = cf_progress_ingress(cf, data, &pktx);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
result = cf_flush_egress(cf, data);
|
||||
result = cf_progress_egress(cf, data, &pktx);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
@@ -2402,7 +2498,7 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
|
||||
|
||||
out:
|
||||
if(result == CURLE_RECV_ERROR && ctx->qconn &&
|
||||
ngtcp2_conn_is_in_draining_period(ctx->qconn)) {
|
||||
ngtcp2_conn_in_draining_period(ctx->qconn)) {
|
||||
/* When a QUIC server instance is shutting down, it may send us a
|
||||
* CONNECTION_CLOSE right away. Our connection then enters the DRAINING
|
||||
* state.
|
||||
@@ -2439,6 +2535,9 @@ out:
|
||||
r_ip, r_port, curl_easy_strerror(result));
|
||||
}
|
||||
#endif
|
||||
if(!result && ctx->qconn) {
|
||||
result = check_and_set_expiry(cf, data, &pktx);
|
||||
}
|
||||
DEBUGF(LOG_CF(data, cf, "connect -> %d, done=%d", result, *done));
|
||||
CF_DATA_RESTORE(cf, save);
|
||||
return result;
|
||||
@@ -2510,13 +2609,11 @@ static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
|
||||
not in use by any other transfer, there shouldn't be any data here,
|
||||
only "protocol frames" */
|
||||
*input_pending = FALSE;
|
||||
Curl_attach_connection(data, cf->conn);
|
||||
if(cf_process_ingress(cf, data))
|
||||
if(cf_progress_ingress(cf, data, NULL))
|
||||
alive = FALSE;
|
||||
else {
|
||||
alive = TRUE;
|
||||
}
|
||||
Curl_detach_connection(data);
|
||||
}
|
||||
|
||||
return alive;
|
||||
|
||||
@@ -277,7 +277,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
|
||||
stream->id = -1;
|
||||
Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
|
||||
H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
|
||||
DEBUGF(LOG_CF(data, cf, "data setup (easy %p)", (void *)data));
|
||||
DEBUGF(LOG_CF(data, cf, "data setup"));
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
|
||||
else {
|
||||
DEBUGASSERT(data->multi);
|
||||
for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
|
||||
if(H3_STREAM_ID(sdata) == stream3_id) {
|
||||
if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream3_id) {
|
||||
return sdata;
|
||||
}
|
||||
}
|
||||
@@ -425,12 +425,8 @@ static ssize_t stream_resp_read(void *reader_ctx,
|
||||
*err = CURLE_OK;
|
||||
return nread;
|
||||
}
|
||||
else if(nread < 0) {
|
||||
*err = CURLE_AGAIN;
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
*err = stream->resp_got_header? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
|
||||
*err = CURLE_AGAIN;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -461,8 +457,8 @@ static CURLcode cf_recv_body(struct Curl_cfilter *cf,
|
||||
if(nwritten < 0 && result != CURLE_AGAIN) {
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%"PRId64"] recv_body error %zd",
|
||||
stream->id, nwritten));
|
||||
failf(data, "Error %zd in HTTP/3 response body for stream[%"PRId64"]",
|
||||
nwritten, stream->id);
|
||||
failf(data, "Error %d in HTTP/3 response body for stream[%"PRId64"]",
|
||||
result, stream->id);
|
||||
stream->closed = TRUE;
|
||||
stream->reset = TRUE;
|
||||
stream->send_closed = TRUE;
|
||||
@@ -595,8 +591,13 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf,
|
||||
"for [h3sid=%"PRId64"] -> %d",
|
||||
stream? stream->id : -1, cf_ev_name(ev),
|
||||
stream3_id, result));
|
||||
quiche_h3_event_free(ev);
|
||||
return result;
|
||||
if(data == sdata) {
|
||||
/* Only report this error to the caller if it is about the
|
||||
* transfer we were called with. Otherwise we fail a transfer
|
||||
* due to a problem in another one. */
|
||||
quiche_h3_event_free(ev);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
quiche_h3_event_free(ev);
|
||||
}
|
||||
@@ -649,7 +650,7 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
|
||||
}
|
||||
}
|
||||
else if((size_t)nread < pktlen) {
|
||||
DEBUGF(LOG_CF(r->data, r->cf, "ingress, quiche only read %zd/%zd bytes",
|
||||
DEBUGF(LOG_CF(r->data, r->cf, "ingress, quiche only read %zd/%zu bytes",
|
||||
nread, pktlen));
|
||||
}
|
||||
|
||||
@@ -826,7 +827,7 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
|
||||
if(!stream) {
|
||||
*err = CURLE_RECV_ERROR;
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!Curl_bufq_is_empty(&stream->recvbuf)) {
|
||||
@@ -883,8 +884,10 @@ out:
|
||||
}
|
||||
if(nread > 0)
|
||||
ctx->data_recvd += nread;
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%"PRId64"] cf_recv(total=%zd) -> %zd, %d",
|
||||
stream->id, ctx->data_recvd, nread, *err));
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%"PRId64"] cf_recv(total=%"
|
||||
CURL_FORMAT_CURL_OFF_T ") -> %zd, %d",
|
||||
stream ? stream->id : (int64_t)0,
|
||||
ctx->data_recvd, nread, *err));
|
||||
return nread;
|
||||
}
|
||||
|
||||
@@ -909,8 +912,7 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
|
||||
if(!stream) {
|
||||
*err = h3_data_setup(cf, data);
|
||||
if(*err) {
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
stream = H3_STREAM_CTX(data);
|
||||
DEBUGASSERT(stream);
|
||||
@@ -995,8 +997,7 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
|
||||
stream->closed = FALSE;
|
||||
stream->reset = FALSE;
|
||||
|
||||
infof(data, "Using HTTP/3 Stream ID: %" PRId64 " (easy handle %p)",
|
||||
stream3_id, (void *)data);
|
||||
infof(data, "Using HTTP/3 Stream ID: %" PRId64, stream3_id);
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] opened for %s",
|
||||
stream3_id, data->state.url));
|
||||
|
||||
@@ -1068,7 +1069,7 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
stream->send_closed = TRUE;
|
||||
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] send body(len=%zu, "
|
||||
"left=%zd) -> %zd",
|
||||
"left=%" CURL_FORMAT_CURL_OFF_T ") -> %zd",
|
||||
stream->id, len, stream->upload_left, nwritten));
|
||||
*err = CURLE_OK;
|
||||
}
|
||||
@@ -1151,10 +1152,8 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
|
||||
(void)arg1;
|
||||
(void)arg2;
|
||||
switch(event) {
|
||||
case CF_CTRL_DATA_SETUP: {
|
||||
result = h3_data_setup(cf, data);
|
||||
case CF_CTRL_DATA_SETUP:
|
||||
break;
|
||||
}
|
||||
case CF_CTRL_DATA_PAUSE:
|
||||
result = h3_data_pause(cf, data, (arg1 != 0));
|
||||
break;
|
||||
@@ -1343,11 +1342,6 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* we do not get a setup event for the initial transfer */
|
||||
result = h3_data_setup(cf, data);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = cf_flush_egress(cf, data);
|
||||
if(result)
|
||||
return result;
|
||||
@@ -1555,13 +1549,11 @@ static bool cf_quiche_conn_is_alive(struct Curl_cfilter *cf,
|
||||
not in use by any other transfer, there shouldn't be any data here,
|
||||
only "protocol frames" */
|
||||
*input_pending = FALSE;
|
||||
Curl_attach_connection(data, cf->conn);
|
||||
if(cf_process_ingress(cf, data))
|
||||
alive = FALSE;
|
||||
else {
|
||||
alive = TRUE;
|
||||
}
|
||||
Curl_detach_connection(data);
|
||||
}
|
||||
|
||||
return alive;
|
||||
|
||||
@@ -362,7 +362,7 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
|
||||
}
|
||||
|
||||
out:
|
||||
DEBUGF(LOG_CF(data, cf, "recvd %zu packets with %zd bytes -> %d",
|
||||
DEBUGF(LOG_CF(data, cf, "recvd %zu packets with %zu bytes -> %d",
|
||||
pkts, total_nread, result));
|
||||
return result;
|
||||
}
|
||||
@@ -425,7 +425,7 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
|
||||
}
|
||||
|
||||
out:
|
||||
DEBUGF(LOG_CF(data, cf, "recvd %zu packets with %zd bytes -> %d",
|
||||
DEBUGF(LOG_CF(data, cf, "recvd %zu packets with %zu bytes -> %d",
|
||||
pkts, total_nread, result));
|
||||
return result;
|
||||
}
|
||||
@@ -482,7 +482,7 @@ static CURLcode recvfrom_packets(struct Curl_cfilter *cf,
|
||||
}
|
||||
|
||||
out:
|
||||
DEBUGF(LOG_CF(data, cf, "recvd %zu packets with %zd bytes -> %d",
|
||||
DEBUGF(LOG_CF(data, cf, "recvd %zu packets with %zu bytes -> %d",
|
||||
pkts, total_nread, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -100,11 +100,9 @@
|
||||
|
||||
/* Local functions: */
|
||||
static const char *sftp_libssh2_strerror(unsigned long err);
|
||||
#ifdef CURL_LIBSSH2_DEBUG
|
||||
static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
|
||||
static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
|
||||
static LIBSSH2_FREE_FUNC(my_libssh2_free);
|
||||
#endif
|
||||
static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data);
|
||||
static CURLcode ssh_connect(struct Curl_easy *data, bool *done);
|
||||
static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done);
|
||||
@@ -284,8 +282,6 @@ static CURLcode libssh2_session_error_to_CURLE(int err)
|
||||
return CURLE_SSH;
|
||||
}
|
||||
|
||||
#ifdef CURL_LIBSSH2_DEBUG
|
||||
|
||||
static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc)
|
||||
{
|
||||
(void)abstract; /* arg not used */
|
||||
@@ -305,8 +301,6 @@ static LIBSSH2_FREE_FUNC(my_libssh2_free)
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SSH State machine related code
|
||||
*/
|
||||
@@ -895,6 +889,7 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
|
||||
}
|
||||
|
||||
if(found) {
|
||||
int rc;
|
||||
infof(data, "Found host %s in %s",
|
||||
conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
|
||||
|
||||
@@ -944,9 +939,15 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
|
||||
}
|
||||
|
||||
infof(data, "Set \"%s\" as SSH hostkey type", hostkey_method);
|
||||
result = libssh2_session_error_to_CURLE(
|
||||
libssh2_session_method_pref(
|
||||
sshc->ssh_session, LIBSSH2_METHOD_HOSTKEY, hostkey_method));
|
||||
rc = libssh2_session_method_pref(sshc->ssh_session,
|
||||
LIBSSH2_METHOD_HOSTKEY, hostkey_method);
|
||||
if(rc) {
|
||||
char *errmsg = NULL;
|
||||
int errlen;
|
||||
libssh2_session_last_error(sshc->ssh_session, &errmsg, &errlen, 0);
|
||||
failf(data, "libssh2: %s", errmsg);
|
||||
result = libssh2_session_error_to_CURLE(rc);
|
||||
}
|
||||
}
|
||||
else {
|
||||
infof(data, "Did not find host %s in %s",
|
||||
@@ -3268,13 +3269,12 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
|
||||
sock = conn->sock[FIRSTSOCKET];
|
||||
#endif /* CURL_LIBSSH2_DEBUG */
|
||||
|
||||
#ifdef CURL_LIBSSH2_DEBUG
|
||||
/* libcurl MUST to set custom memory functions so that the kbd_callback
|
||||
funciton's memory allocations can be properled freed */
|
||||
sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
|
||||
my_libssh2_free,
|
||||
my_libssh2_realloc, data);
|
||||
#else
|
||||
sshc->ssh_session = libssh2_session_init_ex(NULL, NULL, NULL, data);
|
||||
#endif
|
||||
|
||||
if(!sshc->ssh_session) {
|
||||
failf(data, "Failure initialising ssh session");
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
@@ -277,7 +277,7 @@ static ssize_t wsftp_send(struct Curl_easy *data, int sockindex,
|
||||
return -1;
|
||||
}
|
||||
DEBUGASSERT(rc == (int)len);
|
||||
infof(data, "sent %zd bytes SFTP from offset %zd",
|
||||
infof(data, "sent %zu bytes SFTP from offset %" CURL_FORMAT_CURL_OFF_T,
|
||||
len, sshc->offset);
|
||||
sshc->offset += len;
|
||||
return (ssize_t)rc;
|
||||
|
||||
@@ -52,7 +52,7 @@ struct x509_context {
|
||||
int cert_num;
|
||||
};
|
||||
|
||||
struct ssl_backend_data {
|
||||
struct bearssl_ssl_backend_data {
|
||||
br_ssl_client_context ctx;
|
||||
struct x509_context x509;
|
||||
unsigned char buf[BR_SSL_BUFSIZE_BIDI];
|
||||
@@ -574,7 +574,8 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct bearssl_ssl_backend_data *backend =
|
||||
(struct bearssl_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
|
||||
@@ -751,7 +752,8 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
|
||||
unsigned target)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct bearssl_ssl_backend_data *backend =
|
||||
(struct bearssl_ssl_backend_data *)connssl->backend;
|
||||
unsigned state;
|
||||
unsigned char *buf;
|
||||
size_t len;
|
||||
@@ -820,7 +822,8 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct bearssl_ssl_backend_data *backend =
|
||||
(struct bearssl_ssl_backend_data *)connssl->backend;
|
||||
CURLcode ret;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
@@ -842,7 +845,8 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct bearssl_ssl_backend_data *backend =
|
||||
(struct bearssl_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
CURLcode ret;
|
||||
|
||||
@@ -889,7 +893,8 @@ static ssize_t bearssl_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *buf, size_t len, CURLcode *err)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct bearssl_ssl_backend_data *backend =
|
||||
(struct bearssl_ssl_backend_data *)connssl->backend;
|
||||
unsigned char *app;
|
||||
size_t applen;
|
||||
|
||||
@@ -923,7 +928,8 @@ static ssize_t bearssl_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
char *buf, size_t len, CURLcode *err)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct bearssl_ssl_backend_data *backend =
|
||||
(struct bearssl_ssl_backend_data *)connssl->backend;
|
||||
unsigned char *app;
|
||||
size_t applen;
|
||||
|
||||
@@ -1050,10 +1056,12 @@ static bool bearssl_data_pending(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *ctx = cf->ctx;
|
||||
struct bearssl_ssl_backend_data *backend;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(ctx && ctx->backend);
|
||||
return br_ssl_engine_current_state(&ctx->backend->ctx.eng) & BR_SSL_RECVAPP;
|
||||
backend = (struct bearssl_ssl_backend_data *)ctx->backend;
|
||||
return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP;
|
||||
}
|
||||
|
||||
static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM,
|
||||
@@ -1101,7 +1109,8 @@ static CURLcode bearssl_connect_nonblocking(struct Curl_cfilter *cf,
|
||||
static void *bearssl_get_internals(struct ssl_connect_data *connssl,
|
||||
CURLINFO info UNUSED_PARAM)
|
||||
{
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct bearssl_ssl_backend_data *backend =
|
||||
(struct bearssl_ssl_backend_data *)connssl->backend;
|
||||
DEBUGASSERT(backend);
|
||||
return &backend->ctx;
|
||||
}
|
||||
@@ -1109,7 +1118,8 @@ static void *bearssl_get_internals(struct ssl_connect_data *connssl,
|
||||
static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct bearssl_ssl_backend_data *backend =
|
||||
(struct bearssl_ssl_backend_data *)connssl->backend;
|
||||
size_t i;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
@@ -1147,7 +1157,7 @@ static CURLcode bearssl_sha256sum(const unsigned char *input,
|
||||
const struct Curl_ssl Curl_ssl_bearssl = {
|
||||
{ CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */
|
||||
SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX | SSLSUPP_HTTPS_PROXY,
|
||||
sizeof(struct ssl_backend_data),
|
||||
sizeof(struct bearssl_ssl_backend_data),
|
||||
|
||||
Curl_none_init, /* init */
|
||||
Curl_none_cleanup, /* cleanup */
|
||||
|
||||
@@ -103,14 +103,14 @@
|
||||
#define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12)
|
||||
#define CURL_GSKPROTO_LAST 5
|
||||
|
||||
struct ssl_backend_data {
|
||||
struct gskit_ssl_backend_data {
|
||||
gsk_handle handle;
|
||||
int iocport;
|
||||
int localfd;
|
||||
int remotefd;
|
||||
};
|
||||
|
||||
#define BACKEND connssl->backend
|
||||
#define BACKEND ((struct gskit_ssl_backend_data *)connssl->backend)
|
||||
|
||||
/* Supported ciphers. */
|
||||
struct gskit_cipher {
|
||||
@@ -518,6 +518,7 @@ static int pipe_ssloverssl(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
|
||||
struct ssl_connect_data *connssl_next = cf_ssl_next?
|
||||
cf_ssl_next->ctx : NULL;
|
||||
struct gskit_ssl_backend_data *backend_next;
|
||||
struct pollfd fds[2];
|
||||
int n;
|
||||
int m;
|
||||
@@ -531,6 +532,8 @@ static int pipe_ssloverssl(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
return 0; /* No SSL over SSL: OK. */
|
||||
|
||||
DEBUGASSERT(connssl_next->backend);
|
||||
backend_next = (struct gskit_ssl_backend_data *)connssl_next->backend;
|
||||
|
||||
n = 1;
|
||||
fds[0].fd = BACKEND->remotefd;
|
||||
fds[1].fd = Curl_conn_cf_get_socket(cf, data);
|
||||
@@ -550,8 +553,7 @@ static int pipe_ssloverssl(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
if(fds[0].revents & POLLOUT) {
|
||||
/* Try getting data from HTTPS proxy and pipe it upstream. */
|
||||
n = 0;
|
||||
i = gsk_secure_soc_read(connssl_next->backend->handle,
|
||||
buf, sizeof(buf), &n);
|
||||
i = gsk_secure_soc_read(backend_next->handle, buf, sizeof(buf), &n);
|
||||
switch(i) {
|
||||
case GSK_OK:
|
||||
if(n) {
|
||||
@@ -575,7 +577,7 @@ static int pipe_ssloverssl(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
if(n < 0)
|
||||
return -1;
|
||||
if(n) {
|
||||
i = gsk_secure_soc_write(connssl_next->backend->handle, buf, n, &m);
|
||||
i = gsk_secure_soc_write(backend_next->handle, buf, n, &m);
|
||||
if(i != GSK_OK || n != m)
|
||||
return -1;
|
||||
ret = 1;
|
||||
@@ -1294,7 +1296,7 @@ const struct Curl_ssl Curl_ssl_gskit = {
|
||||
SSLSUPP_CERTINFO |
|
||||
SSLSUPP_PINNEDPUBKEY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
sizeof(struct gskit_ssl_backend_data),
|
||||
|
||||
gskit_init, /* init */
|
||||
gskit_cleanup, /* cleanup */
|
||||
|
||||
@@ -76,7 +76,7 @@ static bool gtls_inited = FALSE;
|
||||
|
||||
# include <gnutls/ocsp.h>
|
||||
|
||||
struct ssl_backend_data {
|
||||
struct gtls_ssl_backend_data {
|
||||
struct gtls_instance gtls;
|
||||
};
|
||||
|
||||
@@ -91,7 +91,9 @@ static ssize_t gtls_push(void *s, const void *buf, size_t blen)
|
||||
DEBUGASSERT(data);
|
||||
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
|
||||
if(nwritten < 0) {
|
||||
gnutls_transport_set_errno(connssl->backend->gtls.session,
|
||||
struct gtls_ssl_backend_data *backend =
|
||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||
gnutls_transport_set_errno(backend->gtls.session,
|
||||
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
|
||||
nwritten = -1;
|
||||
}
|
||||
@@ -109,7 +111,9 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen)
|
||||
DEBUGASSERT(data);
|
||||
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
|
||||
if(nread < 0) {
|
||||
gnutls_transport_set_errno(connssl->backend->gtls.session,
|
||||
struct gtls_ssl_backend_data *backend =
|
||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||
gnutls_transport_set_errno(backend->gtls.session,
|
||||
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
|
||||
nread = -1;
|
||||
}
|
||||
@@ -212,7 +216,8 @@ static CURLcode handshake(struct Curl_cfilter *cf,
|
||||
bool nonblocking)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct gtls_ssl_backend_data *backend =
|
||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||
gnutls_session_t session;
|
||||
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
|
||||
|
||||
@@ -679,7 +684,8 @@ static CURLcode
|
||||
gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct gtls_ssl_backend_data *backend =
|
||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
long * const pverifyresult = &ssl_config->certverifyresult;
|
||||
@@ -1346,7 +1352,8 @@ gtls_connect_common(struct Curl_cfilter *cf,
|
||||
|
||||
/* Finish connecting once the handshake is done */
|
||||
if(ssl_connect_1 == connssl->connecting_state) {
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct gtls_ssl_backend_data *backend =
|
||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||
gnutls_session_t session;
|
||||
DEBUGASSERT(backend);
|
||||
session = backend->gtls.session;
|
||||
@@ -1390,11 +1397,13 @@ static bool gtls_data_pending(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *ctx = cf->ctx;
|
||||
struct gtls_ssl_backend_data *backend;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(ctx && ctx->backend);
|
||||
if(ctx->backend->gtls.session &&
|
||||
0 != gnutls_record_check_pending(ctx->backend->gtls.session))
|
||||
backend = (struct gtls_ssl_backend_data *)ctx->backend;
|
||||
if(backend->gtls.session &&
|
||||
0 != gnutls_record_check_pending(backend->gtls.session))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1406,7 +1415,8 @@ static ssize_t gtls_send(struct Curl_cfilter *cf,
|
||||
CURLcode *curlcode)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct gtls_ssl_backend_data *backend =
|
||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||
ssize_t rc;
|
||||
|
||||
(void)data;
|
||||
@@ -1428,7 +1438,8 @@ static void gtls_close(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct gtls_ssl_backend_data *backend =
|
||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||
|
||||
(void) data;
|
||||
DEBUGASSERT(backend);
|
||||
@@ -1463,7 +1474,8 @@ static int gtls_shutdown(struct Curl_cfilter *cf,
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct gtls_ssl_backend_data *backend =
|
||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||
int retval = 0;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
@@ -1541,7 +1553,8 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
|
||||
CURLcode *curlcode)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct gtls_ssl_backend_data *backend =
|
||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||
ssize_t ret;
|
||||
|
||||
(void)data;
|
||||
@@ -1620,7 +1633,8 @@ static bool gtls_cert_status_request(void)
|
||||
static void *gtls_get_internals(struct ssl_connect_data *connssl,
|
||||
CURLINFO info UNUSED_PARAM)
|
||||
{
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct gtls_ssl_backend_data *backend =
|
||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||
(void)info;
|
||||
DEBUGASSERT(backend);
|
||||
return backend->gtls.session;
|
||||
@@ -1634,7 +1648,7 @@ const struct Curl_ssl Curl_ssl_gnutls = {
|
||||
SSLSUPP_PINNEDPUBKEY |
|
||||
SSLSUPP_HTTPS_PROXY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
sizeof(struct gtls_ssl_backend_data),
|
||||
|
||||
gtls_init, /* init */
|
||||
gtls_cleanup, /* cleanup */
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
struct ssl_backend_data {
|
||||
struct mbed_ssl_backend_data {
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ssl_context ssl;
|
||||
@@ -255,7 +255,8 @@ static CURLcode
|
||||
set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||
int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3;
|
||||
@@ -307,7 +308,8 @@ static CURLcode
|
||||
mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
@@ -697,7 +699,8 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
int ret;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
const mbedtls_x509_crt *peercert;
|
||||
const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
|
||||
@@ -860,7 +863,8 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
CURLcode retcode = CURLE_OK;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
|
||||
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
|
||||
@@ -915,7 +919,8 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
CURLcode *curlcode)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||
int ret = -1;
|
||||
|
||||
(void)data;
|
||||
@@ -939,7 +944,8 @@ static void mbedtls_close_all(struct Curl_easy *data)
|
||||
static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||
char buf[32];
|
||||
|
||||
(void)data;
|
||||
@@ -968,7 +974,8 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
CURLcode *curlcode)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||
int ret = -1;
|
||||
ssize_t len = -1;
|
||||
|
||||
@@ -1204,10 +1211,12 @@ static bool mbedtls_data_pending(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *ctx = cf->ctx;
|
||||
struct mbed_ssl_backend_data *backend;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(ctx && ctx->backend);
|
||||
return mbedtls_ssl_get_bytes_avail(&ctx->backend->ssl) != 0;
|
||||
backend = (struct mbed_ssl_backend_data *)ctx->backend;
|
||||
return mbedtls_ssl_get_bytes_avail(&backend->ssl) != 0;
|
||||
}
|
||||
|
||||
static CURLcode mbedtls_sha256sum(const unsigned char *input,
|
||||
@@ -1234,7 +1243,8 @@ static CURLcode mbedtls_sha256sum(const unsigned char *input,
|
||||
static void *mbedtls_get_internals(struct ssl_connect_data *connssl,
|
||||
CURLINFO info UNUSED_PARAM)
|
||||
{
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct mbed_ssl_backend_data *backend =
|
||||
(struct mbed_ssl_backend_data *)connssl->backend;
|
||||
(void)info;
|
||||
DEBUGASSERT(backend);
|
||||
return &backend->ssl;
|
||||
@@ -1249,7 +1259,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
|
||||
SSLSUPP_SSL_CTX |
|
||||
SSLSUPP_HTTPS_PROXY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
sizeof(struct mbed_ssl_backend_data),
|
||||
|
||||
mbedtls_init, /* init */
|
||||
mbedtls_cleanup, /* cleanup */
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
/* enough to fit the string "PEM Token #[0|1]" */
|
||||
#define SLOTSIZE 13
|
||||
|
||||
struct ssl_backend_data {
|
||||
struct nss_ssl_backend_data {
|
||||
PRFileDesc *handle;
|
||||
char *client_nickname;
|
||||
struct Curl_easy *data;
|
||||
@@ -489,7 +489,8 @@ static CURLcode nss_create_object(struct ssl_connect_data *connssl,
|
||||
|
||||
const int slot_id = (cacert) ? 0 : 1;
|
||||
char *slot_name = aprintf("PEM Token #%d", slot_id);
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
@@ -806,7 +807,9 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
|
||||
struct Curl_cfilter *cf = (struct Curl_cfilter *)arg;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct Curl_easy *data = connssl->backend->data;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
struct Curl_easy *data = backend->data;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
#ifdef SSL_ENABLE_OCSP_STAPLING
|
||||
@@ -851,7 +854,9 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
|
||||
{
|
||||
struct Curl_cfilter *cf = (struct Curl_cfilter *)arg;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct Curl_easy *data = connssl->backend->data;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
struct Curl_easy *data = backend->data;
|
||||
unsigned int buflenmax = 50;
|
||||
unsigned char buf[50];
|
||||
unsigned int buflen;
|
||||
@@ -1055,7 +1060,9 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
|
||||
{
|
||||
struct Curl_cfilter *cf = (struct Curl_cfilter *)arg;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct Curl_easy *data = connssl->backend->data;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
struct Curl_easy *data = backend->data;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct ssl_config_data *ssl_config;
|
||||
PRErrorCode err = PR_GetError();
|
||||
@@ -1117,7 +1124,8 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
|
||||
const char *pinnedpubkey)
|
||||
{
|
||||
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
struct Curl_easy *data = NULL;
|
||||
CERTCertificate *cert;
|
||||
|
||||
@@ -1173,7 +1181,8 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
|
||||
struct SECKEYPrivateKeyStr **pRetKey)
|
||||
{
|
||||
struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
struct Curl_easy *data = NULL;
|
||||
const char *nickname = NULL;
|
||||
static const char pem_slotname[] = "PEM Token #1";
|
||||
@@ -1538,7 +1547,8 @@ static void nss_cleanup(void)
|
||||
static void close_one(struct ssl_connect_data *connssl)
|
||||
{
|
||||
/* before the cleanup, check whether we are using a client certificate */
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
bool client_cert = true;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
@@ -1580,7 +1590,8 @@ static void close_one(struct ssl_connect_data *connssl)
|
||||
static void nss_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
(void)data;
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
@@ -1796,7 +1807,8 @@ static CURLcode nss_fail_connect(struct Curl_cfilter *cf,
|
||||
CURLcode curlerr)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
@@ -1826,7 +1838,8 @@ static CURLcode nss_set_blocking(struct Curl_cfilter *cf,
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
PRSocketOptionData sock_opt;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
@@ -1849,7 +1862,8 @@ static CURLcode nss_setup_connect(struct Curl_cfilter *cf,
|
||||
PRBool ssl_cbc_random_iv;
|
||||
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
|
||||
@@ -2031,14 +2045,16 @@ static CURLcode nss_setup_connect(struct Curl_cfilter *cf,
|
||||
/* Is there an SSL filter "in front" of us or are we writing directly
|
||||
* to the socket? */
|
||||
if(connssl_next) {
|
||||
struct nss_ssl_backend_data *backend_next =
|
||||
(struct nss_ssl_backend_data *)connssl_next->backend;
|
||||
/* The filter should be connected by now, with full handshake */
|
||||
DEBUGASSERT(connssl_next->backend->handle);
|
||||
DEBUGASSERT(backend_next->handle);
|
||||
DEBUGASSERT(ssl_connection_complete == connssl_next->state);
|
||||
/* We tell our NSS instance to use do IO with the 'next' NSS
|
||||
* instance. This NSS instance will take ownership of the next
|
||||
* one, including its destruction. We therefore need to `disown`
|
||||
* the next filter's handle, once import succeeds. */
|
||||
nspr_io = connssl_next->backend->handle;
|
||||
nspr_io = backend->handle;
|
||||
second_layer = TRUE;
|
||||
}
|
||||
else {
|
||||
@@ -2077,8 +2093,11 @@ static CURLcode nss_setup_connect(struct Curl_cfilter *cf,
|
||||
|
||||
PR_Close(model); /* We don't need this any more */
|
||||
model = NULL;
|
||||
if(connssl_next) /* steal the NSS handle we just imported successfully */
|
||||
connssl_next->backend->handle = NULL;
|
||||
if(connssl_next) { /* steal the NSS handle we just imported successfully */
|
||||
struct nss_ssl_backend_data *backend_next =
|
||||
(struct nss_ssl_backend_data *)connssl_next->backend;
|
||||
backend_next->handle = NULL;
|
||||
}
|
||||
|
||||
/* This is the password associated with the cert that we're using */
|
||||
if(ssl_config->key_passwd) {
|
||||
@@ -2154,7 +2173,8 @@ static CURLcode nss_do_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
CURLcode result = CURLE_SSL_CONNECT_ERROR;
|
||||
@@ -2299,7 +2319,8 @@ static ssize_t nss_send(struct Curl_cfilter *cf,
|
||||
CURLcode *curlcode)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
ssize_t rc;
|
||||
|
||||
(void)data;
|
||||
@@ -2337,7 +2358,9 @@ static bool
|
||||
nss_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
PRFileDesc *fd = connssl->backend->handle->lower;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
PRFileDesc *fd = backend->handle->lower;
|
||||
char buf;
|
||||
|
||||
(void) data;
|
||||
@@ -2353,7 +2376,8 @@ static ssize_t nss_recv(struct Curl_cfilter *cf,
|
||||
CURLcode *curlcode)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
ssize_t nread;
|
||||
|
||||
(void)data;
|
||||
@@ -2455,7 +2479,8 @@ static bool nss_false_start(void)
|
||||
static void *nss_get_internals(struct ssl_connect_data *connssl,
|
||||
CURLINFO info UNUSED_PARAM)
|
||||
{
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
(void)info;
|
||||
DEBUGASSERT(backend);
|
||||
return backend->handle;
|
||||
@@ -2465,9 +2490,11 @@ static bool nss_attach_data(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
|
||||
if(!connssl->backend->data)
|
||||
connssl->backend->data = data;
|
||||
if(!backend->data)
|
||||
backend->data = data;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -2475,9 +2502,11 @@ static void nss_detach_data(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct nss_ssl_backend_data *backend =
|
||||
(struct nss_ssl_backend_data *)connssl->backend;
|
||||
|
||||
if(connssl->backend->data == data)
|
||||
connssl->backend->data = NULL;
|
||||
if(backend->data == data)
|
||||
backend->data = NULL;
|
||||
}
|
||||
|
||||
const struct Curl_ssl Curl_ssl_nss = {
|
||||
@@ -2488,7 +2517,7 @@ const struct Curl_ssl Curl_ssl_nss = {
|
||||
SSLSUPP_PINNEDPUBKEY |
|
||||
SSLSUPP_HTTPS_PROXY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
sizeof(struct nss_ssl_backend_data),
|
||||
|
||||
nss_init, /* init */
|
||||
nss_cleanup, /* cleanup */
|
||||
|
||||
@@ -296,7 +296,7 @@ typedef unsigned long sslerr_t;
|
||||
#define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
||||
#endif /* !LIBRESSL_VERSION_NUMBER */
|
||||
|
||||
struct ssl_backend_data {
|
||||
struct ossl_ssl_backend_data {
|
||||
/* these ones requires specific SSL-types */
|
||||
SSL_CTX* ctx;
|
||||
SSL* handle;
|
||||
@@ -722,6 +722,8 @@ static int bio_cf_out_write(BIO *bio, const char *buf, int blen)
|
||||
{
|
||||
struct Curl_cfilter *cf = BIO_get_data(bio);
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||
ssize_t nwritten;
|
||||
CURLcode result = CURLE_SEND_ERROR;
|
||||
@@ -731,7 +733,7 @@ static int bio_cf_out_write(BIO *bio, const char *buf, int blen)
|
||||
DEBUGF(LOG_CF(data, cf, "bio_cf_out_write(len=%d) -> %d, err=%d",
|
||||
blen, (int)nwritten, result));
|
||||
BIO_clear_retry_flags(bio);
|
||||
connssl->backend->io_result = result;
|
||||
backend->io_result = result;
|
||||
if(nwritten < 0) {
|
||||
if(CURLE_AGAIN == result)
|
||||
BIO_set_retry_write(bio);
|
||||
@@ -743,6 +745,8 @@ static int bio_cf_in_read(BIO *bio, char *buf, int blen)
|
||||
{
|
||||
struct Curl_cfilter *cf = BIO_get_data(bio);
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||
ssize_t nread;
|
||||
CURLcode result = CURLE_RECV_ERROR;
|
||||
@@ -756,7 +760,7 @@ static int bio_cf_in_read(BIO *bio, char *buf, int blen)
|
||||
DEBUGF(LOG_CF(data, cf, "bio_cf_in_read(len=%d) -> %d, err=%d",
|
||||
blen, (int)nread, result));
|
||||
BIO_clear_retry_flags(bio);
|
||||
connssl->backend->io_result = result;
|
||||
backend->io_result = result;
|
||||
if(nread < 0) {
|
||||
if(CURLE_AGAIN == result)
|
||||
BIO_set_retry_read(bio);
|
||||
@@ -764,13 +768,13 @@ static int bio_cf_in_read(BIO *bio, char *buf, int blen)
|
||||
|
||||
/* Before returning server replies to the SSL instance, we need
|
||||
* to have setup the x509 store or verification will fail. */
|
||||
if(!connssl->backend->x509_store_setup) {
|
||||
result = Curl_ssl_setup_x509_store(cf, data, connssl->backend->ctx);
|
||||
if(!backend->x509_store_setup) {
|
||||
result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
|
||||
if(result) {
|
||||
connssl->backend->io_result = result;
|
||||
backend->io_result = result;
|
||||
return -1;
|
||||
}
|
||||
connssl->backend->x509_store_setup = TRUE;
|
||||
backend->x509_store_setup = TRUE;
|
||||
}
|
||||
|
||||
return (int)nread;
|
||||
@@ -1885,7 +1889,8 @@ static struct curl_slist *ossl_engines_list(struct Curl_easy *data)
|
||||
static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(backend);
|
||||
@@ -1931,7 +1936,8 @@ static int ossl_shutdown(struct Curl_cfilter *cf,
|
||||
int buffsize;
|
||||
int err;
|
||||
bool done = FALSE;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
int loop = 10;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
@@ -2329,7 +2335,8 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
|
||||
OCSP_BASICRESP *br = NULL;
|
||||
X509_STORE *st = NULL;
|
||||
STACK_OF(X509) *ch = NULL;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
X509 *cert;
|
||||
OCSP_CERTID *id = NULL;
|
||||
int cert_status, crl_reason;
|
||||
@@ -2729,7 +2736,7 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
|
||||
|
||||
#ifdef HAS_MODERN_SET_PROTO_VER
|
||||
static CURLcode
|
||||
set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx)
|
||||
ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx)
|
||||
{
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
/* first, TLS min version... */
|
||||
@@ -2826,9 +2833,9 @@ typedef long ctx_option_t;
|
||||
|
||||
#if !defined(HAS_MODERN_SET_PROTO_VER)
|
||||
static CURLcode
|
||||
set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
long ssl_version = conn_config->version;
|
||||
@@ -2841,8 +2848,10 @@ set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
|
||||
#ifdef TLS1_3_VERSION
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
DEBUGASSERT(connssl->backend);
|
||||
SSL_CTX_set_max_proto_version(connssl->backend->ctx, TLS1_3_VERSION);
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
DEBUGASSERT(backend);
|
||||
SSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION);
|
||||
*ctx_options |= SSL_OP_NO_TLSv1_2;
|
||||
}
|
||||
#else
|
||||
@@ -3447,7 +3456,8 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
|
||||
const char * const ssl_cert_type = ssl_config->cert_type;
|
||||
const bool verifypeer = conn_config->verifypeer;
|
||||
char error_buffer[256];
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
|
||||
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
|
||||
DEBUGASSERT(backend);
|
||||
@@ -3589,9 +3599,9 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
|
||||
ctx_options |= SSL_OP_NO_SSLv3;
|
||||
|
||||
#if HAS_MODERN_SET_PROTO_VER /* 1.1.0 */
|
||||
result = set_ssl_version_min_max(cf, backend->ctx);
|
||||
result = ossl_set_ssl_version_min_max(cf, backend->ctx);
|
||||
#else
|
||||
result = set_ssl_version_min_max_legacy(&ctx_options, cf, data);
|
||||
result = ossl_set_ssl_version_min_max_legacy(&ctx_options, cf, data);
|
||||
#endif
|
||||
if(result != CURLE_OK)
|
||||
return result;
|
||||
@@ -3820,7 +3830,8 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
|
||||
{
|
||||
int err;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
|
||||
|| ssl_connect_2_reading == connssl->connecting_state
|
||||
@@ -3983,8 +3994,8 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
|
||||
* Heavily modified from:
|
||||
* https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL
|
||||
*/
|
||||
static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
|
||||
const char *pinnedpubkey)
|
||||
static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
|
||||
const char *pinnedpubkey)
|
||||
{
|
||||
/* Scratch */
|
||||
int len1 = 0, len2 = 0;
|
||||
@@ -4062,7 +4073,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
|
||||
char buffer[2048];
|
||||
const char *ptr;
|
||||
BIO *mem = BIO_new(BIO_s_mem());
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
@@ -4077,7 +4089,7 @@ static CURLcode servercert(struct Curl_cfilter *cf,
|
||||
|
||||
if(data->set.ssl.certinfo)
|
||||
/* asked to gather certificate info */
|
||||
(void)Curl_ossl_certchain(data, connssl->backend->handle);
|
||||
(void)Curl_ossl_certchain(data, backend->handle);
|
||||
|
||||
backend->server_cert = SSL_get1_peer_certificate(backend->handle);
|
||||
if(!backend->server_cert) {
|
||||
@@ -4245,7 +4257,7 @@ static CURLcode servercert(struct Curl_cfilter *cf,
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
|
||||
if(!result && ptr) {
|
||||
result = pkp_pin_peer_pubkey(data, backend->server_cert, ptr);
|
||||
result = ossl_pkp_pin_peer_pubkey(data, backend->server_cert, ptr);
|
||||
if(result)
|
||||
failf(data, "SSL: public key does not match pinned public key");
|
||||
}
|
||||
@@ -4414,11 +4426,13 @@ static CURLcode ossl_connect(struct Curl_cfilter *cf,
|
||||
static bool ossl_data_pending(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *ctx = cf->ctx;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(ctx && ctx->backend);
|
||||
if(ctx->backend->handle && SSL_pending(ctx->backend->handle))
|
||||
DEBUGASSERT(connssl && backend);
|
||||
if(backend->handle && SSL_pending(backend->handle))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
@@ -4437,7 +4451,8 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
|
||||
int memlen;
|
||||
int rc;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(backend);
|
||||
@@ -4533,7 +4548,8 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
|
||||
int buffsize;
|
||||
struct connectdata *conn = cf->conn;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(backend);
|
||||
@@ -4756,7 +4772,8 @@ static void *ossl_get_internals(struct ssl_connect_data *connssl,
|
||||
CURLINFO info)
|
||||
{
|
||||
/* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct ossl_ssl_backend_data *backend =
|
||||
(struct ossl_ssl_backend_data *)connssl->backend;
|
||||
DEBUGASSERT(backend);
|
||||
return info == CURLINFO_TLS_SESSION ?
|
||||
(void *)backend->ctx : (void *)backend->handle;
|
||||
@@ -4789,7 +4806,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
|
||||
#endif
|
||||
SSLSUPP_HTTPS_PROXY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
sizeof(struct ossl_ssl_backend_data),
|
||||
|
||||
ossl_init, /* init */
|
||||
ossl_cleanup, /* cleanup */
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#include "strerror.h"
|
||||
#include "multiif.h"
|
||||
|
||||
struct ssl_backend_data
|
||||
struct rustls_ssl_backend_data
|
||||
{
|
||||
const struct rustls_client_config *config;
|
||||
struct rustls_connection *conn;
|
||||
@@ -67,10 +67,12 @@ static bool
|
||||
cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *ctx = cf->ctx;
|
||||
struct rustls_ssl_backend_data *backend;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(ctx && ctx->backend);
|
||||
return ctx->backend->data_pending;
|
||||
backend = (struct rustls_ssl_backend_data *)ctx->backend;
|
||||
return backend->data_pending;
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
@@ -136,7 +138,8 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data, CURLcode *err)
|
||||
{
|
||||
struct ssl_connect_data *const connssl = cf->ctx;
|
||||
struct ssl_backend_data *const backend = connssl->backend;
|
||||
struct rustls_ssl_backend_data *const backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
struct io_ctx io_ctx;
|
||||
size_t tls_bytes_read = 0;
|
||||
rustls_io_result io_error;
|
||||
@@ -191,7 +194,8 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
char *plainbuf, size_t plainlen, CURLcode *err)
|
||||
{
|
||||
struct ssl_connect_data *const connssl = cf->ctx;
|
||||
struct ssl_backend_data *const backend = connssl->backend;
|
||||
struct rustls_ssl_backend_data *const backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
struct rustls_connection *rconn = NULL;
|
||||
size_t n = 0;
|
||||
size_t plain_bytes_copied = 0;
|
||||
@@ -283,7 +287,8 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
const void *plainbuf, size_t plainlen, CURLcode *err)
|
||||
{
|
||||
struct ssl_connect_data *const connssl = cf->ctx;
|
||||
struct ssl_backend_data *const backend = connssl->backend;
|
||||
struct rustls_ssl_backend_data *const backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
struct rustls_connection *rconn = NULL;
|
||||
struct io_ctx io_ctx;
|
||||
size_t plainwritten = 0;
|
||||
@@ -373,7 +378,7 @@ cr_hostname_is_ip(const char *hostname)
|
||||
|
||||
static CURLcode
|
||||
cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
struct ssl_backend_data *const backend)
|
||||
struct rustls_ssl_backend_data *const backend)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
@@ -491,7 +496,8 @@ cr_connect_nonblocking(struct Curl_cfilter *cf,
|
||||
{
|
||||
struct ssl_connect_data *const connssl = cf->ctx;
|
||||
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
|
||||
struct ssl_backend_data *const backend = connssl->backend;
|
||||
struct rustls_ssl_backend_data *const backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
struct rustls_connection *rconn = NULL;
|
||||
CURLcode tmperr = CURLE_OK;
|
||||
int result;
|
||||
@@ -504,7 +510,8 @@ cr_connect_nonblocking(struct Curl_cfilter *cf,
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
if(ssl_connection_none == connssl->state) {
|
||||
result = cr_init_backend(cf, data, connssl->backend);
|
||||
result = cr_init_backend(cf, data,
|
||||
(struct rustls_ssl_backend_data *)connssl->backend);
|
||||
if(result != CURLE_OK) {
|
||||
return result;
|
||||
}
|
||||
@@ -594,7 +601,8 @@ cr_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
{
|
||||
struct ssl_connect_data *const connssl = cf->ctx;
|
||||
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
|
||||
struct ssl_backend_data *const backend = connssl->backend;
|
||||
struct rustls_ssl_backend_data *const backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
struct rustls_connection *rconn = NULL;
|
||||
|
||||
(void)data;
|
||||
@@ -617,7 +625,8 @@ static void *
|
||||
cr_get_internals(struct ssl_connect_data *connssl,
|
||||
CURLINFO info UNUSED_PARAM)
|
||||
{
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct rustls_ssl_backend_data *backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
DEBUGASSERT(backend);
|
||||
return &backend->conn;
|
||||
}
|
||||
@@ -626,7 +635,8 @@ static void
|
||||
cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct rustls_ssl_backend_data *backend =
|
||||
(struct rustls_ssl_backend_data *)connssl->backend;
|
||||
CURLcode tmperr = CURLE_OK;
|
||||
ssize_t n = 0;
|
||||
|
||||
@@ -659,7 +669,7 @@ const struct Curl_ssl Curl_ssl_rustls = {
|
||||
SSLSUPP_CAINFO_BLOB | /* supports */
|
||||
SSLSUPP_TLS13_CIPHERSUITES |
|
||||
SSLSUPP_HTTPS_PROXY,
|
||||
sizeof(struct ssl_backend_data),
|
||||
sizeof(struct rustls_ssl_backend_data),
|
||||
|
||||
Curl_none_init, /* init */
|
||||
Curl_none_cleanup, /* cleanup */
|
||||
|
||||
@@ -33,13 +33,12 @@
|
||||
|
||||
#ifdef USE_SCHANNEL
|
||||
|
||||
#define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
|
||||
|
||||
#ifndef USE_WINDOWS_SSPI
|
||||
# error "Can't compile SCHANNEL support without SSPI."
|
||||
#endif
|
||||
|
||||
#include "schannel.h"
|
||||
#include "schannel_int.h"
|
||||
#include "vtls.h"
|
||||
#include "vtls_int.h"
|
||||
#include "strcase.h"
|
||||
@@ -186,9 +185,9 @@
|
||||
#define PKCS12_NO_PERSIST_KEY 0x00008000
|
||||
#endif
|
||||
|
||||
static CURLcode pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const char *pinnedpubkey);
|
||||
static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const char *pinnedpubkey);
|
||||
|
||||
static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
|
||||
void *BufDataPtr, unsigned long BufByteSize)
|
||||
@@ -207,9 +206,9 @@ static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
set_ssl_version_min_max(DWORD *enabled_protocols,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
schannel_set_ssl_version_min_max(DWORD *enabled_protocols,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
long ssl_version = conn_config->version;
|
||||
@@ -500,7 +499,8 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
|
||||
DWORD flags = 0;
|
||||
DWORD enabled_protocols = 0;
|
||||
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)(connssl->backend);
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
@@ -563,7 +563,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
|
||||
case CURL_SSLVERSION_TLSv1_2:
|
||||
case CURL_SSLVERSION_TLSv1_3:
|
||||
{
|
||||
result = set_ssl_version_min_max(&enabled_protocols, cf, data);
|
||||
result = schannel_set_ssl_version_min_max(&enabled_protocols, cf, data);
|
||||
if(result != CURLE_OK)
|
||||
return result;
|
||||
break;
|
||||
@@ -1075,7 +1075,8 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
ssize_t written = -1;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
SecBuffer outbuf;
|
||||
@@ -1349,7 +1350,8 @@ static CURLcode
|
||||
schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
int i;
|
||||
ssize_t nread = -1, written = -1;
|
||||
@@ -1607,7 +1609,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
|
||||
if(pubkey_ptr) {
|
||||
result = pkp_pin_peer_pubkey(cf, data, pubkey_ptr);
|
||||
result = schannel_pkp_pin_peer_pubkey(cf, data, pubkey_ptr);
|
||||
if(result) {
|
||||
failf(data, "SSL: public key does not match pinned public key");
|
||||
return result;
|
||||
@@ -1686,7 +1688,8 @@ static CURLcode
|
||||
schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
CURLcode result = CURLE_OK;
|
||||
SECURITY_STATUS sspi_status = SEC_E_OK;
|
||||
@@ -1931,7 +1934,8 @@ schannel_connect_common(struct Curl_cfilter *cf,
|
||||
* Available on Windows 7 or later.
|
||||
*/
|
||||
{
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)connssl->backend;
|
||||
DEBUGASSERT(backend);
|
||||
cf->conn->sslContext = &backend->ctxt->ctxt_handle;
|
||||
}
|
||||
@@ -1960,7 +1964,8 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
SecBufferDesc outbuf_desc;
|
||||
SECURITY_STATUS sspi_status = SEC_E_OK;
|
||||
CURLcode result;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)connssl->backend;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
@@ -2110,7 +2115,8 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
/* we want the length of the encrypted buffer to be at least large enough
|
||||
that it can hold all the bytes requested and some TLS record overhead. */
|
||||
size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)connssl->backend;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
@@ -2443,12 +2449,13 @@ static bool schannel_data_pending(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
const struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)connssl->backend;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
if(connssl->backend->ctxt) /* SSL/TLS is in use */
|
||||
if(backend->ctxt) /* SSL/TLS is in use */
|
||||
return (backend->decdata_offset > 0 ||
|
||||
(backend->encdata_offset > 0 && !backend->encdata_is_incomplete));
|
||||
else
|
||||
@@ -2486,12 +2493,13 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
|
||||
* Shutting Down an Schannel Connection
|
||||
*/
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)connssl->backend;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
if(connssl->backend->ctxt) {
|
||||
if(backend->ctxt) {
|
||||
infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
|
||||
connssl->hostname, connssl->port);
|
||||
}
|
||||
@@ -2611,12 +2619,13 @@ static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
|
||||
return Curl_win32_random(entropy, length);
|
||||
}
|
||||
|
||||
static CURLcode pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const char *pinnedpubkey)
|
||||
static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const char *pinnedpubkey)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)connssl->backend;
|
||||
CERT_CONTEXT *pCertContextServer = NULL;
|
||||
|
||||
/* Result is returned to caller */
|
||||
@@ -2742,7 +2751,8 @@ static CURLcode schannel_sha256sum(const unsigned char *input,
|
||||
static void *schannel_get_internals(struct ssl_connect_data *connssl,
|
||||
CURLINFO info UNUSED_PARAM)
|
||||
{
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct schannel_ssl_backend_data *backend =
|
||||
(struct schannel_ssl_backend_data *)connssl->backend;
|
||||
(void)info;
|
||||
DEBUGASSERT(backend);
|
||||
return &backend->ctxt->ctxt_handle;
|
||||
@@ -2759,7 +2769,7 @@ const struct Curl_ssl Curl_ssl_schannel = {
|
||||
SSLSUPP_TLS13_CIPHERSUITES |
|
||||
SSLSUPP_HTTPS_PROXY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
sizeof(struct schannel_ssl_backend_data),
|
||||
|
||||
schannel_init, /* init */
|
||||
schannel_cleanup, /* cleanup */
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
|
||||
#ifdef USE_SCHANNEL
|
||||
|
||||
#define SCHANNEL_USE_BLACKLISTS 1
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4201)
|
||||
@@ -81,119 +79,5 @@ extern const struct Curl_ssl Curl_ssl_schannel;
|
||||
CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
/* structs to expose only in schannel.c and schannel_verify.c */
|
||||
#ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#ifdef __MINGW64_VERSION_MAJOR
|
||||
#define HAS_MANUAL_VERIFY_API
|
||||
#endif
|
||||
#else
|
||||
#ifdef CERT_CHAIN_REVOCATION_CHECK_CHAIN
|
||||
#define HAS_MANUAL_VERIFY_API
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) \
|
||||
&& !defined(DISABLE_SCHANNEL_CLIENT_CERT)
|
||||
#define HAS_CLIENT_CERT_PATH
|
||||
#endif
|
||||
|
||||
#ifndef SCH_CREDENTIALS_VERSION
|
||||
|
||||
#define SCH_CREDENTIALS_VERSION 0x00000005
|
||||
|
||||
typedef enum _eTlsAlgorithmUsage
|
||||
{
|
||||
TlsParametersCngAlgUsageKeyExchange,
|
||||
TlsParametersCngAlgUsageSignature,
|
||||
TlsParametersCngAlgUsageCipher,
|
||||
TlsParametersCngAlgUsageDigest,
|
||||
TlsParametersCngAlgUsageCertSig
|
||||
} eTlsAlgorithmUsage;
|
||||
|
||||
typedef struct _CRYPTO_SETTINGS
|
||||
{
|
||||
eTlsAlgorithmUsage eAlgorithmUsage;
|
||||
UNICODE_STRING strCngAlgId;
|
||||
DWORD cChainingModes;
|
||||
PUNICODE_STRING rgstrChainingModes;
|
||||
DWORD dwMinBitLength;
|
||||
DWORD dwMaxBitLength;
|
||||
} CRYPTO_SETTINGS, * PCRYPTO_SETTINGS;
|
||||
|
||||
typedef struct _TLS_PARAMETERS
|
||||
{
|
||||
DWORD cAlpnIds;
|
||||
PUNICODE_STRING rgstrAlpnIds;
|
||||
DWORD grbitDisabledProtocols;
|
||||
DWORD cDisabledCrypto;
|
||||
PCRYPTO_SETTINGS pDisabledCrypto;
|
||||
DWORD dwFlags;
|
||||
} TLS_PARAMETERS, * PTLS_PARAMETERS;
|
||||
|
||||
typedef struct _SCH_CREDENTIALS
|
||||
{
|
||||
DWORD dwVersion;
|
||||
DWORD dwCredFormat;
|
||||
DWORD cCreds;
|
||||
PCCERT_CONTEXT* paCred;
|
||||
HCERTSTORE hRootStore;
|
||||
|
||||
DWORD cMappers;
|
||||
struct _HMAPPER **aphMappers;
|
||||
|
||||
DWORD dwSessionLifespan;
|
||||
DWORD dwFlags;
|
||||
DWORD cTlsParameters;
|
||||
PTLS_PARAMETERS pTlsParameters;
|
||||
} SCH_CREDENTIALS, * PSCH_CREDENTIALS;
|
||||
|
||||
#define SCH_CRED_MAX_SUPPORTED_PARAMETERS 16
|
||||
#define SCH_CRED_MAX_SUPPORTED_ALPN_IDS 16
|
||||
#define SCH_CRED_MAX_SUPPORTED_CRYPTO_SETTINGS 16
|
||||
#define SCH_CRED_MAX_SUPPORTED_CHAINING_MODES 16
|
||||
|
||||
#endif
|
||||
|
||||
struct Curl_schannel_cred {
|
||||
CredHandle cred_handle;
|
||||
TimeStamp time_stamp;
|
||||
TCHAR *sni_hostname;
|
||||
#ifdef HAS_CLIENT_CERT_PATH
|
||||
HCERTSTORE client_cert_store;
|
||||
#endif
|
||||
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 recv() (that is, status is
|
||||
SEC_E_INCOMPLETE_MESSAGE) then set this true. after an recv() adds
|
||||
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 recv_renegotiating; /* true if recv is doing renegotiation */
|
||||
bool use_alpn; /* true if ALPN is used for this connection */
|
||||
#ifdef HAS_MANUAL_VERIFY_API
|
||||
bool use_manual_cred_validation; /* true if manual cred validation is used */
|
||||
#endif
|
||||
};
|
||||
#endif /* EXPOSE_SCHANNEL_INTERNAL_STRUCTS */
|
||||
|
||||
#endif /* USE_SCHANNEL */
|
||||
#endif /* HEADER_CURL_SCHANNEL_H */
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
#ifndef HEADER_CURL_SCHANNEL_INT_H
|
||||
#define HEADER_CURL_SCHANNEL_INT_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Marc Hoersken, <info@marc-hoersken.de>, et al.
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
|
||||
#ifdef USE_SCHANNEL
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#ifdef __MINGW64_VERSION_MAJOR
|
||||
#define HAS_MANUAL_VERIFY_API
|
||||
#endif
|
||||
#else
|
||||
#ifdef CERT_CHAIN_REVOCATION_CHECK_CHAIN
|
||||
#define HAS_MANUAL_VERIFY_API
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) \
|
||||
&& !defined(DISABLE_SCHANNEL_CLIENT_CERT)
|
||||
#define HAS_CLIENT_CERT_PATH
|
||||
#endif
|
||||
|
||||
#ifndef SCH_CREDENTIALS_VERSION
|
||||
|
||||
#define SCH_CREDENTIALS_VERSION 0x00000005
|
||||
|
||||
typedef enum _eTlsAlgorithmUsage
|
||||
{
|
||||
TlsParametersCngAlgUsageKeyExchange,
|
||||
TlsParametersCngAlgUsageSignature,
|
||||
TlsParametersCngAlgUsageCipher,
|
||||
TlsParametersCngAlgUsageDigest,
|
||||
TlsParametersCngAlgUsageCertSig
|
||||
} eTlsAlgorithmUsage;
|
||||
|
||||
typedef struct _CRYPTO_SETTINGS
|
||||
{
|
||||
eTlsAlgorithmUsage eAlgorithmUsage;
|
||||
UNICODE_STRING strCngAlgId;
|
||||
DWORD cChainingModes;
|
||||
PUNICODE_STRING rgstrChainingModes;
|
||||
DWORD dwMinBitLength;
|
||||
DWORD dwMaxBitLength;
|
||||
} CRYPTO_SETTINGS, * PCRYPTO_SETTINGS;
|
||||
|
||||
typedef struct _TLS_PARAMETERS
|
||||
{
|
||||
DWORD cAlpnIds;
|
||||
PUNICODE_STRING rgstrAlpnIds;
|
||||
DWORD grbitDisabledProtocols;
|
||||
DWORD cDisabledCrypto;
|
||||
PCRYPTO_SETTINGS pDisabledCrypto;
|
||||
DWORD dwFlags;
|
||||
} TLS_PARAMETERS, * PTLS_PARAMETERS;
|
||||
|
||||
typedef struct _SCH_CREDENTIALS
|
||||
{
|
||||
DWORD dwVersion;
|
||||
DWORD dwCredFormat;
|
||||
DWORD cCreds;
|
||||
PCCERT_CONTEXT* paCred;
|
||||
HCERTSTORE hRootStore;
|
||||
|
||||
DWORD cMappers;
|
||||
struct _HMAPPER **aphMappers;
|
||||
|
||||
DWORD dwSessionLifespan;
|
||||
DWORD dwFlags;
|
||||
DWORD cTlsParameters;
|
||||
PTLS_PARAMETERS pTlsParameters;
|
||||
} SCH_CREDENTIALS, * PSCH_CREDENTIALS;
|
||||
|
||||
#define SCH_CRED_MAX_SUPPORTED_PARAMETERS 16
|
||||
#define SCH_CRED_MAX_SUPPORTED_ALPN_IDS 16
|
||||
#define SCH_CRED_MAX_SUPPORTED_CRYPTO_SETTINGS 16
|
||||
#define SCH_CRED_MAX_SUPPORTED_CHAINING_MODES 16
|
||||
|
||||
#endif /* SCH_CREDENTIALS_VERSION */
|
||||
|
||||
struct Curl_schannel_cred {
|
||||
CredHandle cred_handle;
|
||||
TimeStamp time_stamp;
|
||||
TCHAR *sni_hostname;
|
||||
#ifdef HAS_CLIENT_CERT_PATH
|
||||
HCERTSTORE client_cert_store;
|
||||
#endif
|
||||
int refcount;
|
||||
};
|
||||
|
||||
struct Curl_schannel_ctxt {
|
||||
CtxtHandle ctxt_handle;
|
||||
TimeStamp time_stamp;
|
||||
};
|
||||
|
||||
struct schannel_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 recv() (that is, status is
|
||||
SEC_E_INCOMPLETE_MESSAGE) then set this true. after an recv() adds
|
||||
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 recv_renegotiating; /* true if recv is doing renegotiation */
|
||||
bool use_alpn; /* true if ALPN is used for this connection */
|
||||
#ifdef HAS_MANUAL_VERIFY_API
|
||||
bool use_manual_cred_validation; /* true if manual cred validation is used */
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* USE_SCHANNEL */
|
||||
#endif /* HEADER_CURL_SCHANNEL_INT_H */
|
||||
@@ -36,8 +36,8 @@
|
||||
# error "Can't compile SCHANNEL support without SSPI."
|
||||
#endif
|
||||
|
||||
#define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
|
||||
#include "schannel.h"
|
||||
#include "schannel_int.h"
|
||||
|
||||
#ifdef HAS_MANUAL_VERIFY_API
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
#define BACKEND connssl->backend
|
||||
#define BACKEND ((struct schannel_ssl_backend_data *)connssl->backend)
|
||||
|
||||
#define MAX_CAFILE_SIZE 1048576 /* 1 MiB */
|
||||
#define BEGIN_CERT "-----BEGIN CERTIFICATE-----"
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
#define ioErr -36
|
||||
#define paramErr -50
|
||||
|
||||
struct ssl_backend_data {
|
||||
struct st_ssl_backend_data {
|
||||
SSLContextRef ssl_ctx;
|
||||
bool ssl_direction; /* true if writing, false if reading */
|
||||
size_t ssl_write_buffered_length;
|
||||
@@ -836,7 +836,8 @@ static OSStatus bio_cf_in_read(SSLConnectionRef connection,
|
||||
{
|
||||
struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct st_ssl_backend_data *backend =
|
||||
(struct st_ssl_backend_data *)connssl->backend;
|
||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||
ssize_t nread;
|
||||
CURLcode result;
|
||||
@@ -859,6 +860,9 @@ static OSStatus bio_cf_in_read(SSLConnectionRef connection,
|
||||
}
|
||||
nread = 0;
|
||||
}
|
||||
else if(nread == 0) {
|
||||
rtn = errSSLClosedGraceful;
|
||||
}
|
||||
else if((size_t)nread < *dataLength) {
|
||||
rtn = errSSLWouldBlock;
|
||||
}
|
||||
@@ -872,7 +876,8 @@ static OSStatus bio_cf_out_write(SSLConnectionRef connection,
|
||||
{
|
||||
struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct st_ssl_backend_data *backend =
|
||||
(struct st_ssl_backend_data *)connssl->backend;
|
||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||
ssize_t nwritten;
|
||||
CURLcode result;
|
||||
@@ -1338,7 +1343,8 @@ static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct st_ssl_backend_data *backend =
|
||||
(struct st_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
long ssl_version = conn_config->version;
|
||||
long ssl_version_max = conn_config->version_max;
|
||||
@@ -1633,7 +1639,8 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct st_ssl_backend_data *backend =
|
||||
(struct st_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
const struct curl_blob *ssl_cablob = conn_config->ca_info_blob;
|
||||
@@ -2515,7 +2522,8 @@ static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct st_ssl_backend_data *backend =
|
||||
(struct st_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
OSStatus err;
|
||||
SSLCipherSuite cipher;
|
||||
@@ -2896,7 +2904,8 @@ static CURLcode collect_server_cert(struct Curl_cfilter *cf,
|
||||
CURLcode result = ssl_config->certinfo ?
|
||||
CURLE_PEER_FAILED_VERIFICATION : CURLE_OK;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct st_ssl_backend_data *backend =
|
||||
(struct st_ssl_backend_data *)connssl->backend;
|
||||
CFArrayRef server_certs = NULL;
|
||||
SecCertificateRef server_cert;
|
||||
OSStatus err;
|
||||
@@ -3139,7 +3148,8 @@ static CURLcode sectransp_connect(struct Curl_cfilter *cf,
|
||||
static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct st_ssl_backend_data *backend =
|
||||
(struct st_ssl_backend_data *)connssl->backend;
|
||||
|
||||
(void) data;
|
||||
|
||||
@@ -3166,7 +3176,8 @@ static int sectransp_shutdown(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct st_ssl_backend_data *backend =
|
||||
(struct st_ssl_backend_data *)connssl->backend;
|
||||
ssize_t nread;
|
||||
int what;
|
||||
int rc;
|
||||
@@ -3244,7 +3255,8 @@ static bool sectransp_data_pending(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
const struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct st_ssl_backend_data *backend =
|
||||
(struct st_ssl_backend_data *)connssl->backend;
|
||||
OSStatus err;
|
||||
size_t buffer;
|
||||
|
||||
@@ -3308,7 +3320,8 @@ static ssize_t sectransp_send(struct Curl_cfilter *cf,
|
||||
CURLcode *curlcode)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct st_ssl_backend_data *backend =
|
||||
(struct st_ssl_backend_data *)connssl->backend;
|
||||
size_t processed = 0UL;
|
||||
OSStatus err;
|
||||
|
||||
@@ -3376,7 +3389,8 @@ static ssize_t sectransp_recv(struct Curl_cfilter *cf,
|
||||
CURLcode *curlcode)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct st_ssl_backend_data *backend =
|
||||
(struct st_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
size_t processed = 0UL;
|
||||
OSStatus err;
|
||||
@@ -3434,7 +3448,8 @@ again:
|
||||
static void *sectransp_get_internals(struct ssl_connect_data *connssl,
|
||||
CURLINFO info UNUSED_PARAM)
|
||||
{
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct st_ssl_backend_data *backend =
|
||||
(struct st_ssl_backend_data *)connssl->backend;
|
||||
(void)info;
|
||||
DEBUGASSERT(backend);
|
||||
return backend->ssl_ctx;
|
||||
@@ -3450,7 +3465,7 @@ const struct Curl_ssl Curl_ssl_sectransp = {
|
||||
#endif /* SECTRANSP_PINNEDPUBKEY */
|
||||
SSLSUPP_HTTPS_PROXY,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
sizeof(struct st_ssl_backend_data),
|
||||
|
||||
Curl_none_init, /* init */
|
||||
Curl_none_cleanup, /* cleanup */
|
||||
|
||||
@@ -453,7 +453,7 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGF(infof(data, DMSG(data, "%s Session ID in cache for %s %s://%s:%d"),
|
||||
DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
|
||||
no_match? "Didn't find": "Found",
|
||||
Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
|
||||
cf->conn->handler->scheme, connssl->hostname, connssl->port));
|
||||
@@ -601,8 +601,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
|
||||
if(added)
|
||||
*added = TRUE;
|
||||
|
||||
DEBUGF(infof(data, DMSG(data, "Added Session ID to cache for %s://%s:%d"
|
||||
" [%s]"), store->scheme, store->name, store->remote_port,
|
||||
DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
|
||||
store->scheme, store->name, store->remote_port,
|
||||
Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server"));
|
||||
return CURLE_OK;
|
||||
}
|
||||
@@ -893,8 +893,8 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
|
||||
/* only do this if pinnedpubkey starts with "sha256//", length 8 */
|
||||
if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
|
||||
CURLcode encode;
|
||||
size_t encodedlen, pinkeylen;
|
||||
char *encoded, *pinkeycopy, *begin_pos, *end_pos;
|
||||
size_t encodedlen = 0, pinkeylen;
|
||||
char *encoded = NULL, *pinkeycopy, *begin_pos, *end_pos;
|
||||
unsigned char *sha256sumdigest;
|
||||
|
||||
if(!Curl_ssl->sha256sum) {
|
||||
@@ -907,14 +907,12 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
|
||||
if(!sha256sumdigest)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
encode = Curl_ssl->sha256sum(pubkey, pubkeylen,
|
||||
sha256sumdigest, CURL_SHA256_DIGEST_LENGTH);
|
||||
sha256sumdigest, CURL_SHA256_DIGEST_LENGTH);
|
||||
|
||||
if(encode != CURLE_OK)
|
||||
return encode;
|
||||
|
||||
encode = Curl_base64_encode((char *)sha256sumdigest,
|
||||
CURL_SHA256_DIGEST_LENGTH, &encoded,
|
||||
&encodedlen);
|
||||
if(!encode)
|
||||
encode = Curl_base64_encode((char *)sha256sumdigest,
|
||||
CURL_SHA256_DIGEST_LENGTH, &encoded,
|
||||
&encodedlen);
|
||||
Curl_safefree(sha256sumdigest);
|
||||
|
||||
if(encode)
|
||||
@@ -1506,7 +1504,7 @@ static void ssl_cf_close(struct Curl_cfilter *cf,
|
||||
|
||||
CF_DATA_SAVE(save, cf, data);
|
||||
cf_close(cf, data);
|
||||
cf->next->cft->close(cf->next, data);
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
CF_DATA_RESTORE(cf, save);
|
||||
}
|
||||
|
||||
@@ -1530,7 +1528,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
|
||||
DEBUGASSERT(connssl);
|
||||
DEBUGASSERT(cf->conn->host.name);
|
||||
|
||||
result = cf->next->cft->connect(cf->next, data, blocking, done);
|
||||
result = cf->next->cft->do_connect(cf->next, data, blocking, done);
|
||||
if(result || !*done)
|
||||
goto out;
|
||||
|
||||
@@ -1594,6 +1592,7 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
|
||||
ssize_t nread;
|
||||
|
||||
CF_DATA_SAVE(save, cf, data);
|
||||
*err = CURLE_OK;
|
||||
nread = Curl_ssl->recv_plain(cf, data, buf, len, err);
|
||||
if(nread > 0) {
|
||||
DEBUGASSERT((size_t)nread <= len);
|
||||
|
||||
@@ -73,7 +73,7 @@ struct ssl_connect_data {
|
||||
char *hostname; /* hostname for verification */
|
||||
char *dispname; /* display version of hostname */
|
||||
const struct alpn_spec *alpn; /* ALPN to use or NULL for none */
|
||||
struct ssl_backend_data *backend; /* vtls backend specific props */
|
||||
void *backend; /* vtls backend specific props */
|
||||
struct cf_call_data call_data; /* data handle used in current call */
|
||||
struct curltime handshake_done; /* time when handshake finished */
|
||||
int port; /* remote port at origin */
|
||||
@@ -81,6 +81,7 @@ struct ssl_connect_data {
|
||||
};
|
||||
|
||||
|
||||
#undef CF_CTX_CALL_DATA
|
||||
#define CF_CTX_CALL_DATA(cf) \
|
||||
((struct ssl_connect_data *)(cf)->ctx)->call_data
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
#undef USE_BIO_CHAIN
|
||||
#endif
|
||||
|
||||
struct ssl_backend_data {
|
||||
struct wolfssl_ssl_backend_data {
|
||||
SSL_CTX* ctx;
|
||||
SSL* handle;
|
||||
CURLcode io_result; /* result of last BIO cfilter operation */
|
||||
@@ -281,13 +281,15 @@ static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen)
|
||||
{
|
||||
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||
ssize_t nwritten;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
|
||||
connssl->backend->io_result = result;
|
||||
backend->io_result = result;
|
||||
DEBUGF(LOG_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
|
||||
blen, nwritten, result));
|
||||
wolfSSL_BIO_clear_retry_flags(bio);
|
||||
@@ -300,6 +302,8 @@ static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
|
||||
{
|
||||
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||
ssize_t nread;
|
||||
CURLcode result = CURLE_OK;
|
||||
@@ -310,7 +314,7 @@ static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
|
||||
return 0;
|
||||
|
||||
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
|
||||
connssl->backend->io_result = result;
|
||||
backend->io_result = result;
|
||||
DEBUGF(LOG_CF(data, cf, "bio_read(len=%d) -> %zd, %d",
|
||||
blen, nread, result));
|
||||
wolfSSL_BIO_clear_retry_flags(bio);
|
||||
@@ -352,8 +356,10 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
char *ciphers, *curves;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
|
||||
const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
SSL_METHOD* req_method = NULL;
|
||||
#ifdef HAVE_LIBOQS
|
||||
@@ -366,6 +372,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
#else
|
||||
#define use_sni(x) Curl_nop_stmt
|
||||
#endif
|
||||
bool imported_ca_info_blob = false;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
@@ -410,8 +417,13 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
#endif
|
||||
break;
|
||||
case CURL_SSLVERSION_TLSv1_2:
|
||||
#ifndef WOLFSSL_NO_TLS12
|
||||
req_method = TLSv1_2_client_method();
|
||||
use_sni(TRUE);
|
||||
#else
|
||||
failf(data, "wolfSSL does not support TLS 1.2");
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
break;
|
||||
case CURL_SSLVERSION_TLSv1_3:
|
||||
#ifdef WOLFSSL_TLS13
|
||||
@@ -494,13 +506,28 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ca_info_blob) {
|
||||
if(wolfSSL_CTX_load_verify_buffer(
|
||||
backend->ctx, ca_info_blob->data, ca_info_blob->len,
|
||||
SSL_FILETYPE_PEM
|
||||
) != SSL_SUCCESS) {
|
||||
failf(data, "error importing CA certificate blob");
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
else {
|
||||
imported_ca_info_blob = true;
|
||||
infof(data, "successfully imported CA certificate blob");
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_FILESYSTEM
|
||||
/* load trusted cacert */
|
||||
if(conn_config->CAfile) {
|
||||
if(1 != SSL_CTX_load_verify_locations(backend->ctx,
|
||||
conn_config->CAfile,
|
||||
conn_config->CApath)) {
|
||||
if(conn_config->verifypeer) {
|
||||
if(conn_config->verifypeer && !imported_ca_info_blob) {
|
||||
/* Fail if we insist on successfully verifying the server. */
|
||||
failf(data, "error setting certificate verify locations:"
|
||||
" CAfile: %s CApath: %s",
|
||||
@@ -699,7 +726,8 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
int ret = -1;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
|
||||
@@ -892,7 +920,8 @@ wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
|
||||
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
|
||||
@@ -950,7 +979,8 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
|
||||
CURLcode *curlcode)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
char error_buffer[WOLFSSL_MAX_ERROR_SZ];
|
||||
int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
|
||||
int rc;
|
||||
@@ -992,7 +1022,8 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
|
||||
static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
|
||||
(void) data;
|
||||
|
||||
@@ -1019,7 +1050,8 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
|
||||
CURLcode *curlcode)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
char error_buffer[WOLFSSL_MAX_ERROR_SZ];
|
||||
int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
|
||||
int nread;
|
||||
@@ -1108,11 +1140,14 @@ static bool wolfssl_data_pending(struct Curl_cfilter *cf,
|
||||
const struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *ctx = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(ctx && ctx->backend);
|
||||
if(ctx->backend->handle) /* SSL is in use */
|
||||
return (0 != SSL_pending(ctx->backend->handle)) ? TRUE : FALSE;
|
||||
|
||||
backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
|
||||
if(backend->handle) /* SSL is in use */
|
||||
return (0 != SSL_pending(backend->handle)) ? TRUE : FALSE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1126,15 +1161,17 @@ static int wolfssl_shutdown(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *ctx = cf->ctx;
|
||||
struct wolfssl_ssl_backend_data *backend;
|
||||
int retval = 0;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(ctx && ctx->backend);
|
||||
|
||||
if(ctx->backend->handle) {
|
||||
backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
|
||||
if(backend->handle) {
|
||||
ERR_clear_error();
|
||||
SSL_free(ctx->backend->handle);
|
||||
ctx->backend->handle = NULL;
|
||||
SSL_free(backend->handle);
|
||||
backend->handle = NULL;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -1305,7 +1342,8 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
|
||||
static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
|
||||
CURLINFO info UNUSED_PARAM)
|
||||
{
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct wolfssl_ssl_backend_data *backend =
|
||||
(struct wolfssl_ssl_backend_data *)connssl->backend;
|
||||
(void)info;
|
||||
DEBUGASSERT(backend);
|
||||
return backend->handle;
|
||||
@@ -1320,9 +1358,10 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
|
||||
#ifdef USE_BIO_CHAIN
|
||||
SSLSUPP_HTTPS_PROXY |
|
||||
#endif
|
||||
SSLSUPP_CAINFO_BLOB |
|
||||
SSLSUPP_SSL_CTX,
|
||||
|
||||
sizeof(struct ssl_backend_data),
|
||||
sizeof(struct wolfssl_ssl_backend_data),
|
||||
|
||||
wolfssl_init, /* init */
|
||||
wolfssl_cleanup, /* cleanup */
|
||||
|
||||
@@ -35,10 +35,13 @@
|
||||
|
||||
#endif /* __INTEL_COMPILER && __unix__ */
|
||||
|
||||
#define BUILDING_WARNLESS_C 1
|
||||
|
||||
#include "warnless.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#undef read
|
||||
#undef write
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#define CURL_MASK_UCHAR ((unsigned char)~0)
|
||||
@@ -376,6 +379,9 @@ ssize_t curlx_write(int fd, const void *buf, size_t count)
|
||||
return (ssize_t)write(fd, buf, curlx_uztoui(count));
|
||||
}
|
||||
|
||||
/* Ensure that warnless.h continues to have an effect in "unity" builds. */
|
||||
#undef HEADER_CURL_WARNLESS_H
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
#if defined(__INTEL_COMPILER) && defined(__unix__)
|
||||
|
||||
@@ -75,12 +75,10 @@ ssize_t curlx_read(int fd, void *buf, size_t count);
|
||||
|
||||
ssize_t curlx_write(int fd, const void *buf, size_t count);
|
||||
|
||||
#ifndef BUILDING_WARNLESS_C
|
||||
# undef read
|
||||
# define read(fd, buf, count) curlx_read(fd, buf, count)
|
||||
# undef write
|
||||
# define write(fd, buf, count) curlx_write(fd, buf, count)
|
||||
#endif
|
||||
#undef read
|
||||
#define read(fd, buf, count) curlx_read(fd, buf, count)
|
||||
#undef write
|
||||
#define write(fd, buf, count) curlx_write(fd, buf, count)
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
|
||||
+30
-26
@@ -126,8 +126,9 @@ static void ws_dec_info(struct ws_decoder *dec, struct Curl_easy *data,
|
||||
dec->head_len, dec->head_total);
|
||||
}
|
||||
else {
|
||||
infof(data, "WS-DEC: %s [%s%s payload=%zd/%zd]", msg,
|
||||
ws_frame_name_of_op(dec->head[0]),
|
||||
infof(data, "WS-DEC: %s [%s%s payload=%" CURL_FORMAT_CURL_OFF_T
|
||||
"/%" CURL_FORMAT_CURL_OFF_T "]",
|
||||
msg, ws_frame_name_of_op(dec->head[0]),
|
||||
(dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
|
||||
dec->payload_offset, dec->payload_len);
|
||||
}
|
||||
@@ -272,7 +273,8 @@ static CURLcode ws_dec_pass_payload(struct ws_decoder *dec,
|
||||
Curl_bufq_skip(inraw, (size_t)nwritten);
|
||||
dec->payload_offset += (curl_off_t)nwritten;
|
||||
remain = dec->payload_len - dec->payload_offset;
|
||||
/* infof(data, "WS-DEC: passed %zd bytes payload, %zd remain",
|
||||
/* infof(data, "WS-DEC: passed %zd bytes payload, %"
|
||||
CURL_FORMAT_CURL_OFF_T " remain",
|
||||
nwritten, remain); */
|
||||
}
|
||||
|
||||
@@ -351,8 +353,9 @@ static void update_meta(struct websocket *ws,
|
||||
static void ws_enc_info(struct ws_encoder *enc, struct Curl_easy *data,
|
||||
const char *msg)
|
||||
{
|
||||
infof(data, "WS-ENC: %s [%s%s%s payload=%zd/%zd]", msg,
|
||||
ws_frame_name_of_op(enc->firstbyte),
|
||||
infof(data, "WS-ENC: %s [%s%s%s payload=%" CURL_FORMAT_CURL_OFF_T
|
||||
"/%" CURL_FORMAT_CURL_OFF_T "]",
|
||||
msg, ws_frame_name_of_op(enc->firstbyte),
|
||||
(enc->firstbyte & WSBIT_OPCODE_MASK) == WSBIT_OPCODE_CONT ?
|
||||
" CONT" : "",
|
||||
(enc->firstbyte & WSBIT_FIN)? "" : " NON-FIN",
|
||||
@@ -839,7 +842,7 @@ static ssize_t nw_in_recv(void *reader_ctx,
|
||||
|
||||
CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
|
||||
size_t buflen, size_t *nread,
|
||||
struct curl_ws_frame **metap)
|
||||
const struct curl_ws_frame **metap)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
struct websocket *ws;
|
||||
@@ -921,7 +924,8 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
|
||||
ctx.payload_len, ctx.bufidx);
|
||||
*metap = &ws->frame;
|
||||
*nread = ws->frame.len;
|
||||
/* infof(data, "curl_ws_recv(len=%zu) -> %zu bytes (frame at %zd, %zd left)",
|
||||
/* infof(data, "curl_ws_recv(len=%zu) -> %zu bytes (frame at %"
|
||||
CURL_FORMAT_CURL_OFF_T ", %" CURL_FORMAT_CURL_OFF_T " left)",
|
||||
buflen, *nread, ws->frame.offset, ws->frame.bytesleft); */
|
||||
return CURLE_OK;
|
||||
}
|
||||
@@ -966,10 +970,10 @@ static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
CURL_EXTERN CURLcode curl_ws_send(struct Curl_easy *data, const void *buffer,
|
||||
CURL_EXTERN CURLcode curl_ws_send(CURL *data, const void *buffer,
|
||||
size_t buflen, size_t *sent,
|
||||
curl_off_t totalsize,
|
||||
unsigned int sendflags)
|
||||
curl_off_t fragsize,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct websocket *ws;
|
||||
ssize_t nwritten, n;
|
||||
@@ -987,14 +991,13 @@ CURL_EXTERN CURLcode curl_ws_send(struct Curl_easy *data, const void *buffer,
|
||||
return CURLE_SEND_ERROR;
|
||||
}
|
||||
if(!data->conn->proto.ws) {
|
||||
failf(data, "Not a websocket transfer on connection #%ld",
|
||||
data->conn->connection_id);
|
||||
failf(data, "Not a websocket transfer");
|
||||
return CURLE_SEND_ERROR;
|
||||
}
|
||||
ws = data->conn->proto.ws;
|
||||
|
||||
if(data->set.ws_raw_mode) {
|
||||
if(totalsize || sendflags)
|
||||
if(fragsize || flags)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
if(!buflen)
|
||||
/* nothing to do */
|
||||
@@ -1027,23 +1030,24 @@ CURL_EXTERN CURLcode curl_ws_send(struct Curl_easy *data, const void *buffer,
|
||||
if(space < 14)
|
||||
return CURLE_AGAIN;
|
||||
|
||||
if(sendflags & CURLWS_OFFSET) {
|
||||
if(totalsize) {
|
||||
/* a frame series 'totalsize' bytes big, this is the first */
|
||||
n = ws_enc_write_head(data, &ws->enc, sendflags, totalsize,
|
||||
if(flags & CURLWS_OFFSET) {
|
||||
if(fragsize) {
|
||||
/* a frame series 'fragsize' bytes big, this is the first */
|
||||
n = ws_enc_write_head(data, &ws->enc, flags, fragsize,
|
||||
&ws->sendbuf, &result);
|
||||
if(n < 0)
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
if((curl_off_t)buflen > ws->enc.payload_remain) {
|
||||
infof(data, "WS: unaligned frame size (sending %zu instead of %zd)",
|
||||
infof(data, "WS: unaligned frame size (sending %zu instead of %"
|
||||
CURL_FORMAT_CURL_OFF_T ")",
|
||||
buflen, ws->enc.payload_remain);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!ws->enc.payload_remain) {
|
||||
n = ws_enc_write_head(data, &ws->enc, sendflags, (curl_off_t)buflen,
|
||||
n = ws_enc_write_head(data, &ws->enc, flags, (curl_off_t)buflen,
|
||||
&ws->sendbuf, &result);
|
||||
if(n < 0)
|
||||
return result;
|
||||
@@ -1082,7 +1086,7 @@ CURLcode Curl_ws_disconnect(struct Curl_easy *data,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
|
||||
CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
|
||||
{
|
||||
/* we only return something for websocket, called from within the callback
|
||||
when not using raw mode */
|
||||
@@ -1096,7 +1100,7 @@ CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
|
||||
|
||||
CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
|
||||
size_t *nread,
|
||||
struct curl_ws_frame **metap)
|
||||
const struct curl_ws_frame **metap)
|
||||
{
|
||||
(void)curl;
|
||||
(void)buffer;
|
||||
@@ -1108,19 +1112,19 @@ CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
|
||||
|
||||
CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer,
|
||||
size_t buflen, size_t *sent,
|
||||
curl_off_t framesize,
|
||||
unsigned int sendflags)
|
||||
curl_off_t fragsize,
|
||||
unsigned int flags)
|
||||
{
|
||||
(void)curl;
|
||||
(void)buffer;
|
||||
(void)buflen;
|
||||
(void)sent;
|
||||
(void)framesize;
|
||||
(void)sendflags;
|
||||
(void)fragsize;
|
||||
(void)flags;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
}
|
||||
|
||||
CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
|
||||
CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
|
||||
{
|
||||
(void)data;
|
||||
return NULL;
|
||||
|
||||
Reference in New Issue
Block a user