summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib')
-rw-r--r--Utilities/cmcurl/lib/CMakeLists.txt21
-rw-r--r--Utilities/cmcurl/lib/altsvc.c10
-rw-r--r--Utilities/cmcurl/lib/arpa_telnet.h9
-rw-r--r--Utilities/cmcurl/lib/asyn-ares.c149
-rw-r--r--Utilities/cmcurl/lib/asyn-thread.c50
-rw-r--r--Utilities/cmcurl/lib/base64.c1
-rw-r--r--Utilities/cmcurl/lib/c-hyper.c106
-rw-r--r--Utilities/cmcurl/lib/cf-h1-proxy.c55
-rw-r--r--Utilities/cmcurl/lib/cf-h2-proxy.c67
-rw-r--r--Utilities/cmcurl/lib/cf-haproxy.c20
-rw-r--r--Utilities/cmcurl/lib/cf-https-connect.c54
-rw-r--r--Utilities/cmcurl/lib/cf-socket.c93
-rw-r--r--Utilities/cmcurl/lib/cfilters.c204
-rw-r--r--Utilities/cmcurl/lib/cfilters.h113
-rw-r--r--Utilities/cmcurl/lib/conncache.c25
-rw-r--r--Utilities/cmcurl/lib/connect.c93
-rw-r--r--Utilities/cmcurl/lib/content_encoding.c281
-rw-r--r--Utilities/cmcurl/lib/content_encoding.h9
-rw-r--r--Utilities/cmcurl/lib/cookie.c32
-rw-r--r--Utilities/cmcurl/lib/curl_config.h.cmake27
-rw-r--r--Utilities/cmcurl/lib/curl_hmac.h3
-rw-r--r--Utilities/cmcurl/lib/curl_memory.h6
-rw-r--r--Utilities/cmcurl/lib/curl_multibyte.c4
-rw-r--r--Utilities/cmcurl/lib/curl_multibyte.h8
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.c9
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_wb.c14
-rw-r--r--Utilities/cmcurl/lib/curl_path.h2
-rw-r--r--Utilities/cmcurl/lib/curl_rtmp.c2
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.c3
-rw-r--r--Utilities/cmcurl/lib/curl_setup.h141
-rw-r--r--Utilities/cmcurl/lib/curl_setup_once.h8
-rw-r--r--Utilities/cmcurl/lib/curl_sspi.h16
-rw-r--r--Utilities/cmcurl/lib/curl_trc.c26
-rw-r--r--Utilities/cmcurl/lib/curl_trc.h108
-rw-r--r--Utilities/cmcurl/lib/doh.c43
-rw-r--r--Utilities/cmcurl/lib/dynbuf.c6
-rw-r--r--Utilities/cmcurl/lib/dynhds.c29
-rw-r--r--Utilities/cmcurl/lib/dynhds.h9
-rw-r--r--Utilities/cmcurl/lib/easy.c84
-rw-r--r--Utilities/cmcurl/lib/easy_lock.h9
-rw-r--r--Utilities/cmcurl/lib/file.c8
-rw-r--r--Utilities/cmcurl/lib/fopen.c77
-rw-r--r--Utilities/cmcurl/lib/formdata.c8
-rw-r--r--Utilities/cmcurl/lib/ftp.c6
-rw-r--r--Utilities/cmcurl/lib/ftplistparser.c3
-rw-r--r--Utilities/cmcurl/lib/functypes.h2
-rw-r--r--Utilities/cmcurl/lib/getenv.c5
-rw-r--r--Utilities/cmcurl/lib/hostasyn.c11
-rw-r--r--Utilities/cmcurl/lib/hostip.c115
-rw-r--r--Utilities/cmcurl/lib/hostip.h4
-rw-r--r--Utilities/cmcurl/lib/hostip6.c7
-rw-r--r--Utilities/cmcurl/lib/hsts.c28
-rw-r--r--Utilities/cmcurl/lib/http.c236
-rw-r--r--Utilities/cmcurl/lib/http.h6
-rw-r--r--Utilities/cmcurl/lib/http2.c134
-rw-r--r--Utilities/cmcurl/lib/http_aws_sigv4.c11
-rw-r--r--Utilities/cmcurl/lib/http_chunks.c83
-rw-r--r--Utilities/cmcurl/lib/http_chunks.h4
-rw-r--r--Utilities/cmcurl/lib/http_proxy.c2
-rw-r--r--Utilities/cmcurl/lib/idn.c2
-rw-r--r--Utilities/cmcurl/lib/imap.c4
-rw-r--r--Utilities/cmcurl/lib/ldap.c20
-rw-r--r--Utilities/cmcurl/lib/md4.c5
-rw-r--r--Utilities/cmcurl/lib/memdebug.c2
-rw-r--r--Utilities/cmcurl/lib/memdebug.h4
-rw-r--r--Utilities/cmcurl/lib/mime.c5
-rw-r--r--Utilities/cmcurl/lib/mprintf.c7
-rw-r--r--Utilities/cmcurl/lib/mqtt.c9
-rw-r--r--Utilities/cmcurl/lib/multi.c295
-rw-r--r--Utilities/cmcurl/lib/multihandle.h15
-rw-r--r--Utilities/cmcurl/lib/netrc.c2
-rw-r--r--Utilities/cmcurl/lib/openldap.c54
-rw-r--r--Utilities/cmcurl/lib/pop3.c2
-rw-r--r--Utilities/cmcurl/lib/progress.c8
-rw-r--r--Utilities/cmcurl/lib/rand.c28
-rw-r--r--Utilities/cmcurl/lib/rand.h2
-rw-r--r--Utilities/cmcurl/lib/rename.c2
-rw-r--r--Utilities/cmcurl/lib/rtsp.c359
-rw-r--r--Utilities/cmcurl/lib/rtsp.h9
-rw-r--r--Utilities/cmcurl/lib/select.c2
-rw-r--r--Utilities/cmcurl/lib/sendf.c326
-rw-r--r--Utilities/cmcurl/lib/sendf.h127
-rw-r--r--Utilities/cmcurl/lib/setopt.c220
-rw-r--r--Utilities/cmcurl/lib/setup-win32.h13
-rw-r--r--Utilities/cmcurl/lib/share.h10
-rw-r--r--Utilities/cmcurl/lib/smb.c9
-rw-r--r--Utilities/cmcurl/lib/smtp.c2
-rw-r--r--Utilities/cmcurl/lib/socketpair.c6
-rw-r--r--Utilities/cmcurl/lib/socketpair.h17
-rw-r--r--Utilities/cmcurl/lib/socks.c48
-rw-r--r--Utilities/cmcurl/lib/strdup.c28
-rw-r--r--Utilities/cmcurl/lib/strdup.h3
-rw-r--r--Utilities/cmcurl/lib/strerror.c20
-rw-r--r--Utilities/cmcurl/lib/strerror.h2
-rw-r--r--Utilities/cmcurl/lib/system_win32.c4
-rw-r--r--Utilities/cmcurl/lib/system_win32.h6
-rw-r--r--Utilities/cmcurl/lib/tftp.c14
-rw-r--r--Utilities/cmcurl/lib/tftp.h3
-rw-r--r--Utilities/cmcurl/lib/timediff.c2
-rw-r--r--Utilities/cmcurl/lib/timeval.c7
-rw-r--r--Utilities/cmcurl/lib/transfer.c277
-rw-r--r--Utilities/cmcurl/lib/url.c1187
-rw-r--r--Utilities/cmcurl/lib/url.h9
-rw-r--r--Utilities/cmcurl/lib/urlapi.c45
-rw-r--r--Utilities/cmcurl/lib/urldata.h86
-rw-r--r--Utilities/cmcurl/lib/vauth/digest.c1
-rw-r--r--Utilities/cmcurl/lib/version.c12
-rw-r--r--Utilities/cmcurl/lib/version_win32.c4
-rw-r--r--Utilities/cmcurl/lib/version_win32.h4
-rw-r--r--Utilities/cmcurl/lib/vquic/curl_msh3.c35
-rw-r--r--Utilities/cmcurl/lib/vquic/curl_ngtcp2.c360
-rw-r--r--Utilities/cmcurl/lib/vquic/curl_quiche.c249
-rw-r--r--Utilities/cmcurl/lib/vquic/vquic.c27
-rw-r--r--Utilities/cmcurl/lib/vquic/vquic_int.h6
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh.c46
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh2.c262
-rw-r--r--Utilities/cmcurl/lib/vssh/ssh.h1
-rw-r--r--Utilities/cmcurl/lib/vssh/wolfssh.c3
-rw-r--r--Utilities/cmcurl/lib/vtls/bearssl.c54
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.c121
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.h6
-rw-r--r--Utilities/cmcurl/lib/vtls/keylog.c9
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.c10
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c2
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c526
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.h21
-rw-r--r--Utilities/cmcurl/lib/vtls/rustls.c117
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c174
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel_int.h17
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel_verify.c64
-rw-r--r--Utilities/cmcurl/lib/vtls/sectransp.c40
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c419
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.h80
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls_int.h40
-rw-r--r--Utilities/cmcurl/lib/vtls/wolfssl.c37
-rw-r--r--Utilities/cmcurl/lib/vtls/x509asn1.c10
-rw-r--r--Utilities/cmcurl/lib/warnless.c12
-rw-r--r--Utilities/cmcurl/lib/warnless.h21
-rw-r--r--Utilities/cmcurl/lib/ws.c8
139 files changed, 4887 insertions, 3917 deletions
diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt
index 9899b9d..bf25d89 100644
--- a/Utilities/cmcurl/lib/CMakeLists.txt
+++ b/Utilities/cmcurl/lib/CMakeLists.txt
@@ -85,20 +85,25 @@ endif()
return() # The rest of this file is not needed for building within CMake.
#-----------------------------------------------------------------------------
-add_library(
- curlu # special libcurlu library just for unittests
- STATIC
- EXCLUDE_FROM_ALL
- ${HHEADERS} ${CSOURCES}
-)
-target_compile_definitions(curlu PUBLIC UNITTESTS CURL_STATICLIB)
+if(BUILD_TESTING)
+ add_library(
+ curlu # special libcurlu library just for unittests
+ STATIC
+ EXCLUDE_FROM_ALL
+ ${HHEADERS} ${CSOURCES}
+ )
+ target_compile_definitions(curlu PUBLIC UNITTESTS CURL_STATICLIB)
+endif()
if(ENABLE_CURLDEBUG)
# We must compile these sources separately to avoid memdebug.h redefinitions
# applying to them.
set_source_files_properties(memdebug.c curl_multibyte.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
endif()
-target_link_libraries(curlu PRIVATE ${CURL_LIBS})
+
+if(BUILD_TESTING)
+ target_link_libraries(curlu PRIVATE ${CURL_LIBS})
+endif()
transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake)
diff --git a/Utilities/cmcurl/lib/altsvc.c b/Utilities/cmcurl/lib/altsvc.c
index 22b0b69..35450d6 100644
--- a/Utilities/cmcurl/lib/altsvc.c
+++ b/Utilities/cmcurl/lib/altsvc.c
@@ -97,7 +97,7 @@ static struct altsvc *altsvc_createid(const char *srchost,
unsigned int srcport,
unsigned int dstport)
{
- struct altsvc *as = calloc(sizeof(struct altsvc), 1);
+ struct altsvc *as = calloc(1, sizeof(struct altsvc));
size_t hlen;
size_t dlen;
if(!as)
@@ -123,15 +123,13 @@ static struct altsvc *altsvc_createid(const char *srchost,
dlen -= 2;
}
- as->src.host = Curl_memdup(srchost, hlen + 1);
+ as->src.host = Curl_strndup(srchost, hlen);
if(!as->src.host)
goto error;
- as->src.host[hlen] = 0;
- as->dst.host = Curl_memdup(dsthost, dlen + 1);
+ as->dst.host = Curl_strndup(dsthost, dlen);
if(!as->dst.host)
goto error;
- as->dst.host[dlen] = 0;
as->src.alpnid = srcalpnid;
as->dst.alpnid = dstalpnid;
@@ -301,7 +299,7 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
*/
struct altsvcinfo *Curl_altsvc_init(void)
{
- struct altsvcinfo *asi = calloc(sizeof(struct altsvcinfo), 1);
+ struct altsvcinfo *asi = calloc(1, sizeof(struct altsvcinfo));
if(!asi)
return NULL;
Curl_llist_init(&asi->list, NULL);
diff --git a/Utilities/cmcurl/lib/arpa_telnet.h b/Utilities/cmcurl/lib/arpa_telnet.h
index de13738..228b446 100644
--- a/Utilities/cmcurl/lib/arpa_telnet.h
+++ b/Utilities/cmcurl/lib/arpa_telnet.h
@@ -56,12 +56,14 @@ static const char * const telnetoptions[]=
"TERM SPEED", "LFLOW", "LINEMODE", "XDISPLOC",
"OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON"
};
+#define CURL_TELOPT(x) telnetoptions[x]
+#else
+#define CURL_TELOPT(x) ""
#endif
#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON
#define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM)
-#define CURL_TELOPT(x) telnetoptions[x]
#define CURL_NTELOPTS 40
@@ -103,7 +105,12 @@ static const char * const telnetcmds[]=
#define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \
((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) )
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
#define CURL_TELCMD(x) telnetcmds[(x)-CURL_TELCMD_MINIMUM]
+#else
+#define CURL_TELCMD(x) ""
+#endif
#endif /* CURL_DISABLE_TELNET */
diff --git a/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c
index e73e41d..437c933 100644
--- a/Utilities/cmcurl/lib/asyn-ares.c
+++ b/Utilities/cmcurl/lib/asyn-ares.c
@@ -60,13 +60,13 @@
#include "progress.h"
#include "timediff.h"
-# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
- defined(WIN32)
-# define CARES_STATICLIB
-# endif
-# include <ares.h>
-# include <ares_version.h> /* really old c-ares didn't include this by
- itself */
+#if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
+ defined(_WIN32)
+# define CARES_STATICLIB
+#endif
+#include <ares.h>
+#include <ares_version.h> /* really old c-ares didn't include this by
+ itself */
#if ARES_VERSION >= 0x010500
/* c-ares 1.5.0 or later, the callback proto is modified */
@@ -228,9 +228,9 @@ static void destroy_async_data(struct Curl_async *async);
void Curl_resolver_cancel(struct Curl_easy *data)
{
DEBUGASSERT(data);
- if(data->state.async.resolver)
- ares_cancel((ares_channel)data->state.async.resolver);
- destroy_async_data(&data->state.async);
+ if(data->conn->resolve_async.resolver)
+ ares_cancel((ares_channel)data->conn->resolve_async.resolver);
+ destroy_async_data(&data->conn->resolve_async);
}
/*
@@ -278,14 +278,14 @@ int Curl_resolver_getsock(struct Curl_easy *data,
struct timeval timebuf;
struct timeval *timeout;
long milli;
- int max = ares_getsock((ares_channel)data->state.async.resolver,
+ int max = ares_getsock((ares_channel)data->conn->resolve_async.resolver,
(ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
maxtime.tv_usec = 0;
- timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime,
- &timebuf);
+ timeout = ares_timeout((ares_channel)data->conn->resolve_async.resolver,
+ &maxtime, &timebuf);
milli = (long)curlx_tvtoms(timeout);
if(milli == 0)
milli += 10;
@@ -313,8 +313,8 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
int i;
int num = 0;
- bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks,
- ARES_GETSOCK_MAXNUM);
+ bitmask = ares_getsock((ares_channel)data->conn->resolve_async.resolver,
+ socks, ARES_GETSOCK_MAXNUM);
for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
pfd[i].events = 0;
@@ -344,12 +344,12 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
if(!nfds)
/* Call ares_process() unconditionally here, even if we simply timed out
above, as otherwise the ares name resolve won't timeout! */
- ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
- ARES_SOCKET_BAD);
+ ares_process_fd((ares_channel)data->conn->resolve_async.resolver,
+ ARES_SOCKET_BAD, ARES_SOCKET_BAD);
else {
/* move through the descriptors and ask for processing on them */
for(i = 0; i < num; i++)
- ares_process_fd((ares_channel)data->state.async.resolver,
+ ares_process_fd((ares_channel)data->conn->resolve_async.resolver,
(pfd[i].revents & (POLLRDNORM|POLLIN))?
pfd[i].fd:ARES_SOCKET_BAD,
(pfd[i].revents & (POLLWRNORM|POLLOUT))?
@@ -368,7 +368,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dns)
{
- struct thread_data *res = data->state.async.tdata;
+ struct thread_data *res = data->conn->resolve_async.tdata;
CURLcode result = CURLE_OK;
DEBUGASSERT(dns);
@@ -397,7 +397,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
ARES_ECANCELLED synchronously for all pending responses. This will
leave us with res->num_pending == 0, which is perfect for the next
block. */
- ares_cancel((ares_channel)data->state.async.resolver);
+ ares_cancel((ares_channel)data->conn->resolve_async.resolver);
DEBUGASSERT(res->num_pending == 0);
}
#endif
@@ -408,12 +408,12 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
them */
res->temp_ai = NULL;
- if(!data->state.async.dns)
+ if(!data->conn->resolve_async.dns)
result = Curl_resolver_error(data);
else
- *dns = data->state.async.dns;
+ *dns = data->conn->resolve_async.dns;
- destroy_async_data(&data->state.async);
+ destroy_async_data(&data->conn->resolve_async);
}
return result;
@@ -464,7 +464,8 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
store.tv_sec = itimeout/1000;
store.tv_usec = (itimeout%1000)*1000;
- tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv);
+ tvp = ares_timeout((ares_channel)data->conn->resolve_async.resolver,
+ &store, &tv);
/* use the timeout period ares returned to us above if less than one
second is left, otherwise just use 1000ms to make sure the progress
@@ -478,7 +479,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
return CURLE_UNRECOVERABLE_POLL;
result = Curl_resolver_is_resolved(data, entry);
- if(result || data->state.async.done)
+ if(result || data->conn->resolve_async.done)
break;
if(Curl_pgrsUpdate(data))
@@ -499,12 +500,12 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
}
if(result)
/* failure, so we cancel the ares operation */
- ares_cancel((ares_channel)data->state.async.resolver);
+ ares_cancel((ares_channel)data->conn->resolve_async.resolver);
/* Operation complete, if the lookup was successful we now have the entry
in the cache. */
if(entry)
- *entry = data->state.async.dns;
+ *entry = data->conn->resolve_async.dns;
if(result)
/* close the connection, since we can't return failure here without
@@ -571,12 +572,13 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
be valid so only defer it when we know the 'status' says its fine! */
return;
- res = data->state.async.tdata;
+ res = data->conn->resolve_async.tdata;
if(res) {
res->num_pending--;
if(CURL_ASYNC_SUCCESS == status) {
- struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
+ struct Curl_addrinfo *ai = Curl_he2ai(hostent,
+ data->conn->resolve_async.port);
if(ai) {
compound_results(res, ai);
}
@@ -727,14 +729,16 @@ static void addrinfo_cb(void *arg, int status, int timeouts,
struct ares_addrinfo *result)
{
struct Curl_easy *data = (struct Curl_easy *)arg;
- struct thread_data *res = data->state.async.tdata;
- (void)timeouts;
- if(ARES_SUCCESS == status) {
- res->temp_ai = ares2addr(result->nodes);
- res->last_status = CURL_ASYNC_SUCCESS;
- ares_freeaddrinfo(result);
+ if(data->conn) {
+ struct thread_data *res = data->conn->resolve_async.tdata;
+ (void)timeouts;
+ if(ARES_SUCCESS == status) {
+ res->temp_ai = ares2addr(result->nodes);
+ res->last_status = CURL_ASYNC_SUCCESS;
+ ares_freeaddrinfo(result);
+ }
+ res->num_pending--;
}
- res->num_pending--;
}
#endif
@@ -755,15 +759,15 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
size_t namelen = strlen(hostname);
*waitp = 0; /* default to synchronous response */
- res = calloc(sizeof(struct thread_data) + namelen, 1);
+ res = calloc(1, sizeof(struct thread_data) + namelen);
if(res) {
strcpy(res->hostname, hostname);
- data->state.async.hostname = res->hostname;
- data->state.async.port = port;
- data->state.async.done = FALSE; /* not done */
- data->state.async.status = 0; /* clear */
- data->state.async.dns = NULL; /* clear */
- data->state.async.tdata = res;
+ data->conn->resolve_async.hostname = res->hostname;
+ data->conn->resolve_async.port = port;
+ data->conn->resolve_async.done = FALSE; /* not done */
+ data->conn->resolve_async.status = 0; /* clear */
+ data->conn->resolve_async.dns = NULL; /* clear */
+ data->conn->resolve_async.tdata = res;
/* initial status - failed */
res->last_status = ARES_ENOTFOUND;
@@ -793,8 +797,8 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
hints.ai_flags = ARES_AI_NUMERICSERV;
msnprintf(service, sizeof(service), "%d", port);
res->num_pending = 1;
- ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
- service, &hints, addrinfo_cb, data);
+ ares_getaddrinfo((ares_channel)data->conn->resolve_async.resolver,
+ hostname, service, &hints, addrinfo_cb, data);
}
#else
@@ -804,10 +808,10 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
res->num_pending = 2;
/* areschannel is already setup in the Curl_open() function */
- ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
- PF_INET, query_completed_cb, data);
- ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
- PF_INET6, query_completed_cb, data);
+ ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
+ hostname, PF_INET, query_completed_cb, data);
+ ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
+ hostname, PF_INET6, query_completed_cb, data);
}
else
#endif
@@ -815,7 +819,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
res->num_pending = 1;
/* areschannel is already setup in the Curl_open() function */
- ares_gethostbyname((ares_channel)data->state.async.resolver,
+ ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
hostname, PF_INET,
query_completed_cb, data);
}
@@ -829,6 +833,7 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
char *servers)
{
CURLcode result = CURLE_NOT_BUILT_IN;
+ ares_channel channel, lchannel = NULL;
int ares_result;
/* If server is NULL or empty, this would purge all DNS servers
@@ -841,11 +846,23 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
return CURLE_OK;
#ifdef HAVE_CARES_SERVERS_CSV
+ if(data->conn)
+ channel = data->conn->resolve_async.resolver;
+ else {
+ /* we are called by setopt on a data without a connection (yet). In that
+ * case we set the value on a local instance for checking.
+ * The configured data options are set when the connection for this
+ * transfer is created. */
+ result = Curl_resolver_init(data, (void **)&lchannel);
+ if(result)
+ goto out;
+ channel = lchannel;
+ }
+
#ifdef HAVE_CARES_PORTS_CSV
- ares_result = ares_set_servers_ports_csv(data->state.async.resolver,
- servers);
+ ares_result = ares_set_servers_ports_csv(channel, servers);
#else
- ares_result = ares_set_servers_csv(data->state.async.resolver, servers);
+ ares_result = ares_set_servers_csv(channel, servers);
#endif
switch(ares_result) {
case ARES_SUCCESS:
@@ -861,6 +878,9 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
result = CURLE_BAD_FUNCTION_ARGUMENT;
break;
}
+out:
+ if(lchannel)
+ Curl_resolver_cleanup(lchannel);
#else /* too old c-ares version! */
(void)data;
(void)(ares_result);
@@ -872,11 +892,14 @@ CURLcode Curl_set_dns_interface(struct Curl_easy *data,
const char *interf)
{
#ifdef HAVE_CARES_LOCAL_DEV
- if(!interf)
- interf = "";
-
- ares_set_local_dev((ares_channel)data->state.async.resolver, interf);
+ if(data->conn) {
+ /* not a setopt test run, set the value */
+ if(!interf)
+ interf = "";
+ ares_set_local_dev((ares_channel)data->conn->resolve_async.resolver,
+ interf);
+ }
return CURLE_OK;
#else /* c-ares version too old! */
(void)data;
@@ -900,8 +923,11 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
}
}
- ares_set_local_ip4((ares_channel)data->state.async.resolver,
- ntohl(a4.s_addr));
+ if(data->conn) {
+ /* not a setopt test run, set the value */
+ ares_set_local_ip4((ares_channel)data->conn->resolve_async.resolver,
+ ntohl(a4.s_addr));
+ }
return CURLE_OK;
#else /* c-ares version too old! */
@@ -927,7 +953,10 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
}
}
- ares_set_local_ip6((ares_channel)data->state.async.resolver, a6);
+ if(data->conn) {
+ /* not a setopt test run, set the value */
+ ares_set_local_ip6((ares_channel)data->conn->resolve_async.resolver, a6);
+ }
return CURLE_OK;
#else /* c-ares version too old! */
diff --git a/Utilities/cmcurl/lib/asyn-thread.c b/Utilities/cmcurl/lib/asyn-thread.c
index a2e294f..63414b6 100644
--- a/Utilities/cmcurl/lib/asyn-thread.c
+++ b/Utilities/cmcurl/lib/asyn-thread.c
@@ -136,7 +136,7 @@ static void destroy_async_data(struct Curl_async *);
*/
void Curl_resolver_cancel(struct Curl_easy *data)
{
- destroy_async_data(&data->state.async);
+ destroy_async_data(&data->conn->resolve_async);
}
/* This function is used to init a threaded resolve */
@@ -173,7 +173,7 @@ struct thread_data {
static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
{
- return &(data->state.async.tdata->tsd);
+ return &(data->conn->resolve_async.tdata->tsd);
}
/* Destroy resolver thread synchronization data */
@@ -196,7 +196,7 @@ void destroy_thread_sync_data(struct thread_sync_data *tsd)
* the other end (for reading) is always closed in the parent thread.
*/
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
- sclose(tsd->sock_pair[1]);
+ wakeup_close(tsd->sock_pair[1]);
}
#endif
memset(tsd, 0, sizeof(*tsd));
@@ -233,8 +233,8 @@ int init_thread_sync_data(struct thread_data *td,
Curl_mutex_init(tsd->mtx);
#ifndef CURL_DISABLE_SOCKETPAIR
- /* create socket pair, avoid AF_LOCAL since it doesn't build on Solaris */
- if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &tsd->sock_pair[0]) < 0) {
+ /* create socket pair or pipe */
+ if(wakeup_create(&tsd->sock_pair[0]) < 0) {
tsd->sock_pair[0] = CURL_SOCKET_BAD;
tsd->sock_pair[1] = CURL_SOCKET_BAD;
goto err_exit;
@@ -254,7 +254,7 @@ int init_thread_sync_data(struct thread_data *td,
err_exit:
#ifndef CURL_DISABLE_SOCKETPAIR
if(tsd->sock_pair[0] != CURL_SOCKET_BAD) {
- sclose(tsd->sock_pair[0]);
+ wakeup_close(tsd->sock_pair[0]);
tsd->sock_pair[0] = CURL_SOCKET_BAD;
}
#endif
@@ -320,7 +320,7 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
/* DNS has been resolved, signal client task */
buf[0] = 1;
- if(swrite(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
+ if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
/* update sock_erro to errno */
tsd->sock_error = SOCKERRNO;
}
@@ -428,9 +428,9 @@ static bool init_resolve_thread(struct Curl_easy *data,
{
struct thread_data *td = calloc(1, sizeof(struct thread_data));
int err = ENOMEM;
- struct Curl_async *asp = &data->state.async;
+ struct Curl_async *asp = &data->conn->resolve_async;
- data->state.async.tdata = td;
+ data->conn->resolve_async.tdata = td;
if(!td)
goto errno_exit;
@@ -488,7 +488,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
- td = data->state.async.tdata;
+ td = data->conn->resolve_async.tdata;
DEBUGASSERT(td);
DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
@@ -500,18 +500,18 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
else
DEBUGASSERT(0);
- data->state.async.done = TRUE;
+ data->conn->resolve_async.done = TRUE;
if(entry)
- *entry = data->state.async.dns;
+ *entry = data->conn->resolve_async.dns;
- if(!data->state.async.dns && report)
+ if(!data->conn->resolve_async.dns && report)
/* a name was not resolved, report error */
result = Curl_resolver_error(data);
- destroy_async_data(&data->state.async);
+ destroy_async_data(&data->conn->resolve_async);
- if(!data->state.async.dns && report)
+ if(!data->conn->resolve_async.dns && report)
connclose(data->conn, "asynch resolve failed");
return result;
@@ -524,7 +524,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
*/
void Curl_resolver_kill(struct Curl_easy *data)
{
- struct thread_data *td = data->state.async.tdata;
+ struct thread_data *td = data->conn->resolve_async.tdata;
/* If we're still resolving, we must wait for the threads to fully clean up,
unfortunately. Otherwise, we can simply cancel to clean up any resolver
@@ -563,7 +563,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **entry)
{
- struct thread_data *td = data->state.async.tdata;
+ struct thread_data *td = data->conn->resolve_async.tdata;
int done = 0;
DEBUGASSERT(entry);
@@ -581,13 +581,13 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
if(done) {
getaddrinfo_complete(data);
- if(!data->state.async.dns) {
+ if(!data->conn->resolve_async.dns) {
CURLcode result = Curl_resolver_error(data);
- destroy_async_data(&data->state.async);
+ destroy_async_data(&data->conn->resolve_async);
return result;
}
- destroy_async_data(&data->state.async);
- *entry = data->state.async.dns;
+ destroy_async_data(&data->conn->resolve_async);
+ *entry = data->conn->resolve_async.dns;
}
else {
/* poll for name lookup done with exponential backoff up to 250ms */
@@ -619,9 +619,9 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
int ret_val = 0;
timediff_t milli;
timediff_t ms;
- struct resdata *reslv = (struct resdata *)data->state.async.resolver;
+ struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
#ifndef CURL_DISABLE_SOCKETPAIR
- struct thread_data *td = data->state.async.tdata;
+ struct thread_data *td = data->conn->resolve_async.tdata;
#else
(void)socks;
#endif
@@ -662,7 +662,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
int port,
int *waitp)
{
- struct resdata *reslv = (struct resdata *)data->state.async.resolver;
+ struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
*waitp = 0; /* default to synchronous response */
@@ -691,7 +691,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
{
struct addrinfo hints;
int pf = PF_INET;
- struct resdata *reslv = (struct resdata *)data->state.async.resolver;
+ struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
*waitp = 0; /* default to synchronous response */
diff --git a/Utilities/cmcurl/lib/base64.c b/Utilities/cmcurl/lib/base64.c
index 2a49b5a..919eb62 100644
--- a/Utilities/cmcurl/lib/base64.c
+++ b/Utilities/cmcurl/lib/base64.c
@@ -31,6 +31,7 @@
!defined(CURL_DISABLE_SMTP) || \
!defined(CURL_DISABLE_POP3) || \
!defined(CURL_DISABLE_IMAP) || \
+ !defined(CURL_DISABLE_DIGEST_AUTH) || \
!defined(CURL_DISABLE_DOH) || defined(USE_SSL) || defined(BUILDING_CURL)
#include "curl/curl.h"
#include "warnless.h"
diff --git a/Utilities/cmcurl/lib/c-hyper.c b/Utilities/cmcurl/lib/c-hyper.c
index 5726ff1..787d6bb 100644
--- a/Utilities/cmcurl/lib/c-hyper.c
+++ b/Utilities/cmcurl/lib/c-hyper.c
@@ -22,6 +22,10 @@
*
***************************************************************************/
+/* Curl's integration with Hyper. This replaces certain functions in http.c,
+ * based on configuration #defines. This implementation supports HTTP/1.1 but
+ * not HTTP/2.
+ */
#include "curl_setup.h"
#if !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER)
@@ -172,17 +176,15 @@ static int hyper_each_header(void *userdata,
Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
- if(!data->state.hconnect || !data->set.suppress_connect_headers) {
- writetype = CLIENTWRITE_HEADER;
- if(data->state.hconnect)
- writetype |= CLIENTWRITE_CONNECT;
- if(data->req.httpcode/100 == 1)
- writetype |= CLIENTWRITE_1XX;
- result = Curl_client_write(data, writetype, headp, len);
- if(result) {
- data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
- return HYPER_ITER_BREAK;
- }
+ writetype = CLIENTWRITE_HEADER;
+ if(data->state.hconnect)
+ writetype |= CLIENTWRITE_CONNECT;
+ if(data->req.httpcode/100 == 1)
+ writetype |= CLIENTWRITE_1XX;
+ result = Curl_client_write(data, writetype, headp, len);
+ if(result) {
+ data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
+ return HYPER_ITER_BREAK;
}
result = Curl_bump_headersize(data, len, FALSE);
@@ -201,7 +203,7 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
struct SingleRequest *k = &data->req;
CURLcode result = CURLE_OK;
- if(0 == k->bodywrites++) {
+ if(0 == k->bodywrites) {
bool done = FALSE;
#if defined(USE_NTLM)
struct connectdata *conn = data->conn;
@@ -241,11 +243,6 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
return HYPER_ITER_BREAK;
}
}
- if(k->ignorebody)
- return HYPER_ITER_CONTINUE;
- if(0 == len)
- return HYPER_ITER_CONTINUE;
- Curl_debug(data, CURLINFO_DATA_IN, buf, len);
result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
if(result) {
@@ -253,12 +250,6 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
return HYPER_ITER_BREAK;
}
- data->req.bytecount += len;
- result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
- if(result) {
- data->state.hresult = result;
- return HYPER_ITER_BREAK;
- }
return HYPER_ITER_CONTINUE;
}
@@ -310,13 +301,14 @@ static CURLcode status_line(struct Curl_easy *data,
Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
len);
- if(!data->state.hconnect || !data->set.suppress_connect_headers) {
- writetype = CLIENTWRITE_HEADER|CLIENTWRITE_STATUS;
- result = Curl_client_write(data, writetype,
- Curl_dyn_ptr(&data->state.headerb), len);
- if(result)
- return result;
- }
+ writetype = CLIENTWRITE_HEADER|CLIENTWRITE_STATUS;
+ if(data->state.hconnect)
+ writetype |= CLIENTWRITE_CONNECT;
+ result = Curl_client_write(data, writetype,
+ Curl_dyn_ptr(&data->state.headerb), len);
+ if(result)
+ return result;
+
result = Curl_bump_headersize(data, len, FALSE);
return result;
}
@@ -551,11 +543,9 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
static CURLcode debug_request(struct Curl_easy *data,
const char *method,
- const char *path,
- bool h2)
+ const char *path)
{
- char *req = aprintf("%s %s HTTP/%s\r\n", method, path,
- h2?"2":"1.1");
+ char *req = aprintf("%s %s HTTP/1.1\r\n", method, path);
if(!req)
return CURLE_OUT_OF_MEMORY;
Curl_debug(data, CURLINFO_HEADER_OUT, req, strlen(req));
@@ -637,7 +627,6 @@ CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
static CURLcode request_target(struct Curl_easy *data,
struct connectdata *conn,
const char *method,
- bool h2,
hyper_request *req)
{
CURLcode result;
@@ -649,26 +638,13 @@ static CURLcode request_target(struct Curl_easy *data,
if(result)
return result;
- if(h2 && hyper_request_set_uri_parts(req,
- /* scheme */
- (uint8_t *)data->state.up.scheme,
- strlen(data->state.up.scheme),
- /* authority */
- (uint8_t *)conn->host.name,
- strlen(conn->host.name),
- /* path_and_query */
- (uint8_t *)Curl_dyn_uptr(&r),
- Curl_dyn_len(&r))) {
- failf(data, "error setting uri parts to hyper");
- result = CURLE_OUT_OF_MEMORY;
- }
- else if(!h2 && hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
+ if(hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
Curl_dyn_len(&r))) {
failf(data, "error setting uri to hyper");
result = CURLE_OUT_OF_MEMORY;
}
else
- result = debug_request(data, method, Curl_dyn_ptr(&r), h2);
+ result = debug_request(data, method, Curl_dyn_ptr(&r));
Curl_dyn_free(&r);
@@ -899,7 +875,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
const char *p_accept; /* Accept: string */
const char *method;
Curl_HttpReq httpreq;
- bool h2 = FALSE;
const char *te = NULL; /* transfer-encoding */
hyper_code rc;
@@ -907,6 +882,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
may be parts of the request that is not yet sent, since we can deal with
the rest of the request in the PERFORM phase. */
*done = TRUE;
+ Curl_client_cleanup(data);
infof(data, "Time for the Hyper dance");
memset(h, 0, sizeof(struct hyptransfer));
@@ -917,6 +893,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
Curl_http_method(data, conn, &method, &httpreq);
+ DEBUGASSERT(data->req.bytecount == 0);
+
/* setup the authentication headers */
{
char *pq = NULL;
@@ -972,8 +950,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
goto error;
}
if(conn->alpn == CURL_HTTP_VERSION_2) {
- hyper_clientconn_options_http2(options, 1);
- h2 = TRUE;
+ failf(data, "ALPN protocol h2 not supported with Hyper");
+ result = CURLE_UNSUPPORTED_PROTOCOL;
+ goto error;
}
hyper_clientconn_options_set_preserve_header_case(options, 1);
hyper_clientconn_options_set_preserve_header_order(options, 1);
@@ -1024,7 +1003,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
}
}
else {
- if(!h2 && !data->state.disableexpect) {
+ if(!data->state.disableexpect) {
data->state.expect100header = TRUE;
}
}
@@ -1035,7 +1014,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
goto error;
}
- result = request_target(data, conn, method, h2, req);
+ result = request_target(data, conn, method, req);
if(result)
goto error;
@@ -1056,19 +1035,10 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(result)
goto error;
- if(!h2) {
- if(data->state.aptr.host) {
- result = Curl_hyper_header(data, headers, data->state.aptr.host);
- if(result)
- goto error;
- }
- }
- else {
- /* For HTTP/2, we show the Host: header as if we sent it, to make it look
- like for HTTP/1 but it isn't actually sent since :authority is then
- used. */
- Curl_debug(data, CURLINFO_HEADER_OUT, data->state.aptr.host,
- strlen(data->state.aptr.host));
+ if(data->state.aptr.host) {
+ result = Curl_hyper_header(data, headers, data->state.aptr.host);
+ if(result)
+ goto error;
}
if(data->state.aptr.proxyuserpwd) {
diff --git a/Utilities/cmcurl/lib/cf-h1-proxy.c b/Utilities/cmcurl/lib/cf-h1-proxy.c
index 6748021..2e23b0b 100644
--- a/Utilities/cmcurl/lib/cf-h1-proxy.c
+++ b/Utilities/cmcurl/lib/cf-h1-proxy.c
@@ -374,7 +374,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
curl_socket_t tunnelsocket = Curl_conn_cf_get_socket(cf, data);
char *linep;
size_t perline;
- int error;
+ int error, writetype;
#define SELECT_OK 0
#define SELECT_ERROR 1
@@ -386,12 +386,12 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
return CURLE_OK;
while(ts->keepon) {
- ssize_t gotbytes;
+ ssize_t nread;
char byte;
/* Read one byte at a time to avoid a race condition. Wait at most one
second before looping to ensure continuous pgrsUpdates. */
- result = Curl_read(data, tunnelsocket, &byte, 1, &gotbytes);
+ result = Curl_read(data, tunnelsocket, &byte, 1, &nread);
if(result == CURLE_AGAIN)
/* socket buffer drained, return */
return CURLE_OK;
@@ -404,7 +404,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
break;
}
- if(gotbytes <= 0) {
+ if(nread <= 0) {
if(data->set.proxyauth && data->state.authproxy.avail &&
data->state.aptr.proxyuserpwd) {
/* proxy auth was requested and there was proxy auth available,
@@ -437,11 +437,11 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
properly to know when the end of the body is reached */
CHUNKcode r;
CURLcode extra;
- ssize_t tookcareof = 0;
+ size_t consumed = 0;
/* now parse the chunked piece of data so that we can
properly tell when the stream ends */
- r = Curl_httpchunk_read(data, &byte, 1, &tookcareof, &extra);
+ r = Curl_httpchunk_read(data, &byte, 1, &consumed, &extra);
if(r == CHUNKE_STOP) {
/* we're done reading chunks! */
infof(data, "chunk reading DONE");
@@ -467,15 +467,12 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
/* output debug if that is requested */
Curl_debug(data, CURLINFO_HEADER_IN, linep, perline);
- if(!data->set.suppress_connect_headers) {
- /* send the header to the callback */
- int writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
- (ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
-
- result = Curl_client_write(data, writetype, linep, perline);
- if(result)
- return result;
- }
+ /* send the header to the callback */
+ writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
+ (ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
+ result = Curl_client_write(data, writetype, linep, perline);
+ if(result)
+ return result;
result = Curl_bump_headersize(data, perline, TRUE);
if(result)
@@ -502,6 +499,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
else if(ts->chunked_encoding) {
CHUNKcode r;
CURLcode extra;
+ size_t consumed = 0;
infof(data, "Ignore chunked response-body");
@@ -516,8 +514,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
/* now parse the chunked piece of data so that we can properly
tell when the stream ends */
- r = Curl_httpchunk_read(data, linep + 1, 1, &gotbytes,
- &extra);
+ r = Curl_httpchunk_read(data, linep + 1, 1, &consumed, &extra);
if(r == CHUNKE_STOP) {
/* we're done reading chunks! */
infof(data, "chunk reading DONE");
@@ -1038,31 +1035,29 @@ out:
return result;
}
-static int cf_h1_proxy_get_select_socks(struct Curl_cfilter *cf,
+static void cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
- curl_socket_t *socks)
+ struct easy_pollset *ps)
{
struct h1_tunnel_state *ts = cf->ctx;
- int fds;
- fds = cf->next->cft->get_select_socks(cf->next, data, socks);
- if(!fds && cf->next->connected && !cf->connected) {
+ if(!cf->connected) {
/* If we are not connected, but the filter "below" is
* and not waiting on something, we are tunneling. */
- socks[0] = Curl_conn_cf_get_socket(cf, data);
+ curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
if(ts) {
/* when we've sent a CONNECT to a proxy, we should rather either
wait for the socket to become readable to be able to get the
response headers or if we're still sending the request, wait
for write. */
- if(ts->CONNECT.sending == HTTPSEND_REQUEST) {
- return GETSOCK_WRITESOCK(0);
- }
- return GETSOCK_READSOCK(0);
+ if(ts->CONNECT.sending == HTTPSEND_REQUEST)
+ Curl_pollset_set_out_only(data, ps, sock);
+ else
+ Curl_pollset_set_in_only(data, ps, sock);
}
- return GETSOCK_WRITESOCK(0);
+ else
+ Curl_pollset_set_out_only(data, ps, sock);
}
- return fds;
}
static void cf_h1_proxy_destroy(struct Curl_cfilter *cf,
@@ -1093,7 +1088,7 @@ struct Curl_cftype Curl_cft_h1_proxy = {
cf_h1_proxy_connect,
cf_h1_proxy_close,
Curl_cf_http_proxy_get_host,
- cf_h1_proxy_get_select_socks,
+ cf_h1_proxy_adjust_pollset,
Curl_cf_def_data_pending,
Curl_cf_def_send,
Curl_cf_def_recv,
diff --git a/Utilities/cmcurl/lib/cf-h2-proxy.c b/Utilities/cmcurl/lib/cf-h2-proxy.c
index dbc895d..147acdc 100644
--- a/Utilities/cmcurl/lib/cf-h2-proxy.c
+++ b/Utilities/cmcurl/lib/cf-h2-proxy.c
@@ -688,12 +688,8 @@ static int proxy_h2_on_frame_recv(nghttp2_session *session,
* 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)) {
- data->req.keepon &= ~KEEP_SEND_HOLD;
+ if(CURL_WANT_SEND(data)) {
drain_tunnel(cf, data, &ctx->tunnel);
- CURL_TRC_CF(data, cf, "[%d] un-holding after SETTINGS",
- stream_id);
}
break;
case NGHTTP2_GOAWAY:
@@ -727,12 +723,8 @@ static int proxy_h2_on_frame_recv(nghttp2_session *session,
}
break;
case NGHTTP2_WINDOW_UPDATE:
- if((data->req.keepon & KEEP_SEND_HOLD) &&
- (data->req.keepon & KEEP_SEND)) {
- data->req.keepon &= ~KEEP_SEND_HOLD;
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
- CURL_TRC_CF(data, cf, "[%d] unpausing after win update",
- stream_id);
+ if(CURL_WANT_SEND(data)) {
+ drain_tunnel(cf, data, &ctx->tunnel);
}
break;
default:
@@ -909,7 +901,6 @@ static CURLcode proxy_h2_submit(int32_t *pstream_id,
{
struct dynhds h2_headers;
nghttp2_nv *nva = NULL;
- unsigned int i;
int32_t stream_id = -1;
size_t nheader;
CURLcode result;
@@ -920,22 +911,12 @@ static CURLcode proxy_h2_submit(int32_t *pstream_id,
if(result)
goto out;
- nheader = Curl_dynhds_count(&h2_headers);
- nva = malloc(sizeof(nghttp2_nv) * nheader);
+ nva = Curl_dynhds_to_nva(&h2_headers, &nheader);
if(!nva) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
- for(i = 0; i < nheader; ++i) {
- struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i);
- nva[i].name = (unsigned char *)e->name;
- nva[i].namelen = e->namelen;
- nva[i].value = (unsigned char *)e->value;
- nva[i].valuelen = e->valuelen;
- nva[i].flags = NGHTTP2_NV_FLAG_NONE;
- }
-
if(read_callback) {
nghttp2_data_provider data_prd;
@@ -1187,25 +1168,31 @@ static bool cf_h2_proxy_data_pending(struct Curl_cfilter *cf,
return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
}
-static int cf_h2_proxy_get_select_socks(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- curl_socket_t *sock)
+static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
- int bitmap = GETSOCK_BLANK;
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
- sock[0] = Curl_conn_cf_get_socket(cf, data);
- bitmap |= GETSOCK_READSOCK(0);
+ curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
+ bool want_recv, want_send;
- /* HTTP/2 layer wants to send data) AND there's a window to send data in */
- if(nghttp2_session_want_write(ctx->h2) &&
- nghttp2_session_get_remote_window_size(ctx->h2))
- bitmap |= GETSOCK_WRITESOCK(0);
+ Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
+ if(ctx->h2 && (want_recv || want_send)) {
+ struct cf_call_data save;
+ bool c_exhaust, s_exhaust;
- CF_DATA_RESTORE(cf, save);
- return bitmap;
+ CF_DATA_SAVE(save, cf, data);
+ c_exhaust = !nghttp2_session_get_remote_window_size(ctx->h2);
+ s_exhaust = ctx->tunnel.stream_id >= 0 &&
+ !nghttp2_session_get_stream_remote_window_size(
+ ctx->h2, ctx->tunnel.stream_id);
+ want_recv = (want_recv || c_exhaust || s_exhaust);
+ want_send = (!s_exhaust && want_send) ||
+ (!c_exhaust && nghttp2_session_want_write(ctx->h2));
+
+ Curl_pollset_set(data, ps, sock, want_recv, want_send);
+ CF_DATA_RESTORE(cf, save);
+ }
}
static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf,
@@ -1542,7 +1529,7 @@ struct Curl_cftype Curl_cft_h2_proxy = {
cf_h2_proxy_connect,
cf_h2_proxy_close,
Curl_cf_http_proxy_get_host,
- cf_h2_proxy_get_select_socks,
+ cf_h2_proxy_adjust_pollset,
cf_h2_proxy_data_pending,
cf_h2_proxy_send,
cf_h2_proxy_recv,
@@ -1560,7 +1547,7 @@ CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf,
CURLcode result = CURLE_OUT_OF_MEMORY;
(void)data;
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx)
goto out;
diff --git a/Utilities/cmcurl/lib/cf-haproxy.c b/Utilities/cmcurl/lib/cf-haproxy.c
index 39ac415..1ca4393 100644
--- a/Utilities/cmcurl/lib/cf-haproxy.c
+++ b/Utilities/cmcurl/lib/cf-haproxy.c
@@ -171,23 +171,17 @@ static void cf_haproxy_close(struct Curl_cfilter *cf,
cf->next->cft->do_close(cf->next, data);
}
-static int cf_haproxy_get_select_socks(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- curl_socket_t *socks)
+static void cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
{
- int fds;
-
- fds = cf->next->cft->get_select_socks(cf->next, data, socks);
- if(!fds && cf->next->connected && !cf->connected) {
+ if(cf->next->connected && !cf->connected) {
/* If we are not connected, but the filter "below" is
* and not waiting on something, we are sending. */
- socks[0] = Curl_conn_cf_get_socket(cf, data);
- return GETSOCK_WRITESOCK(0);
+ Curl_pollset_set_out_only(data, ps, Curl_conn_cf_get_socket(cf, data));
}
- return fds;
}
-
struct Curl_cftype Curl_cft_haproxy = {
"HAPROXY",
0,
@@ -196,7 +190,7 @@ struct Curl_cftype Curl_cft_haproxy = {
cf_haproxy_connect,
cf_haproxy_close,
Curl_cf_def_get_host,
- cf_haproxy_get_select_socks,
+ cf_haproxy_adjust_pollset,
Curl_cf_def_data_pending,
Curl_cf_def_send,
Curl_cf_def_recv,
@@ -214,7 +208,7 @@ static CURLcode cf_haproxy_create(struct Curl_cfilter **pcf,
CURLcode result;
(void)data;
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
diff --git a/Utilities/cmcurl/lib/cf-https-connect.c b/Utilities/cmcurl/lib/cf-https-connect.c
index be54aec..b4f33c8 100644
--- a/Utilities/cmcurl/lib/cf-https-connect.c
+++ b/Utilities/cmcurl/lib/cf-https-connect.c
@@ -188,9 +188,6 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
#endif
infof(data, "using HTTP/2");
break;
- case CURL_HTTP_VERSION_1_1:
- infof(data, "using HTTP/1.1");
- break;
default:
infof(data, "using HTTP/1.x");
break;
@@ -325,42 +322,25 @@ out:
return result;
}
-static int cf_hc_get_select_socks(struct Curl_cfilter *cf,
+static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
- curl_socket_t *socks)
+ struct easy_pollset *ps)
{
- struct cf_hc_ctx *ctx = cf->ctx;
- size_t i, j, s;
- int brc, rc = GETSOCK_BLANK;
- curl_socket_t bsocks[MAX_SOCKSPEREASYHANDLE];
- struct cf_hc_baller *ballers[2];
-
- if(cf->connected)
- return cf->next->cft->get_select_socks(cf->next, data, socks);
-
- ballers[0] = &ctx->h3_baller;
- ballers[1] = &ctx->h21_baller;
- for(i = s = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
- struct cf_hc_baller *b = ballers[i];
- if(!cf_hc_baller_is_active(b))
- continue;
- brc = Curl_conn_cf_get_select_socks(b->cf, data, bsocks);
- CURL_TRC_CF(data, cf, "get_selected_socks(%s) -> %x", b->name, brc);
- if(!brc)
- continue;
- for(j = 0; j < MAX_SOCKSPEREASYHANDLE && s < MAX_SOCKSPEREASYHANDLE; ++j) {
- if((brc & GETSOCK_WRITESOCK(j)) || (brc & GETSOCK_READSOCK(j))) {
- socks[s] = bsocks[j];
- if(brc & GETSOCK_WRITESOCK(j))
- rc |= GETSOCK_WRITESOCK(s);
- if(brc & GETSOCK_READSOCK(j))
- rc |= GETSOCK_READSOCK(s);
- s++;
- }
+ if(!cf->connected) {
+ struct cf_hc_ctx *ctx = cf->ctx;
+ struct cf_hc_baller *ballers[2];
+ size_t i;
+
+ ballers[0] = &ctx->h3_baller;
+ ballers[1] = &ctx->h21_baller;
+ for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
+ struct cf_hc_baller *b = ballers[i];
+ if(!cf_hc_baller_is_active(b))
+ continue;
+ Curl_conn_cf_adjust_pollset(b->cf, data, ps);
}
+ CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
}
- CURL_TRC_CF(data, cf, "get_selected_socks -> %x", rc);
- return rc;
}
static bool cf_hc_data_pending(struct Curl_cfilter *cf,
@@ -455,7 +435,7 @@ struct Curl_cftype Curl_cft_http_connect = {
cf_hc_connect,
cf_hc_close,
Curl_cf_def_get_host,
- cf_hc_get_select_socks,
+ cf_hc_adjust_pollset,
cf_hc_data_pending,
Curl_cf_def_send,
Curl_cf_def_recv,
@@ -475,7 +455,7 @@ static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
CURLcode result = CURLE_OK;
(void)data;
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
diff --git a/Utilities/cmcurl/lib/cf-socket.c b/Utilities/cmcurl/lib/cf-socket.c
index ce3f9e9..e42b4a8 100644
--- a/Utilities/cmcurl/lib/cf-socket.c
+++ b/Utilities/cmcurl/lib/cf-socket.c
@@ -81,7 +81,7 @@
#include "memdebug.h"
-#if defined(ENABLE_IPV6) && defined(IPV6_V6ONLY) && defined(WIN32)
+#if defined(ENABLE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
/* It makes support for IPv4-mapped IPv6 addresses.
* Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
* Windows Vista and later: default is on;
@@ -102,11 +102,7 @@ static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
#if defined(TCP_NODELAY)
curl_socklen_t onoff = (curl_socklen_t) 1;
int level = IPPROTO_TCP;
-#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
char buffer[STRERROR_LEN];
-#else
- (void) data;
-#endif
if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
sizeof(onoff)) < 0)
@@ -127,6 +123,7 @@ static void nosigpipe(struct Curl_easy *data,
curl_socket_t sockfd)
{
int onoff = 1;
+ (void)data;
if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
sizeof(onoff)) < 0) {
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
@@ -662,7 +659,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
int err = 0;
curl_socklen_t errSize = sizeof(err);
-#ifdef WIN32
+#ifdef _WIN32
/*
* In October 2003 we effectively nullified this function on Windows due to
* problems with it using all CPU in multi-threaded cases.
@@ -883,34 +880,14 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
struct cf_socket_ctx *ctx = cf->ctx;
if(ctx && CURL_SOCKET_BAD != ctx->sock) {
- if(ctx->active) {
- /* We share our socket at cf->conn->sock[cf->sockindex] when active.
- * If it is no longer there, someone has stolen (and hopefully
- * closed it) and we just forget about it.
- */
- if(ctx->sock == cf->conn->sock[cf->sockindex]) {
- CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
- ", active)", ctx->sock);
- socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
- cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
- }
- else {
- CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
- ") no longer at conn->sock[], discarding", ctx->sock);
- /* TODO: we do not want this to happen. Need to check which
- * code is messing with conn->sock[cf->sockindex] */
- }
- ctx->sock = CURL_SOCKET_BAD;
- if(cf->sockindex == FIRSTSOCKET)
- cf->conn->remote_addr = NULL;
- }
- else {
- /* this is our local socket, we did never publish it */
- CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
- ", not active)", ctx->sock);
- socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
- ctx->sock = CURL_SOCKET_BAD;
- }
+ CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
+ ")", ctx->sock);
+ if(ctx->sock == cf->conn->sock[cf->sockindex])
+ cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
+ socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
+ ctx->sock = CURL_SOCKET_BAD;
+ if(ctx->active && cf->sockindex == FIRSTSOCKET)
+ cf->conn->remote_addr = NULL;
Curl_bufq_reset(&ctx->recvbuf);
ctx->active = FALSE;
ctx->buffer_recv = FALSE;
@@ -1169,6 +1146,7 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
*done = FALSE; /* a very negative world view is best */
if(ctx->sock == CURL_SOCKET_BAD) {
+ int error;
result = cf_socket_open(cf, data);
if(result)
@@ -1181,8 +1159,12 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
/* Connect TCP socket */
rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
+ error = SOCKERRNO;
+ set_local_ip(cf, data);
+ CURL_TRC_CF(data, cf, "local address %s port %d...",
+ ctx->l_ip, ctx->l_port);
if(-1 == rc) {
- result = socket_connect_result(data, ctx->r_ip, SOCKERRNO);
+ result = socket_connect_result(data, ctx->r_ip, error);
goto out;
}
}
@@ -1220,13 +1202,14 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
out:
if(result) {
if(ctx->error) {
+ set_local_ip(cf, data);
data->state.os_errno = ctx->error;
SET_SOCKERRNO(ctx->error);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
{
char buffer[STRERROR_LEN];
- infof(data, "connect to %s port %u failed: %s",
- ctx->r_ip, ctx->r_port,
+ infof(data, "connect to %s port %u from %s port %d failed: %s",
+ ctx->r_ip, ctx->r_port, ctx->l_ip, ctx->l_port,
Curl_strerror(ctx->error, buffer, sizeof(buffer)));
}
#endif
@@ -1252,20 +1235,19 @@ static void cf_socket_get_host(struct Curl_cfilter *cf,
*pport = cf->conn->port;
}
-static int cf_socket_get_select_socks(struct Curl_cfilter *cf,
+static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
- curl_socket_t *socks)
+ struct easy_pollset *ps)
{
struct cf_socket_ctx *ctx = cf->ctx;
- int rc = GETSOCK_BLANK;
- (void)data;
- if(!cf->connected && ctx->sock != CURL_SOCKET_BAD) {
- socks[0] = ctx->sock;
- rc |= GETSOCK_WRITESOCK(0);
+ if(ctx->sock != CURL_SOCKET_BAD) {
+ if(!cf->connected)
+ Curl_pollset_set_out_only(data, ps, ctx->sock);
+ else
+ Curl_pollset_add_in(data, ps, ctx->sock);
+ CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
}
-
- return rc;
}
static bool cf_socket_data_pending(struct Curl_cfilter *cf,
@@ -1518,6 +1500,9 @@ static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
case CF_CTRL_DATA_SETUP:
Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
break;
+ case CF_CTRL_FORGET_SOCKET:
+ ctx->sock = CURL_SOCKET_BAD;
+ break;
}
return CURLE_OK;
}
@@ -1612,7 +1597,7 @@ struct Curl_cftype Curl_cft_tcp = {
cf_tcp_connect,
cf_socket_close,
cf_socket_get_host,
- cf_socket_get_select_socks,
+ cf_socket_adjust_pollset,
cf_socket_data_pending,
cf_socket_send,
cf_socket_recv,
@@ -1635,7 +1620,7 @@ CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
(void)data;
(void)conn;
DEBUGASSERT(transport == TRNSPRT_TCP);
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -1742,7 +1727,7 @@ struct Curl_cftype Curl_cft_udp = {
cf_udp_connect,
cf_socket_close,
cf_socket_get_host,
- cf_socket_get_select_socks,
+ cf_socket_adjust_pollset,
cf_socket_data_pending,
cf_socket_send,
cf_socket_recv,
@@ -1765,7 +1750,7 @@ CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
(void)data;
(void)conn;
DEBUGASSERT(transport == TRNSPRT_UDP || transport == TRNSPRT_QUIC);
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -1793,7 +1778,7 @@ struct Curl_cftype Curl_cft_unix = {
cf_tcp_connect,
cf_socket_close,
cf_socket_get_host,
- cf_socket_get_select_socks,
+ cf_socket_adjust_pollset,
cf_socket_data_pending,
cf_socket_send,
cf_socket_recv,
@@ -1816,7 +1801,7 @@ CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
(void)data;
(void)conn;
DEBUGASSERT(transport == TRNSPRT_UNIX);
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -1857,7 +1842,7 @@ struct Curl_cftype Curl_cft_tcp_accept = {
cf_tcp_accept_connect,
cf_socket_close,
cf_socket_get_host, /* TODO: not accurate */
- cf_socket_get_select_socks,
+ cf_socket_adjust_pollset,
cf_socket_data_pending,
cf_socket_send,
cf_socket_recv,
@@ -1879,7 +1864,7 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
Curl_conn_cf_discard_all(data, conn, sockindex);
DEBUGASSERT(conn->sock[sockindex] == CURL_SOCKET_BAD);
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
diff --git a/Utilities/cmcurl/lib/cfilters.c b/Utilities/cmcurl/lib/cfilters.c
index f74eb40..e78ecd7 100644
--- a/Utilities/cmcurl/lib/cfilters.c
+++ b/Utilities/cmcurl/lib/cfilters.c
@@ -33,6 +33,7 @@
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
#include "multiif.h"
#include "progress.h"
+#include "select.h"
#include "warnless.h"
/* The last 3 #include files should be in this order */
@@ -70,12 +71,14 @@ void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
}
}
-int Curl_cf_def_get_select_socks(struct Curl_cfilter *cf,
+void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
- curl_socket_t *socks)
+ struct easy_pollset *ps)
{
- return cf->next?
- cf->next->cft->get_select_socks(cf->next, data, socks) : 0;
+ /* NOP */
+ (void)cf;
+ (void)data;
+ (void)ps;
}
bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
@@ -212,7 +215,7 @@ CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
CURLcode result = CURLE_OUT_OF_MEMORY;
DEBUGASSERT(cft);
- cf = calloc(sizeof(*cf), 1);
+ cf = calloc(1, sizeof(*cf));
if(!cf)
goto out;
@@ -303,15 +306,6 @@ void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
cf->cft->do_close(cf, data);
}
-int Curl_conn_cf_get_select_socks(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- curl_socket_t *socks)
-{
- if(cf)
- return cf->cft->get_select_socks(cf, data, socks);
- return 0;
-}
-
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
@@ -433,22 +427,31 @@ bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
return FALSE;
}
-int Curl_conn_get_select_socks(struct Curl_easy *data, int sockindex,
- curl_socket_t *socks)
+void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
+{
+ /* Get the lowest not-connected filter, if there are any */
+ while(cf && !cf->connected && cf->next && !cf->next->connected)
+ cf = cf->next;
+ /* From there on, give all filters a chance to adjust the pollset.
+ * Lower filters are called later, so they may override */
+ while(cf) {
+ cf->cft->adjust_pollset(cf, data, ps);
+ cf = cf->next;
+ }
+}
+
+void Curl_conn_adjust_pollset(struct Curl_easy *data,
+ struct easy_pollset *ps)
{
- struct Curl_cfilter *cf;
+ int i;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
- cf = data->conn->cfilter[sockindex];
-
- /* if the next one is not yet connected, that's the one we want */
- while(cf && cf->next && !cf->next->connected)
- cf = cf->next;
- if(cf) {
- return cf->cft->get_select_socks(cf, data, socks);
+ for(i = 0; i < 2; ++i) {
+ Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
}
- return GETSOCK_BLANK;
}
void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
@@ -524,6 +527,18 @@ curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
return data->conn? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
}
+void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex)
+{
+ if(data->conn) {
+ struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
+ if(cf)
+ (void)Curl_conn_cf_cntrl(cf, data, TRUE,
+ CF_CTRL_FORGET_SOCKET, 0, NULL);
+ fake_sclose(data->conn->sock[sockindex]);
+ data->conn->sock[sockindex] = CURL_SOCKET_BAD;
+ }
+}
+
static CURLcode cf_cntrl_all(struct connectdata *conn,
struct Curl_easy *data,
bool ignore_result,
@@ -646,3 +661,142 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
&n, NULL) : CURLE_UNKNOWN_OPTION;
return (result || n <= 0)? 1 : (size_t)n;
}
+
+
+void Curl_pollset_reset(struct Curl_easy *data,
+ struct easy_pollset *ps)
+{
+ size_t i;
+ (void)data;
+ memset(ps, 0, sizeof(*ps));
+ for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
+ ps->sockets[i] = CURL_SOCKET_BAD;
+}
+
+/**
+ *
+ */
+void Curl_pollset_change(struct Curl_easy *data,
+ struct easy_pollset *ps, curl_socket_t sock,
+ int add_flags, int remove_flags)
+{
+ unsigned int i;
+
+ (void)data;
+ DEBUGASSERT(VALID_SOCK(sock));
+ if(!VALID_SOCK(sock))
+ return;
+
+ DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
+ DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
+ DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */
+ for(i = 0; i < ps->num; ++i) {
+ if(ps->sockets[i] == sock) {
+ ps->actions[i] &= (unsigned char)(~remove_flags);
+ ps->actions[i] |= (unsigned char)add_flags;
+ /* all gone? remove socket */
+ if(!ps->actions[i]) {
+ if((i + 1) < ps->num) {
+ memmove(&ps->sockets[i], &ps->sockets[i + 1],
+ (ps->num - (i + 1)) * sizeof(ps->sockets[0]));
+ memmove(&ps->actions[i], &ps->actions[i + 1],
+ (ps->num - (i + 1)) * sizeof(ps->actions[0]));
+ }
+ --ps->num;
+ }
+ return;
+ }
+ }
+ /* not present */
+ if(add_flags) {
+ /* Having more SOCKETS per easy handle than what is defined
+ * is a programming error. This indicates that we need
+ * to raise this limit, making easy_pollset larger.
+ * Since we use this in tight loops, we do not want to make
+ * the pollset dynamic unnecessarily.
+ * The current maximum in practise is HTTP/3 eyeballing where
+ * we have up to 4 sockets involved in connection setup.
+ */
+ DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE);
+ if(i < MAX_SOCKSPEREASYHANDLE) {
+ ps->sockets[i] = sock;
+ ps->actions[i] = (unsigned char)add_flags;
+ ps->num = i + 1;
+ }
+ }
+}
+
+void Curl_pollset_set(struct Curl_easy *data,
+ struct easy_pollset *ps, curl_socket_t sock,
+ bool do_in, bool do_out)
+{
+ Curl_pollset_change(data, ps, sock,
+ (do_in?CURL_POLL_IN:0)|(do_out?CURL_POLL_OUT:0),
+ (!do_in?CURL_POLL_IN:0)|(!do_out?CURL_POLL_OUT:0));
+}
+
+static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
+ int bitmap, curl_socket_t *socks)
+{
+ if(bitmap) {
+ int i;
+ for(i = 0; i < MAX_SOCKSPEREASYHANDLE; ++i) {
+ if(!(bitmap & GETSOCK_MASK_RW(i)) || !VALID_SOCK((socks[i]))) {
+ break;
+ }
+ if(bitmap & GETSOCK_READSOCK(i)) {
+ if(bitmap & GETSOCK_WRITESOCK(i))
+ Curl_pollset_add_inout(data, ps, socks[i]);
+ else
+ /* is READ, since we checked MASK_RW above */
+ Curl_pollset_add_in(data, ps, socks[i]);
+ }
+ else
+ Curl_pollset_add_out(data, ps, socks[i]);
+ }
+ }
+}
+
+void Curl_pollset_add_socks(struct Curl_easy *data,
+ struct easy_pollset *ps,
+ int (*get_socks_cb)(struct Curl_easy *data,
+ struct connectdata *conn,
+ curl_socket_t *socks))
+{
+ curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
+ int bitmap;
+
+ DEBUGASSERT(data->conn);
+ bitmap = get_socks_cb(data, data->conn, socks);
+ ps_add(data, ps, bitmap, socks);
+}
+
+void Curl_pollset_add_socks2(struct Curl_easy *data,
+ struct easy_pollset *ps,
+ int (*get_socks_cb)(struct Curl_easy *data,
+ curl_socket_t *socks))
+{
+ curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
+ int bitmap;
+
+ bitmap = get_socks_cb(data, socks);
+ ps_add(data, ps, bitmap, socks);
+}
+
+void Curl_pollset_check(struct Curl_easy *data,
+ struct easy_pollset *ps, curl_socket_t sock,
+ bool *pwant_read, bool *pwant_write)
+{
+ unsigned int i;
+
+ (void)data;
+ DEBUGASSERT(VALID_SOCK(sock));
+ for(i = 0; i < ps->num; ++i) {
+ if(ps->sockets[i] == sock) {
+ *pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
+ *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
+ return;
+ }
+ }
+ *pwant_read = *pwant_write = FALSE;
+}
diff --git a/Utilities/cmcurl/lib/cfilters.h b/Utilities/cmcurl/lib/cfilters.h
index 2c65264..09a3f16 100644
--- a/Utilities/cmcurl/lib/cfilters.h
+++ b/Utilities/cmcurl/lib/cfilters.h
@@ -60,14 +60,34 @@ typedef void Curl_cft_get_host(struct Curl_cfilter *cf,
const char **pdisplay_host,
int *pport);
-/* Filters may return sockets and fdset flags they are waiting for.
- * The passes array has room for up to MAX_SOCKSPEREASYHANDLE sockets.
- * @return read/write fdset for index in socks
- * or GETSOCK_BLANK when nothing to wait on
+struct easy_pollset;
+
+/* Passing in an easy_pollset for monitoring of sockets, let
+ * filters add or remove sockets actions (CURL_POLL_OUT, CURL_POLL_IN).
+ * This may add a socket or, in case no actions remain, remove
+ * a socket from the set.
+ *
+ * Filter implementations need to call filters "below" *after* they have
+ * made their adjustments. This allows lower filters to override "upper"
+ * actions. If a "lower" filter is unable to write, it needs to be able
+ * to disallow POLL_OUT.
+ *
+ * A filter without own restrictions/preferences should not modify
+ * the pollset. Filters, whose filter "below" is not connected, should
+ * also do no adjustments.
+ *
+ * Examples: a TLS handshake, while ongoing, might remove POLL_IN
+ * when it needs to write, or vice versa. A HTTP/2 filter might remove
+ * POLL_OUT when a stream window is exhausted and a WINDOW_UPDATE needs
+ * to be received first and add instead POLL_IN.
+ *
+ * @param cf the filter to ask
+ * @param data the easy handle the pollset is about
+ * @param ps the pollset (inout) for the easy handle
*/
-typedef int Curl_cft_get_select_socks(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- curl_socket_t *socks);
+typedef void Curl_cft_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps);
typedef bool Curl_cft_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data);
@@ -110,6 +130,7 @@ typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf,
#define CF_CTRL_DATA_DONE_SEND 8 /* 0 NULL ignored */
/* update conn info at connection and data */
#define CF_CTRL_CONN_INFO_UPDATE (256+0) /* 0 NULL ignored */
+#define CF_CTRL_FORGET_SOCKET (256+1) /* 0 NULL ignored */
/**
* Handle event/control for the filter.
@@ -171,7 +192,7 @@ struct Curl_cftype {
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_adjust_pollset *adjust_pollset; /* adjust transfer poll set */
Curl_cft_data_pending *has_data_pending;/* conn has data pending */
Curl_cft_send *do_send; /* send data */
Curl_cft_recv *do_recv; /* receive data */
@@ -200,9 +221,9 @@ void Curl_cf_def_destroy_this(struct Curl_cfilter *cf,
void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
const char **phost, const char **pdisplay_host,
int *pport);
-int Curl_cf_def_get_select_socks(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- curl_socket_t *socks);
+void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps);
bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data);
ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -279,9 +300,6 @@ CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool blocking, bool *done);
void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data);
-int Curl_conn_cf_get_select_socks(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- curl_socket_t *socks);
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err);
ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -364,11 +382,22 @@ bool Curl_conn_data_pending(struct Curl_easy *data,
curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex);
/**
- * Get any select fd flags and the socket filters at chain `sockindex`
- * at connection `conn` might be waiting for.
+ * Tell filters to forget about the socket at sockindex.
*/
-int Curl_conn_get_select_socks(struct Curl_easy *data, int sockindex,
- curl_socket_t *socks);
+void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex);
+
+/**
+ * Adjust the pollset for the filter chain startgin at `cf`.
+ */
+void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps);
+
+/**
+ * Adjust pollset from filters installed at transfer's connection.
+ */
+void Curl_conn_adjust_pollset(struct Curl_easy *data,
+ struct easy_pollset *ps);
/**
* Receive data through the filter chain at `sockindex` for connection
@@ -468,6 +497,54 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
int sockindex);
+void Curl_pollset_reset(struct Curl_easy *data,
+ struct easy_pollset *ps);
+
+/* Change the poll flags (CURL_POLL_IN/CURL_POLL_OUT) to the poll set for
+ * socket `sock`. If the socket is not already part of the poll set, it
+ * will be added.
+ * If the socket is present and all poll flags are cleared, it will be removed.
+ */
+void Curl_pollset_change(struct Curl_easy *data,
+ struct easy_pollset *ps, curl_socket_t sock,
+ int add_flags, int remove_flags);
+
+void Curl_pollset_set(struct Curl_easy *data,
+ struct easy_pollset *ps, curl_socket_t sock,
+ bool do_in, bool do_out);
+
+#define Curl_pollset_add_in(data, ps, sock) \
+ Curl_pollset_change((data), (ps), (sock), CURL_POLL_IN, 0)
+#define Curl_pollset_add_out(data, ps, sock) \
+ Curl_pollset_change((data), (ps), (sock), CURL_POLL_OUT, 0)
+#define Curl_pollset_add_inout(data, ps, sock) \
+ Curl_pollset_change((data), (ps), (sock), \
+ CURL_POLL_IN|CURL_POLL_OUT, 0)
+#define Curl_pollset_set_in_only(data, ps, sock) \
+ Curl_pollset_change((data), (ps), (sock), \
+ CURL_POLL_IN, CURL_POLL_OUT)
+#define Curl_pollset_set_out_only(data, ps, sock) \
+ Curl_pollset_change((data), (ps), (sock), \
+ CURL_POLL_OUT, CURL_POLL_IN)
+
+void Curl_pollset_add_socks(struct Curl_easy *data,
+ struct easy_pollset *ps,
+ int (*get_socks_cb)(struct Curl_easy *data,
+ struct connectdata *conn,
+ curl_socket_t *socks));
+void Curl_pollset_add_socks2(struct Curl_easy *data,
+ struct easy_pollset *ps,
+ int (*get_socks_cb)(struct Curl_easy *data,
+ curl_socket_t *socks));
+
+/**
+ * Check if the pollset, as is, wants to read and/or write regarding
+ * the given socket.
+ */
+void Curl_pollset_check(struct Curl_easy *data,
+ struct easy_pollset *ps, curl_socket_t sock,
+ bool *pwant_read, bool *pwant_write);
+
/**
* Types and macros used to keep the current easy handle in filter calls,
* allowing for nested invocations. See #10336.
diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c
index 93d8768..66f18ec 100644
--- a/Utilities/cmcurl/lib/conncache.c
+++ b/Utilities/cmcurl/lib/conncache.c
@@ -107,7 +107,7 @@ int Curl_conncache_init(struct conncache *connc, int size)
connc->closure_handle = curl_easy_init();
if(!connc->closure_handle)
return 1; /* bad */
- connc->closure_handle->internal = true;
+ connc->closure_handle->state.internal = true;
Curl_hash_init(&connc->hash, size, Curl_hash_str,
Curl_str_key_compare, free_bundle_hash_entry);
@@ -243,7 +243,7 @@ CURLcode Curl_conncache_add_conn(struct Curl_easy *data)
conn->connection_id = connc->next_connection_id++;
connc->num_conn++;
- DEBUGF(infof(data, "Added connection %ld. "
+ DEBUGF(infof(data, "Added connection %" CURL_FORMAT_CURL_OFF_T ". "
"The cache now contains %zu members",
conn->connection_id, connc->num_conn));
@@ -379,21 +379,26 @@ conncache_find_first_connection(struct conncache *connc)
bool Curl_conncache_return_conn(struct Curl_easy *data,
struct connectdata *conn)
{
- /* data->multi->maxconnects can be negative, deal with it. */
- size_t maxconnects =
- (data->multi->maxconnects < 0) ? data->multi->num_easy * 4:
- data->multi->maxconnects;
+ unsigned int maxconnects = !data->multi->maxconnects ?
+ data->multi->num_easy * 4: data->multi->maxconnects;
struct connectdata *conn_candidate = NULL;
conn->lastused = Curl_now(); /* it was used up until now */
- if(maxconnects > 0 &&
- Curl_conncache_size(data) > maxconnects) {
+ if(maxconnects && Curl_conncache_size(data) > maxconnects) {
infof(data, "Connection cache is full, closing the oldest one");
conn_candidate = Curl_conncache_extract_oldest(data);
if(conn_candidate) {
- /* the winner gets the honour of being disconnected */
- Curl_disconnect(data, conn_candidate, /* dead_connection */ FALSE);
+ /* Use the closure handle for this disconnect so that anything that
+ happens during the disconnect is not stored and associated with the
+ 'data' handle which already just finished a transfer and it is
+ important that details from this (unrelated) disconnect does not
+ taint meta-data in the data handle. */
+ struct conncache *connc = data->state.conn_cache;
+ connc->closure_handle->state.buffer = data->state.buffer;
+ connc->closure_handle->set.buffer_size = data->set.buffer_size;
+ Curl_disconnect(connc->closure_handle, conn_candidate,
+ /* dead_connection */ FALSE);
}
}
diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c
index c7ba3e2..ec5ab71 100644
--- a/Utilities/cmcurl/lib/connect.c
+++ b/Utilities/cmcurl/lib/connect.c
@@ -84,6 +84,9 @@
#include "curl_memory.h"
#include "memdebug.h"
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
/*
* Curl_timeleft() returns the amount of milliseconds left allowed for the
@@ -348,6 +351,7 @@ void Curl_conncontrol(struct connectdata *conn,
*/
struct eyeballer {
const char *name;
+ const struct Curl_addrinfo *first; /* complete address list, not owned */
const struct Curl_addrinfo *addr; /* List of addresses to try, not owned */
int ai_family; /* matching address family only */
cf_ip_connect_create *cf_create; /* for creating cf */
@@ -359,9 +363,12 @@ struct eyeballer {
expire_id timeout_id; /* ID for Curl_expire() */
CURLcode result;
int error;
+ BIT(rewinded); /* if we rewinded the addr list */
BIT(has_started); /* attempts have started */
BIT(is_done); /* out of addresses/time */
BIT(connected); /* cf has connected */
+ BIT(inconclusive); /* connect was not a hard failure, we
+ * might talk to a restarting server */
};
@@ -408,7 +415,7 @@ static CURLcode eyeballer_new(struct eyeballer **pballer,
#endif
"ip"));
baller->cf_create = cf_create;
- baller->addr = addr;
+ baller->first = baller->addr = addr;
baller->ai_family = ai_family;
baller->primary = primary;
baller->delay_ms = delay_ms;
@@ -438,6 +445,13 @@ static void baller_free(struct eyeballer *baller,
}
}
+static void baller_rewind(struct eyeballer *baller)
+{
+ baller->rewinded = TRUE;
+ baller->addr = baller->first;
+ baller->inconclusive = FALSE;
+}
+
static void baller_next_addr(struct eyeballer *baller)
{
baller->addr = addr_next_match(baller->addr, baller->ai_family);
@@ -528,6 +542,10 @@ static CURLcode baller_start_next(struct Curl_cfilter *cf,
{
if(cf->sockindex == FIRSTSOCKET) {
baller_next_addr(baller);
+ /* If we get inconclusive answers from the server(s), we make
+ * a second iteration over the address list */
+ if(!baller->addr && baller->inconclusive && !baller->rewinded)
+ baller_rewind(baller);
baller_start(cf, data, baller, timeoutms);
}
else {
@@ -566,6 +584,8 @@ static CURLcode baller_connect(struct Curl_cfilter *cf,
baller->result = CURLE_OPERATION_TIMEDOUT;
}
}
+ else if(baller->result == CURLE_WEIRD_SERVER_REPLY)
+ baller->inconclusive = TRUE;
}
return baller->result;
}
@@ -595,7 +615,7 @@ evaluate:
*connected = FALSE; /* a very negative world view is best */
now = Curl_now();
ongoing = not_started = 0;
- for(i = 0; i < sizeof(ctx->baller)/sizeof(ctx->baller[0]); i++) {
+ for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
struct eyeballer *baller = ctx->baller[i];
if(!baller || baller->is_done)
@@ -656,7 +676,7 @@ evaluate:
if(not_started > 0) {
int added = 0;
- for(i = 0; i < sizeof(ctx->baller)/sizeof(ctx->baller[0]); i++) {
+ for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
struct eyeballer *baller = ctx->baller[i];
if(!baller || baller->has_started)
@@ -691,13 +711,13 @@ evaluate:
/* all ballers have failed to connect. */
CURL_TRC_CF(data, cf, "all eyeballers failed");
result = CURLE_COULDNT_CONNECT;
- for(i = 0; i < sizeof(ctx->baller)/sizeof(ctx->baller[0]); i++) {
+ for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
struct eyeballer *baller = ctx->baller[i];
+ if(!baller)
+ continue;
CURL_TRC_CF(data, cf, "%s assess started=%d, result=%d",
- baller?baller->name:NULL,
- baller?baller->has_started:0,
- baller?baller->result:0);
- if(baller && baller->has_started && baller->result) {
+ baller->name, baller->has_started, baller->result);
+ if(baller->has_started && baller->result) {
result = baller->result;
break;
}
@@ -838,7 +858,7 @@ static void cf_he_ctx_clear(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(ctx);
DEBUGASSERT(data);
- for(i = 0; i < sizeof(ctx->baller)/sizeof(ctx->baller[0]); i++) {
+ for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
baller_free(ctx->baller[i], data);
ctx->baller[i] = NULL;
}
@@ -846,35 +866,22 @@ static void cf_he_ctx_clear(struct Curl_cfilter *cf, struct Curl_easy *data)
ctx->winner = NULL;
}
-static int cf_he_get_select_socks(struct Curl_cfilter *cf,
+static void cf_he_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
- curl_socket_t *socks)
+ struct easy_pollset *ps)
{
struct cf_he_ctx *ctx = cf->ctx;
- size_t i, s;
- int wrc, rc = GETSOCK_BLANK;
- curl_socket_t wsocks[MAX_SOCKSPEREASYHANDLE];
-
- if(cf->connected)
- return cf->next->cft->get_select_socks(cf->next, data, socks);
-
- for(i = s = 0; i < sizeof(ctx->baller)/sizeof(ctx->baller[0]); i++) {
- struct eyeballer *baller = ctx->baller[i];
- if(!baller || !baller->cf)
- continue;
+ size_t i;
- wrc = Curl_conn_cf_get_select_socks(baller->cf, data, wsocks);
- if(wrc) {
- /* TODO: we assume we get at most one socket back */
- socks[s] = wsocks[0];
- if(wrc & GETSOCK_WRITESOCK(0))
- rc |= GETSOCK_WRITESOCK(s);
- if(wrc & GETSOCK_READSOCK(0))
- rc |= GETSOCK_READSOCK(s);
- s++;
+ if(!cf->connected) {
+ for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
+ struct eyeballer *baller = ctx->baller[i];
+ if(!baller || !baller->cf)
+ continue;
+ Curl_conn_cf_adjust_pollset(baller->cf, data, ps);
}
+ CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
}
- return rc;
}
static CURLcode cf_he_connect(struct Curl_cfilter *cf,
@@ -956,7 +963,7 @@ static bool cf_he_data_pending(struct Curl_cfilter *cf,
if(cf->connected)
return cf->next->cft->has_data_pending(cf->next, data);
- for(i = 0; i < sizeof(ctx->baller)/sizeof(ctx->baller[0]); i++) {
+ for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
struct eyeballer *baller = ctx->baller[i];
if(!baller || !baller->cf)
continue;
@@ -975,7 +982,7 @@ static struct curltime get_max_baller_time(struct Curl_cfilter *cf,
size_t i;
memset(&tmax, 0, sizeof(tmax));
- for(i = 0; i < sizeof(ctx->baller)/sizeof(ctx->baller[0]); i++) {
+ for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
struct eyeballer *baller = ctx->baller[i];
memset(&t, 0, sizeof(t));
@@ -1000,7 +1007,7 @@ static CURLcode cf_he_query(struct Curl_cfilter *cf,
int reply_ms = -1;
size_t i;
- for(i = 0; i < sizeof(ctx->baller)/sizeof(ctx->baller[0]); i++) {
+ for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
struct eyeballer *baller = ctx->baller[i];
int breply_ms;
@@ -1055,7 +1062,7 @@ struct Curl_cftype Curl_cft_happy_eyeballs = {
cf_he_connect,
cf_he_close,
Curl_cf_def_get_host,
- cf_he_get_select_socks,
+ cf_he_adjust_pollset,
cf_he_data_pending,
Curl_cf_def_send,
Curl_cf_def_recv,
@@ -1089,7 +1096,7 @@ cf_happy_eyeballs_create(struct Curl_cfilter **pcf,
(void)data;
(void)conn;
*pcf = NULL;
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -1122,13 +1129,13 @@ struct transport_provider transport_providers[] = {
#ifdef ENABLE_QUIC
{ TRNSPRT_QUIC, Curl_cf_quic_create },
#endif
+#ifndef CURL_DISABLE_TFTP
{ TRNSPRT_UDP, Curl_cf_udp_create },
+#endif
+#ifdef USE_UNIX_SOCKETS
{ TRNSPRT_UNIX, Curl_cf_unix_create },
-};
-
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
+};
static cf_ip_connect_create *get_cf_create(int transport)
{
@@ -1319,7 +1326,7 @@ struct Curl_cftype Curl_cft_setup = {
cf_setup_connect,
cf_setup_close,
Curl_cf_def_get_host,
- Curl_cf_def_get_select_socks,
+ Curl_cf_def_adjust_pollset,
Curl_cf_def_data_pending,
Curl_cf_def_send,
Curl_cf_def_recv,
@@ -1340,7 +1347,7 @@ static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
CURLcode result = CURLE_OK;
(void)data;
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c
index ec4750e..082e0fa 100644
--- a/Utilities/cmcurl/lib/content_encoding.c
+++ b/Utilities/cmcurl/lib/content_encoding.c
@@ -63,6 +63,9 @@
#ifndef CURL_DISABLE_HTTP
+/* allow no more than 5 "chained" compression steps */
+#define MAX_ENCODE_STACK 5
+
#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
@@ -95,7 +98,7 @@ typedef enum {
/* Deflate and gzip writer. */
struct zlib_writer {
- struct contenc_writer super;
+ struct Curl_cwriter super;
zlibInitState zlib_init; /* zlib init state */
uInt trailerlen; /* Remaining trailer byte count. */
z_stream z; /* State structure for zlib. */
@@ -171,7 +174,7 @@ static CURLcode process_trailer(struct Curl_easy *data,
}
static CURLcode inflate_stream(struct Curl_easy *data,
- struct contenc_writer *writer,
+ struct Curl_cwriter *writer, int type,
zlibInitState started)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
@@ -196,7 +199,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
/* because the buffer size is fixed, iteratively decompress and transfer to
- the client via downstream_write function. */
+ the client via next_write function. */
while(!done) {
int status; /* zlib status */
done = TRUE;
@@ -217,7 +220,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
if(z->avail_out != DSIZ) {
if(status == Z_OK || status == Z_STREAM_END) {
zp->zlib_init = started; /* Data started. */
- result = Curl_unencode_write(data, writer->downstream, decomp,
+ result = Curl_cwriter_write(data, writer->next, type, decomp,
DSIZ - z->avail_out);
if(result) {
exit_zlib(data, z, &zp->zlib_init, result);
@@ -274,8 +277,8 @@ static CURLcode inflate_stream(struct Curl_easy *data,
/* Deflate handler. */
-static CURLcode deflate_init_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
+static CURLcode deflate_do_init(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
@@ -290,13 +293,16 @@ static CURLcode deflate_init_writer(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode deflate_unencode_write(struct Curl_easy *data,
- struct contenc_writer *writer,
+static CURLcode deflate_do_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
+ if(!(type & CLIENTWRITE_BODY))
+ return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+
/* Set the compressed input when this function is called */
z->next_in = (Bytef *) buf;
z->avail_in = (uInt) nbytes;
@@ -305,11 +311,11 @@ static CURLcode deflate_unencode_write(struct Curl_easy *data,
return process_trailer(data, zp);
/* Now uncompress the data */
- return inflate_stream(data, writer, ZLIB_INFLATING);
+ return inflate_stream(data, writer, type, ZLIB_INFLATING);
}
-static void deflate_close_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
+static void deflate_do_close(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
@@ -317,19 +323,19 @@ static void deflate_close_writer(struct Curl_easy *data,
exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
}
-static const struct content_encoding deflate_encoding = {
+static const struct Curl_cwtype deflate_encoding = {
"deflate",
NULL,
- deflate_init_writer,
- deflate_unencode_write,
- deflate_close_writer,
+ deflate_do_init,
+ deflate_do_write,
+ deflate_do_close,
sizeof(struct zlib_writer)
};
/* Gzip handler. */
-static CURLcode gzip_init_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
+static CURLcode gzip_do_init(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
@@ -441,19 +447,22 @@ static enum {
}
#endif
-static CURLcode gzip_unencode_write(struct Curl_easy *data,
- struct contenc_writer *writer,
+static CURLcode gzip_do_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
+ if(!(type & CLIENTWRITE_BODY))
+ return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+
if(zp->zlib_init == ZLIB_INIT_GZIP) {
/* Let zlib handle the gzip decompression entirely */
z->next_in = (Bytef *) buf;
z->avail_in = (uInt) nbytes;
/* Now uncompress the data */
- return inflate_stream(data, writer, ZLIB_INIT_GZIP);
+ return inflate_stream(data, writer, type, ZLIB_INIT_GZIP);
}
#ifndef OLD_ZLIB_SUPPORT
@@ -565,12 +574,12 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data,
}
/* We've parsed the header, now uncompress the data */
- return inflate_stream(data, writer, ZLIB_GZIP_INFLATING);
+ return inflate_stream(data, writer, type, ZLIB_GZIP_INFLATING);
#endif
}
-static void gzip_close_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
+static void gzip_do_close(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
@@ -578,12 +587,12 @@ static void gzip_close_writer(struct Curl_easy *data,
exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
}
-static const struct content_encoding gzip_encoding = {
+static const struct Curl_cwtype gzip_encoding = {
"gzip",
"x-gzip",
- gzip_init_writer,
- gzip_unencode_write,
- gzip_close_writer,
+ gzip_do_init,
+ gzip_do_write,
+ gzip_do_close,
sizeof(struct zlib_writer)
};
@@ -593,7 +602,7 @@ static const struct content_encoding gzip_encoding = {
#ifdef HAVE_BROTLI
/* Brotli writer. */
struct brotli_writer {
- struct contenc_writer super;
+ struct Curl_cwriter super;
BrotliDecoderState *br; /* State structure for brotli. */
};
@@ -635,8 +644,8 @@ static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
return CURLE_WRITE_ERROR;
}
-static CURLcode brotli_init_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
+static CURLcode brotli_do_init(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
struct brotli_writer *bp = (struct brotli_writer *) writer;
(void) data;
@@ -645,8 +654,8 @@ static CURLcode brotli_init_writer(struct Curl_easy *data,
return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY;
}
-static CURLcode brotli_unencode_write(struct Curl_easy *data,
- struct contenc_writer *writer,
+static CURLcode brotli_do_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
struct brotli_writer *bp = (struct brotli_writer *) writer;
@@ -657,6 +666,9 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data,
CURLcode result = CURLE_OK;
BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
+ if(!(type & CLIENTWRITE_BODY))
+ return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+
if(!bp->br)
return CURLE_WRITE_ERROR; /* Stream already ended. */
@@ -670,7 +682,7 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data,
dstleft = DSIZ;
r = BrotliDecoderDecompressStream(bp->br,
&nbytes, &src, &dstleft, &dst, NULL);
- result = Curl_unencode_write(data, writer->downstream,
+ result = Curl_cwriter_write(data, writer->next, type,
decomp, DSIZ - dstleft);
if(result)
break;
@@ -693,8 +705,8 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data,
return result;
}
-static void brotli_close_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
+static void brotli_do_close(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
struct brotli_writer *bp = (struct brotli_writer *) writer;
@@ -706,12 +718,12 @@ static void brotli_close_writer(struct Curl_easy *data,
}
}
-static const struct content_encoding brotli_encoding = {
+static const struct Curl_cwtype brotli_encoding = {
"br",
NULL,
- brotli_init_writer,
- brotli_unencode_write,
- brotli_close_writer,
+ brotli_do_init,
+ brotli_do_write,
+ brotli_do_close,
sizeof(struct brotli_writer)
};
#endif
@@ -720,13 +732,13 @@ static const struct content_encoding brotli_encoding = {
#ifdef HAVE_ZSTD
/* Zstd writer. */
struct zstd_writer {
- struct contenc_writer super;
+ struct Curl_cwriter super;
ZSTD_DStream *zds; /* State structure for zstd. */
void *decomp;
};
-static CURLcode zstd_init_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
+static CURLcode zstd_do_init(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
struct zstd_writer *zp = (struct zstd_writer *) writer;
@@ -737,8 +749,8 @@ static CURLcode zstd_init_writer(struct Curl_easy *data,
return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
}
-static CURLcode zstd_unencode_write(struct Curl_easy *data,
- struct contenc_writer *writer,
+static CURLcode zstd_do_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
CURLcode result = CURLE_OK;
@@ -747,6 +759,9 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data,
ZSTD_outBuffer out;
size_t errorCode;
+ if(!(type & CLIENTWRITE_BODY))
+ return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+
if(!zp->decomp) {
zp->decomp = malloc(DSIZ);
if(!zp->decomp)
@@ -766,7 +781,7 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data,
return CURLE_BAD_CONTENT_ENCODING;
}
if(out.pos > 0) {
- result = Curl_unencode_write(data, writer->downstream,
+ result = Curl_cwriter_write(data, writer->next, type,
zp->decomp, out.pos);
if(result)
break;
@@ -778,8 +793,8 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data,
return result;
}
-static void zstd_close_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
+static void zstd_do_close(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
struct zstd_writer *zp = (struct zstd_writer *) writer;
@@ -795,52 +810,30 @@ static void zstd_close_writer(struct Curl_easy *data,
}
}
-static const struct content_encoding zstd_encoding = {
+static const struct Curl_cwtype zstd_encoding = {
"zstd",
NULL,
- zstd_init_writer,
- zstd_unencode_write,
- zstd_close_writer,
+ zstd_do_init,
+ zstd_do_write,
+ zstd_do_close,
sizeof(struct zstd_writer)
};
#endif
/* Identity handler. */
-static CURLcode identity_init_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
-{
- (void)data;
- (void)writer;
- return CURLE_OK;
-}
-
-static CURLcode identity_unencode_write(struct Curl_easy *data,
- struct contenc_writer *writer,
- const char *buf, size_t nbytes)
-{
- return Curl_unencode_write(data, writer->downstream, buf, nbytes);
-}
-
-static void identity_close_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
-{
- (void) data;
- (void) writer;
-}
-
-static const struct content_encoding identity_encoding = {
+static const struct Curl_cwtype identity_encoding = {
"identity",
"none",
- identity_init_writer,
- identity_unencode_write,
- identity_close_writer,
- sizeof(struct contenc_writer)
+ Curl_cwriter_def_init,
+ Curl_cwriter_def_write,
+ Curl_cwriter_def_close,
+ sizeof(struct Curl_cwriter)
};
/* supported content encodings table. */
-static const struct content_encoding * const encodings[] = {
+static const struct Curl_cwtype * const encodings[] = {
&identity_encoding,
#ifdef HAVE_LIBZ
&deflate_encoding,
@@ -856,13 +849,17 @@ static const struct content_encoding * const encodings[] = {
};
-/* Return a list of comma-separated names of supported encodings. */
-char *Curl_all_content_encodings(void)
+/* Provide a list of comma-separated names of supported encodings.
+*/
+void Curl_all_content_encodings(char *buf, size_t blen)
{
size_t len = 0;
- const struct content_encoding * const *cep;
- const struct content_encoding *ce;
- char *ace;
+ const struct Curl_cwtype * const *cep;
+ const struct Curl_cwtype *ce;
+
+ DEBUGASSERT(buf);
+ DEBUGASSERT(blen);
+ buf[0] = 0;
for(cep = encodings; *cep; cep++) {
ce = *cep;
@@ -870,12 +867,12 @@ char *Curl_all_content_encodings(void)
len += strlen(ce->name) + 2;
}
- if(!len)
- return strdup(CONTENT_ENCODING_DEFAULT);
-
- ace = malloc(len);
- if(ace) {
- char *p = ace;
+ if(!len) {
+ if(blen >= sizeof(CONTENT_ENCODING_DEFAULT))
+ strcpy(buf, CONTENT_ENCODING_DEFAULT);
+ }
+ else if(blen > len) {
+ char *p = buf;
for(cep = encodings; *cep; cep++) {
ce = *cep;
if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) {
@@ -887,75 +884,60 @@ char *Curl_all_content_encodings(void)
}
p[-2] = '\0';
}
-
- return ace;
}
-
/* Deferred error dummy writer. */
-static CURLcode error_init_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
+static CURLcode error_do_init(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
(void)data;
(void)writer;
return CURLE_OK;
}
-static CURLcode error_unencode_write(struct Curl_easy *data,
- struct contenc_writer *writer,
+static CURLcode error_do_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
- char *all = Curl_all_content_encodings();
+ char all[256];
+ (void)Curl_all_content_encodings(all, sizeof(all));
(void) writer;
(void) buf;
(void) nbytes;
- if(!all)
- return CURLE_OUT_OF_MEMORY;
+ if(!(type & CLIENTWRITE_BODY))
+ return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+
failf(data, "Unrecognized content encoding type. "
"libcurl understands %s content encodings.", all);
- free(all);
return CURLE_BAD_CONTENT_ENCODING;
}
-static void error_close_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
+static void error_do_close(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
(void) data;
(void) writer;
}
-static const struct content_encoding error_encoding = {
- NULL,
+static const struct Curl_cwtype error_writer = {
+ "ce-error",
NULL,
- error_init_writer,
- error_unencode_write,
- error_close_writer,
- sizeof(struct contenc_writer)
+ error_do_init,
+ error_do_write,
+ error_do_close,
+ sizeof(struct Curl_cwriter)
};
-/* Write data using an unencoding writer stack. "nbytes" is not
- allowed to be 0. */
-CURLcode Curl_unencode_write(struct Curl_easy *data,
- struct contenc_writer *writer,
- const char *buf, size_t nbytes)
-{
- if(!nbytes)
- return CURLE_OK;
- if(!writer)
- return CURLE_WRITE_ERROR;
- return writer->handler->unencode_write(data, writer, buf, nbytes);
-}
-
/* Find the content encoding by name. */
-static const struct content_encoding *find_encoding(const char *name,
+static const struct Curl_cwtype *find_encoding(const char *name,
size_t len)
{
- const struct content_encoding * const *cep;
+ const struct Curl_cwtype * const *cep;
for(cep = encodings; *cep; cep++) {
- const struct content_encoding *ce = *cep;
+ const struct Curl_cwtype *ce = *cep;
if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
(ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
return ce;
@@ -969,7 +951,8 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
const char *enclist, int is_transfer)
{
struct SingleRequest *k = &data->req;
- unsigned int order = is_transfer? 2: 1;
+ Curl_cwriter_phase phase = is_transfer?
+ CURL_CW_TRANSFER_DECODE:CURL_CW_CONTENT_DECODE;
CURLcode result;
do {
@@ -992,23 +975,32 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
Curl_httpchunk_init(data); /* init our chunky engine. */
}
else if(namelen) {
- const struct content_encoding *encoding;
- struct contenc_writer *writer;
- if(is_transfer && !data->set.http_transfer_encoding)
+ const struct Curl_cwtype *cwt;
+ struct Curl_cwriter *writer;
+
+ if((is_transfer && !data->set.http_transfer_encoding) ||
+ (!is_transfer && data->set.http_ce_skip)) {
/* not requested, ignore */
return CURLE_OK;
+ }
- encoding = find_encoding(name, namelen);
- if(!encoding)
- encoding = &error_encoding; /* Defer error at stack use. */
+ if(Curl_cwriter_count(data, phase) + 1 >= MAX_ENCODE_STACK) {
+ failf(data, "Reject response due to more than %u content encodings",
+ MAX_ENCODE_STACK);
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ cwt = find_encoding(name, namelen);
+ if(!cwt)
+ cwt = &error_writer; /* Defer error at use. */
- result = Curl_client_create_writer(&writer, data, encoding, order);
+ result = Curl_cwriter_create(&writer, data, cwt, phase);
if(result)
return result;
- result = Curl_client_add_writer(data, writer);
+ result = Curl_cwriter_add(data, writer);
if(result) {
- Curl_client_free_writer(data, writer);
+ Curl_cwriter_free(data, writer);
return result;
}
}
@@ -1028,20 +1020,15 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
return CURLE_NOT_BUILT_IN;
}
-CURLcode Curl_unencode_write(struct Curl_easy *data,
- struct contenc_writer *writer,
- const char *buf, size_t nbytes)
+void Curl_all_content_encodings(char *buf, size_t blen)
{
- (void) data;
- (void) writer;
- (void) buf;
- (void) nbytes;
- return CURLE_NOT_BUILT_IN;
+ DEBUGASSERT(buf);
+ DEBUGASSERT(blen);
+ if(blen < sizeof(CONTENT_ENCODING_DEFAULT))
+ buf[0] = 0;
+ else
+ strcpy(buf, CONTENT_ENCODING_DEFAULT);
}
-char *Curl_all_content_encodings(void)
-{
- return strdup(CONTENT_ENCODING_DEFAULT); /* Satisfy caller. */
-}
#endif /* CURL_DISABLE_HTTP */
diff --git a/Utilities/cmcurl/lib/content_encoding.h b/Utilities/cmcurl/lib/content_encoding.h
index ef7930c..1addf23 100644
--- a/Utilities/cmcurl/lib/content_encoding.h
+++ b/Utilities/cmcurl/lib/content_encoding.h
@@ -25,15 +25,10 @@
***************************************************************************/
#include "curl_setup.h"
-struct contenc_writer;
+struct Curl_cwriter;
-char *Curl_all_content_encodings(void);
+void Curl_all_content_encodings(char *buf, size_t blen);
CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
const char *enclist, int is_transfer);
-CURLcode Curl_unencode_write(struct Curl_easy *data,
- struct contenc_writer *writer,
- const char *buf, size_t nbytes);
-void Curl_unencode_cleanup(struct Curl_easy *data);
-
#endif /* HEADER_CURL_CONTENT_ENCODING_H */
diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c
index af01203..9095cea 100644
--- a/Utilities/cmcurl/lib/cookie.c
+++ b/Utilities/cmcurl/lib/cookie.c
@@ -330,7 +330,7 @@ static char *sanitize_cookie_path(const char *cookie_path)
*/
void Curl_cookie_loadfiles(struct Curl_easy *data)
{
- struct curl_slist *list = data->set.cookielist;
+ struct curl_slist *list = data->state.cookielist;
if(list) {
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
while(list) {
@@ -365,9 +365,7 @@ static void strstore(char **str, const char *newstr, size_t len)
DEBUGASSERT(newstr);
DEBUGASSERT(str);
free(*str);
- *str = Curl_memdup(newstr, len + 1);
- if(*str)
- (*str)[len] = 0;
+ *str = Curl_strndup(newstr, len);
}
/*
@@ -1029,15 +1027,23 @@ Curl_cookie_add(struct Curl_easy *data,
* dereference it.
*/
if(data && (domain && co->domain && !Curl_host_is_ipnum(co->domain))) {
- const psl_ctx_t *psl = Curl_psl_use(data);
- int acceptable;
-
- if(psl) {
- acceptable = psl_is_cookie_domain_acceptable(psl, domain, co->domain);
- Curl_psl_release(data);
+ bool acceptable = FALSE;
+ char lcase[256];
+ char lcookie[256];
+ size_t dlen = strlen(domain);
+ size_t clen = strlen(co->domain);
+ if((dlen < sizeof(lcase)) && (clen < sizeof(lcookie))) {
+ const psl_ctx_t *psl = Curl_psl_use(data);
+ if(psl) {
+ /* the PSL check requires lowercase domain name and pattern */
+ Curl_strntolower(lcase, domain, dlen + 1);
+ Curl_strntolower(lcookie, co->domain, clen + 1);
+ acceptable = psl_is_cookie_domain_acceptable(psl, lcase, lcookie);
+ Curl_psl_release(data);
+ }
+ else
+ acceptable = !bad_domain(domain, strlen(domain));
}
- else
- acceptable = !bad_domain(domain, strlen(domain));
if(!acceptable) {
infof(data, "cookie '%s' dropped, domain '%s' must not "
@@ -1347,7 +1353,7 @@ static int cookie_sort_ct(const void *p1, const void *p2)
static struct Cookie *dup_cookie(struct Cookie *src)
{
- struct Cookie *d = calloc(sizeof(struct Cookie), 1);
+ struct Cookie *d = calloc(1, sizeof(struct Cookie));
if(d) {
CLONE(domain);
CLONE(path);
diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake
index d4bb274..a3c5af5 100644
--- a/Utilities/cmcurl/lib/curl_config.h.cmake
+++ b/Utilities/cmcurl/lib/curl_config.h.cmake
@@ -67,9 +67,15 @@
/* disables FTP */
#cmakedefine CURL_DISABLE_FTP 1
+/* disables curl_easy_options API for existing options to curl_easy_setopt */
+#cmakedefine CURL_DISABLE_GETOPTIONS 1
+
/* disables GOPHER */
#cmakedefine CURL_DISABLE_GOPHER 1
+/* disables headers-api support */
+#cmakedefine CURL_DISABLE_HEADERS_API 1
+
/* disables HSTS support */
#cmakedefine CURL_DISABLE_HSTS 1
@@ -91,6 +97,9 @@
/* disables MIME support */
#cmakedefine CURL_DISABLE_MIME 1
+/* disables local binding support */
+#cmakedefine CURL_DISABLE_BINDLOCAL 1
+
/* disables MQTT */
#cmakedefine CURL_DISABLE_MQTT 1
@@ -161,9 +170,6 @@
/* Define to 1 if you have _Atomic support. */
#cmakedefine HAVE_ATOMIC 1
-/* Define to 1 if you have the `fchmod' function. */
-#cmakedefine HAVE_FCHMOD 1
-
/* Define to 1 if you have the `fnmatch' function. */
#cmakedefine HAVE_FNMATCH 1
@@ -201,6 +207,9 @@
/* Define to 1 if you have the fseeko function. */
#cmakedefine HAVE_FSEEKO 1
+/* Define to 1 if you have the fseeko declaration. */
+#cmakedefine HAVE_DECL_FSEEKO 1
+
/* Define to 1 if you have the _fseeki64 function. */
#cmakedefine HAVE__FSEEKI64 1
@@ -306,9 +315,6 @@
/* Define to 1 if symbol `ADDRESS_FAMILY' exists */
#cmakedefine HAVE_ADDRESS_FAMILY 1
-/* Define to 1 if you have the <inttypes.h> header file. */
-#cmakedefine HAVE_INTTYPES_H 1
-
/* Define to 1 if you have the ioctlsocket function. */
#cmakedefine HAVE_IOCTLSOCKET 1
@@ -492,9 +498,6 @@
/* Define to 1 if you have the <stdbool.h> header file. */
#cmakedefine HAVE_STDBOOL_H 1
-/* Define to 1 if you have the <stdint.h> header file. */
-#cmakedefine HAVE_STDINT_H 1
-
/* Define to 1 if you have the strcasecmp function. */
#cmakedefine HAVE_STRCASECMP 1
@@ -591,12 +594,6 @@
/* Define to 1 if you have the <utime.h> header file. */
#cmakedefine HAVE_UTIME_H 1
-/* Define to 1 if compiler supports C99 variadic macro style. */
-#cmakedefine HAVE_VARIADIC_MACROS_C99 1
-
-/* Define to 1 if compiler supports old gcc variadic macro style. */
-#cmakedefine HAVE_VARIADIC_MACROS_GCC 1
-
/* Define to 1 if you have the windows.h header file. */
#cmakedefine HAVE_WINDOWS_H 1
diff --git a/Utilities/cmcurl/lib/curl_hmac.h b/Utilities/cmcurl/lib/curl_hmac.h
index 2ea03dd..7a5387a 100644
--- a/Utilities/cmcurl/lib/curl_hmac.h
+++ b/Utilities/cmcurl/lib/curl_hmac.h
@@ -25,7 +25,8 @@
***************************************************************************/
#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \
- || !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH)
+ || !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) \
+ || defined(USE_LIBSSH2)
#include <curl/curl.h>
diff --git a/Utilities/cmcurl/lib/curl_memory.h b/Utilities/cmcurl/lib/curl_memory.h
index b8c46d7..714ad71 100644
--- a/Utilities/cmcurl/lib/curl_memory.h
+++ b/Utilities/cmcurl/lib/curl_memory.h
@@ -68,7 +68,7 @@
#undef send
#undef recv
-#ifdef WIN32
+#ifdef _WIN32
# ifdef UNICODE
# undef wcsdup
# undef _wcsdup
@@ -134,7 +134,7 @@ extern curl_free_callback Curl_cfree;
extern curl_realloc_callback Curl_crealloc;
extern curl_strdup_callback Curl_cstrdup;
extern curl_calloc_callback Curl_ccalloc;
-#if defined(WIN32) && defined(UNICODE)
+#if defined(_WIN32) && defined(UNICODE)
extern curl_wcsdup_callback Curl_cwcsdup;
#endif
@@ -160,7 +160,7 @@ extern curl_wcsdup_callback Curl_cwcsdup;
#undef free
#define free(ptr) Curl_cfree(ptr)
-#ifdef WIN32
+#ifdef _WIN32
# ifdef UNICODE
# undef wcsdup
# define wcsdup(ptr) Curl_cwcsdup(ptr)
diff --git a/Utilities/cmcurl/lib/curl_multibyte.c b/Utilities/cmcurl/lib/curl_multibyte.c
index 522ea34..ff21098 100644
--- a/Utilities/cmcurl/lib/curl_multibyte.c
+++ b/Utilities/cmcurl/lib/curl_multibyte.c
@@ -32,7 +32,7 @@
#include "curl_setup.h"
-#if defined(WIN32)
+#if defined(_WIN32)
#include "curl_multibyte.h"
@@ -84,7 +84,7 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
return str_utf8;
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
#if defined(USE_WIN32_LARGE_FILES) || defined(USE_WIN32_SMALL_FILES)
diff --git a/Utilities/cmcurl/lib/curl_multibyte.h b/Utilities/cmcurl/lib/curl_multibyte.h
index ddac1f6..8b9ac71 100644
--- a/Utilities/cmcurl/lib/curl_multibyte.h
+++ b/Utilities/cmcurl/lib/curl_multibyte.h
@@ -25,7 +25,7 @@
***************************************************************************/
#include "curl_setup.h"
-#if defined(WIN32)
+#if defined(_WIN32)
/*
* MultiByte conversions using Windows kernel32 library.
@@ -33,7 +33,7 @@
wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8);
char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
-#endif /* WIN32 */
+#endif /* _WIN32 */
/*
* Macros curlx_convert_UTF8_to_tchar(), curlx_convert_tchar_to_UTF8()
@@ -54,7 +54,7 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
* ensure that the curl memdebug override macros do not replace them.
*/
-#if defined(UNICODE) && defined(WIN32)
+#if defined(UNICODE) && defined(_WIN32)
#define curlx_convert_UTF8_to_tchar(ptr) curlx_convert_UTF8_to_wchar((ptr))
#define curlx_convert_tchar_to_UTF8(ptr) curlx_convert_wchar_to_UTF8((ptr))
@@ -78,7 +78,7 @@ typedef union {
const unsigned char *const_tbyte_ptr;
} xcharp_u;
-#endif /* UNICODE && WIN32 */
+#endif /* UNICODE && _WIN32 */
#define curlx_unicodefree(ptr) \
do { \
diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c
index cc0ed91..6f6d75c 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_core.c
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.c
@@ -111,6 +111,7 @@
# include <wincrypt.h>
#else
# error "Can't compile NTLM support without a crypto library with DES."
+# define CURL_NTLM_NOT_SUPPORTED
#endif
#include "urldata.h"
@@ -130,6 +131,7 @@
#define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00"
#define NTLMv2_BLOB_LEN (44 -16 + ntlm->target_info_len + 4)
+#if !defined(CURL_NTLM_NOT_SUPPORTED)
/*
* Turns a 56-bit key into being 64-bit wide.
*/
@@ -144,6 +146,7 @@ static void extend_key_56_to_64(const unsigned char *key_56, char *key)
key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
}
+#endif
#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
/*
@@ -337,6 +340,10 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
encrypt_des(plaintext, results, keys);
encrypt_des(plaintext, results + 8, keys + 7);
encrypt_des(plaintext, results + 16, keys + 14);
+#else
+ (void)keys;
+ (void)plaintext;
+ (void)results;
#endif
}
@@ -347,9 +354,11 @@ CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
unsigned char *lmbuffer /* 21 bytes */)
{
unsigned char pw[14];
+#if !defined(CURL_NTLM_NOT_SUPPORTED)
static const unsigned char magic[] = {
0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
};
+#endif
size_t len = CURLMIN(strlen(password), 14);
Curl_strntoupper((char *)pw, password, len);
diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.c b/Utilities/cmcurl/lib/curl_ntlm_wb.c
index aa7bea7..b087a37 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_wb.c
+++ b/Utilities/cmcurl/lib/curl_ntlm_wb.c
@@ -68,7 +68,9 @@
/* Portable 'sclose_nolog' used only in child process instead of 'sclose'
to avoid fooling the socket leak detector */
-#if defined(HAVE_CLOSESOCKET)
+#ifdef HAVE_PIPE
+# define sclose_nolog(x) close((x))
+#elif defined(HAVE_CLOSESOCKET)
# define sclose_nolog(x) closesocket((x))
#elif defined(HAVE_CLOSESOCKET_CAMEL)
# define sclose_nolog(x) CloseSocket((x))
@@ -189,7 +191,7 @@ static CURLcode ntlm_wb_init(struct Curl_easy *data, struct ntlmdata *ntlm,
goto done;
}
- if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) {
+ if(wakeup_create(sockfds)) {
failf(data, "Could not open socket pair. errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
goto done;
@@ -197,8 +199,8 @@ static CURLcode ntlm_wb_init(struct Curl_easy *data, struct ntlmdata *ntlm,
child_pid = fork();
if(child_pid == -1) {
- sclose(sockfds[0]);
- sclose(sockfds[1]);
+ wakeup_close(sockfds[0]);
+ wakeup_close(sockfds[1]);
failf(data, "Could not fork. errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
goto done;
@@ -268,7 +270,7 @@ static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm,
Curl_dyn_init(&b, MAX_NTLM_WB_RESPONSE);
while(len_in > 0) {
- ssize_t written = swrite(ntlm->ntlm_auth_hlpr_socket, input, len_in);
+ ssize_t written = wakeup_write(ntlm->ntlm_auth_hlpr_socket, input, len_in);
if(written == -1) {
/* Interrupted by a signal, retry it */
if(errno == EINTR)
@@ -282,7 +284,7 @@ static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm,
/* Read one line */
while(1) {
ssize_t size =
- sread(ntlm->ntlm_auth_hlpr_socket, buf, data->set.buffer_size);
+ wakeup_read(ntlm->ntlm_auth_hlpr_socket, buf, data->set.buffer_size);
if(size == -1) {
if(errno == EINTR)
continue;
diff --git a/Utilities/cmcurl/lib/curl_path.h b/Utilities/cmcurl/lib/curl_path.h
index 9ed09de..cbe51c2 100644
--- a/Utilities/cmcurl/lib/curl_path.h
+++ b/Utilities/cmcurl/lib/curl_path.h
@@ -28,7 +28,7 @@
#include <curl/curl.h>
#include "urldata.h"
-#ifdef WIN32
+#ifdef _WIN32
# undef PATH_MAX
# define PATH_MAX MAX_PATH
# ifndef R_OK
diff --git a/Utilities/cmcurl/lib/curl_rtmp.c b/Utilities/cmcurl/lib/curl_rtmp.c
index 406fb42..f7cf54e 100644
--- a/Utilities/cmcurl/lib/curl_rtmp.c
+++ b/Utilities/cmcurl/lib/curl_rtmp.c
@@ -39,7 +39,7 @@
/* The last #include file should be: */
#include "memdebug.h"
-#if defined(WIN32) && !defined(USE_LWIPSOCK)
+#if defined(_WIN32) && !defined(USE_LWIPSOCK)
#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e)
#define SET_RCVTIMEO(tv,s) int tv = s*1000
#elif defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD)
diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c
index 91ddf10..78ad298 100644
--- a/Utilities/cmcurl/lib/curl_sasl.c
+++ b/Utilities/cmcurl/lib/curl_sasl.c
@@ -262,6 +262,8 @@ static void sasl_state(struct SASL *sasl, struct Curl_easy *data,
sasl->state = newstate;
}
+#if defined(USE_NTLM) || defined(USE_GSASL) || defined(USE_KERBEROS5) || \
+ !defined(CURL_DISABLE_DIGEST_AUTH)
/* Get the SASL server message and convert it to binary. */
static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
struct bufref *out)
@@ -284,6 +286,7 @@ static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
}
return result;
}
+#endif
/* Encode the outgoing SASL message. */
static CURLcode build_message(struct SASL *sasl, struct bufref *msg)
diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h
index 8557cf4..7fe6397 100644
--- a/Utilities/cmcurl/lib/curl_setup.h
+++ b/Utilities/cmcurl/lib/curl_setup.h
@@ -28,6 +28,11 @@
#define CURL_NO_OLDIES
#endif
+/* Set default _WIN32_WINNT */
+#ifdef __MINGW32__
+#include <_mingw.h>
+#endif
+
/*
* Disable Visual Studio warnings:
* 4127 "conditional expression is constant"
@@ -36,15 +41,7 @@
#pragma warning(disable:4127)
#endif
-/*
- * Define WIN32 when build target is Win32 API
- */
-
-#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
-#define WIN32
-#endif
-
-#ifdef WIN32
+#ifdef _WIN32
/*
* Don't include unneeded stuff in Windows headers to avoid compiler
* warnings and macro clashes.
@@ -82,7 +79,7 @@
#ifdef _WIN32_WCE
# include "config-win32ce.h"
#else
-# ifdef WIN32
+# ifdef _WIN32
# include "config-win32.h"
# endif
#endif
@@ -218,6 +215,23 @@
# define CURL_DISABLE_RTSP
#endif
+/*
+ * When HTTP is disabled, disable HTTP-only features
+ */
+
+#if defined(CURL_DISABLE_HTTP)
+# define CURL_DISABLE_ALTSVC 1
+# define CURL_DISABLE_COOKIES 1
+# define CURL_DISABLE_BASIC_AUTH 1
+# define CURL_DISABLE_BEARER_AUTH 1
+# define CURL_DISABLE_AWS 1
+# define CURL_DISABLE_DOH 1
+# define CURL_DISABLE_FORM_API 1
+# define CURL_DISABLE_HEADERS_API 1
+# define CURL_DISABLE_HSTS 1
+# define CURL_DISABLE_HTTP_AUTH 1
+#endif
+
/* ================================================================ */
/* No system header file shall be included in this file before this */
/* point. */
@@ -335,23 +349,6 @@
#include <curl/stdcheaders.h>
#endif
-#ifdef __POCC__
-# include <sys/types.h>
-# include <unistd.h>
-# define sys_nerr EILSEQ
-#endif
-
-/*
- * Salford-C kludge section (mostly borrowed from wxWidgets).
- */
-#ifdef __SALFORDC__
- #pragma suppress 353 /* Possible nested comments */
- #pragma suppress 593 /* Define not used */
- #pragma suppress 61 /* enum has no name */
- #pragma suppress 106 /* unnamed, unused parameter */
- #include <clib.h>
-#endif
-
/* Default Windows file API selection. */
#ifdef _WIN32
# if defined(_MSC_VER) && (_INTEGRAL_MAX_BITS >= 64)
@@ -515,11 +512,11 @@
5. set dir/file naming defines
*/
-#ifdef WIN32
+#ifdef _WIN32
# define DIR_CHAR "\\"
-#else /* WIN32 */
+#else /* _WIN32 */
# ifdef MSDOS /* Watt-32 */
@@ -544,27 +541,7 @@
# define DIR_CHAR "/"
-# ifndef fileno /* sunos 4 have this as a macro! */
- int fileno(FILE *stream);
-# endif
-
-#endif /* WIN32 */
-
-/*
- * msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN
- * defined in ws2tcpip.h as well as to provide IPv6 support.
- * Does not apply if lwIP is used.
- */
-
-#if defined(_MSC_VER) && !defined(__POCC__) && !defined(USE_LWIPSOCK)
-# if !defined(HAVE_WS2TCPIP_H) || \
- ((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN))
-# undef HAVE_GETADDRINFO_THREADSAFE
-# undef HAVE_FREEADDRINFO
-# undef HAVE_GETADDRINFO
-# undef ENABLE_IPV6
-# endif
-#endif
+#endif /* _WIN32 */
/* ---------------------------------------------------------------- */
/* resolver specialty compile-time defines */
@@ -572,20 +549,11 @@
/* ---------------------------------------------------------------- */
/*
- * lcc-win32 doesn't have _beginthreadex(), lacks threads support.
- */
-
-#if defined(__LCC__) && defined(WIN32)
-# undef USE_THREADS_POSIX
-# undef USE_THREADS_WIN32
-#endif
-
-/*
* MSVC threads support requires a multi-threaded runtime library.
* _beginthreadex() is not available in single-threaded ones.
*/
-#if defined(_MSC_VER) && !defined(__POCC__) && !defined(_MT)
+#if defined(_MSC_VER) && !defined(_MT)
# undef USE_THREADS_POSIX
# undef USE_THREADS_WIN32
#endif
@@ -596,6 +564,9 @@
#if defined(ENABLE_IPV6) && defined(HAVE_GETADDRINFO)
# define CURLRES_IPV6
+#elif defined(ENABLE_IPV6) && (defined(_WIN32) || defined(__CYGWIN__))
+/* assume on Windows that IPv6 without getaddrinfo is a broken build */
+# error "Unexpected build: IPv6 is enabled but getaddrinfo was not found."
#else
# define CURLRES_IPV4
#endif
@@ -615,35 +586,6 @@
/* ---------------------------------------------------------------- */
-/*
- * msvc 6.0 does not have struct sockaddr_storage and
- * does not define IPPROTO_ESP in winsock2.h. But both
- * are available if PSDK is properly installed.
- */
-
-#if defined(_MSC_VER) && !defined(__POCC__)
-# if !defined(HAVE_WINSOCK2_H) || ((_MSC_VER < 1300) && !defined(IPPROTO_ESP))
-# undef HAVE_STRUCT_SOCKADDR_STORAGE
-# endif
-#endif
-
-/*
- * Intentionally fail to build when using msvc 6.0 without PSDK installed.
- * The brave of heart can circumvent this, defining ALLOW_MSVC6_WITHOUT_PSDK
- * in lib/config-win32.h although absolutely discouraged and unsupported.
- */
-
-#if defined(_MSC_VER) && !defined(__POCC__)
-# if !defined(HAVE_WINDOWS_H) || ((_MSC_VER < 1300) && !defined(_FILETIME_))
-# if !defined(ALLOW_MSVC6_WITHOUT_PSDK)
-# error MSVC 6.0 requires "February 2003 Platform SDK" a.k.a. \
- "Windows Server 2003 PSDK"
-# else
-# define CURL_DISABLE_LDAP 1
-# endif
-# endif
-#endif
-
#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && !defined(USE_WIN32_IDN)
/* The lib and header are present */
#define USE_LIBIDN2
@@ -709,6 +651,18 @@
# define WARN_UNUSED_RESULT
#endif
+/* noreturn attribute */
+
+#if !defined(CURL_NORETURN)
+#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__)
+# define CURL_NORETURN __attribute__((__noreturn__))
+#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
+# define CURL_NORETURN __declspec(noreturn)
+#else
+# define CURL_NORETURN
+#endif
+#endif
+
/*
* Include macros and defines that should only be processed once.
*/
@@ -767,7 +721,7 @@
/* In Windows the default file mode is text but an application can override it.
Therefore we specify it explicitly. https://github.com/curl/curl/pull/258
*/
-#if defined(WIN32) || defined(MSDOS)
+#if defined(_WIN32) || defined(MSDOS)
#define FOPEN_READTEXT "rt"
#define FOPEN_WRITETEXT "wt"
#define FOPEN_APPENDTEXT "at"
@@ -822,7 +776,8 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
#define UNITTEST static
#endif
-#if defined(USE_NGHTTP2) || defined(USE_HYPER)
+/* Hyper supports HTTP2 also, but Curl's integration with Hyper does not */
+#if defined(USE_NGHTTP2)
#define USE_HTTP2
#endif
@@ -835,11 +790,11 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
/* Certain Windows implementations are not aligned with what curl expects,
so always use the local one on this platform. E.g. the mingw-w64
implementation can return wrong results for non-ASCII inputs. */
-#if defined(HAVE_BASENAME) && defined(WIN32)
+#if defined(HAVE_BASENAME) && defined(_WIN32)
#undef HAVE_BASENAME
#endif
-#if defined(USE_UNIX_SOCKETS) && defined(WIN32)
+#if defined(USE_UNIX_SOCKETS) && defined(_WIN32)
# if !defined(UNIX_PATH_MAX)
/* Replicating logic present in afunix.h
(distributed with newer Windows 10 SDK versions only) */
diff --git a/Utilities/cmcurl/lib/curl_setup_once.h b/Utilities/cmcurl/lib/curl_setup_once.h
index c1ed059..bf0ee66 100644
--- a/Utilities/cmcurl/lib/curl_setup_once.h
+++ b/Utilities/cmcurl/lib/curl_setup_once.h
@@ -56,7 +56,7 @@
#include <sys/time.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
#endif
@@ -70,11 +70,7 @@
#endif
#ifdef USE_WOLFSSL
-# if defined(HAVE_STDINT_H)
-# include <stdint.h>
-# elif defined(HAVE_INTTYPES_H)
-# include <inttypes.h>
-# endif
+#include <stdint.h>
#endif
#ifdef USE_SCHANNEL
diff --git a/Utilities/cmcurl/lib/curl_sspi.h b/Utilities/cmcurl/lib/curl_sspi.h
index 5af7c24..b26c391 100644
--- a/Utilities/cmcurl/lib/curl_sspi.h
+++ b/Utilities/cmcurl/lib/curl_sspi.h
@@ -88,6 +88,22 @@ extern PSecurityFunctionTable s_pSecFn;
# define CRYPT_E_REVOKED ((HRESULT)0x80092010L)
#endif
+#ifndef CRYPT_E_NO_REVOCATION_DLL
+# define CRYPT_E_NO_REVOCATION_DLL ((HRESULT)0x80092011L)
+#endif
+
+#ifndef CRYPT_E_NO_REVOCATION_CHECK
+# define CRYPT_E_NO_REVOCATION_CHECK ((HRESULT)0x80092012L)
+#endif
+
+#ifndef CRYPT_E_REVOCATION_OFFLINE
+# define CRYPT_E_REVOCATION_OFFLINE ((HRESULT)0x80092013L)
+#endif
+
+#ifndef CRYPT_E_NOT_IN_REVOCATION_DATABASE
+# define CRYPT_E_NOT_IN_REVOCATION_DATABASE ((HRESULT)0x80092014L)
+#endif
+
#ifdef UNICODE
# define SECFLAG_WINNT_AUTH_IDENTITY \
(unsigned long)SEC_WINNT_AUTH_IDENTITY_UNICODE
diff --git a/Utilities/cmcurl/lib/curl_trc.c b/Utilities/cmcurl/lib/curl_trc.c
index e53b305..0ebe40b 100644
--- a/Utilities/cmcurl/lib/curl_trc.c
+++ b/Utilities/cmcurl/lib/curl_trc.c
@@ -61,10 +61,6 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type,
"* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
if(data->set.fdebug) {
bool inCallback = Curl_is_in_callback(data);
- /* CURLOPT_DEBUGFUNCTION doc says the user may set CURLOPT_PRIVATE to
- distinguish their handle from internal handles. */
- if(data->internal)
- DEBUGASSERT(!data->set.private_data);
Curl_set_in_callback(data, true);
(void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
Curl_set_in_callback(data, inCallback);
@@ -109,6 +105,8 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
}
}
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+
/* Curl_infof() is for info message along the way */
#define MAXINFO 2048
@@ -128,13 +126,11 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
}
}
-#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
-
void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
const char *fmt, ...)
{
DEBUGASSERT(cf);
- if(data && Curl_trc_cf_is_verbose(cf, data)) {
+ if(Curl_trc_cf_is_verbose(cf, data)) {
va_list ap;
int len;
char buffer[MAXINFO + 2];
@@ -232,24 +228,14 @@ CURLcode Curl_trc_init(void)
if(config) {
return Curl_trc_opt(config);
}
-#endif
+#endif /* DEBUGBUILD */
return CURLE_OK;
}
-#else /* !CURL_DISABLE_VERBOSE_STRINGS) */
+#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
CURLcode Curl_trc_init(void)
{
return CURLE_OK;
}
-#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
-void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
- const char *fmt, ...)
-{
- (void)data;
- (void)cf;
- (void)fmt;
-}
-#endif
-
-#endif /* !DEBUGBUILD */
+#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
diff --git a/Utilities/cmcurl/lib/curl_trc.h b/Utilities/cmcurl/lib/curl_trc.h
index 84b5471..ade9108 100644
--- a/Utilities/cmcurl/lib/curl_trc.h
+++ b/Utilities/cmcurl/lib/curl_trc.h
@@ -55,19 +55,6 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type,
char *ptr, size_t size);
/**
- * Output an informational message when transfer's verbose logging is enabled.
- */
-void Curl_infof(struct Curl_easy *data,
-#if defined(__GNUC__) && !defined(printf) && \
- defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
- !defined(__MINGW32__)
- const char *fmt, ...)
- __attribute__((format(printf, 2, 3)));
-#else
- const char *fmt, ...);
-#endif
-
-/**
* Output a failure message on registered callbacks for transfer.
*/
void Curl_failf(struct Curl_easy *data,
@@ -82,39 +69,15 @@ void Curl_failf(struct Curl_easy *data,
#define failf Curl_failf
-/**
- * Output an informational message when both transfer's verbose logging
- * and connection filters verbose logging are enabled.
- */
-void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
-#if defined(__GNUC__) && !defined(printf) && \
- defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
- !defined(__MINGW32__)
- const char *fmt, ...)
- __attribute__((format(printf, 3, 4)));
-#else
- const char *fmt, ...);
-#endif
-
#define CURL_LOG_LVL_NONE 0
#define CURL_LOG_LVL_INFO 1
-#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
-/* informational messages enabled */
-
-#define Curl_trc_is_verbose(data) ((data) && (data)->set.verbose)
-#define Curl_trc_cf_is_verbose(cf, data) \
- ((data) && (data)->set.verbose && \
- (cf) && (cf)->cft->log_level >= CURL_LOG_LVL_INFO)
-
-/* explainer: we have some mix configuration and werror settings
- * that define HAVE_VARIADIC_MACROS_C99 even though C89 is enforced
- * on gnuc and some other compiler. Need to treat carefully.
- */
-#if defined(HAVE_VARIADIC_MACROS_C99) && \
- defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define CURL_HAVE_C99
+#endif
+#ifdef CURL_HAVE_C99
#define infof(data, ...) \
do { if(Curl_trc_is_verbose(data)) \
Curl_infof(data, __VA_ARGS__); } while(0)
@@ -122,29 +85,62 @@ void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
do { if(Curl_trc_cf_is_verbose(cf, data)) \
Curl_trc_cf_infof(data, cf, __VA_ARGS__); } while(0)
-#else /* no variadic macro args */
+#else
#define infof Curl_infof
#define CURL_TRC_CF Curl_trc_cf_infof
-#endif /* variadic macro args */
+#endif
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+/* informational messages enabled */
-#else /* !CURL_DISABLE_VERBOSE_STRINGS */
+#define Curl_trc_is_verbose(data) ((data) && (data)->set.verbose)
+#define Curl_trc_cf_is_verbose(cf, data) \
+ ((data) && (data)->set.verbose && \
+ (cf) && (cf)->cft->log_level >= CURL_LOG_LVL_INFO)
+
+/**
+ * Output an informational message when transfer's verbose logging is enabled.
+ */
+void Curl_infof(struct Curl_easy *data,
+#if defined(__GNUC__) && !defined(printf) && defined(CURL_HAVE_C99) && \
+ !defined(__MINGW32__)
+ const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+#else
+ const char *fmt, ...);
+#endif
+
+/**
+ * Output an informational message when both transfer's verbose logging
+ * and connection filters verbose logging are enabled.
+ */
+void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
+#if defined(__GNUC__) && !defined(printf) && defined(CURL_HAVE_C99) && \
+ !defined(__MINGW32__)
+ const char *fmt, ...)
+ __attribute__((format(printf, 3, 4)));
+#else
+ const char *fmt, ...);
+#endif
+
+#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
/* All informational messages are not compiled in for size savings */
#define Curl_trc_is_verbose(d) ((void)(d), FALSE)
#define Curl_trc_cf_is_verbose(x,y) ((void)(x), (void)(y), FALSE)
-#if defined(HAVE_VARIADIC_MACROS_C99)
-#define infof(...) Curl_nop_stmt
-#define CURL_TRC_CF(...) Curl_nop_stmt
-#define Curl_trc_cf_infof(...) Curl_nop_stmt
-#elif defined(HAVE_VARIADIC_MACROS_GCC)
-#define infof(x...) Curl_nop_stmt
-#define CURL_TRC_CF(x...) Curl_nop_stmt
-#define Curl_trc_cf_infof(x...) Curl_nop_stmt
-#else
-#error "missing VARIADIC macro define, fix and rebuild!"
-#endif
+static void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
+{
+ (void)data; (void)fmt;
+}
+
+static void Curl_trc_cf_infof(struct Curl_easy *data,
+ struct Curl_cfilter *cf,
+ const char *fmt, ...)
+{
+ (void)data; (void)cf; (void)fmt;
+}
-#endif /* CURL_DISABLE_VERBOSE_STRINGS */
+#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
#endif /* HEADER_CURL_TRC_H */
diff --git a/Utilities/cmcurl/lib/doh.c b/Utilities/cmcurl/lib/doh.c
index bb0c89e..1d928e9 100644
--- a/Utilities/cmcurl/lib/doh.c
+++ b/Utilities/cmcurl/lib/doh.c
@@ -242,7 +242,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
/* pass in the struct pointer via a local variable to please coverity and
the gcc typecheck helpers */
struct dynbuf *resp = &p->serverdoh;
- doh->internal = true;
+ doh->state.internal = true;
ERROR_CHECK_SETOPT(CURLOPT_URL, url);
ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https");
ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
@@ -252,6 +252,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
#ifdef USE_HTTP2
ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
+ ERROR_CHECK_SETOPT(CURLOPT_PIPEWAIT, 1L);
#endif
#ifndef CURLDEBUG
/* enforce HTTPS if not debug */
@@ -339,9 +340,10 @@ static CURLcode dohprobe(struct Curl_easy *data,
doh->set.dohfor = data; /* identify for which transfer this is done */
p->easy = doh;
- /* DoH private_data must be null because the user must have a way to
- distinguish their transfer's handle from DoH handles in user
- callbacks (ie SSL CTX callback). */
+ /* DoH handles must not inherit private_data. The handles may be passed to
+ the user via callbacks and the user will be able to identify them as
+ internal handles because private data is not set. The user can then set
+ private_data via CURLOPT_PRIVATE if they so choose. */
DEBUGASSERT(!doh->set.private_data);
if(curl_multi_add_handle(multi, doh))
@@ -372,7 +374,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
int slot;
struct dohdata *dohp;
struct connectdata *conn = data->conn;
- *waitp = TRUE; /* this never returns synchronously */
+ *waitp = FALSE;
(void)hostname;
(void)port;
@@ -380,7 +382,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
DEBUGASSERT(conn);
/* start clean, consider allocating this struct on demand */
- dohp = data->req.doh = calloc(sizeof(struct dohdata), 1);
+ dohp = data->req.doh = calloc(1, sizeof(struct dohdata));
if(!dohp)
return NULL;
@@ -412,12 +414,14 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
dohp->pending++;
}
#endif
+ *waitp = TRUE; /* this never returns synchronously */
return NULL;
error:
curl_slist_free_all(dohp->headers);
data->req.doh->headers = NULL;
for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
+ (void)curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
Curl_close(&dohp->probe[slot].easy);
}
Curl_safefree(data->req.doh);
@@ -787,8 +791,8 @@ static void showdoh(struct Curl_easy *data,
* must be an associated call later to Curl_freeaddrinfo().
*/
-static struct Curl_addrinfo *
-doh2ai(const struct dohentry *de, const char *hostname, int port)
+static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
+ int port, struct Curl_addrinfo **aip)
{
struct Curl_addrinfo *ai;
struct Curl_addrinfo *prevai = NULL;
@@ -801,9 +805,10 @@ doh2ai(const struct dohentry *de, const char *hostname, int port)
int i;
size_t hostlen = strlen(hostname) + 1; /* include null-terminator */
- if(!de)
- /* no input == no output! */
- return NULL;
+ DEBUGASSERT(de);
+
+ if(!de->numaddr)
+ return CURLE_COULDNT_RESOLVE_HOST;
for(i = 0; i < de->numaddr; i++) {
size_t ss_size;
@@ -876,8 +881,9 @@ doh2ai(const struct dohentry *de, const char *hostname, int port)
Curl_freeaddrinfo(firstai);
firstai = NULL;
}
+ *aip = firstai;
- return firstai;
+ return result;
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
@@ -898,6 +904,7 @@ UNITTEST void de_cleanup(struct dohentry *d)
CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dnsp)
{
+ struct connectdata *conn = data->conn;
CURLcode result;
struct dohdata *dohp = data->req.doh;
*dnsp = NULL; /* defaults to no response */
@@ -906,7 +913,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
!dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
- failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
+ failf(data, "Could not DoH-resolve: %s", conn->resolve_async.hostname);
return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY:
CURLE_COULDNT_RESOLVE_HOST;
}
@@ -932,10 +939,12 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
p->dnstype,
&de);
Curl_dyn_free(&p->serverdoh);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
if(rc[slot]) {
infof(data, "DoH: %s type %s for %s", doh_strerror(rc[slot]),
type2name(p->dnstype), dohp->host);
}
+#endif
} /* next slot */
result = CURLE_COULDNT_RESOLVE_HOST; /* until we know better */
@@ -947,10 +956,10 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
infof(data, "DoH Host name: %s", dohp->host);
showdoh(data, &de);
- ai = doh2ai(&de, dohp->host, dohp->port);
- if(!ai) {
+ result = doh2ai(&de, dohp->host, dohp->port, &ai);
+ if(result) {
de_cleanup(&de);
- return CURLE_OUT_OF_MEMORY;
+ return result;
}
if(data->share)
@@ -967,7 +976,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
Curl_freeaddrinfo(ai);
}
else {
- data->state.async.dns = dns;
+ conn->resolve_async.dns = dns;
*dnsp = dns;
result = CURLE_OK; /* address resolution OK */
}
diff --git a/Utilities/cmcurl/lib/dynbuf.c b/Utilities/cmcurl/lib/dynbuf.c
index 0c9c491..2973d8d 100644
--- a/Utilities/cmcurl/lib/dynbuf.c
+++ b/Utilities/cmcurl/lib/dynbuf.c
@@ -77,6 +77,7 @@ static CURLcode dyn_nappend(struct dynbuf *s,
DEBUGASSERT(indx < s->toobig);
DEBUGASSERT(!s->leng || s->bufr);
DEBUGASSERT(a <= s->toobig);
+ DEBUGASSERT(!len || mem);
if(fit > s->toobig) {
Curl_dyn_free(s);
@@ -174,10 +175,12 @@ CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
*/
CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
{
- size_t n = strlen(str);
+ size_t n;
+ DEBUGASSERT(str);
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
+ n = strlen(str);
return dyn_nappend(s, (unsigned char *)str, n);
}
@@ -191,6 +194,7 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
DEBUGASSERT(s);
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
+ DEBUGASSERT(fmt);
rc = Curl_dyn_vprintf(s, fmt, ap);
if(!rc)
diff --git a/Utilities/cmcurl/lib/dynhds.c b/Utilities/cmcurl/lib/dynhds.c
index 979b3e8..d754895 100644
--- a/Utilities/cmcurl/lib/dynhds.c
+++ b/Utilities/cmcurl/lib/dynhds.c
@@ -27,6 +27,10 @@
#include "strcase.h"
/* The last 3 #include files should be in this order */
+#ifdef USE_NGHTTP2
+#include <stdint.h>
+#include <nghttp2/nghttp2.h>
+#endif /* USE_NGHTTP2 */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
@@ -365,3 +369,28 @@ CURLcode Curl_dynhds_h1_dprint(struct dynhds *dynhds, struct dynbuf *dbuf)
return result;
}
+#ifdef USE_NGHTTP2
+
+nghttp2_nv *Curl_dynhds_to_nva(struct dynhds *dynhds, size_t *pcount)
+{
+ nghttp2_nv *nva = calloc(1, sizeof(nghttp2_nv) * dynhds->hds_len);
+ size_t i;
+
+ *pcount = 0;
+ if(!nva)
+ return NULL;
+
+ for(i = 0; i < dynhds->hds_len; ++i) {
+ struct dynhds_entry *e = dynhds->hds[i];
+ DEBUGASSERT(e);
+ nva[i].name = (unsigned char *)e->name;
+ nva[i].namelen = e->namelen;
+ nva[i].value = (unsigned char *)e->value;
+ nva[i].valuelen = e->valuelen;
+ nva[i].flags = NGHTTP2_NV_FLAG_NONE;
+ }
+ *pcount = dynhds->hds_len;
+ return nva;
+}
+
+#endif /* USE_NGHTTP2 */
diff --git a/Utilities/cmcurl/lib/dynhds.h b/Utilities/cmcurl/lib/dynhds.h
index 8a05348..3b53600 100644
--- a/Utilities/cmcurl/lib/dynhds.h
+++ b/Utilities/cmcurl/lib/dynhds.h
@@ -171,4 +171,13 @@ CURLcode Curl_dynhds_h1_add_line(struct dynhds *dynhds,
*/
CURLcode Curl_dynhds_h1_dprint(struct dynhds *dynhds, struct dynbuf *dbuf);
+#ifdef USE_NGHTTP2
+
+#include <stdint.h>
+#include <nghttp2/nghttp2.h>
+
+nghttp2_nv *Curl_dynhds_to_nva(struct dynhds *dynhds, size_t *pcount);
+
+#endif /* USE_NGHTTP2 */
+
#endif /* HEADER_CURL_DYNHDS_H */
diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c
index 6b4fb8e..322d1a4 100644
--- a/Utilities/cmcurl/lib/easy.c
+++ b/Utilities/cmcurl/lib/easy.c
@@ -112,7 +112,7 @@ static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT;
#define system_strdup strdup
#endif
-#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
+#if defined(_MSC_VER) && defined(_DLL)
# pragma warning(disable:4232) /* MSVC extension, dllimport identity */
#endif
@@ -125,11 +125,11 @@ curl_free_callback Curl_cfree = (curl_free_callback)free;
curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
-#if defined(WIN32) && defined(UNICODE)
+#if defined(_WIN32) && defined(UNICODE)
curl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup;
#endif
-#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
+#if defined(_MSC_VER) && defined(_DLL)
# pragma warning(default:4232) /* MSVC extension, dllimport identity */
#endif
@@ -153,7 +153,7 @@ static CURLcode global_init(long flags, bool memoryfuncs)
Curl_crealloc = (curl_realloc_callback)realloc;
Curl_cstrdup = (curl_strdup_callback)system_strdup;
Curl_ccalloc = (curl_calloc_callback)calloc;
-#if defined(WIN32) && defined(UNICODE)
+#if defined(_WIN32) && defined(UNICODE)
Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
#endif
}
@@ -188,18 +188,10 @@ static CURLcode global_init(long flags, bool memoryfuncs)
goto fail;
}
-#if defined(USE_SSH)
if(Curl_ssh_init()) {
+ DEBUGF(fprintf(stderr, "Error: Curl_ssh_init failed\n"));
goto fail;
}
-#endif
-
-#ifdef USE_WOLFSSH
- if(WS_SUCCESS != wolfSSH_Init()) {
- DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n"));
- return CURLE_FAILED_INIT;
- }
-#endif
easy_init_flags = flags;
@@ -295,7 +287,7 @@ void curl_global_cleanup(void)
Curl_ssl_cleanup();
Curl_resolver_global_cleanup();
-#ifdef WIN32
+#ifdef _WIN32
Curl_win32_cleanup(easy_init_flags);
#endif
@@ -752,7 +744,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
return CURLE_RECURSIVE_API_CALL;
/* Copy the MAXCONNECTS option to the multi handle */
- curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, data->set.maxconnects);
+ curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, (long)data->set.maxconnects);
mcode = curl_multi_add_handle(multi, data);
if(mcode) {
@@ -845,8 +837,10 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
dst->set = src->set;
Curl_mime_initpart(&dst->set.mimepost);
- /* clear all string pointers first */
+ /* clear all dest string and blob pointers first, in case we error out
+ mid-function */
memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
+ memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *));
/* duplicate all strings */
for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) {
@@ -855,8 +849,6 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
return result;
}
- /* clear all blob pointers first */
- memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *));
/* duplicate all blobs */
for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]);
@@ -866,10 +858,13 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
/* duplicate memory areas pointed to */
i = STRING_COPYPOSTFIELDS;
- if(src->set.postfieldsize && src->set.str[i]) {
- /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
- dst->set.str[i] = Curl_memdup(src->set.str[i],
- curlx_sotouz(src->set.postfieldsize));
+ if(src->set.str[i]) {
+ if(src->set.postfieldsize == -1)
+ dst->set.str[i] = strdup(src->set.str[i]);
+ else
+ /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
+ dst->set.str[i] = Curl_memdup(src->set.str[i],
+ curlx_sotouz(src->set.postfieldsize));
if(!dst->set.str[i])
return CURLE_OUT_OF_MEMORY;
/* point to the new copy */
@@ -919,18 +914,19 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
outcurl->progress.callback = data->progress.callback;
#ifndef CURL_DISABLE_COOKIES
- if(data->cookies) {
+ outcurl->state.cookielist = NULL;
+ if(data->cookies && data->state.cookie_engine) {
/* If cookies are enabled in the parent handle, we enable them
in the clone as well! */
- outcurl->cookies = Curl_cookie_init(data, NULL, outcurl->cookies,
+ outcurl->cookies = Curl_cookie_init(outcurl, NULL, outcurl->cookies,
data->set.cookiesession);
if(!outcurl->cookies)
goto fail;
}
- if(data->set.cookielist) {
- outcurl->set.cookielist = Curl_slist_duplicate(data->set.cookielist);
- if(!outcurl->set.cookielist)
+ if(data->state.cookielist) {
+ outcurl->state.cookielist = Curl_slist_duplicate(data->state.cookielist);
+ if(!outcurl->state.cookielist)
goto fail;
}
#endif
@@ -976,33 +972,6 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
(void)Curl_hsts_loadcb(outcurl, outcurl->hsts);
}
#endif
- /* Clone the resolver handle, if present, for the new handle */
- if(Curl_resolver_duphandle(outcurl,
- &outcurl->state.async.resolver,
- data->state.async.resolver))
- goto fail;
-
-#ifdef USE_ARES
- {
- CURLcode rc;
-
- rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]);
- if(rc && rc != CURLE_NOT_BUILT_IN)
- goto fail;
-
- rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]);
- if(rc && rc != CURLE_NOT_BUILT_IN)
- goto fail;
-
- rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]);
- if(rc && rc != CURLE_NOT_BUILT_IN)
- goto fail;
-
- rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]);
- if(rc && rc != CURLE_NOT_BUILT_IN)
- goto fail;
- }
-#endif /* USE_ARES */
Curl_initinfo(outcurl);
@@ -1016,13 +985,10 @@ fail:
if(outcurl) {
#ifndef CURL_DISABLE_COOKIES
- curl_slist_free_all(outcurl->set.cookielist);
- outcurl->set.cookielist = NULL;
+ free(outcurl->cookies);
#endif
- Curl_safefree(outcurl->state.buffer);
+ free(outcurl->state.buffer);
Curl_dyn_free(&outcurl->state.headerb);
- Curl_safefree(outcurl->state.url);
- Curl_safefree(outcurl->state.referer);
Curl_altsvc_cleanup(&outcurl->asi);
Curl_hsts_cleanup(&outcurl->hsts);
Curl_freeset(outcurl);
diff --git a/Utilities/cmcurl/lib/easy_lock.h b/Utilities/cmcurl/lib/easy_lock.h
index d3fffd0..4f6764d 100644
--- a/Utilities/cmcurl/lib/easy_lock.h
+++ b/Utilities/cmcurl/lib/easy_lock.h
@@ -93,6 +93,15 @@ static inline void curl_simple_lock_unlock(curl_simple_lock *lock)
atomic_store_explicit(lock, false, memory_order_release);
}
+#elif defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+
+#include <pthread.h>
+
+#define curl_simple_lock pthread_mutex_t
+#define CURL_SIMPLE_LOCK_INIT PTHREAD_MUTEX_INITIALIZER
+#define curl_simple_lock_lock(m) pthread_mutex_lock(m)
+#define curl_simple_lock_unlock(m) pthread_mutex_unlock(m)
+
#else
#undef GLOBAL_INIT_IS_THREADSAFE
diff --git a/Utilities/cmcurl/lib/file.c b/Utilities/cmcurl/lib/file.c
index ffa9fb7..c985071 100644
--- a/Utilities/cmcurl/lib/file.c
+++ b/Utilities/cmcurl/lib/file.c
@@ -69,7 +69,7 @@
#include "curl_memory.h"
#include "memdebug.h"
-#if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
+#if defined(_WIN32) || defined(MSDOS) || defined(__EMX__)
#define DOS_FILESYSTEM 1
#elif defined(__amigaos4__)
#define AMIGA_FILESYSTEM 1
@@ -414,7 +414,6 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
bool size_known;
bool fstated = FALSE;
char *buf = data->state.buffer;
- curl_off_t bytecount = 0;
int fd;
struct FILEPROTO *file;
@@ -563,7 +562,6 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
if(nread <= 0 || (size_known && (expected_size == 0)))
break;
- bytecount += nread;
if(size_known)
expected_size -= nread;
@@ -571,10 +569,6 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
if(result)
return result;
- result = Curl_pgrsSetDownloadCounter(data, bytecount);
- if(result)
- return result;
-
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
else
diff --git a/Utilities/cmcurl/lib/fopen.c b/Utilities/cmcurl/lib/fopen.c
index 75b8a7a..851279f 100644
--- a/Utilities/cmcurl/lib/fopen.c
+++ b/Utilities/cmcurl/lib/fopen.c
@@ -40,6 +40,51 @@
#include "memdebug.h"
/*
+ The dirslash() function breaks a null-terminated pathname string into
+ directory and filename components then returns the directory component up
+ to, *AND INCLUDING*, a final '/'. If there is no directory in the path,
+ this instead returns a "" string.
+
+ This function returns a pointer to malloc'ed memory.
+
+ The input path to this function is expected to have a file name part.
+*/
+
+#ifdef _WIN32
+#define PATHSEP "\\"
+#define IS_SEP(x) (((x) == '/') || ((x) == '\\'))
+#elif defined(MSDOS) || defined(__EMX__) || defined(OS2)
+#define PATHSEP "\\"
+#define IS_SEP(x) ((x) == '\\')
+#else
+#define PATHSEP "/"
+#define IS_SEP(x) ((x) == '/')
+#endif
+
+static char *dirslash(const char *path)
+{
+ size_t n;
+ struct dynbuf out;
+ DEBUGASSERT(path);
+ Curl_dyn_init(&out, CURL_MAX_INPUT_LENGTH);
+ n = strlen(path);
+ if(n) {
+ /* find the rightmost path separator, if any */
+ while(n && !IS_SEP(path[n-1]))
+ --n;
+ /* skip over all the path separators, if any */
+ while(n && IS_SEP(path[n-1]))
+ --n;
+ }
+ if(Curl_dyn_addn(&out, path, n))
+ return NULL;
+ /* if there was a directory, append a single trailing slash */
+ if(n && Curl_dyn_addn(&out, PATHSEP, 1))
+ return NULL;
+ return Curl_dyn_ptr(&out);
+}
+
+/*
* Curl_fopen() opens a file for writing with a temp name, to be renamed
* to the final name when completed. If there is an existing file using this
* name at the time of the open, this function will clone the mode from that
@@ -50,47 +95,44 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
FILE **fh, char **tempname)
{
CURLcode result = CURLE_WRITE_ERROR;
- unsigned char randsuffix[9];
+ unsigned char randbuf[41];
char *tempstore = NULL;
struct_stat sb;
int fd = -1;
+ char *dir = NULL;
*tempname = NULL;
*fh = fopen(filename, FOPEN_WRITETEXT);
if(!*fh)
goto fail;
- if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode))
+ if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode)) {
return CURLE_OK;
+ }
fclose(*fh);
*fh = NULL;
- result = Curl_rand_alnum(data, randsuffix, sizeof(randsuffix));
+ result = Curl_rand_alnum(data, randbuf, sizeof(randbuf));
if(result)
goto fail;
- tempstore = aprintf("%s.%s.tmp", filename, randsuffix);
+ dir = dirslash(filename);
+ if(dir) {
+ /* The temp file name should not end up too long for the target file
+ system */
+ tempstore = aprintf("%s%s.tmp", dir, randbuf);
+ free(dir);
+ }
+
if(!tempstore) {
result = CURLE_OUT_OF_MEMORY;
goto fail;
}
result = CURLE_WRITE_ERROR;
- fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, 0600);
+ fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, 0600|sb.st_mode);
if(fd == -1)
goto fail;
-#ifdef HAVE_FCHMOD
- {
- struct_stat nsb;
- 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, (mode_t)sb.st_mode) == -1)
- goto fail;
- }
- }
-#endif
-
*fh = fdopen(fd, FOPEN_WRITETEXT);
if(!*fh)
goto fail;
@@ -105,7 +147,6 @@ fail:
}
free(tempstore);
-
return result;
}
diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c
index e40c4bc..05dc9b5 100644
--- a/Utilities/cmcurl/lib/formdata.c
+++ b/Utilities/cmcurl/lib/formdata.c
@@ -603,9 +603,9 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
app passed in a bad combo, so we better check for that first. */
if(form->name) {
/* copy name (without strdup; possibly not null-terminated) */
- form->name = Curl_memdup(form->name, form->namelength?
- form->namelength:
- strlen(form->name) + 1);
+ form->name = Curl_strndup(form->name, form->namelength?
+ form->namelength:
+ strlen(form->name));
}
if(!form->name) {
return_value = CURL_FORMADD_MEMORY;
@@ -792,7 +792,7 @@ static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
/* wrap call to fseeko so it matches the calling convention of callback */
static int fseeko_wrapper(void *stream, curl_off_t offset, int whence)
{
-#if defined(HAVE_FSEEKO)
+#if defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
return fseeko(stream, (off_t)offset, whence);
#elif defined(HAVE__FSEEKI64)
return _fseeki64(stream, (__int64)offset, whence);
diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c
index 6e7fda0..28e8ca4 100644
--- a/Utilities/cmcurl/lib/ftp.c
+++ b/Utilities/cmcurl/lib/ftp.c
@@ -819,7 +819,7 @@ static int ftp_domore_getsock(struct Curl_easy *data,
DEBUGF(infof(data, "ftp_domore_getsock()"));
if(conn->cfilter[SECONDARYSOCKET]
&& !Curl_conn_is_connected(conn, SECONDARYSOCKET))
- return Curl_conn_get_select_socks(data, SECONDARYSOCKET, socks);
+ return 0;
if(FTP_STOP == ftpc->state) {
int bits = GETSOCK_READSOCK(0);
@@ -947,7 +947,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
char *port_start = NULL;
char *port_sep = NULL;
- addr = calloc(addrlen + 1, 1);
+ addr = calloc(1, addrlen + 1);
if(!addr) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -4380,7 +4380,7 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct ftp_conn *ftpc = &conn->proto.ftpc;
- ftp = calloc(sizeof(struct FTP), 1);
+ ftp = calloc(1, sizeof(struct FTP));
if(!ftp)
return CURLE_OUT_OF_MEMORY;
diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c
index 2a7ca5b..82f1ea0 100644
--- a/Utilities/cmcurl/lib/ftplistparser.c
+++ b/Utilities/cmcurl/lib/ftplistparser.c
@@ -55,9 +55,6 @@
/* The last #include file should be: */
#include "memdebug.h"
-/* allocs buffer which will contain one line of LIST command response */
-#define FTP_BUFFER_ALLOCSIZE 160
-
typedef enum {
PL_UNIX_TOTALSIZE = 0,
PL_UNIX_FILETYPE,
diff --git a/Utilities/cmcurl/lib/functypes.h b/Utilities/cmcurl/lib/functypes.h
index 075c02e..ea66d32 100644
--- a/Utilities/cmcurl/lib/functypes.h
+++ b/Utilities/cmcurl/lib/functypes.h
@@ -38,7 +38,7 @@
2. For systems with config-*.h files, define them there.
*/
-#ifdef WIN32
+#ifdef _WIN32
/* int recv(SOCKET, char *, int, int) */
#define RECV_TYPE_ARG1 SOCKET
#define RECV_TYPE_ARG2 char *
diff --git a/Utilities/cmcurl/lib/getenv.c b/Utilities/cmcurl/lib/getenv.c
index 8069784..48ee972 100644
--- a/Utilities/cmcurl/lib/getenv.c
+++ b/Utilities/cmcurl/lib/getenv.c
@@ -31,10 +31,11 @@
static char *GetEnv(const char *variable)
{
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP) || \
+ defined(__ORBIS__) || defined(__PROSPERO__) /* PlayStation 4 and 5 */
(void)variable;
return NULL;
-#elif defined(WIN32)
+#elif defined(_WIN32)
/* This uses Windows API instead of C runtime getenv() to get the environment
variable since some changes aren't always visible to the latter. #4774 */
char *buf = NULL;
diff --git a/Utilities/cmcurl/lib/hostasyn.c b/Utilities/cmcurl/lib/hostasyn.c
index 2f6762c..faf01c5 100644
--- a/Utilities/cmcurl/lib/hostasyn.c
+++ b/Utilities/cmcurl/lib/hostasyn.c
@@ -67,10 +67,11 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
int status,
struct Curl_addrinfo *ai)
{
+ struct connectdata *conn = data->conn;
struct Curl_dns_entry *dns = NULL;
CURLcode result = CURLE_OK;
- data->state.async.status = status;
+ conn->resolve_async.status = status;
if(CURL_ASYNC_SUCCESS == status) {
if(ai) {
@@ -78,8 +79,8 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
dns = Curl_cache_addr(data, ai,
- data->state.async.hostname, 0,
- data->state.async.port);
+ conn->resolve_async.hostname, 0,
+ conn->resolve_async.port);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -94,12 +95,12 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
}
}
- data->state.async.dns = dns;
+ conn->resolve_async.dns = dns;
/* Set async.done TRUE last in this function since it may be used multi-
threaded and once this is TRUE the other thread may read fields from the
async struct */
- data->state.async.done = TRUE;
+ conn->resolve_async.done = TRUE;
/* IPv4: The input hostent struct will be freed by ares when we return from
this function */
diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c
index 3cd9a65..e7c318a 100644
--- a/Utilities/cmcurl/lib/hostip.c
+++ b/Utilities/cmcurl/lib/hostip.c
@@ -117,6 +117,13 @@
static void freednsentry(void *freethis);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void show_resolve_info(struct Curl_easy *data,
+ struct Curl_dns_entry *dns);
+#else
+#define show_resolve_info(x,y) Curl_nop_stmt
+#endif
+
/*
* Curl_printable_address() stores a printable version of the 1st address
* given in the 'ai' argument. The result will be stored in the buf that is
@@ -481,9 +488,11 @@ Curl_cache_addr(struct Curl_easy *data,
return NULL;
}
#endif
+ if(!hostlen)
+ hostlen = strlen(hostname);
/* Create a new cache entry */
- dns = calloc(1, sizeof(struct Curl_dns_entry));
+ dns = calloc(1, sizeof(struct Curl_dns_entry) + hostlen);
if(!dns) {
return NULL;
}
@@ -497,6 +506,9 @@ Curl_cache_addr(struct Curl_easy *data,
time(&dns->timestamp);
if(dns->timestamp == 0)
dns->timestamp = 1; /* zero indicates permanent CURLOPT_RESOLVE entry */
+ dns->hostport = port;
+ if(hostlen)
+ memcpy(dns->hostname, hostname, hostlen);
/* Store the resolved data in our DNS cache. */
dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1,
@@ -521,7 +533,7 @@ static struct Curl_addrinfo *get_localhost6(int port, const char *name)
struct sockaddr_in6 sa6;
unsigned char ipv6[16];
unsigned short port16 = (unsigned short)(port & 0xffff);
- ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1);
+ ca = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1);
if(!ca)
return NULL;
@@ -568,7 +580,7 @@ static struct Curl_addrinfo *get_localhost(int port, const char *name)
return NULL;
memcpy(&sa.sin_addr, &ipv4, sizeof(ipv4));
- ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1);
+ ca = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1);
if(!ca)
return NULL;
ca->ai_flags = 0;
@@ -729,7 +741,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
Curl_set_in_callback(data, true);
st = data->set.resolver_start(
#ifdef USE_CURL_ASYNC
- data->state.async.resolver,
+ conn->resolve_async.resolver,
#else
NULL,
#endif
@@ -823,8 +835,10 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
if(!dns)
/* returned failure, bail out nicely */
Curl_freeaddrinfo(addr);
- else
+ else {
rc = CURLRESOLV_RESOLVED;
+ show_resolve_info(data, dns);
+ }
}
}
@@ -839,7 +853,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
* execution. This effectively causes the remainder of the application to run
* within a signal handler which is nonportable and could lead to problems.
*/
-static
+CURL_NORETURN static
void alarmfunc(int sig)
{
(void)sig;
@@ -1269,9 +1283,11 @@ err:
Curl_freeaddrinfo(head);
return CURLE_OUT_OF_MEMORY;
}
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
infof(data, "Added %.*s:%d:%s to DNS cache%s",
(int)hlen, host_begin, port, addresses,
permanent ? "" : " (non-permanent)");
+#endif
/* Wildcard hostname */
if((hlen == 1) && (host_begin[0] == '*')) {
@@ -1285,18 +1301,89 @@ err:
return CURLE_OK;
}
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void show_resolve_info(struct Curl_easy *data,
+ struct Curl_dns_entry *dns)
+{
+ struct Curl_addrinfo *a;
+ CURLcode result = CURLE_OK;
+#ifdef CURLRES_IPV6
+ struct dynbuf out[2];
+#else
+ struct dynbuf out[1];
+#endif
+ DEBUGASSERT(data);
+ DEBUGASSERT(dns);
+
+ if(!data->set.verbose ||
+ /* ignore no name or numerical IP addresses */
+ !dns->hostname[0] || Curl_host_is_ipnum(dns->hostname))
+ return;
+
+ a = dns->addr;
+
+ infof(data, "Host %s:%d was resolved.",
+ (dns->hostname[0] ? dns->hostname : "(none)"), dns->hostport);
+
+ Curl_dyn_init(&out[0], 1024);
+#ifdef CURLRES_IPV6
+ Curl_dyn_init(&out[1], 1024);
+#endif
+
+ while(a) {
+ if(
+#ifdef CURLRES_IPV6
+ a->ai_family == PF_INET6 ||
+#endif
+ a->ai_family == PF_INET) {
+ char buf[MAX_IPADR_LEN];
+ struct dynbuf *d = &out[(a->ai_family != PF_INET)];
+ Curl_printable_address(a, buf, sizeof(buf));
+ if(Curl_dyn_len(d))
+ result = Curl_dyn_addn(d, ", ", 2);
+ if(!result)
+ result = Curl_dyn_add(d, buf);
+ if(result) {
+ infof(data, "too many IP, can't show");
+ goto fail;
+ }
+ }
+ a = a->ai_next;
+ }
+
+#ifdef CURLRES_IPV6
+ infof(data, "IPv6: %s",
+ (Curl_dyn_len(&out[1]) ? Curl_dyn_ptr(&out[1]) : "(none)"));
+#endif
+ infof(data, "IPv4: %s",
+ (Curl_dyn_len(&out[0]) ? Curl_dyn_ptr(&out[0]) : "(none)"));
+
+fail:
+ Curl_dyn_free(&out[0]);
+#ifdef CURLRES_IPV6
+ Curl_dyn_free(&out[1]);
+#endif
+}
+#endif
+
CURLcode Curl_resolv_check(struct Curl_easy *data,
struct Curl_dns_entry **dns)
{
+ CURLcode result;
#if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH)
(void)data;
(void)dns;
#endif
#ifndef CURL_DISABLE_DOH
- if(data->conn->bits.doh)
- return Curl_doh_is_resolved(data, dns);
+ if(data->conn->bits.doh) {
+ result = Curl_doh_is_resolved(data, dns);
+ }
+ else
#endif
- return Curl_resolver_is_resolved(data, dns);
+ result = Curl_resolver_is_resolved(data, dns);
+ if(*dns)
+ show_resolve_info(data, *dns);
+ return result;
}
int Curl_resolv_getsock(struct Curl_easy *data,
@@ -1328,9 +1415,9 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
struct connectdata *conn = data->conn;
#ifdef USE_CURL_ASYNC
- if(data->state.async.dns) {
- conn->dns_entry = data->state.async.dns;
- data->state.async.dns = NULL;
+ if(conn->resolve_async.dns) {
+ conn->dns_entry = conn->resolve_async.dns;
+ conn->resolve_async.dns = NULL;
}
#endif
@@ -1352,11 +1439,11 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
#ifdef USE_CURL_ASYNC
CURLcode Curl_resolver_error(struct Curl_easy *data)
{
+ struct connectdata *conn = data->conn;
const char *host_or_proxy;
CURLcode result;
#ifndef CURL_DISABLE_PROXY
- struct connectdata *conn = data->conn;
if(conn->bits.httpproxy) {
host_or_proxy = "proxy";
result = CURLE_COULDNT_RESOLVE_PROXY;
@@ -1369,7 +1456,7 @@ CURLcode Curl_resolver_error(struct Curl_easy *data)
}
failf(data, "Could not resolve %s: %s", host_or_proxy,
- data->state.async.hostname);
+ conn->resolve_async.hostname);
return result;
}
diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h
index b68f539..fb53a57 100644
--- a/Utilities/cmcurl/lib/hostip.h
+++ b/Utilities/cmcurl/lib/hostip.h
@@ -64,6 +64,10 @@ struct Curl_dns_entry {
time_t timestamp;
/* use-counter, use Curl_resolv_unlock to release reference */
long inuse;
+ /* hostname port number that resolved to addr. */
+ int hostport;
+ /* hostname that resolved to addr. may be NULL (unix domain sockets). */
+ char hostname[1];
};
bool Curl_host_is_ipnum(const char *hostname);
diff --git a/Utilities/cmcurl/lib/hostip6.c b/Utilities/cmcurl/lib/hostip6.c
index 6b0ba55..18969a7 100644
--- a/Utilities/cmcurl/lib/hostip6.c
+++ b/Utilities/cmcurl/lib/hostip6.c
@@ -71,8 +71,7 @@ bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
#if defined(CURLRES_SYNCH)
#ifdef DEBUG_ADDRINFO
-static void dump_addrinfo(struct connectdata *conn,
- const struct Curl_addrinfo *ai)
+static void dump_addrinfo(const struct Curl_addrinfo *ai)
{
printf("dump_addrinfo:\n");
for(; ai; ai = ai->ai_next) {
@@ -84,7 +83,7 @@ static void dump_addrinfo(struct connectdata *conn,
}
}
#else
-#define dump_addrinfo(x,y) Curl_nop_stmt
+#define dump_addrinfo(x) Curl_nop_stmt
#endif
/*
@@ -149,7 +148,7 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
Curl_addrinfo_set_port(res, port);
}
- dump_addrinfo(conn, res);
+ dump_addrinfo(res);
return res;
}
diff --git a/Utilities/cmcurl/lib/hsts.c b/Utilities/cmcurl/lib/hsts.c
index 7ecf004..9314be2 100644
--- a/Utilities/cmcurl/lib/hsts.c
+++ b/Utilities/cmcurl/lib/hsts.c
@@ -40,6 +40,7 @@
#include "fopen.h"
#include "rename.h"
#include "share.h"
+#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -76,7 +77,7 @@ static time_t hsts_debugtime(void *unused)
struct hsts *Curl_hsts_init(void)
{
- struct hsts *h = calloc(sizeof(struct hsts), 1);
+ struct hsts *h = calloc(1, sizeof(struct hsts));
if(h) {
Curl_llist_init(&h->list, NULL);
}
@@ -108,7 +109,7 @@ void Curl_hsts_cleanup(struct hsts **hp)
static struct stsentry *hsts_entry(void)
{
- return calloc(sizeof(struct stsentry), 1);
+ return calloc(1, sizeof(struct stsentry));
}
static CURLcode hsts_create(struct hsts *h,
@@ -116,23 +117,30 @@ static CURLcode hsts_create(struct hsts *h,
bool subdomains,
curl_off_t expires)
{
- struct stsentry *sts = hsts_entry();
+ struct stsentry *sts;
char *duphost;
size_t hlen;
+ DEBUGASSERT(h);
+ DEBUGASSERT(hostname);
+
+ hlen = strlen(hostname);
+ if(hlen && (hostname[hlen - 1] == '.'))
+ /* strip off any trailing dot */
+ --hlen;
+ if(!hlen)
+ /* no host name left */
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ sts = hsts_entry();
if(!sts)
return CURLE_OUT_OF_MEMORY;
- duphost = strdup(hostname);
+ duphost = Curl_strndup(hostname, hlen);
if(!duphost) {
free(sts);
return CURLE_OUT_OF_MEMORY;
}
- hlen = strlen(duphost);
- if(duphost[hlen - 1] == '.')
- /* strip off trailing any dot */
- duphost[--hlen] = 0;
-
sts->host = duphost;
sts->expires = expires;
sts->includeSubDomains = subdomains;
@@ -564,7 +572,7 @@ CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h)
void Curl_hsts_loadfiles(struct Curl_easy *data)
{
- struct curl_slist *l = data->set.hstslist;
+ struct curl_slist *l = data->state.hstslist;
if(l) {
Curl_share_lock(data, CURL_LOCK_DATA_HSTS, CURL_LOCK_ACCESS_SINGLE);
diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c
index 40ef70d..be6d442 100644
--- a/Utilities/cmcurl/lib/http.c
+++ b/Utilities/cmcurl/lib/http.c
@@ -836,6 +836,7 @@ output_auth_headers(struct Curl_easy *data,
(data->state.aptr.user ?
data->state.aptr.user : ""));
#else
+ (void)proxy;
infof(data, "Server auth using %s with user '%s'",
auth, data->state.aptr.user ?
data->state.aptr.user : "");
@@ -845,7 +846,7 @@ output_auth_headers(struct Curl_easy *data,
else
authstatus->multipass = FALSE;
- return CURLE_OK;
+ return result;
}
/**
@@ -970,17 +971,21 @@ Curl_http_output_auth(struct Curl_easy *data,
}
#endif
-/*
- * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
- * headers. They are dealt with both in the transfer.c main loop and in the
- * proxy CONNECT loop.
- */
-
+#if defined(USE_SPNEGO) || defined(USE_NTLM) || \
+ !defined(CURL_DISABLE_DIGEST_AUTH) || \
+ !defined(CURL_DISABLE_BASIC_AUTH) || \
+ !defined(CURL_DISABLE_BEARER_AUTH)
static int is_valid_auth_separator(char ch)
{
return ch == '\0' || ch == ',' || ISSPACE(ch);
}
+#endif
+/*
+ * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
+ * headers. They are dealt with both in the transfer.c main loop and in the
+ * proxy CONNECT loop.
+ */
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
const char *auth) /* the first non-space */
{
@@ -992,11 +997,15 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state :
&conn->http_negotiate_state;
#endif
+#if defined(USE_SPNEGO) || \
+ defined(USE_NTLM) || \
+ !defined(CURL_DISABLE_DIGEST_AUTH) || \
+ !defined(CURL_DISABLE_BASIC_AUTH) || \
+ !defined(CURL_DISABLE_BEARER_AUTH)
+
unsigned long *availp;
struct auth *authp;
- (void) conn; /* In case conditionals make it unused. */
-
if(proxy) {
availp = &data->info.proxyauthavail;
authp = &data->state.authproxy;
@@ -1005,6 +1014,11 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
availp = &data->info.httpauthavail;
authp = &data->state.authhost;
}
+#else
+ (void) proxy;
+#endif
+
+ (void) conn; /* In case conditionals make it unused. */
/*
* Here we check if we want the specific single authentication (using ==) and
@@ -1140,7 +1154,14 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
}
}
#else
- ;
+ {
+ /*
+ * Empty block to terminate the if-else chain correctly.
+ *
+ * A semicolon would yield the same result here, but can cause a
+ * compiler warning when -Wextra is enabled.
+ */
+ }
#endif
/* there may be multiple methods on one line, so keep reading */
@@ -1403,7 +1424,7 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
* and install our own `data->state.fread_func` that
* on subsequent calls reads `in` empty.
* - when the whisked away `in` is empty, the `fread_func`
- * is restored ot its original state.
+ * is restored to its original state.
* The problem is that `fread_func` can only return
* `upload_buffer_size` lengths. If the send we do here
* is larger and blocks, we do re-sending with smaller
@@ -1678,8 +1699,6 @@ static CURLcode expect100(struct Curl_easy *data,
struct dynbuf *req)
{
CURLcode result = CURLE_OK;
- data->state.expect100header = FALSE; /* default to false unless it is set
- to TRUE below */
if(!data->state.disableexpect && Curl_use_http_1_1plus(data, conn) &&
(conn->httpversion < 20)) {
/* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
@@ -2414,14 +2433,16 @@ CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
/* Convert the form structure into a mime structure, then keep
the conversion */
if(!data->state.formp) {
- data->state.formp = calloc(sizeof(curl_mimepart), 1);
+ data->state.formp = calloc(1, sizeof(curl_mimepart));
if(!data->state.formp)
return CURLE_OUT_OF_MEMORY;
Curl_mime_cleanpart(data->state.formp);
result = Curl_getformdata(data, data->state.formp, data->set.httppost,
data->state.fread_func);
- if(result)
+ if(result) {
+ Curl_safefree(data->state.formp);
return result;
+ }
data->state.mimepost = data->state.formp;
}
break;
@@ -2494,6 +2515,29 @@ CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
return result;
}
+static CURLcode addexpect(struct Curl_easy *data, struct connectdata *conn,
+ struct dynbuf *r)
+{
+ data->state.expect100header = FALSE;
+ /* Avoid Expect: 100-continue if Upgrade: is used */
+ if(data->req.upgr101 == UPGR101_INIT) {
+ struct HTTP *http = data->req.p.http;
+ /* For really small puts we don't use Expect: headers at all, and for
+ the somewhat bigger ones we allow the app to disable it. Just make
+ sure that the expect100header is always set to the preferred value
+ here. */
+ char *ptr = Curl_checkheaders(data, STRCONST("Expect"));
+ if(ptr) {
+ data->state.expect100header =
+ Curl_compareheader(ptr, STRCONST("Expect:"),
+ STRCONST("100-continue"));
+ }
+ else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0)
+ return expect100(data, conn, r);
+ }
+ return CURLE_OK;
+}
+
CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
struct dynbuf *r, Curl_HttpReq httpreq)
{
@@ -2506,14 +2550,8 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
#endif
CURLcode result = CURLE_OK;
struct HTTP *http = data->req.p.http;
- const char *ptr;
-
- /* If 'authdone' is FALSE, we must not set the write socket index to the
- Curl_transfer() call below, as we're not ready to actually upload any
- data yet. */
switch(httpreq) {
-
case HTTPREQ_PUT: /* Let's PUT the data to the server! */
if(conn->bits.authneg)
@@ -2531,20 +2569,9 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
return result;
}
- /* For really small puts we don't use Expect: headers at all, and for
- the somewhat bigger ones we allow the app to disable it. Just make
- sure that the expect100header is always set to the preferred value
- here. */
- ptr = Curl_checkheaders(data, STRCONST("Expect"));
- if(ptr) {
- data->state.expect100header =
- Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
- }
- else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) {
- result = expect100(data, conn, r);
- if(result)
- return result;
- }
+ result = addexpect(data, conn, r);
+ if(result)
+ return result;
/* end of headers */
result = Curl_dyn_addn(r, STRCONST("\r\n"));
@@ -2617,22 +2644,9 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
}
#endif
- /* For really small posts we don't use Expect: headers at all, and for
- the somewhat bigger ones we allow the app to disable it. Just make
- sure that the expect100header is always set to the preferred value
- here. */
- ptr = Curl_checkheaders(data, STRCONST("Expect"));
- if(ptr) {
- data->state.expect100header =
- Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
- }
- else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) {
- result = expect100(data, conn, r);
- if(result)
- return result;
- }
- else
- data->state.expect100header = FALSE;
+ result = addexpect(data, conn, r);
+ if(result)
+ return result;
/* make the request end in a true CRLF */
result = Curl_dyn_addn(r, STRCONST("\r\n"));
@@ -2692,22 +2706,9 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
return result;
}
- /* For really small posts we don't use Expect: headers at all, and for
- the somewhat bigger ones we allow the app to disable it. Just make
- sure that the expect100header is always set to the preferred value
- here. */
- ptr = Curl_checkheaders(data, STRCONST("Expect"));
- if(ptr) {
- data->state.expect100header =
- Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
- }
- else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) {
- result = expect100(data, conn, r);
- if(result)
- return result;
- }
- else
- data->state.expect100header = FALSE;
+ result = addexpect(data, conn, r);
+ if(result)
+ return result;
#ifndef USE_HYPER
/* With Hyper the body is always passed on separately */
@@ -3193,7 +3194,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
DEBUGASSERT(Curl_conn_is_http2(data, conn, FIRSTSOCKET));
break;
case CURL_HTTP_VERSION_1_1:
- /* continue with HTTP/1.1 when explicitly requested */
+ /* continue with HTTP/1.x when explicitly requested */
break;
default:
/* Check if user wants to use HTTP/2 with clear TCP */
@@ -3685,7 +3686,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
k->content_range = TRUE;
}
}
- else
+ else if(k->httpcode < 300)
data->state.resume_from = 0; /* get everything */
}
#if !defined(CURL_DISABLE_COOKIES)
@@ -3996,35 +3997,30 @@ CURLcode Curl_bump_headersize(struct Curl_easy *data,
*/
CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
struct connectdata *conn,
- ssize_t *nread,
- bool *stop_reading)
+ const char *buf, size_t blen,
+ size_t *pconsumed)
{
CURLcode result;
struct SingleRequest *k = &data->req;
- ssize_t onread = *nread;
- char *ostr = k->str;
char *headp;
- char *str_start;
char *end_ptr;
/* header line within buffer loop */
+ *pconsumed = 0;
do {
- size_t rest_length;
- size_t full_length;
+ size_t line_length;
int writetype;
- /* str_start is start of line within buf */
- str_start = k->str;
-
/* data is in network encoding so use 0x0a instead of '\n' */
- end_ptr = memchr(str_start, 0x0a, *nread);
+ end_ptr = memchr(buf, 0x0a, blen);
if(!end_ptr) {
/* Not a complete header line within buffer, append the data to
the end of the headerbuff. */
- result = Curl_dyn_addn(&data->state.headerb, str_start, *nread);
+ result = Curl_dyn_addn(&data->state.headerb, buf, blen);
if(result)
return result;
+ *pconsumed += blen;
if(!k->headerline) {
/* check if this looks like a protocol header */
@@ -4036,31 +4032,28 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(st == STATUS_BAD) {
/* this is not the beginning of a protocol first header line */
k->header = FALSE;
- k->badheader = HEADER_ALLBAD;
+ k->badheader = TRUE;
streamclose(conn, "bad HTTP: No end-of-message indicator");
if(!data->set.http09_allowed) {
failf(data, "Received HTTP/0.9 when not allowed");
return CURLE_UNSUPPORTED_PROTOCOL;
}
- break;
+ goto out;
}
}
-
- break; /* read more and try again */
+ goto out; /* read more and try again */
}
/* decrease the size of the remaining (supposed) header line */
- rest_length = (end_ptr - k->str) + 1;
- *nread -= (ssize_t)rest_length;
-
- k->str = end_ptr + 1; /* move past new line */
-
- full_length = k->str - str_start;
-
- result = Curl_dyn_addn(&data->state.headerb, str_start, full_length);
+ line_length = (end_ptr - buf) + 1;
+ result = Curl_dyn_addn(&data->state.headerb, buf, line_length);
if(result)
return result;
+ blen -= line_length;
+ buf += line_length;
+ *pconsumed += line_length;
+
/****
* We now have a FULL header line in 'headerb'.
*****/
@@ -4078,14 +4071,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
return CURLE_UNSUPPORTED_PROTOCOL;
}
k->header = FALSE;
- if(*nread)
+ if(blen)
/* since there's more, this is a partial bad header */
- k->badheader = HEADER_PARTHEADER;
+ k->badheader = TRUE;
else {
/* this was all we read so it's all a bad header */
- k->badheader = HEADER_ALLBAD;
- *nread = onread;
- k->str = ostr;
+ k->badheader = TRUE;
return CURLE_OK;
}
break;
@@ -4139,22 +4130,23 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
/* switch to http2 now. The bytes after response headers
are also processed here, otherwise they are lost. */
- result = Curl_http2_upgrade(data, conn, FIRSTSOCKET,
- k->str, *nread);
+ result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
if(result)
return result;
- *nread = 0;
+ *pconsumed += blen;
+ blen = 0;
}
#ifdef USE_WEBSOCKETS
else if(k->upgr101 == UPGR101_WS) {
/* verify the response */
- result = Curl_ws_accept(data, k->str, *nread);
+ result = Curl_ws_accept(data, buf, blen);
if(result)
return result;
k->header = FALSE; /* no more header to parse! */
if(data->set.connect_only) {
k->keepon &= ~KEEP_RECV; /* read no more content */
- *nread = 0;
+ *pconsumed += blen;
+ blen = 0;
}
}
#endif
@@ -4366,7 +4358,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* out and return home.
*/
if(data->req.no_body)
- *stop_reading = TRUE;
+ k->download_done = TRUE;
#ifndef CURL_DISABLE_RTSP
else if((conn->handler->protocol & CURLPROTO_RTSP) &&
(data->set.rtspreq == RTSPREQ_DESCRIBE) &&
@@ -4375,7 +4367,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
absent, a length 0 must be assumed. It will prevent libcurl from
hanging on DESCRIBE request that got refused for whatever
reason */
- *stop_reading = TRUE;
+ k->download_done = TRUE;
#endif
/* If max download size is *zero* (nothing) we already have
@@ -4386,15 +4378,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(0 == k->maxdownload
&& !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
&& !Curl_conn_is_http3(data, conn, FIRSTSOCKET))
- *stop_reading = TRUE;
+ k->download_done = TRUE;
- if(*stop_reading) {
- /* we make sure that this socket isn't read more now */
- k->keepon &= ~KEEP_RECV;
- }
-
- Curl_debug(data, CURLINFO_HEADER_IN, str_start, headerlen);
- break; /* exit header line loop */
+ Curl_debug(data, CURLINFO_HEADER_IN,
+ Curl_dyn_ptr(&data->state.headerb),
+ Curl_dyn_len(&data->state.headerb));
+ goto out; /* exit header line loop */
}
/* We continue reading headers, reset the line-based header */
@@ -4583,12 +4572,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
Curl_dyn_reset(&data->state.headerb);
}
- while(*k->str); /* header line within buffer */
+ while(blen);
/* We might have reached the end of the header part here, but
there might be a non-header part left in the end of the read
buffer. */
-
+out:
return CURLE_OK;
}
@@ -4618,17 +4607,6 @@ out:
return result;
}
-/* simple implementation of strndup(), which isn't portable */
-static char *my_strndup(const char *ptr, size_t len)
-{
- char *copy = malloc(len + 1);
- if(!copy)
- return NULL;
- memcpy(copy, ptr, len);
- copy[len] = '\0';
- return copy;
-}
-
CURLcode Curl_http_req_make(struct httpreq **preq,
const char *method, size_t m_len,
const char *scheme, size_t s_len,
@@ -4647,17 +4625,17 @@ CURLcode Curl_http_req_make(struct httpreq **preq,
goto out;
memcpy(req->method, method, m_len);
if(scheme) {
- req->scheme = my_strndup(scheme, s_len);
+ req->scheme = Curl_strndup(scheme, s_len);
if(!req->scheme)
goto out;
}
if(authority) {
- req->authority = my_strndup(authority, a_len);
+ req->authority = Curl_strndup(authority, a_len);
if(!req->authority)
goto out;
}
if(path) {
- req->path = my_strndup(path, p_len);
+ req->path = Curl_strndup(path, p_len);
if(!req->path)
goto out;
}
diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h
index 9ee3c65..56b0913 100644
--- a/Utilities/cmcurl/lib/http.h
+++ b/Utilities/cmcurl/lib/http.h
@@ -227,8 +227,8 @@ CURLcode Curl_http_size(struct Curl_easy *data);
CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
struct connectdata *conn,
- ssize_t *nread,
- bool *stop_reading);
+ const char *buf, size_t blen,
+ size_t *pconsumed);
/**
* Curl_http_output_auth() setups the authentication headers for the
@@ -263,7 +263,7 @@ CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len);
* All about a core HTTP request, excluding body and trailers
*/
struct httpreq {
- char method[12];
+ char method[24];
char *scheme;
char *authority;
char *path;
diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c
index c8b0594..9738484 100644
--- a/Utilities/cmcurl/lib/http2.c
+++ b/Utilities/cmcurl/lib/http2.c
@@ -107,14 +107,14 @@ static int populate_settings(nghttp2_settings_entry *iv,
return 3;
}
-static size_t populate_binsettings(uint8_t *binsettings,
- struct Curl_easy *data)
+static ssize_t populate_binsettings(uint8_t *binsettings,
+ struct Curl_easy *data)
{
nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
int ivlen;
ivlen = populate_settings(iv, data);
- /* this returns number of bytes it wrote */
+ /* this returns number of bytes it wrote or a negative number on error. */
return nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
iv, ivlen);
}
@@ -369,12 +369,15 @@ static ssize_t nw_out_writer(void *writer_ctx,
{
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);
- if(nwritten > 0)
- CURL_TRC_CF(data, cf, "[0] egress: wrote %zd bytes", nwritten);
- return nwritten;
+ if(data) {
+ ssize_t nwritten = Curl_conn_cf_send(cf->next, data,
+ (const char *)buf, buflen, err);
+ if(nwritten > 0)
+ CURL_TRC_CF(data, cf, "[0] egress: wrote %zd bytes", nwritten);
+ return nwritten;
+ }
+ return 0;
}
static ssize_t send_callback(nghttp2_session *h2,
@@ -452,9 +455,14 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf,
* in the H1 request and we upgrade from there. This stream
* is opened implicitly as #1. */
uint8_t binsettings[H2_BINSETTINGS_LEN];
- size_t binlen; /* length of the binsettings data */
+ ssize_t binlen; /* length of the binsettings data */
binlen = populate_binsettings(binsettings, data);
+ if(binlen <= 0) {
+ failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
+ result = CURLE_FAILED_INIT;
+ goto out;
+ }
result = http2_data_setup(cf, data, &stream);
if(result)
@@ -1076,16 +1084,11 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
stream->reset = TRUE;
}
stream->send_closed = TRUE;
- data->req.keepon &= ~KEEP_SEND_HOLD;
drain_stream(cf, data, stream);
break;
case NGHTTP2_WINDOW_UPDATE:
- if((data->req.keepon & KEEP_SEND_HOLD) &&
- (data->req.keepon & KEEP_SEND)) {
- data->req.keepon &= ~KEEP_SEND_HOLD;
+ if(CURL_WANT_SEND(data)) {
drain_stream(cf, data, stream);
- CURL_TRC_CF(data, cf, "[%d] un-holding after win update",
- stream_id);
}
break;
default:
@@ -1230,15 +1233,10 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
* 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)) {
+ if(CURL_WANT_SEND(data)) {
struct stream_ctx *stream = H2_STREAM_CTX(data);
- data->req.keepon &= ~KEEP_SEND_HOLD;
- if(stream) {
+ if(stream)
drain_stream(cf, data, stream);
- CURL_TRC_CF(data, cf, "[%d] un-holding after SETTINGS",
- stream_id);
- }
}
}
break;
@@ -1338,7 +1336,6 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
stream->error = error_code;
if(stream->error)
stream->reset = TRUE;
- data_s->req.keepon &= ~KEEP_SEND_HOLD;
if(stream->error)
CURL_TRC_CF(data_s, cf, "[%d] RESET: %s (err %d)",
@@ -1602,10 +1599,10 @@ static int error_callback(nghttp2_session *session,
size_t len,
void *userp)
{
+ struct Curl_cfilter *cf = userp;
+ struct Curl_easy *data = CF_DATA_CURRENT(cf);
(void)session;
- (void)msg;
- (void)len;
- (void)userp;
+ failf(data, "%.*s", (int)len, msg);
return 0;
}
#endif
@@ -1621,7 +1618,7 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
size_t blen;
struct SingleRequest *k = &data->req;
uint8_t binsettings[H2_BINSETTINGS_LEN];
- size_t binlen; /* length of the binsettings data */
+ ssize_t binlen; /* length of the binsettings data */
binlen = populate_binsettings(binsettings, data);
if(binlen <= 0) {
@@ -2052,23 +2049,13 @@ static ssize_t h2_submit(struct stream_ctx **pstream,
/* no longer needed */
Curl_h1_req_parse_free(&stream->h1);
- nheader = Curl_dynhds_count(&h2_headers);
- nva = malloc(sizeof(nghttp2_nv) * nheader);
+ nva = Curl_dynhds_to_nva(&h2_headers, &nheader);
if(!nva) {
*err = CURLE_OUT_OF_MEMORY;
nwritten = -1;
goto out;
}
- for(i = 0; i < nheader; ++i) {
- struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i);
- nva[i].name = (unsigned char *)e->name;
- nva[i].namelen = e->namelen;
- nva[i].value = (unsigned char *)e->value;
- nva[i].valuelen = e->valuelen;
- nva[i].flags = NGHTTP2_NV_FLAG_NONE;
- }
-
h2_pri_spec(data, &pri_spec);
if(!nghttp2_session_check_request_allowed(ctx->h2))
CURL_TRC_CF(data, cf, "send request NOT allowed (via nghttp2)");
@@ -2272,14 +2259,6 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* 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;
- CURL_TRC_CF(data, cf, "[%d] holding send as remote flow "
- "window is exhausted", 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. */
@@ -2331,38 +2310,34 @@ out:
return nwritten;
}
-static int cf_h2_get_select_socks(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- curl_socket_t *sock)
+static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct SingleRequest *k = &data->req;
- struct stream_ctx *stream = H2_STREAM_CTX(data);
- int bitmap = GETSOCK_BLANK;
- struct cf_call_data save;
+ bool want_recv = CURL_WANT_RECV(data);
+ bool want_send = CURL_WANT_SEND(data);
- CF_DATA_SAVE(save, cf, data);
- sock[0] = Curl_conn_cf_get_socket(cf, data);
-
- if(!(k->keepon & (KEEP_RECV_PAUSE|KEEP_RECV_HOLD)))
- /* Unless paused - in an HTTP/2 connection we can basically always get a
- frame so we should always be ready for one */
- bitmap |= GETSOCK_READSOCK(0);
-
- /* we're (still uploading OR the HTTP/2 layer wants to send data) AND
- there's a window to send data in */
- if((((k->keepon & KEEP_SENDBITS) == KEEP_SEND) ||
- nghttp2_session_want_write(ctx->h2)) &&
- (nghttp2_session_get_remote_window_size(ctx->h2) &&
- nghttp2_session_get_stream_remote_window_size(ctx->h2,
- stream->id)))
- bitmap |= GETSOCK_WRITESOCK(0);
+ if(ctx->h2 && (want_recv || want_send)) {
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
+ curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
+ struct cf_call_data save;
+ bool c_exhaust, s_exhaust;
- CF_DATA_RESTORE(cf, save);
- return bitmap;
+ CF_DATA_SAVE(save, cf, data);
+ c_exhaust = !nghttp2_session_get_remote_window_size(ctx->h2);
+ s_exhaust = stream && stream->id >= 0 &&
+ !nghttp2_session_get_stream_remote_window_size(ctx->h2,
+ stream->id);
+ want_recv = (want_recv || c_exhaust || s_exhaust);
+ want_send = (!s_exhaust && want_send) ||
+ (!c_exhaust && nghttp2_session_want_write(ctx->h2));
+
+ Curl_pollset_set(data, ps, sock, want_recv, want_send);
+ CF_DATA_RESTORE(cf, save);
+ }
}
-
static CURLcode cf_h2_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool blocking, bool *done)
@@ -2511,14 +2486,15 @@ static CURLcode cf_h2_cntrl(struct Curl_cfilter *cf,
case CF_CTRL_DATA_PAUSE:
result = http2_data_pause(cf, data, (arg1 != 0));
break;
- case CF_CTRL_DATA_DONE_SEND: {
+ case CF_CTRL_DATA_DONE_SEND:
result = http2_data_done_send(cf, data);
break;
- }
- case CF_CTRL_DATA_DONE: {
+ case CF_CTRL_DATA_DETACH:
+ http2_data_done(cf, data, TRUE);
+ break;
+ case CF_CTRL_DATA_DONE:
http2_data_done(cf, data, arg1 != 0);
break;
- }
default:
break;
}
@@ -2606,7 +2582,7 @@ struct Curl_cftype Curl_cft_nghttp2 = {
cf_h2_connect,
cf_h2_close,
Curl_cf_def_get_host,
- cf_h2_get_select_socks,
+ cf_h2_adjust_pollset,
cf_h2_data_pending,
cf_h2_send,
cf_h2_recv,
@@ -2626,7 +2602,7 @@ static CURLcode http2_cfilter_add(struct Curl_cfilter **pcf,
CURLcode result = CURLE_OUT_OF_MEMORY;
DEBUGASSERT(data->conn);
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx)
goto out;
@@ -2652,7 +2628,7 @@ static CURLcode http2_cfilter_insert_after(struct Curl_cfilter *cf,
CURLcode result = CURLE_OUT_OF_MEMORY;
(void)data;
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx)
goto out;
diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.c b/Utilities/cmcurl/lib/http_aws_sigv4.c
index 901c22f..b673055 100644
--- a/Utilities/cmcurl/lib/http_aws_sigv4.c
+++ b/Utilities/cmcurl/lib/http_aws_sigv4.c
@@ -456,6 +456,7 @@ static CURLcode canon_query(struct Curl_easy *data,
for(i = 0; !result && (i < entry); i++, ap++) {
size_t len;
const char *q = ap->p;
+ bool found_equals = false;
if(!ap->len)
continue;
for(len = ap->len; len && !result; q++, len--) {
@@ -467,9 +468,13 @@ static CURLcode canon_query(struct Curl_easy *data,
case '.':
case '_':
case '~':
+ /* allowed as-is */
+ result = Curl_dyn_addn(dq, q, 1);
+ break;
case '=':
/* allowed as-is */
result = Curl_dyn_addn(dq, q, 1);
+ found_equals = true;
break;
case '%':
/* uppercase the following if hexadecimal */
@@ -497,7 +502,11 @@ static CURLcode canon_query(struct Curl_easy *data,
}
}
}
- if(i < entry - 1) {
+ if(!result && !found_equals) {
+ /* queries without value still need an equals */
+ result = Curl_dyn_addn(dq, "=", 1);
+ }
+ if(!result && i < entry - 1) {
/* insert ampersands between query pairs */
result = Curl_dyn_addn(dq, "&", 1);
}
diff --git a/Utilities/cmcurl/lib/http_chunks.c b/Utilities/cmcurl/lib/http_chunks.c
index 2a401d1..acdb108 100644
--- a/Utilities/cmcurl/lib/http_chunks.c
+++ b/Utilities/cmcurl/lib/http_chunks.c
@@ -75,8 +75,6 @@
*/
-#define isxdigit_ascii(x) Curl_isxdigit(x)
-
void Curl_httpchunk_init(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
@@ -98,9 +96,9 @@ void Curl_httpchunk_init(struct Curl_easy *data)
* For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
*/
CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
- char *datap,
- ssize_t datalen,
- ssize_t *wrote,
+ char *buf,
+ size_t blen,
+ size_t *pconsumed,
CURLcode *extrap)
{
CURLcode result = CURLE_OK;
@@ -108,28 +106,27 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
struct Curl_chunker *ch = &conn->chunk;
struct SingleRequest *k = &data->req;
size_t piece;
- curl_off_t length = (curl_off_t)datalen;
- *wrote = 0; /* nothing's written yet */
+ *pconsumed = 0; /* nothing's written yet */
/* the original data is written to the client, but we go on with the
chunk read process, to properly calculate the content length */
if(data->set.http_te_skip && !k->ignorebody) {
- result = Curl_client_write(data, CLIENTWRITE_BODY, datap, datalen);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, buf, blen);
if(result) {
*extrap = result;
return CHUNKE_PASSTHRU_ERROR;
}
}
- while(length) {
+ while(blen) {
switch(ch->state) {
case CHUNK_HEX:
- if(ISXDIGIT(*datap)) {
+ if(ISXDIGIT(*buf)) {
if(ch->hexindex < CHUNK_MAXNUM_LEN) {
- ch->hexbuffer[ch->hexindex] = *datap;
- datap++;
- length--;
+ ch->hexbuffer[ch->hexindex] = *buf;
+ buf++;
+ blen--;
ch->hexindex++;
}
else {
@@ -143,7 +140,7 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
a hexadecimal digit. */
return CHUNKE_ILLEGAL_HEX;
- /* length and datap are unmodified */
+ /* blen and buf are unmodified */
ch->hexbuffer[ch->hexindex] = 0;
if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize))
@@ -154,7 +151,7 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
case CHUNK_LF:
/* waiting for the LF after a chunk size */
- if(*datap == 0x0a) {
+ if(*buf == 0x0a) {
/* we're now expecting data to come, unless size was zero! */
if(0 == ch->datasize) {
ch->state = CHUNK_TRAILER; /* now check for trailers */
@@ -163,19 +160,21 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
ch->state = CHUNK_DATA;
}
- datap++;
- length--;
+ buf++;
+ blen--;
break;
case CHUNK_DATA:
- /* We expect 'datasize' of data. We have 'length' right now, it can be
+ /* We expect 'datasize' of data. We have 'blen' right now, it can be
more or less than 'datasize'. Get the smallest piece.
*/
- piece = curlx_sotouz((ch->datasize >= length)?length:ch->datasize);
+ piece = blen;
+ if(ch->datasize < (curl_off_t)blen)
+ piece = curlx_sotouz(ch->datasize);
/* Write the data portion available */
if(!data->set.http_te_skip && !k->ignorebody) {
- result = Curl_client_write(data, CLIENTWRITE_BODY, datap, piece);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, buf, piece);
if(result) {
*extrap = result;
@@ -183,10 +182,10 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
}
}
- *wrote += piece;
+ *pconsumed += piece;
ch->datasize -= piece; /* decrease amount left to expect */
- datap += piece; /* move read pointer forward */
- length -= piece; /* decrease space left in this round */
+ buf += piece; /* move read pointer forward */
+ blen -= piece; /* decrease space left in this round */
if(0 == ch->datasize)
/* end of data this round, we now expect a trailing CRLF */
@@ -194,18 +193,18 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
break;
case CHUNK_POSTLF:
- if(*datap == 0x0a) {
+ if(*buf == 0x0a) {
/* The last one before we go back to hex state and start all over. */
Curl_httpchunk_init(data); /* sets state back to CHUNK_HEX */
}
- else if(*datap != 0x0d)
+ else if(*buf != 0x0d)
return CHUNKE_BAD_CHUNK;
- datap++;
- length--;
+ buf++;
+ blen--;
break;
case CHUNK_TRAILER:
- if((*datap == 0x0d) || (*datap == 0x0a)) {
+ if((*buf == 0x0d) || (*buf == 0x0a)) {
char *tr = Curl_dyn_ptr(&conn->trailer);
/* this is the end of a trailer, but if the trailer was zero bytes
there was no trailer and we move on */
@@ -229,7 +228,7 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
}
Curl_dyn_reset(&conn->trailer);
ch->state = CHUNK_TRAILER_CR;
- if(*datap == 0x0a)
+ if(*buf == 0x0a)
/* already on the LF */
break;
}
@@ -240,19 +239,19 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
}
}
else {
- result = Curl_dyn_addn(&conn->trailer, datap, 1);
+ result = Curl_dyn_addn(&conn->trailer, buf, 1);
if(result)
return CHUNKE_OUT_OF_MEMORY;
}
- datap++;
- length--;
+ buf++;
+ blen--;
break;
case CHUNK_TRAILER_CR:
- if(*datap == 0x0a) {
+ if(*buf == 0x0a) {
ch->state = CHUNK_TRAILER_POSTCR;
- datap++;
- length--;
+ buf++;
+ blen--;
}
else
return CHUNKE_BAD_CHUNK;
@@ -261,27 +260,27 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
case CHUNK_TRAILER_POSTCR:
/* We enter this state when a CR should arrive so we expect to
have to first pass a CR before we wait for LF */
- if((*datap != 0x0d) && (*datap != 0x0a)) {
+ if((*buf != 0x0d) && (*buf != 0x0a)) {
/* not a CR then it must be another header in the trailer */
ch->state = CHUNK_TRAILER;
break;
}
- if(*datap == 0x0d) {
+ if(*buf == 0x0d) {
/* skip if CR */
- datap++;
- length--;
+ buf++;
+ blen--;
}
/* now wait for the final LF */
ch->state = CHUNK_STOP;
break;
case CHUNK_STOP:
- if(*datap == 0x0a) {
- length--;
+ if(*buf == 0x0a) {
+ blen--;
/* Record the length of any data left in the end of the buffer
even if there's no more chunks to read */
- ch->datasize = curlx_sotouz(length);
+ ch->datasize = blen;
return CHUNKE_STOP; /* return stop */
}
diff --git a/Utilities/cmcurl/lib/http_chunks.h b/Utilities/cmcurl/lib/http_chunks.h
index ed50713..0a36f37 100644
--- a/Utilities/cmcurl/lib/http_chunks.h
+++ b/Utilities/cmcurl/lib/http_chunks.h
@@ -93,8 +93,8 @@ struct Curl_chunker {
/* The following functions are defined in http_chunks.c */
void Curl_httpchunk_init(struct Curl_easy *data);
-CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, char *datap,
- ssize_t length, ssize_t *wrote,
+CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, char *buf,
+ size_t blen, size_t *pconsumed,
CURLcode *passthru);
#endif /* HEADER_CURL_HTTP_CHUNKS_H */
diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c
index a1d6da9..8e18325 100644
--- a/Utilities/cmcurl/lib/http_proxy.c
+++ b/Utilities/cmcurl/lib/http_proxy.c
@@ -299,7 +299,7 @@ struct Curl_cftype Curl_cft_http_proxy = {
http_proxy_cf_connect,
http_proxy_cf_close,
Curl_cf_http_proxy_get_host,
- Curl_cf_def_get_select_socks,
+ Curl_cf_def_adjust_pollset,
Curl_cf_def_data_pending,
Curl_cf_def_send,
Curl_cf_def_recv,
diff --git a/Utilities/cmcurl/lib/idn.c b/Utilities/cmcurl/lib/idn.c
index a024691..81a177f 100644
--- a/Utilities/cmcurl/lib/idn.c
+++ b/Utilities/cmcurl/lib/idn.c
@@ -36,7 +36,7 @@
#ifdef USE_LIBIDN2
#include <idn2.h>
-#if defined(WIN32) && defined(UNICODE)
+#if defined(_WIN32) && defined(UNICODE)
#define IDN2_LOOKUP(name, host, flags) \
idn2_lookup_u8((const uint8_t *)name, (uint8_t **)host, flags)
#else
diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c
index de64c2a..47cff48 100644
--- a/Utilities/cmcurl/lib/imap.c
+++ b/Utilities/cmcurl/lib/imap.c
@@ -1194,8 +1194,6 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
if(result)
return result;
- data->req.bytecount += chunk;
-
infof(data, "Written %zu bytes, %" CURL_FORMAT_CURL_OFF_TU
" bytes are left for transfer", chunk, size - chunk);
@@ -1430,7 +1428,7 @@ static CURLcode imap_init(struct Curl_easy *data)
CURLcode result = CURLE_OK;
struct IMAP *imap;
- imap = data->req.p.imap = calloc(sizeof(struct IMAP), 1);
+ imap = data->req.p.imap = calloc(1, sizeof(struct IMAP));
if(!imap)
result = CURLE_OUT_OF_MEMORY;
diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c
index 239d3fb..eb5fe795 100644
--- a/Utilities/cmcurl/lib/ldap.c
+++ b/Utilities/cmcurl/lib/ldap.c
@@ -313,7 +313,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
int ldap_ssl = 0;
char *val_b64 = NULL;
size_t val_b64_sz = 0;
- curl_off_t dlsize = 0;
#ifdef LDAP_OPT_NETWORK_TIMEOUT
struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */
#endif
@@ -327,7 +326,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
*done = TRUE; /* unconditionally */
infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d",
- LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
+ LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
infof(data, "LDAP local: %s", data->state.url);
#ifdef HAVE_LDAP_URL_PARSE
@@ -345,7 +344,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
if(conn->given->flags & PROTOPT_SSL)
ldap_ssl = 1;
infof(data, "LDAP local: trying to establish %s connection",
- ldap_ssl ? "encrypted" : "cleartext");
+ ldap_ssl ? "encrypted" : "cleartext");
#if defined(USE_WIN32_LDAP)
host = curlx_convert_UTF8_to_tchar(conn->host.name);
@@ -535,6 +534,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
+ Curl_pgrsSetDownloadCounter(data, 0);
rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);
@@ -596,8 +596,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
- dlsize += name_len + 5;
-
FREE_ON_WINLDAP(name);
ldap_memfree(dn);
}
@@ -659,8 +657,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
- dlsize += attr_len + 3;
-
if((attr_len > 7) &&
(strcmp(";binary", attr + (attr_len - 7)) == 0)) {
/* Binary attribute, encode to base64. */
@@ -689,8 +685,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
-
- dlsize += val_b64_sz;
}
}
else {
@@ -705,8 +699,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
-
- dlsize += vals[i]->bv_len;
}
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
@@ -719,8 +711,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
-
- dlsize++;
}
/* Free memory used to store values */
@@ -734,10 +724,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
if(result)
goto quit;
- dlsize++;
- result = Curl_pgrsSetDownloadCounter(data, dlsize);
- if(result)
- goto quit;
}
if(ber)
diff --git a/Utilities/cmcurl/lib/md4.c b/Utilities/cmcurl/lib/md4.c
index 30ab62e..486e5fa 100644
--- a/Utilities/cmcurl/lib/md4.c
+++ b/Utilities/cmcurl/lib/md4.c
@@ -32,9 +32,8 @@
#include "warnless.h"
#ifdef USE_OPENSSL
-#include <openssl/opensslconf.h>
-#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) && \
- !defined(USE_AMISSL)
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) && !defined(USE_AMISSL)
/* OpenSSL 3.0.0 marks the MD4 functions as deprecated */
#define OPENSSL_NO_MD4
#endif
diff --git a/Utilities/cmcurl/lib/memdebug.c b/Utilities/cmcurl/lib/memdebug.c
index d6952a0..f6ced85 100644
--- a/Utilities/cmcurl/lib/memdebug.c
+++ b/Utilities/cmcurl/lib/memdebug.c
@@ -208,7 +208,7 @@ ALLOC_FUNC char *curl_dbg_strdup(const char *str,
return mem;
}
-#if defined(WIN32) && defined(UNICODE)
+#if defined(_WIN32) && defined(UNICODE)
ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str,
int line, const char *source)
{
diff --git a/Utilities/cmcurl/lib/memdebug.h b/Utilities/cmcurl/lib/memdebug.h
index c9eb5dc..78a0125 100644
--- a/Utilities/cmcurl/lib/memdebug.h
+++ b/Utilities/cmcurl/lib/memdebug.h
@@ -64,7 +64,7 @@ CURL_EXTERN ALLOC_SIZE(2) void *curl_dbg_realloc(void *ptr,
CURL_EXTERN void curl_dbg_free(void *ptr, int line, const char *source);
CURL_EXTERN ALLOC_FUNC char *curl_dbg_strdup(const char *str, int line,
const char *src);
-#if defined(WIN32) && defined(UNICODE)
+#if defined(_WIN32) && defined(UNICODE)
CURL_EXTERN ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str,
int line,
const char *source);
@@ -121,7 +121,7 @@ CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source);
#define send(a,b,c,d) curl_dbg_send(a,b,c,d, __LINE__, __FILE__)
#define recv(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__)
-#ifdef WIN32
+#ifdef _WIN32
# ifdef UNICODE
# undef wcsdup
# define wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__)
diff --git a/Utilities/cmcurl/lib/mime.c b/Utilities/cmcurl/lib/mime.c
index 3b27e59..bb66130 100644
--- a/Utilities/cmcurl/lib/mime.c
+++ b/Utilities/cmcurl/lib/mime.c
@@ -48,7 +48,7 @@
#include "curl_memory.h"
#include "memdebug.h"
-#ifdef WIN32
+#ifdef _WIN32
# ifndef R_OK
# define R_OK 4
# endif
@@ -311,8 +311,7 @@ static char *escape_string(struct Curl_easy *data,
table = formtable;
/* data can be NULL when this function is called indirectly from
curl_formget(). */
- if(strategy == MIMESTRATEGY_MAIL ||
- (data && (data->set.mime_options & CURLMIMEOPT_FORMESCAPE)))
+ if(strategy == MIMESTRATEGY_MAIL || (data && (data->set.mime_formescape)))
table = mimetable;
Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
diff --git a/Utilities/cmcurl/lib/mprintf.c b/Utilities/cmcurl/lib/mprintf.c
index af5d753..6b5df5b 100644
--- a/Utilities/cmcurl/lib/mprintf.c
+++ b/Utilities/cmcurl/lib/mprintf.c
@@ -66,9 +66,7 @@
* Non-ANSI integer extensions
*/
-#if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x520)) || \
- (defined(__POCC__) && defined(_MSC_VER)) || \
- (defined(_WIN32_WCE)) || \
+#if (defined(_WIN32_WCE)) || \
(defined(__MINGW32__)) || \
(defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64))
# define MP_HAVE_INT_EXTENSIONS
@@ -1071,9 +1069,6 @@ static int alloc_addbyter(int output, FILE *data)
return outc; /* fputc() returns like this on success */
}
-extern int Curl_dyn_vprintf(struct dynbuf *dyn,
- const char *format, va_list ap_save);
-
/* appends the formatted string, returns 0 on success, 1 on error */
int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save)
{
diff --git a/Utilities/cmcurl/lib/mqtt.c b/Utilities/cmcurl/lib/mqtt.c
index 54f8882..366235c 100644
--- a/Utilities/cmcurl/lib/mqtt.c
+++ b/Utilities/cmcurl/lib/mqtt.c
@@ -616,9 +616,6 @@ static void mqstate(struct Curl_easy *data,
}
-/* for the publish packet */
-#define MQTT_HEADER_LEN 5 /* max 5 bytes */
-
static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
@@ -677,7 +674,6 @@ MQTT_SUBACK_COMING:
/* FALLTHROUGH */
case MQTT_PUB_REMAIN: {
/* read rest of packet, but no more. Cap to buffer size */
- struct SingleRequest *k = &data->req;
size_t rest = mq->npacket;
if(rest > (size_t)data->set.buffer_size)
rest = (size_t)data->set.buffer_size;
@@ -693,13 +689,8 @@ MQTT_SUBACK_COMING:
result = CURLE_PARTIAL_FILE;
goto end;
}
- Curl_debug(data, CURLINFO_DATA_IN, (char *)pkt, (size_t)nread);
mq->npacket -= nread;
- k->bytecount += nread;
- result = Curl_pgrsSetDownloadCounter(data, k->bytecount);
- if(result)
- goto end;
/* if QoS is set, message contains packet id */
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
index ff753ac..5456113 100644
--- a/Utilities/cmcurl/lib/multi.c
+++ b/Utilities/cmcurl/lib/multi.c
@@ -55,22 +55,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-#ifdef __APPLE__
-
-#define wakeup_write write
-#define wakeup_read read
-#define wakeup_close close
-#define wakeup_create pipe
-
-#else /* __APPLE__ */
-
-#define wakeup_write swrite
-#define wakeup_read sread
-#define wakeup_close sclose
-#define wakeup_create(p) Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, p)
-
-#endif /* __APPLE__ */
-
/*
CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every
@@ -231,10 +215,6 @@ struct Curl_sh_entry {
unsigned int readers; /* this many transfers want to read */
unsigned int writers; /* this many transfers want to write */
};
-/* bits for 'action' having no bits means this socket is not expecting any
- action */
-#define SH_READ 1
-#define SH_WRITE 2
/* look up a given socket in the socket hash, skip invalid sockets */
static struct Curl_sh_entry *sh_getentry(struct Curl_hash *sh,
@@ -416,9 +396,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
Curl_llist_init(&multi->msgsent, NULL);
multi->multiplexing = TRUE;
-
- /* -1 means it not set by user, use the default value */
- multi->maxconnects = -1;
multi->max_concurrent_streams = 100;
#ifdef USE_WINSOCK
@@ -1040,49 +1017,61 @@ static int protocol_getsock(struct Curl_easy *data,
{
if(conn->handler->proto_getsock)
return conn->handler->proto_getsock(data, conn, socks);
- return Curl_conn_get_select_socks(data, FIRSTSOCKET, socks);
+ return GETSOCK_BLANK;
}
-/* returns bitmapped flags for this handle and its sockets. The 'socks[]'
- array contains MAX_SOCKSPEREASYHANDLE entries. */
-static int multi_getsock(struct Curl_easy *data,
- curl_socket_t *socks)
+/* Initializes `poll_set` with the current socket poll actions needed
+ * for transfer `data`. */
+static void multi_getsock(struct Curl_easy *data,
+ struct easy_pollset *ps)
{
- struct connectdata *conn = data->conn;
/* The no connection case can happen when this is called from
curl_multi_remove_handle() => singlesocket() => multi_getsock().
*/
- if(!conn)
- return 0;
+ Curl_pollset_reset(data, ps);
+ if(!data->conn)
+ return;
switch(data->mstate) {
default:
- return 0;
+ break;
case MSTATE_RESOLVING:
- return Curl_resolv_getsock(data, socks);
+ Curl_pollset_add_socks2(data, ps, Curl_resolv_getsock);
+ /* connection filters are not involved in this phase */
+ return;
case MSTATE_PROTOCONNECTING:
case MSTATE_PROTOCONNECT:
- return protocol_getsock(data, conn, socks);
+ Curl_pollset_add_socks(data, ps, protocol_getsock);
+ break;
case MSTATE_DO:
case MSTATE_DOING:
- return doing_getsock(data, conn, socks);
+ Curl_pollset_add_socks(data, ps, doing_getsock);
+ break;
case MSTATE_TUNNELING:
case MSTATE_CONNECTING:
- return Curl_conn_get_select_socks(data, FIRSTSOCKET, socks);
+ break;
case MSTATE_DOING_MORE:
- return domore_getsock(data, conn, socks);
+ Curl_pollset_add_socks(data, ps, domore_getsock);
+ break;
case MSTATE_DID: /* since is set after DO is completed, we switch to
waiting for the same as the PERFORMING state */
case MSTATE_PERFORMING:
- return Curl_single_getsock(data, conn, socks);
+ Curl_pollset_add_socks(data, ps, Curl_single_getsock);
+ break;
+
+ case MSTATE_RATELIMITING:
+ /* nothing to wait for */
+ return;
}
+ /* Let connection filters add/remove as needed */
+ Curl_conn_adjust_pollset(data, ps);
}
CURLMcode curl_multi_fdset(struct Curl_multi *multi,
@@ -1094,8 +1083,8 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
and then we must make sure that is done. */
struct Curl_easy *data;
int this_max_fd = -1;
- curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
- int i;
+ struct easy_pollset ps;
+ unsigned int i;
(void)exc_fd_set; /* not used */
if(!GOOD_MULTI_HANDLE(multi))
@@ -1104,29 +1093,20 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
+ memset(&ps, 0, sizeof(ps));
for(data = multi->easyp; data; data = data->next) {
- int bitmap;
-#ifdef __clang_analyzer_
- /* to prevent "The left operand of '>=' is a garbage value" warnings */
- memset(sockbunch, 0, sizeof(sockbunch));
-#endif
- bitmap = multi_getsock(data, sockbunch);
-
- for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
- if((bitmap & GETSOCK_MASK_RW(i)) && VALID_SOCK((sockbunch[i]))) {
- if(!FDSET_SOCK(sockbunch[i]))
- /* pretend it doesn't exist */
- continue;
- if(bitmap & GETSOCK_READSOCK(i))
- FD_SET(sockbunch[i], read_fd_set);
- if(bitmap & GETSOCK_WRITESOCK(i))
- FD_SET(sockbunch[i], write_fd_set);
- if((int)sockbunch[i] > this_max_fd)
- this_max_fd = (int)sockbunch[i];
- }
- else {
- break;
- }
+ multi_getsock(data, &ps);
+
+ for(i = 0; i < ps.num; i++) {
+ if(!FDSET_SOCK(ps.sockets[i]))
+ /* pretend it doesn't exist */
+ continue;
+ if(ps.actions[i] & CURL_POLL_IN)
+ FD_SET(ps.sockets[i], read_fd_set);
+ if(ps.actions[i] & CURL_POLL_OUT)
+ FD_SET(ps.sockets[i], write_fd_set);
+ if((int)ps.sockets[i] > this_max_fd)
+ this_max_fd = (int)ps.sockets[i];
}
}
@@ -1162,9 +1142,8 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
bool use_wakeup)
{
struct Curl_easy *data;
- curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
- int bitmap;
- unsigned int i;
+ struct easy_pollset ps;
+ size_t i;
unsigned int nfds = 0;
unsigned int curlfds;
long timeout_internal;
@@ -1190,17 +1169,10 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
return CURLM_BAD_FUNCTION_ARGUMENT;
/* Count up how many fds we have from the multi handle */
+ memset(&ps, 0, sizeof(ps));
for(data = multi->easyp; data; data = data->next) {
- bitmap = multi_getsock(data, sockbunch);
-
- for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
- if((bitmap & GETSOCK_MASK_RW(i)) && VALID_SOCK((sockbunch[i]))) {
- ++nfds;
- }
- else {
- break;
- }
- }
+ multi_getsock(data, &ps);
+ nfds += ps.num;
}
/* If the internally desired timeout is actually shorter than requested from
@@ -1241,40 +1213,35 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
if(curlfds) {
/* Add the curl handles to our pollfds first */
for(data = multi->easyp; data; data = data->next) {
- bitmap = multi_getsock(data, sockbunch);
+ multi_getsock(data, &ps);
- for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
- if((bitmap & GETSOCK_MASK_RW(i)) && VALID_SOCK((sockbunch[i]))) {
- struct pollfd *ufd = &ufds[nfds++];
-#ifdef USE_WINSOCK
- long mask = 0;
-#endif
- ufd->fd = sockbunch[i];
- ufd->events = 0;
- if(bitmap & GETSOCK_READSOCK(i)) {
+ for(i = 0; i < ps.num; i++) {
+ struct pollfd *ufd = &ufds[nfds++];
#ifdef USE_WINSOCK
- mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
+ long mask = 0;
#endif
- ufd->events |= POLLIN;
- }
- if(bitmap & GETSOCK_WRITESOCK(i)) {
+ ufd->fd = ps.sockets[i];
+ ufd->events = 0;
+ if(ps.actions[i] & CURL_POLL_IN) {
#ifdef USE_WINSOCK
- mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
- reset_socket_fdwrite(sockbunch[i]);
+ mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
#endif
- ufd->events |= POLLOUT;
- }
+ ufd->events |= POLLIN;
+ }
+ if(ps.actions[i] & CURL_POLL_OUT) {
#ifdef USE_WINSOCK
- if(WSAEventSelect(sockbunch[i], multi->wsa_event, mask) != 0) {
- if(ufds_malloc)
- free(ufds);
- return CURLM_INTERNAL_ERROR;
- }
+ mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
+ reset_socket_fdwrite(ps.sockets[i]);
#endif
+ ufd->events |= POLLOUT;
}
- else {
- break;
+#ifdef USE_WINSOCK
+ if(WSAEventSelect(ps.sockets[i], multi->wsa_event, mask) != 0) {
+ if(ufds_malloc)
+ free(ufds);
+ return CURLM_INTERNAL_ERROR;
}
+#endif
}
}
}
@@ -1386,21 +1353,16 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
if(curlfds) {
for(data = multi->easyp; data; data = data->next) {
- bitmap = multi_getsock(data, sockbunch);
-
- for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
- if(bitmap & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))) {
- wsa_events.lNetworkEvents = 0;
- if(WSAEnumNetworkEvents(sockbunch[i], NULL, &wsa_events) == 0) {
- if(ret && !pollrc && wsa_events.lNetworkEvents)
- retcode++;
- }
- WSAEventSelect(sockbunch[i], multi->wsa_event, 0);
- }
- else {
- /* break on entry not checked for being readable or writable */
- break;
+ multi_getsock(data, &ps);
+
+ for(i = 0; i < ps.num; i++) {
+ wsa_events.lNetworkEvents = 0;
+ if(WSAEnumNetworkEvents(ps.sockets[i], NULL,
+ &wsa_events) == 0) {
+ if(ret && !pollrc && wsa_events.lNetworkEvents)
+ retcode++;
}
+ WSAEventSelect(ps.sockets[i], multi->wsa_event, 0);
}
}
}
@@ -2021,8 +1983,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(dns) {
#ifdef CURLRES_ASYNCH
- data->state.async.dns = dns;
- data->state.async.done = TRUE;
+ conn->resolve_async.dns = dns;
+ conn->resolve_async.done = TRUE;
#endif
result = CURLE_OK;
infof(data, "Hostname '%s' was found in DNS cache", hostname);
@@ -2895,53 +2857,36 @@ CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
static CURLMcode singlesocket(struct Curl_multi *multi,
struct Curl_easy *data)
{
- curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
- int i;
+ struct easy_pollset cur_poll;
+ unsigned int i;
struct Curl_sh_entry *entry;
curl_socket_t s;
- int num;
- unsigned int curraction;
- unsigned char actions[MAX_SOCKSPEREASYHANDLE];
int rc;
- for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
- socks[i] = CURL_SOCKET_BAD;
-
/* Fill in the 'current' struct with the state as it is now: what sockets to
supervise and for what actions */
- curraction = multi_getsock(data, socks);
+ multi_getsock(data, &cur_poll);
/* We have 0 .. N sockets already and we get to know about the 0 .. M
sockets we should have from now on. Detect the differences, remove no
longer supervised ones and add new ones */
/* walk over the sockets we got right now */
- for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) &&
- (curraction & GETSOCK_MASK_RW(i));
- i++) {
- unsigned char action = CURL_POLL_NONE;
- unsigned char prevaction = 0;
+ for(i = 0; i < cur_poll.num; i++) {
+ unsigned char cur_action = cur_poll.actions[i];
+ unsigned char last_action = 0;
int comboaction;
- bool sincebefore = FALSE;
- s = socks[i];
+ s = cur_poll.sockets[i];
/* get it from the hash */
entry = sh_getentry(&multi->sockhash, s);
-
- if(curraction & GETSOCK_READSOCK(i))
- action |= CURL_POLL_IN;
- if(curraction & GETSOCK_WRITESOCK(i))
- action |= CURL_POLL_OUT;
-
- actions[i] = action;
if(entry) {
/* check if new for this transfer */
- int j;
- for(j = 0; j< data->numsocks; j++) {
- if(s == data->sockets[j]) {
- prevaction = data->actions[j];
- sincebefore = TRUE;
+ unsigned int j;
+ for(j = 0; j< data->last_poll.num; j++) {
+ if(s == data->last_poll.sockets[j]) {
+ last_action = data->last_poll.actions[j];
break;
}
}
@@ -2953,23 +2898,23 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
/* fatal */
return CURLM_OUT_OF_MEMORY;
}
- if(sincebefore && (prevaction != action)) {
+ if(last_action && (last_action != cur_action)) {
/* Socket was used already, but different action now */
- if(prevaction & CURL_POLL_IN)
+ if(last_action & CURL_POLL_IN)
entry->readers--;
- if(prevaction & CURL_POLL_OUT)
+ if(last_action & CURL_POLL_OUT)
entry->writers--;
- if(action & CURL_POLL_IN)
+ if(cur_action & CURL_POLL_IN)
entry->readers++;
- if(action & CURL_POLL_OUT)
+ if(cur_action & CURL_POLL_OUT)
entry->writers++;
}
- else if(!sincebefore) {
- /* a new user */
+ else if(!last_action) {
+ /* a new transfer using this socket */
entry->users++;
- if(action & CURL_POLL_IN)
+ if(cur_action & CURL_POLL_IN)
entry->readers++;
- if(action & CURL_POLL_OUT)
+ if(cur_action & CURL_POLL_OUT)
entry->writers++;
/* add 'data' to the transfer hash on this socket! */
@@ -2980,11 +2925,11 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
}
}
- comboaction = (entry->writers? CURL_POLL_OUT : 0) |
+ comboaction = (entry->writers ? CURL_POLL_OUT : 0) |
(entry->readers ? CURL_POLL_IN : 0);
/* socket existed before and has the same action set as before */
- if(sincebefore && ((int)entry->action == comboaction))
+ if(last_action && ((int)entry->action == comboaction))
/* same, continue */
continue;
@@ -2992,6 +2937,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
set_in_callback(multi, TRUE);
rc = multi->socket_cb(data, s, comboaction, multi->socket_userp,
entry->socketp);
+
set_in_callback(multi, FALSE);
if(rc == -1) {
multi->dead = TRUE;
@@ -3002,16 +2948,15 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
entry->action = comboaction; /* store the current action state */
}
- num = i; /* number of sockets */
-
- /* when we've walked over all the sockets we should have right now, we must
- make sure to detect sockets that are removed */
- for(i = 0; i< data->numsocks; i++) {
- int j;
+ /* Check for last_poll.sockets that no longer appear in cur_poll.sockets.
+ * Need to remove the easy handle from the multi->sockhash->transfers and
+ * remove multi->sockhash entry when this was the last transfer */
+ for(i = 0; i< data->last_poll.num; i++) {
+ unsigned int j;
bool stillused = FALSE;
- s = data->sockets[i];
- for(j = 0; j < num; j++) {
- if(s == socks[j]) {
+ s = data->last_poll.sockets[i];
+ for(j = 0; j < cur_poll.num; j++) {
+ if(s == cur_poll.sockets[j]) {
/* this is still supervised */
stillused = TRUE;
break;
@@ -3024,7 +2969,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
/* if this is NULL here, the socket has been closed and notified so
already by Curl_multi_closed() */
if(entry) {
- unsigned char oldactions = data->actions[i];
+ unsigned char oldactions = data->last_poll.actions[i];
/* this socket has been removed. Decrease user count */
entry->users--;
if(oldactions & CURL_POLL_OUT)
@@ -3052,11 +2997,10 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
}
}
}
- } /* for loop over numsocks */
+ } /* for loop over num */
- memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
- memcpy(data->actions, actions, num*sizeof(char));
- data->numsocks = num;
+ /* Remember for next time */
+ memcpy(&data->last_poll, &cur_poll, sizeof(data->last_poll));
return CURLM_OK;
}
@@ -3296,6 +3240,7 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
{
CURLMcode res = CURLM_OK;
va_list param;
+ unsigned long uarg;
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@@ -3328,7 +3273,9 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
multi->timer_userp = va_arg(param, void *);
break;
case CURLMOPT_MAXCONNECTS:
- multi->maxconnects = va_arg(param, long);
+ uarg = va_arg(param, unsigned long);
+ if(uarg <= UINT_MAX)
+ multi->maxconnects = (unsigned int)uarg;
break;
case CURLMOPT_MAX_HOST_CONNECTIONS:
multi->max_host_connections = va_arg(param, long);
@@ -3350,9 +3297,9 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
case CURLMOPT_MAX_CONCURRENT_STREAMS:
{
long streams = va_arg(param, long);
- if(streams < 1)
+ if((streams < 1) || (streams > INT_MAX))
streams = 100;
- multi->max_concurrent_streams = curlx_sltoui(streams);
+ multi->max_concurrent_streams = (unsigned int)streams;
}
break;
default:
@@ -3782,11 +3729,11 @@ struct Curl_easy **curl_multi_get_handles(struct Curl_multi *multi)
struct Curl_easy **a = malloc(sizeof(struct Curl_easy *) *
(multi->num_easy + 1));
if(a) {
- int i = 0;
+ unsigned int i = 0;
struct Curl_easy *e = multi->easyp;
while(e) {
DEBUGASSERT(i < multi->num_easy);
- if(!e->internal)
+ if(!e->state.internal)
a[i++] = e;
e = e->next;
}
diff --git a/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h
index 5b16bb6..e03e382 100644
--- a/Utilities/cmcurl/lib/multihandle.h
+++ b/Utilities/cmcurl/lib/multihandle.h
@@ -93,9 +93,9 @@ struct Curl_multi {
struct Curl_easy *easyp;
struct Curl_easy *easylp; /* last node */
- int num_easy; /* amount of entries in the linked list above. */
- int num_alive; /* amount of easy handles that are added but have not yet
- reached COMPLETE state */
+ unsigned int num_easy; /* amount of entries in the linked list above. */
+ unsigned int num_alive; /* amount of easy handles that are added but have
+ not yet reached COMPLETE state */
struct Curl_llist msglist; /* a list of messages from completed transfers */
@@ -136,9 +136,6 @@ struct Curl_multi {
/* Shared connection cache (bundles)*/
struct conncache conn_cache;
- long maxconnects; /* if >0, a fixed limit of the maximum number of entries
- we're allowed to grow the connection cache to */
-
long max_host_connections; /* if >0, a fixed limit of the maximum number
of connections per host */
@@ -150,8 +147,6 @@ struct Curl_multi {
void *timer_userp;
struct curltime timer_lastcall; /* the fixed time for the timeout for the
previous callback */
- unsigned int max_concurrent_streams;
-
#ifdef USE_WINSOCK
WSAEVENT wsa_event; /* winsock event used for waits */
#else
@@ -160,6 +155,10 @@ struct Curl_multi {
0 is used for read, 1 is used for write */
#endif
#endif
+ unsigned int max_concurrent_streams;
+ unsigned int maxconnects; /* if >0, a fixed limit of the maximum number of
+ entries we're allowed to grow the connection
+ cache to */
#define IPV6_UNKNOWN 0
#define IPV6_DEAD 1
#define IPV6_WORKS 2
diff --git a/Utilities/cmcurl/lib/netrc.c b/Utilities/cmcurl/lib/netrc.c
index e6a09b1..038c6dc 100644
--- a/Utilities/cmcurl/lib/netrc.c
+++ b/Utilities/cmcurl/lib/netrc.c
@@ -327,7 +327,7 @@ int Curl_parsenetrc(const char *host, char **loginp, char **passwordp,
}
retcode = parsenetrc(host, loginp, passwordp, filealloc);
free(filealloc);
-#ifdef WIN32
+#ifdef _WIN32
if(retcode == NETRC_FILE_MISSING) {
/* fallback to the old-style "_netrc" file */
filealloc = curl_maprintf("%s%s_netrc", home, DIR_CHAR);
diff --git a/Utilities/cmcurl/lib/openldap.c b/Utilities/cmcurl/lib/openldap.c
index 3aff306..131f474 100644
--- a/Utilities/cmcurl/lib/openldap.c
+++ b/Utilities/cmcurl/lib/openldap.c
@@ -319,31 +319,12 @@ static CURLcode oldap_setup_connection(struct Curl_easy *data,
{
CURLcode result;
LDAPURLDesc *lud;
- struct ldapconninfo *li;
+ (void)conn;
/* Early URL syntax check. */
result = oldap_url_parse(data, &lud);
ldap_free_urldesc(lud);
- if(!result) {
- li = calloc(1, sizeof(struct ldapconninfo));
- if(!li)
- result = CURLE_OUT_OF_MEMORY;
- else {
- li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme);
- conn->proto.ldapc = li;
- connkeep(conn, "OpenLDAP default");
-
- /* Initialize the SASL storage */
- Curl_sasl_init(&li->sasl, data, &saslldap);
-
- /* Clear the TLS upgraded flag */
- conn->bits.tls_upgraded = FALSE;
-
- result = oldap_parse_login_options(conn);
- }
- }
-
return result;
}
@@ -537,7 +518,7 @@ static CURLcode oldap_perform_starttls(struct Curl_easy *data)
static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
- struct ldapconninfo *li = conn->proto.ldapc;
+ struct ldapconninfo *li;
static const int version = LDAP_VERSION3;
int rc;
char *hosturl;
@@ -547,6 +528,26 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
(void)done;
+ DEBUGASSERT(!conn->proto.ldapc);
+ li = calloc(1, sizeof(struct ldapconninfo));
+ if(!li)
+ return CURLE_OUT_OF_MEMORY;
+ else {
+ CURLcode result;
+ li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme);
+ conn->proto.ldapc = li;
+
+ /* Initialize the SASL storage */
+ Curl_sasl_init(&li->sasl, data, &saslldap);
+
+ /* Clear the TLS upgraded flag */
+ conn->bits.tls_upgraded = FALSE;
+
+ result = oldap_parse_login_options(conn);
+ if(result)
+ return result;
+ }
+
hosturl = aprintf("ldap%s://%s:%d",
conn->handler->flags & PROTOPT_SSL? "s": "",
conn->host.name, conn->remote_port);
@@ -886,6 +887,11 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done)
result = oldap_url_parse(data, &lud);
if(!result) {
+ Sockbuf *sb;
+ /* re-install the libcurl SSL handlers into the sockbuf. */
+ ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
+ ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
+
rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope,
lud->lud_filter, lud->lud_attrs, 0,
NULL, NULL, NULL, 0, &msgid);
@@ -947,18 +953,12 @@ static CURLcode client_write(struct Curl_easy *data,
if(!len && plen && prefix[plen - 1] == ' ')
plen--;
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) prefix, plen);
- if(!result)
- data->req.bytecount += plen;
}
if(!result && value) {
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) value, len);
- if(!result)
- data->req.bytecount += len;
}
if(!result && suffix) {
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) suffix, slen);
- if(!result)
- data->req.bytecount += slen;
}
return result;
}
diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c
index a9d5fdd6..3e0f20a 100644
--- a/Utilities/cmcurl/lib/pop3.c
+++ b/Utilities/cmcurl/lib/pop3.c
@@ -1088,7 +1088,7 @@ static CURLcode pop3_init(struct Curl_easy *data)
CURLcode result = CURLE_OK;
struct POP3 *pop3;
- pop3 = data->req.p.pop3 = calloc(sizeof(struct POP3), 1);
+ pop3 = data->req.p.pop3 = calloc(1, sizeof(struct POP3));
if(!pop3)
result = CURLE_OUT_OF_MEMORY;
diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c
index e783a9c..e96cbf7 100644
--- a/Utilities/cmcurl/lib/progress.c
+++ b/Utilities/cmcurl/lib/progress.c
@@ -304,7 +304,7 @@ timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
* 'actual' is the time in milliseconds it took to actually download the
* last 'size' bytes.
*/
- actual = Curl_timediff(now, start);
+ actual = Curl_timediff_ceil(now, start);
if(actual < minimum) {
/* if it downloaded the data faster than the limit, make it wait the
difference */
@@ -319,12 +319,6 @@ timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
*/
CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
{
- if(data->set.max_filesize && (size > data->set.max_filesize)) {
- failf(data, "Exceeded the maximum allowed file size "
- "(%" CURL_FORMAT_CURL_OFF_T ")",
- data->set.max_filesize);
- return CURLE_FILESIZE_EXCEEDED;
- }
data->progress.downloaded = size;
return CURLE_OK;
}
diff --git a/Utilities/cmcurl/lib/rand.c b/Utilities/cmcurl/lib/rand.c
index 6bd9613..3383c49 100644
--- a/Utilities/cmcurl/lib/rand.c
+++ b/Utilities/cmcurl/lib/rand.c
@@ -32,10 +32,6 @@
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
-#ifdef HAVE_ARC4RANDOM
-/* Some platforms might have the prototype missing (ubuntu + libressl) */
-uint32_t arc4random(void);
-#endif
#include <curl/curl.h>
#include "urldata.h"
@@ -50,7 +46,7 @@ uint32_t arc4random(void);
#include "curl_memory.h"
#include "memdebug.h"
-#ifdef WIN32
+#ifdef _WIN32
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
# define HAVE_WIN_BCRYPTGENRANDOM
@@ -105,7 +101,6 @@ CURLcode Curl_win32_random(unsigned char *entropy, size_t length)
static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
{
- unsigned int r;
CURLcode result = CURLE_OK;
static unsigned int randseed;
static bool seeded = FALSE;
@@ -138,7 +133,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
/* ---- non-cryptographic version following ---- */
-#ifdef WIN32
+#ifdef _WIN32
if(!seeded) {
result = Curl_win32_random((unsigned char *)rnd, sizeof(*rnd));
if(result != CURLE_NOT_BUILT_IN)
@@ -146,12 +141,14 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
}
#endif
-#ifdef HAVE_ARC4RANDOM
- *rnd = (unsigned int)arc4random();
- return CURLE_OK;
+#if defined(HAVE_ARC4RANDOM) && !defined(USE_OPENSSL)
+ if(!seeded) {
+ *rnd = (unsigned int)arc4random();
+ return CURLE_OK;
+ }
#endif
-#if defined(RANDOM_FILE) && !defined(WIN32)
+#if defined(RANDOM_FILE) && !defined(_WIN32)
if(!seeded) {
/* if there's a random file to read a seed from, use it */
int fd = open(RANDOM_FILE, O_RDONLY);
@@ -175,9 +172,12 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
seeded = TRUE;
}
- /* Return an unsigned 32-bit pseudo-random number. */
- r = randseed = randseed * 1103515245 + 12345;
- *rnd = (r << 16) | ((r >> 16) & 0xFFFF);
+ {
+ unsigned int r;
+ /* Return an unsigned 32-bit pseudo-random number. */
+ r = randseed = randseed * 1103515245 + 12345;
+ *rnd = (r << 16) | ((r >> 16) & 0xFFFF);
+ }
return CURLE_OK;
}
diff --git a/Utilities/cmcurl/lib/rand.h b/Utilities/cmcurl/lib/rand.h
index 1d009f5..bc05239 100644
--- a/Utilities/cmcurl/lib/rand.h
+++ b/Utilities/cmcurl/lib/rand.h
@@ -41,7 +41,7 @@ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd,
size_t num);
-#ifdef WIN32
+#ifdef _WIN32
/* Random generator shared between the Schannel vtls and Curl_rand*()
functions */
CURLcode Curl_win32_random(unsigned char *entropy, size_t length);
diff --git a/Utilities/cmcurl/lib/rename.c b/Utilities/cmcurl/lib/rename.c
index 97a66e9..4c88698 100644
--- a/Utilities/cmcurl/lib/rename.c
+++ b/Utilities/cmcurl/lib/rename.c
@@ -40,7 +40,7 @@
/* return 0 on success, 1 on error */
int Curl_rename(const char *oldpath, const char *newpath)
{
-#ifdef WIN32
+#ifdef _WIN32
/* rename() on Windows doesn't overwrite, so we can't use it here.
MoveFileEx() will overwrite and is usually atomic, however it fails
when there are open handles to the file. */
diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c
index ccd7264..e673bb8 100644
--- a/Utilities/cmcurl/lib/rtsp.c
+++ b/Utilities/cmcurl/lib/rtsp.c
@@ -45,8 +45,8 @@
#include "curl_memory.h"
#include "memdebug.h"
-#define RTP_PKT_LENGTH(p) ((((int)((unsigned char)((p)[2]))) << 8) | \
- ((int)((unsigned char)((p)[3]))))
+#define RTP_PKT_LENGTH(p) ((((unsigned int)((unsigned char)((p)[2]))) << 8) | \
+ ((unsigned int)((unsigned char)((p)[3]))))
/* protocol-specific functions set up to be called by the main engine */
static CURLcode rtsp_do(struct Curl_easy *data, bool *done);
@@ -59,14 +59,19 @@ static int rtsp_getsock_do(struct Curl_easy *data,
/*
* Parse and write out any available RTP data.
- *
- * nread: amount of data left after k->str. will be modified if RTP
- * data is parsed and k->str is moved up
- * readmore: whether or not the RTP parser needs more data right away
+ * @param data the transfer
+ * @param conn the connection
+ * @param buf data read from connection
+ * @param blen amount of data in buf
+ * @param consumed out, number of blen consumed
+ * @param readmore out, TRUE iff complete buf was consumed and more data
+ * is needed
*/
static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
struct connectdata *conn,
- ssize_t *nread,
+ const char *buf,
+ size_t blen,
+ size_t *pconsumed,
bool *readmore);
static CURLcode rtsp_setup_connection(struct Curl_easy *data,
@@ -88,7 +93,7 @@ static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
}
static
-CURLcode rtp_client_write(struct Curl_easy *data, char *ptr, size_t len);
+CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len);
static
CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport);
@@ -585,153 +590,249 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
return result;
}
-
-static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
- struct connectdata *conn,
- ssize_t *nread,
- bool *readmore) {
- struct SingleRequest *k = &data->req;
+static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
+ struct connectdata *conn,
+ const char *buf,
+ size_t blen,
+ bool in_body,
+ size_t *pconsumed)
+{
struct rtsp_conn *rtspc = &(conn->proto.rtspc);
- unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;
+ CURLcode result = CURLE_OK;
- char *rtp; /* moving pointer to rtp data */
- ssize_t rtp_dataleft; /* how much data left to parse in this round */
- CURLcode result;
- bool interleaved = false;
- size_t skip_size = 0;
+ *pconsumed = 0;
+ while(blen) {
+ switch(rtspc->state) {
- if(Curl_dyn_len(&rtspc->buf)) {
- /* There was some leftover data the last time. Append new buffers */
- if(Curl_dyn_addn(&rtspc->buf, k->str, *nread))
- return CURLE_OUT_OF_MEMORY;
- rtp = Curl_dyn_ptr(&rtspc->buf);
- rtp_dataleft = Curl_dyn_len(&rtspc->buf);
- }
- else {
- /* Just parse the request buffer directly */
- rtp = k->str;
- rtp_dataleft = *nread;
- }
-
- while(rtp_dataleft > 0) {
- if(rtp[0] == '$') {
- if(rtp_dataleft > 4) {
- unsigned char rtp_channel;
- int rtp_length;
- int idx;
- int off;
-
- /* Parse the header */
- /* The channel identifier immediately follows and is 1 byte */
- rtp_channel = (unsigned char)rtp[1];
- idx = rtp_channel / 8;
- off = rtp_channel % 8;
- if(!(rtp_channel_mask[idx] & (1 << off))) {
- /* invalid channel number, maybe not an RTP packet */
- rtp++;
- rtp_dataleft--;
- skip_size++;
- continue;
+ case RTP_PARSE_SKIP: {
+ DEBUGASSERT(Curl_dyn_len(&rtspc->buf) == 0);
+ if(in_body && buf[0] != '$') {
+ /* in BODY and no valid start, do not consume and return */
+ goto out;
+ }
+ while(blen && buf[0] != '$') {
+ if(!in_body && buf[0] == 'R' &&
+ data->set.rtspreq != RTSPREQ_RECEIVE) {
+ if(strncmp(buf, "RTSP/", (blen < 5) ? blen : 5) == 0) {
+ /* This could be the next response, no consume and return */
+ if(*pconsumed) {
+ DEBUGF(infof(data, "RTP rtsp_filter_rtp[SKIP] RTSP/ prefix, "
+ "skipping %zd bytes of junk", *pconsumed));
+ }
+ rtspc->state = RTP_PARSE_SKIP;
+ rtspc->in_header = TRUE;
+ goto out;
+ }
}
- if(skip_size > 0) {
- DEBUGF(infof(data, "Skip the malformed interleaved data %lu "
- "bytes", skip_size));
+ /* junk, consume without buffering */
+ *pconsumed += 1;
+ ++buf;
+ --blen;
+ }
+ if(blen && buf[0] == '$') {
+ /* possible start of an RTP message, buffer */
+ if(Curl_dyn_addn(&rtspc->buf, buf, 1)) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
- skip_size = 0;
- rtspc->rtp_channel = rtp_channel;
-
- /* The length is two bytes */
- rtp_length = RTP_PKT_LENGTH(rtp);
+ *pconsumed += 1;
+ ++buf;
+ --blen;
+ rtspc->state = RTP_PARSE_CHANNEL;
+ }
+ break;
+ }
- if(rtp_dataleft < rtp_length + 4) {
- /* Need more - incomplete payload */
- *readmore = TRUE;
- break;
+ case RTP_PARSE_CHANNEL: {
+ int idx = ((unsigned char)buf[0]) / 8;
+ int off = ((unsigned char)buf[0]) % 8;
+ DEBUGASSERT(Curl_dyn_len(&rtspc->buf) == 1);
+ if(!(data->state.rtp_channel_mask[idx] & (1 << off))) {
+ /* invalid channel number, junk or BODY data */
+ rtspc->state = RTP_PARSE_SKIP;
+ if(in_body) {
+ /* we do not consume this byte, it is BODY data */
+ DEBUGF(infof(data, "RTSP: invalid RTP channel %d in BODY, "
+ "treating as BODY data", idx));
+ if(*pconsumed == 0) {
+ /* We did not consume the initial '$' in our buffer, but had
+ * it from an earlier call. We cannot un-consume it and have
+ * to write it directly as BODY data */
+ result = Curl_client_write(data, CLIENTWRITE_BODY,
+ Curl_dyn_ptr(&rtspc->buf), 1);
+ Curl_dyn_free(&rtspc->buf);
+ if(result)
+ goto out;
+ }
+ else {
+ /* un-consume the '$' and leave */
+ Curl_dyn_free(&rtspc->buf);
+ *pconsumed -= 1;
+ --buf;
+ ++blen;
+ goto out;
+ }
}
- interleaved = true;
- /* We have the full RTP interleaved packet
- * Write out the header including the leading '$' */
- DEBUGF(infof(data, "RTP write channel %d rtp_length %d",
- rtspc->rtp_channel, rtp_length));
- result = rtp_client_write(data, &rtp[0], rtp_length + 4);
- if(result) {
- *readmore = FALSE;
- return result;
+ else {
+ /* not BODY, forget the junk '$'. Do not consume this byte,
+ * it might be a start */
+ infof(data, "RTSP: invalid RTP channel %d, skipping", idx);
+ Curl_dyn_free(&rtspc->buf);
}
+ break;
+ }
+ /* a valid channel, so we expect this to be a real RTP message */
+ rtspc->rtp_channel = (unsigned char)buf[0];
+ if(Curl_dyn_addn(&rtspc->buf, buf, 1)) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ *pconsumed += 1;
+ ++buf;
+ --blen;
+ rtspc->state = RTP_PARSE_LEN;
+ break;
+ }
- /* Move forward in the buffer */
- rtp_dataleft -= rtp_length + 4;
- rtp += rtp_length + 4;
+ case RTP_PARSE_LEN: {
+ size_t rtp_len = Curl_dyn_len(&rtspc->buf);
+ const char *rtp_buf;
+ DEBUGASSERT(rtp_len >= 2 && rtp_len < 4);
+ if(Curl_dyn_addn(&rtspc->buf, buf, 1)) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ *pconsumed += 1;
+ ++buf;
+ --blen;
+ if(rtp_len == 2)
+ break;
+ rtp_buf = Curl_dyn_ptr(&rtspc->buf);
+ rtspc->rtp_len = RTP_PKT_LENGTH(rtp_buf) + 4;
+ rtspc->state = RTP_PARSE_DATA;
+ break;
+ }
- if(data->set.rtspreq == RTSPREQ_RECEIVE) {
- /* If we are in a passive receive, give control back
- * to the app as often as we can.
- */
- k->keepon &= ~KEEP_RECV;
+ case RTP_PARSE_DATA: {
+ size_t rtp_len = Curl_dyn_len(&rtspc->buf);
+ size_t needed;
+ DEBUGASSERT(rtp_len < rtspc->rtp_len);
+ needed = rtspc->rtp_len - rtp_len;
+ if(needed <= blen) {
+ if(Curl_dyn_addn(&rtspc->buf, buf, needed)) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
+ *pconsumed += needed;
+ buf += needed;
+ blen -= needed;
+ /* complete RTP message in buffer */
+ DEBUGF(infof(data, "RTP write channel %d rtp_len %zu",
+ rtspc->rtp_channel, rtspc->rtp_len));
+ result = rtp_client_write(data, Curl_dyn_ptr(&rtspc->buf),
+ rtspc->rtp_len);
+ Curl_dyn_free(&rtspc->buf);
+ rtspc->state = RTP_PARSE_SKIP;
+ if(result)
+ goto out;
}
else {
- /* Need more - incomplete header */
- *readmore = TRUE;
- break;
- }
- }
- else {
- /* If the following data begins with 'RTSP/', which might be an RTSP
- message, we should stop skipping the data. */
- /* If `k-> headerline> 0 && !interleaved` is true, we are maybe in the
- middle of an RTSP message. It is difficult to determine this, so we
- stop skipping. */
- size_t prefix_len = (rtp_dataleft < 5) ? rtp_dataleft : 5;
- if((k->headerline > 0 && !interleaved) ||
- strncmp(rtp, "RTSP/", prefix_len) == 0) {
- if(skip_size > 0) {
- DEBUGF(infof(data, "Skip the malformed interleaved data %lu "
- "bytes", skip_size));
+ if(Curl_dyn_addn(&rtspc->buf, buf, blen)) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
- break; /* maybe is an RTSP message */
+ *pconsumed += blen;
+ buf += blen;
+ blen = 0;
}
- /* Skip incorrect data util the next RTP packet or RTSP message */
- do {
- rtp++;
- rtp_dataleft--;
- skip_size++;
- } while(rtp_dataleft > 0 && rtp[0] != '$' && rtp[0] != 'R');
+ break;
+ }
+
+ default:
+ DEBUGASSERT(0);
+ return CURLE_RECV_ERROR;
}
}
+out:
+ return result;
+}
+
+static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
+ struct connectdata *conn,
+ const char *buf,
+ size_t blen,
+ size_t *pconsumed,
+ bool *readmore)
+{
+ struct rtsp_conn *rtspc = &(conn->proto.rtspc);
+ CURLcode result = CURLE_OK;
+ size_t consumed = 0;
+ bool in_body;
- if(rtp_dataleft && rtp[0] == '$') {
- DEBUGF(infof(data, "RTP Rewinding %zd %s", rtp_dataleft,
- *readmore ? "(READMORE)" : ""));
+ if(!data->req.header)
+ rtspc->in_header = FALSE;
+ in_body = (data->req.headerline && !rtspc->in_header) &&
+ (data->req.size >= 0) &&
+ (data->req.bytecount < data->req.size);
- /* Store the incomplete RTP packet for a "rewind" */
- if(!Curl_dyn_len(&rtspc->buf)) {
- /* nothing was stored, add this data */
- if(Curl_dyn_addn(&rtspc->buf, rtp, rtp_dataleft))
- return CURLE_OUT_OF_MEMORY;
- }
- else {
- /* keep the remainder */
- Curl_dyn_tail(&rtspc->buf, rtp_dataleft);
- }
+ *readmore = FALSE;
+ *pconsumed = 0;
+ if(!blen) {
+ goto out;
+ }
- /* As far as the transfer is concerned, this data is consumed */
- *nread = 0;
- return CURLE_OK;
+ /* If header parsing is not onging, extract RTP messages */
+ if(!rtspc->in_header) {
+ result = rtsp_filter_rtp(data, conn, buf, blen, in_body, &consumed);
+ if(result)
+ goto out;
+ *pconsumed += consumed;
+ buf += consumed;
+ blen -= consumed;
}
- /* Fix up k->str to point just after the last RTP packet */
- k->str += *nread - rtp_dataleft;
- *nread = rtp_dataleft;
+ /* we want to parse headers, do so */
+ if(data->req.header && blen) {
+ rtspc->in_header = TRUE;
+ result = Curl_http_readwrite_headers(data, conn, buf, blen,
+ &consumed);
+ if(result)
+ goto out;
+
+ *pconsumed += consumed;
+ buf += consumed;
+ blen -= consumed;
+
+ if(!data->req.header)
+ rtspc->in_header = FALSE;
+
+ if(!rtspc->in_header) {
+ /* If header parsing is done and data left, extract RTP messages */
+ in_body = (data->req.headerline && !rtspc->in_header) &&
+ (data->req.size >= 0) &&
+ (data->req.bytecount < data->req.size);
+ result = rtsp_filter_rtp(data, conn, buf, blen, in_body, &consumed);
+ if(result)
+ goto out;
+ *pconsumed += consumed;
+ }
+ }
- /* If we get here, we have finished with the leftover/merge buffer */
- Curl_dyn_free(&rtspc->buf);
+ if(rtspc->state != RTP_PARSE_SKIP)
+ *readmore = TRUE;
- return CURLE_OK;
+out:
+ if(!*readmore && data->set.rtspreq == RTSPREQ_RECEIVE) {
+ /* In special mode RECEIVE, we just process one chunk of network
+ * data, so we stop the transfer here, if we have no incomplete
+ * RTP message pending. */
+ data->req.keepon &= ~KEEP_RECV;
+ }
+ return result;
}
static
-CURLcode rtp_client_write(struct Curl_easy *data, char *ptr, size_t len)
+CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len)
{
size_t wrote;
curl_write_callback writeit;
@@ -756,7 +857,7 @@ CURLcode rtp_client_write(struct Curl_easy *data, char *ptr, size_t len)
}
Curl_set_in_callback(data, true);
- wrote = writeit(ptr, 1, len, user_ptr);
+ wrote = writeit((char *)ptr, 1, len, user_ptr);
Curl_set_in_callback(data, false);
if(CURL_WRITEFUNC_PAUSE == wrote) {
diff --git a/Utilities/cmcurl/lib/rtsp.h b/Utilities/cmcurl/lib/rtsp.h
index 111bac2..237b80f 100644
--- a/Utilities/cmcurl/lib/rtsp.h
+++ b/Utilities/cmcurl/lib/rtsp.h
@@ -39,6 +39,12 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header);
#endif /* CURL_DISABLE_RTSP */
+typedef enum {
+ RTP_PARSE_SKIP,
+ RTP_PARSE_CHANNEL,
+ RTP_PARSE_LEN,
+ RTP_PARSE_DATA
+} rtp_parse_st;
/*
* RTSP Connection data
*
@@ -47,6 +53,9 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header);
struct rtsp_conn {
struct dynbuf buf;
int rtp_channel;
+ size_t rtp_len;
+ rtp_parse_st state;
+ BIT(in_header);
};
/****************************************************************************
diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c
index cae9beb..d92e745 100644
--- a/Utilities/cmcurl/lib/select.c
+++ b/Utilities/cmcurl/lib/select.c
@@ -76,7 +76,7 @@ int Curl_wait_ms(timediff_t timeout_ms)
}
#if defined(MSDOS)
delay(timeout_ms);
-#elif defined(WIN32)
+#elif defined(_WIN32)
/* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */
#if TIMEDIFF_T_MAX >= ULONG_MAX
if(timeout_ms >= ULONG_MAX)
diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c
index 0482c5d..a2fac0c 100644
--- a/Utilities/cmcurl/lib/sendf.c
+++ b/Utilities/cmcurl/lib/sendf.c
@@ -50,6 +50,7 @@
#include "strdup.h"
#include "http2.h"
#include "headers.h"
+#include "progress.h"
#include "ws.h"
/* The last 3 #include files should be in this order */
@@ -57,6 +58,9 @@
#include "curl_memory.h"
#include "memdebug.h"
+
+static CURLcode do_init_stack(struct Curl_easy *data);
+
#if defined(CURL_DO_LINEEND_CONV) && !defined(CURL_DISABLE_FTP)
/*
* convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
@@ -385,17 +389,17 @@ static CURLcode chop_write(struct Curl_easy *data,
the future to leave the original data alone.
*/
CURLcode Curl_client_write(struct Curl_easy *data,
- int type,
- char *ptr,
- size_t len)
+ int type, char *buf, size_t blen)
{
+ CURLcode result;
+
#if !defined(CURL_DISABLE_FTP) && defined(CURL_DO_LINEEND_CONV)
/* FTP data may need conversion. */
if((type & CLIENTWRITE_BODY) &&
(data->conn->handler->protocol & PROTO_FAMILY_FTP) &&
data->conn->proto.ftpc.transfertype == 'A') {
/* convert end-of-line markers */
- len = convert_lineends(data, ptr, len);
+ blen = convert_lineends(data, buf, blen);
}
#endif
/* it is one of those, at least */
@@ -405,14 +409,14 @@ CURLcode Curl_client_write(struct Curl_easy *data,
/* INFO is only INFO */
DEBUGASSERT(!(type & CLIENTWRITE_INFO) || (type == CLIENTWRITE_INFO));
- if(type == CLIENTWRITE_BODY) {
- if(data->req.ignorebody)
- return CURLE_OK;
-
- if(data->req.writer_stack && !data->set.http_ce_skip)
- return Curl_unencode_write(data, data->req.writer_stack, ptr, len);
+ if(!data->req.writer_stack) {
+ result = do_init_stack(data);
+ if(result)
+ return result;
+ DEBUGASSERT(data->req.writer_stack);
}
- return chop_write(data, type, FALSE, ptr, len);
+
+ return Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
}
CURLcode Curl_client_unpause(struct Curl_easy *data)
@@ -449,12 +453,12 @@ CURLcode Curl_client_unpause(struct Curl_easy *data)
void Curl_client_cleanup(struct Curl_easy *data)
{
- struct contenc_writer *writer = data->req.writer_stack;
+ struct Curl_cwriter *writer = data->req.writer_stack;
size_t i;
while(writer) {
- data->req.writer_stack = writer->downstream;
- writer->handler->close_writer(data, writer);
+ data->req.writer_stack = writer->next;
+ writer->cwt->do_close(data, writer);
free(writer);
writer = data->req.writer_stack;
}
@@ -463,61 +467,222 @@ void Curl_client_cleanup(struct Curl_easy *data)
Curl_dyn_free(&data->state.tempwrite[i].b);
}
data->state.tempcount = 0;
+ data->req.bytecount = 0;
+ data->req.headerline = 0;
+}
+/* Write data using an unencoding writer stack. "nbytes" is not
+ allowed to be 0. */
+CURLcode Curl_cwriter_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
+ const char *buf, size_t nbytes)
+{
+ if(!nbytes)
+ return CURLE_OK;
+ if(!writer)
+ return CURLE_WRITE_ERROR;
+ return writer->cwt->do_write(data, writer, type, buf, nbytes);
}
-/* Real client writer: no downstream. */
-static CURLcode client_cew_init(struct Curl_easy *data,
- struct contenc_writer *writer)
+CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
- (void) data;
+ (void)data;
(void)writer;
return CURLE_OK;
}
-static CURLcode client_cew_write(struct Curl_easy *data,
- struct contenc_writer *writer,
- const char *buf, size_t nbytes)
+CURLcode Curl_cwriter_def_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
+ const char *buf, size_t nbytes)
{
- (void)writer;
- if(!nbytes || data->req.ignorebody)
- return CURLE_OK;
- return chop_write(data, CLIENTWRITE_BODY, FALSE, (char *)buf, nbytes);
+ return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
}
-static void client_cew_close(struct Curl_easy *data,
- struct contenc_writer *writer)
+void Curl_cwriter_def_close(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
(void) data;
(void) writer;
}
-static const struct content_encoding client_cew = {
+/* Real client writer to installed callbacks. */
+static CURLcode cw_client_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
+ const char *buf, size_t nbytes)
+{
+ (void)writer;
+ if(!nbytes)
+ return CURLE_OK;
+ return chop_write(data, type, FALSE, (char *)buf, nbytes);
+}
+
+static const struct Curl_cwtype cw_client = {
+ "client",
NULL,
+ Curl_cwriter_def_init,
+ cw_client_write,
+ Curl_cwriter_def_close,
+ sizeof(struct Curl_cwriter)
+};
+
+static size_t get_max_body_write_len(struct Curl_easy *data, curl_off_t limit)
+{
+ if(limit != -1) {
+ /* How much more are we allowed to write? */
+ curl_off_t remain_diff;
+ remain_diff = limit - data->req.bytecount;
+ if(remain_diff < 0) {
+ /* already written too much! */
+ return 0;
+ }
+#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
+ else if(remain_diff > SSIZE_T_MAX) {
+ return SIZE_T_MAX;
+ }
+#endif
+ else {
+ return (size_t)remain_diff;
+ }
+ }
+ return SIZE_T_MAX;
+}
+
+/* Download client writer in phase CURL_CW_PROTOCOL that
+ * sees the "real" download body data. */
+static CURLcode cw_download_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
+ const char *buf, size_t nbytes)
+{
+ CURLcode result;
+ size_t nwrite, excess_len = 0;
+ const char *excess_data = NULL;
+
+ if(!(type & CLIENTWRITE_BODY)) {
+ if((type & CLIENTWRITE_CONNECT) && data->set.suppress_connect_headers)
+ return CURLE_OK;
+ return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+ }
+
+ nwrite = nbytes;
+ if(-1 != data->req.maxdownload) {
+ size_t wmax = get_max_body_write_len(data, data->req.maxdownload);
+ if(nwrite > wmax) {
+ excess_len = nbytes - wmax;
+ nwrite = wmax;
+ excess_data = buf + nwrite;
+ }
+
+ if(nwrite == wmax) {
+ data->req.download_done = TRUE;
+ }
+ }
+
+ if(data->set.max_filesize) {
+ size_t wmax = get_max_body_write_len(data, data->set.max_filesize);
+ if(nwrite > wmax) {
+ nwrite = wmax;
+ }
+ }
+
+ data->req.bytecount += nwrite;
+ ++data->req.bodywrites;
+ if(!data->req.ignorebody && nwrite) {
+ result = Curl_cwriter_write(data, writer->next, type, buf, nwrite);
+ if(result)
+ return result;
+ }
+ result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
+ if(result)
+ return result;
+
+ if(excess_len) {
+ if(data->conn->handler->readwrite) {
+ /* RTSP hack moved from transfer loop to here */
+ bool readmore = FALSE; /* indicates data is incomplete, need more */
+ size_t consumed = 0;
+ result = data->conn->handler->readwrite(data, data->conn,
+ excess_data, excess_len,
+ &consumed, &readmore);
+ if(result)
+ return result;
+ DEBUGASSERT(consumed <= excess_len);
+ excess_len -= consumed;
+ if(readmore) {
+ data->req.download_done = FALSE;
+ data->req.keepon |= KEEP_RECV; /* we're not done reading */
+ }
+ }
+ if(excess_len && !data->req.ignorebody) {
+ infof(data,
+ "Excess found writing body:"
+ " excess = %zu"
+ ", size = %" CURL_FORMAT_CURL_OFF_T
+ ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
+ ", bytecount = %" CURL_FORMAT_CURL_OFF_T,
+ excess_len, data->req.size, data->req.maxdownload,
+ data->req.bytecount);
+ connclose(data->conn, "excess found in a read");
+ }
+ }
+ else if(nwrite < nbytes) {
+ failf(data, "Exceeded the maximum allowed file size "
+ "(%" CURL_FORMAT_CURL_OFF_T ") with %"
+ CURL_FORMAT_CURL_OFF_T " bytes",
+ data->set.max_filesize, data->req.bytecount);
+ return CURLE_FILESIZE_EXCEEDED;
+ }
+
+ return CURLE_OK;
+}
+
+static const struct Curl_cwtype cw_download = {
+ "download",
NULL,
- client_cew_init,
- client_cew_write,
- client_cew_close,
- sizeof(struct contenc_writer)
+ Curl_cwriter_def_init,
+ cw_download_write,
+ Curl_cwriter_def_close,
+ sizeof(struct Curl_cwriter)
+};
+
+/* RAW client writer in phase CURL_CW_RAW that
+ * enabled tracing of raw data. */
+static CURLcode cw_raw_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
+ const char *buf, size_t nbytes)
+{
+ if(type & CLIENTWRITE_BODY && data->set.verbose && !data->req.ignorebody) {
+ Curl_debug(data, CURLINFO_DATA_IN, (char *)buf, nbytes);
+ }
+ return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+}
+
+static const struct Curl_cwtype cw_raw = {
+ "raw",
+ NULL,
+ Curl_cwriter_def_init,
+ cw_raw_write,
+ Curl_cwriter_def_close,
+ sizeof(struct Curl_cwriter)
};
/* Create an unencoding writer stage using the given handler. */
-CURLcode Curl_client_create_writer(struct contenc_writer **pwriter,
+CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
struct Curl_easy *data,
- const struct content_encoding *ce_handler,
- int order)
+ const struct Curl_cwtype *cwt,
+ Curl_cwriter_phase phase)
{
- struct contenc_writer *writer;
+ struct Curl_cwriter *writer;
CURLcode result = CURLE_OUT_OF_MEMORY;
- DEBUGASSERT(ce_handler->writersize >= sizeof(struct contenc_writer));
- writer = (struct contenc_writer *) calloc(1, ce_handler->writersize);
+ DEBUGASSERT(cwt->cwriter_size >= sizeof(struct Curl_cwriter));
+ writer = (struct Curl_cwriter *) calloc(1, cwt->cwriter_size);
if(!writer)
goto out;
- writer->handler = ce_handler;
- writer->order = order;
- result = ce_handler->init_writer(data, writer);
+ writer->cwt = cwt;
+ writer->phase = phase;
+ result = cwt->do_init(data, writer);
out:
*pwriter = result? NULL : writer;
@@ -526,55 +691,74 @@ out:
return result;
}
-void Curl_client_free_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
+void Curl_cwriter_free(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
if(writer) {
- writer->handler->close_writer(data, writer);
+ writer->cwt->do_close(data, writer);
free(writer);
}
}
-/* allow no more than 5 "chained" compression steps */
-#define MAX_ENCODE_STACK 5
+size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase)
+{
+ struct Curl_cwriter *w;
+ size_t n = 0;
+ for(w = data->req.writer_stack; w; w = w->next) {
+ if(w->phase == phase)
+ ++n;
+ }
+ return n;
+}
-static CURLcode init_writer_stack(struct Curl_easy *data)
+static CURLcode do_init_stack(struct Curl_easy *data)
{
+ struct Curl_cwriter *writer;
+ CURLcode result;
+
DEBUGASSERT(!data->req.writer_stack);
- return Curl_client_create_writer(&data->req.writer_stack,
- data, &client_cew, 0);
+ result = Curl_cwriter_create(&data->req.writer_stack,
+ data, &cw_client, CURL_CW_CLIENT);
+ if(result)
+ return result;
+
+ result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
+ if(result)
+ return result;
+ result = Curl_cwriter_add(data, writer);
+ if(result) {
+ Curl_cwriter_free(data, writer);
+ }
+
+ result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
+ if(result)
+ return result;
+ result = Curl_cwriter_add(data, writer);
+ if(result) {
+ Curl_cwriter_free(data, writer);
+ }
+ return result;
}
-CURLcode Curl_client_add_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
+CURLcode Curl_cwriter_add(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
{
CURLcode result;
+ struct Curl_cwriter **anchor = &data->req.writer_stack;
- if(!data->req.writer_stack) {
- result = init_writer_stack(data);
+ if(!*anchor) {
+ result = do_init_stack(data);
if(result)
return result;
}
- if(data->req.writer_stack_depth++ >= MAX_ENCODE_STACK) {
- failf(data, "Reject response due to more than %u content encodings",
- MAX_ENCODE_STACK);
- return CURLE_BAD_CONTENT_ENCODING;
- }
-
- /* Stack the unencoding stage. */
- if(writer->order >= data->req.writer_stack->order) {
- writer->downstream = data->req.writer_stack;
- data->req.writer_stack = writer;
- }
- else {
- struct contenc_writer *w = data->req.writer_stack;
- while(w->downstream && writer->order < w->downstream->order)
- w = w->downstream;
- writer->downstream = w->downstream;
- w->downstream = writer;
- }
+ /* Insert the writer as first in its phase.
+ * Skip existing writers of lower phases. */
+ while(*anchor && (*anchor)->phase < writer->phase)
+ anchor = &((*anchor)->next);
+ writer->next = *anchor;
+ *anchor = writer;
return CURLE_OK;
}
diff --git a/Utilities/cmcurl/lib/sendf.h b/Utilities/cmcurl/lib/sendf.h
index 9ee00bb..a70189f 100644
--- a/Utilities/cmcurl/lib/sendf.h
+++ b/Utilities/cmcurl/lib/sendf.h
@@ -50,43 +50,122 @@
#define CLIENTWRITE_1XX (1<<5) /* a 1xx response related HEADER */
#define CLIENTWRITE_TRAILER (1<<6) /* a trailer HEADER */
+/**
+ * Write `len` bytes at `prt` to the client. `type` indicates what
+ * kind of data is being written.
+ */
CURLcode Curl_client_write(struct Curl_easy *data, int type, char *ptr,
size_t len) WARN_UNUSED_RESULT;
+/**
+ * For a paused transfer, there might be buffered data held back.
+ * Attempt to flush this data to the client. This *may* trigger
+ * another pause of the transfer.
+ */
CURLcode Curl_client_unpause(struct Curl_easy *data);
+
+/**
+ * Free all resources related to client writing.
+ */
void Curl_client_cleanup(struct Curl_easy *data);
-struct contenc_writer {
- const struct content_encoding *handler; /* Encoding handler. */
- struct contenc_writer *downstream; /* Downstream writer. */
- unsigned int order; /* Ordering within writer stack. */
+/**
+ * Client Writers - a chain passing transfer BODY data to the client.
+ * Main application: HTTP and related protocols
+ * Other uses: monitoring of download progress
+ *
+ * Writers in the chain are order by their `phase`. First come all
+ * writers in CURL_CW_RAW, followed by any in CURL_CW_TRANSFER_DECODE,
+ * followed by any in CURL_CW_PROTOCOL, etc.
+ *
+ * When adding a writer, it is inserted as first in its phase. This means
+ * the order of adding writers of the same phase matters, but writers for
+ * different phases may be added in any order.
+ *
+ * Writers which do modify the BODY data written are expected to be of
+ * phases TRANSFER_DECODE or CONTENT_DECODE. The other phases are intended
+ * for monitoring writers. Which do *not* modify the data but gather
+ * statistics or update progress reporting.
+ */
+
+/* Phase a writer operates at. */
+typedef enum {
+ CURL_CW_RAW, /* raw data written, before any decoding */
+ CURL_CW_TRANSFER_DECODE, /* remove transfer-encodings */
+ CURL_CW_PROTOCOL, /* after transfer, but before content decoding */
+ CURL_CW_CONTENT_DECODE, /* remove content-encodings */
+ CURL_CW_CLIENT /* data written to client */
+} Curl_cwriter_phase;
+
+/* Client Writer Type, provides the implementation */
+struct Curl_cwtype {
+ const char *name; /* writer name. */
+ const char *alias; /* writer name alias, maybe NULL. */
+ CURLcode (*do_init)(struct Curl_easy *data,
+ struct Curl_cwriter *writer);
+ CURLcode (*do_write)(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
+ const char *buf, size_t nbytes);
+ void (*do_close)(struct Curl_easy *data,
+ struct Curl_cwriter *writer);
+ size_t cwriter_size; /* sizeof() allocated struct Curl_cwriter */
};
-/* Content encoding writer. */
-struct content_encoding {
- const char *name; /* Encoding name. */
- const char *alias; /* Encoding name alias. */
- CURLcode (*init_writer)(struct Curl_easy *data,
- struct contenc_writer *writer);
- CURLcode (*unencode_write)(struct Curl_easy *data,
- struct contenc_writer *writer,
- const char *buf, size_t nbytes);
- void (*close_writer)(struct Curl_easy *data,
- struct contenc_writer *writer);
- size_t writersize;
+/* Client writer instance */
+struct Curl_cwriter {
+ const struct Curl_cwtype *cwt; /* type implementation */
+ struct Curl_cwriter *next; /* Downstream writer. */
+ Curl_cwriter_phase phase; /* phase at which it operates */
};
+/**
+ * Create a new cwriter instance with given type and phase. Is not
+ * inserted into the writer chain by this call.
+ * Invokes `writer->do_init()`.
+ */
+CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
+ struct Curl_easy *data,
+ const struct Curl_cwtype *ce_handler,
+ Curl_cwriter_phase phase);
-CURLcode Curl_client_create_writer(struct contenc_writer **pwriter,
- struct Curl_easy *data,
- const struct content_encoding *ce_handler,
- int order);
+/**
+ * Free a cwriter instance.
+ * Invokes `writer->do_close()`.
+ */
+void Curl_cwriter_free(struct Curl_easy *data,
+ struct Curl_cwriter *writer);
-void Curl_client_free_writer(struct Curl_easy *data,
- struct contenc_writer *writer);
+/**
+ * Count the number of writers installed of the given phase.
+ */
+size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase);
-CURLcode Curl_client_add_writer(struct Curl_easy *data,
- struct contenc_writer *writer);
+/**
+ * Adds a writer to the transfer's writer chain.
+ * The writers `phase` determines where in the chain it is inserted.
+ */
+CURLcode Curl_cwriter_add(struct Curl_easy *data,
+ struct Curl_cwriter *writer);
+
+/**
+ * Convenience method for calling `writer->do_write()` that
+ * checks for NULL writer.
+ */
+CURLcode Curl_cwriter_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
+ const char *buf, size_t nbytes);
+
+/**
+ * Default implementations for do_init, do_write, do_close that
+ * do nothing and pass the data through.
+ */
+CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
+ struct Curl_cwriter *writer);
+CURLcode Curl_cwriter_def_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
+ const char *buf, size_t nbytes);
+void Curl_cwriter_def_close(struct Curl_easy *data,
+ struct Curl_cwriter *writer);
/* internal read-function, does plain socket, SSL and krb4 */
diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c
index 0d399ad..a08140c 100644
--- a/Utilities/cmcurl/lib/setopt.c
+++ b/Utilities/cmcurl/lib/setopt.c
@@ -50,6 +50,7 @@
#include "multiif.h"
#include "altsvc.h"
#include "hsts.h"
+#include "tftp.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -171,7 +172,7 @@ static CURLcode protocol2num(const char *str, curl_prot_t *val)
str = strchr(str, ',');
tlen = str? (size_t) (str - token): strlen(token);
if(tlen) {
- const struct Curl_handler *h = Curl_builtin_scheme(token, tlen);
+ const struct Curl_handler *h = Curl_getn_scheme_handler(token, tlen);
if(!h)
return CURLE_UNSUPPORTED_PROTOCOL;
@@ -261,43 +262,43 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Set the absolute number of maximum simultaneous alive connection that
* libcurl is allowed to have.
*/
- arg = va_arg(param, long);
- if(arg < 0)
+ uarg = va_arg(param, unsigned long);
+ if(uarg > UINT_MAX)
return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.maxconnects = arg;
+ data->set.maxconnects = (unsigned int)uarg;
break;
case CURLOPT_FORBID_REUSE:
/*
* When this transfer is done, it must not be left to be reused by a
* subsequent transfer but shall be closed immediately.
*/
- data->set.reuse_forbid = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.reuse_forbid = (0 != va_arg(param, long));
break;
case CURLOPT_FRESH_CONNECT:
/*
* This transfer shall not use a previously cached connection but
* should be made with a fresh new connect!
*/
- data->set.reuse_fresh = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.reuse_fresh = (0 != va_arg(param, long));
break;
case CURLOPT_VERBOSE:
/*
* Verbose means infof() calls that give a lot of information about
* the connection and transfer procedures as well as internal choices.
*/
- data->set.verbose = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.verbose = (0 != va_arg(param, long));
break;
case CURLOPT_HEADER:
/*
* Set to include the header in the general data output stream.
*/
- data->set.include_header = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.include_header = (0 != va_arg(param, long));
break;
case CURLOPT_NOPROGRESS:
/*
* Shut off the internal supported progress meter
*/
- data->set.hide_progress = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.hide_progress = (0 != va_arg(param, long));
if(data->set.hide_progress)
data->progress.flags |= PGRS_HIDE;
else
@@ -307,7 +308,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* Do not include the body part in the output data stream.
*/
- data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.opt_no_body = (0 != va_arg(param, long));
#ifndef CURL_DISABLE_HTTP
if(data->set.opt_no_body)
/* in HTTP lingo, no body means using the HEAD request... */
@@ -321,11 +322,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Don't output the >=400 error code HTML-page, but instead only
* return error.
*/
- data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.http_fail_on_error = (0 != va_arg(param, long));
break;
case CURLOPT_KEEP_SENDING_ON_ERROR:
- data->set.http_keep_sending_on_error = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
+ data->set.http_keep_sending_on_error = (0 != va_arg(param, long));
break;
case CURLOPT_UPLOAD:
case CURLOPT_PUT:
@@ -353,7 +353,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Try to get the file time of the remote document. The time will
* later (possibly) become available using curl_easy_getinfo().
*/
- data->set.get_filetime = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.get_filetime = (0 != va_arg(param, long));
break;
case CURLOPT_SERVER_RESPONSE_TIMEOUT:
/*
@@ -379,7 +379,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* TFTP option that specifies the block size to use for data transmission.
*/
arg = va_arg(param, long);
- if(arg < 0)
+ if(arg > TFTP_BLKSIZE_MAX || arg < TFTP_BLKSIZE_MIN)
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.tftp_blksize = arg;
break;
@@ -409,7 +409,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
*
* Transfer using ASCII (instead of BINARY).
*/
- data->set.prefer_ascii = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.prefer_ascii = (0 != va_arg(param, long));
break;
case CURLOPT_TIMECONDITION:
/*
@@ -577,7 +577,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* Switch on automatic referer that gets set if curl follows locations.
*/
- data->set.http_auto_referer = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.http_auto_referer = (0 != va_arg(param, long));
break;
case CURLOPT_ACCEPT_ENCODING:
@@ -592,28 +592,23 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
*/
argptr = va_arg(param, char *);
if(argptr && !*argptr) {
- argptr = Curl_all_content_encodings();
- if(!argptr)
- result = CURLE_OUT_OF_MEMORY;
- else {
- result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
- free(argptr);
- }
+ char all[256];
+ Curl_all_content_encodings(all, sizeof(all));
+ result = Curl_setstropt(&data->set.str[STRING_ENCODING], all);
}
else
result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
break;
case CURLOPT_TRANSFER_ENCODING:
- data->set.http_transfer_encoding = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
+ data->set.http_transfer_encoding = (0 != va_arg(param, long));
break;
case CURLOPT_FOLLOWLOCATION:
/*
* Follow Location: header hints on an HTTP-server.
*/
- data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.http_follow_location = (0 != va_arg(param, long));
break;
case CURLOPT_UNRESTRICTED_AUTH:
@@ -621,8 +616,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Send authentication (user+password) when following locations, even when
* hostname changed.
*/
- data->set.allow_auth_to_other_hosts =
- (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.allow_auth_to_other_hosts = (0 != va_arg(param, long));
break;
case CURLOPT_MAXREDIRS:
@@ -736,7 +730,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Set header option.
*/
arg = va_arg(param, long);
- data->set.sep_headers = (bool)((arg & CURLHEADER_SEPARATE)? TRUE: FALSE);
+ data->set.sep_headers = !!(arg & CURLHEADER_SEPARATE);
break;
#if !defined(CURL_DISABLE_COOKIES)
@@ -760,18 +754,18 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
return CURLE_BAD_FUNCTION_ARGUMENT;
/* append the cookie file name to the list of file names, and deal with
them later */
- cl = curl_slist_append(data->set.cookielist, argptr);
+ cl = curl_slist_append(data->state.cookielist, argptr);
if(!cl) {
- curl_slist_free_all(data->set.cookielist);
- data->set.cookielist = NULL;
+ curl_slist_free_all(data->state.cookielist);
+ data->state.cookielist = NULL;
return CURLE_OUT_OF_MEMORY;
}
- data->set.cookielist = cl; /* store the list for later use */
+ data->state.cookielist = cl; /* store the list for later use */
}
else {
/* clear the list of cookie files */
- curl_slist_free_all(data->set.cookielist);
- data->set.cookielist = NULL;
+ curl_slist_free_all(data->state.cookielist);
+ data->state.cookielist = NULL;
if(!data->share || !data->share->cookies) {
/* throw away all existing cookies if this isn't a shared cookie
@@ -811,17 +805,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* prevent the forthcoming read-cookies-from-file actions to accept
* cookies that are marked as being session cookies, as they belong to a
* previous session.
- *
- * In the original Netscape cookie spec, "session cookies" are cookies
- * with no expire date set. RFC2109 describes the same action if no
- * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds
- * a 'Discard' action that can enforce the discard even for cookies that
- * have a Max-Age.
- *
- * We run mostly with the original cookie spec, as hardly anyone implements
- * anything else.
*/
- data->set.cookiesession = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.cookiesession = (0 != va_arg(param, long));
break;
case CURLOPT_COOKIELIST:
@@ -956,7 +941,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
if(arg)
return CURLE_BAD_FUNCTION_ARGUMENT;
#else
- data->set.http09_allowed = arg ? TRUE : FALSE;
+ data->set.http09_allowed = !!arg;
#endif
break;
@@ -997,8 +982,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_MIME_OPTIONS:
- data->set.mime_options = (unsigned int)va_arg(param, long);
- break;
+ arg = va_arg(param, long);
+ data->set.mime_formescape = !!(arg & CURLMIMEOPT_FORMESCAPE);
+ break;
# endif
#endif
@@ -1018,8 +1004,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/* the DIGEST_IE bit is only used to set a special marker, for all the
rest we need to handle it as normal DIGEST */
- data->state.authhost.iestyle =
- (bool)((auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE);
+ data->state.authhost.iestyle = !!(auth & CURLAUTH_DIGEST_IE);
if(auth & CURLAUTH_DIGEST_IE) {
auth |= CURLAUTH_DIGEST; /* set standard digest bit */
@@ -1072,8 +1057,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* Tunnel operations through the proxy instead of normal proxy use
*/
- data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
+ data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long));
break;
case CURLOPT_PROXYPORT:
@@ -1102,8 +1086,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/* the DIGEST_IE bit is only used to set a special marker, for all the
rest we need to handle it as normal DIGEST */
- data->state.authproxy.iestyle =
- (bool)((auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE);
+ data->state.authproxy.iestyle = !!(auth & CURLAUTH_DIGEST_IE);
if(auth & CURLAUTH_DIGEST_IE) {
auth |= CURLAUTH_DIGEST; /* set standard digest bit */
@@ -1203,7 +1186,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* Set flag for NEC SOCK5 support
*/
- data->set.socks5_gssapi_nec = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.socks5_gssapi_nec = (0 != va_arg(param, long));
break;
#endif
#ifndef CURL_DISABLE_PROXY
@@ -1251,7 +1234,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* An option that changes the command to one that asks for a list only, no
* file info details. Used for FTP, POP3 and SFTP.
*/
- data->set.list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.list_only = (0 != va_arg(param, long));
break;
#endif
case CURLOPT_APPEND:
@@ -1259,7 +1242,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* We want to upload and append to an existing file. Used for FTP and
* SFTP.
*/
- data->set.remote_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.remote_append = (0 != va_arg(param, long));
break;
#ifndef CURL_DISABLE_FTP
@@ -1270,7 +1253,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = va_arg(param, long);
if((arg < CURLFTPMETHOD_DEFAULT) || (arg >= CURLFTPMETHOD_LAST))
return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.ftp_filemethod = (unsigned char)(curl_ftpfile)arg;
+ data->set.ftp_filemethod = (unsigned char)arg;
break;
case CURLOPT_FTPPORT:
/*
@@ -1278,26 +1261,26 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
*/
result = Curl_setstropt(&data->set.str[STRING_FTPPORT],
va_arg(param, char *));
- data->set.ftp_use_port = (data->set.str[STRING_FTPPORT]) ? TRUE : FALSE;
+ data->set.ftp_use_port = !!(data->set.str[STRING_FTPPORT]);
break;
case CURLOPT_FTP_USE_EPRT:
- data->set.ftp_use_eprt = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.ftp_use_eprt = (0 != va_arg(param, long));
break;
case CURLOPT_FTP_USE_EPSV:
- data->set.ftp_use_epsv = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.ftp_use_epsv = (0 != va_arg(param, long));
break;
case CURLOPT_FTP_USE_PRET:
- data->set.ftp_use_pret = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.ftp_use_pret = (0 != va_arg(param, long));
break;
case CURLOPT_FTP_SSL_CCC:
arg = va_arg(param, long);
if((arg < CURLFTPSSL_CCC_NONE) || (arg >= CURLFTPSSL_CCC_LAST))
return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.ftp_ccc = (unsigned char)(curl_ftpccc)arg;
+ data->set.ftp_ccc = (unsigned char)arg;
break;
case CURLOPT_FTP_SKIP_PASV_IP:
@@ -1305,7 +1288,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the
* bypass of the IP address in PASV responses.
*/
- data->set.ftp_skip_ip = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.ftp_skip_ip = (0 != va_arg(param, long));
break;
case CURLOPT_FTP_ACCOUNT:
@@ -1333,7 +1316,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
*/
result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL],
va_arg(param, char *));
- data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE;
+ data->set.krb = !!(data->set.str[STRING_KRB_LEVEL]);
break;
#endif
#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
@@ -1867,14 +1850,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* Kludgy option to enable CRLF conversions. Subject for removal.
*/
- data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.crlf = (0 != va_arg(param, long));
break;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_HAPROXYPROTOCOL:
/*
* Set to send the HAProxy Proxy Protocol header
*/
- data->set.haproxyprotocol = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.haproxyprotocol = (0 != va_arg(param, long));
break;
case CURLOPT_HAPROXY_CLIENT_IP:
/*
@@ -1926,22 +1909,17 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* Enable peer SSL verifying.
*/
- data->set.ssl.primary.verifypeer = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
+ data->set.ssl.primary.verifypeer = (0 != va_arg(param, long));
/* Update the current connection ssl_config. */
- if(data->conn) {
- data->conn->ssl_config.verifypeer =
- data->set.ssl.primary.verifypeer;
- }
+ Curl_ssl_conn_config_update(data, FALSE);
break;
#ifndef CURL_DISABLE_DOH
case CURLOPT_DOH_SSL_VERIFYPEER:
/*
* Enable peer SSL verifying for DoH.
*/
- data->set.doh_verifypeer = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
+ data->set.doh_verifypeer = (0 != va_arg(param, long));
break;
#endif
#ifndef CURL_DISABLE_PROXY
@@ -1953,10 +1931,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
(0 != va_arg(param, long))?TRUE:FALSE;
/* Update the current connection proxy_ssl_config. */
- if(data->conn) {
- data->conn->proxy_ssl_config.verifypeer =
- data->set.proxy_ssl.primary.verifypeer;
- }
+ Curl_ssl_conn_config_update(data, TRUE);
break;
#endif
case CURLOPT_SSL_VERIFYHOST:
@@ -1968,13 +1943,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/* Obviously people are not reading documentation and too many thought
this argument took a boolean when it wasn't and misused it.
Treat 1 and 2 the same */
- data->set.ssl.primary.verifyhost = (bool)((arg & 3) ? TRUE : FALSE);
+ data->set.ssl.primary.verifyhost = !!(arg & 3);
/* Update the current connection ssl_config. */
- if(data->conn) {
- data->conn->ssl_config.verifyhost =
- data->set.ssl.primary.verifyhost;
- }
+ Curl_ssl_conn_config_update(data, FALSE);
break;
#ifndef CURL_DISABLE_DOH
case CURLOPT_DOH_SSL_VERIFYHOST:
@@ -1984,7 +1956,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = va_arg(param, long);
/* Treat both 1 and 2 as TRUE */
- data->set.doh_verifyhost = (bool)((arg & 3) ? TRUE : FALSE);
+ data->set.doh_verifyhost = !!(arg & 3);
break;
#endif
#ifndef CURL_DISABLE_PROXY
@@ -1996,12 +1968,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/* Treat both 1 and 2 as TRUE */
data->set.proxy_ssl.primary.verifyhost = (bool)((arg & 3)?TRUE:FALSE);
-
/* Update the current connection proxy_ssl_config. */
- if(data->conn) {
- data->conn->proxy_ssl_config.verifyhost =
- data->set.proxy_ssl.primary.verifyhost;
- }
+ Curl_ssl_conn_config_update(data, TRUE);
break;
#endif
case CURLOPT_SSL_VERIFYSTATUS:
@@ -2013,14 +1981,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
}
- data->set.ssl.primary.verifystatus = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
+ data->set.ssl.primary.verifystatus = (0 != va_arg(param, long));
/* Update the current connection ssl_config. */
- if(data->conn) {
- data->conn->ssl_config.verifystatus =
- data->set.ssl.primary.verifystatus;
- }
+ Curl_ssl_conn_config_update(data, FALSE);
break;
#ifndef CURL_DISABLE_DOH
case CURLOPT_DOH_SSL_VERIFYSTATUS:
@@ -2032,8 +1996,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
}
- data->set.doh_verifystatus = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
+ data->set.doh_verifystatus = (0 != va_arg(param, long));
break;
#endif
case CURLOPT_SSL_CTX_FUNCTION:
@@ -2067,12 +2030,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
}
- data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.ssl.falsestart = (0 != va_arg(param, long));
break;
case CURLOPT_CERTINFO:
#ifdef USE_SSL
if(Curl_ssl_supports(data, SSLSUPP_CERTINFO))
- data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.ssl.certinfo = (0 != va_arg(param, long));
else
#endif
result = CURLE_NOT_BUILT_IN;
@@ -2118,14 +2081,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Specify entire PEM of the CA certificate
*/
#ifdef USE_SSL
- if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB))
+ if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) {
result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO],
va_arg(param, struct curl_blob *));
+ break;
+ }
else
#endif
return CURLE_NOT_BUILT_IN;
-
- break;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_CAINFO:
/*
@@ -2141,13 +2104,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Specify entire PEM of the CA certificate
*/
#ifdef USE_SSL
- if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB))
+ if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) {
result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY],
va_arg(param, struct curl_blob *));
+ break;
+ }
else
#endif
return CURLE_NOT_BUILT_IN;
- break;
#endif
case CURLOPT_CAPATH:
/*
@@ -2278,7 +2242,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* The application asks not to set any signal() or alarm() handlers,
* even when using a timeout.
*/
- data->set.no_signal = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.no_signal = (0 != va_arg(param, long));
break;
case CURLOPT_SHARE:
@@ -2453,11 +2417,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Enable or disable TCP_NODELAY, which will disable/enable the Nagle
* algorithm
*/
- data->set.tcp_nodelay = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.tcp_nodelay = (0 != va_arg(param, long));
break;
case CURLOPT_IGNORE_CONTENT_LENGTH:
- data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.ignorecl = (0 != va_arg(param, long));
break;
case CURLOPT_CONNECT_ONLY:
@@ -2532,8 +2496,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_SSL_SESSIONID_CACHE:
- data->set.ssl.primary.sessionid = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
+ data->set.ssl.primary.sessionid = (0 != va_arg(param, long));
#ifndef CURL_DISABLE_PROXY
data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid;
#endif
@@ -2622,7 +2585,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* disable libcurl transfer encoding is used
*/
#ifndef USE_HYPER
- data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
+ data->set.http_te_skip = (0 == va_arg(param, long));
break;
#else
return CURLE_NOT_BUILT_IN; /* hyper doesn't support */
@@ -2632,7 +2595,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* raw data passed to the application when content encoding is used
*/
- data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
+ data->set.http_ce_skip = (0 == va_arg(param, long));
break;
#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
@@ -2733,7 +2696,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
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;
+ data->set.mail_rcpt_allowfails = (0 != va_arg(param, long));
break;
#endif
@@ -2745,7 +2708,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_SASL_IR:
/* Enable/disable SASL initial response */
- data->set.sasl_ir = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.sasl_ir = (0 != va_arg(param, long));
break;
#ifndef CURL_DISABLE_RTSP
case CURLOPT_RTSP_REQUEST:
@@ -2859,7 +2822,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#endif
#ifndef CURL_DISABLE_FTP
case CURLOPT_WILDCARDMATCH:
- data->set.wildcard_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.wildcard_enabled = (0 != va_arg(param, long));
break;
case CURLOPT_CHUNK_BGN_FUNCTION:
data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback);
@@ -2942,7 +2905,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
#endif
case CURLOPT_TCP_KEEPALIVE:
- data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.tcp_keepalive = (0 != va_arg(param, long));
break;
case CURLOPT_TCP_KEEPIDLE:
arg = va_arg(param, long);
@@ -2971,7 +2934,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_SSL_ENABLE_NPN:
break;
case CURLOPT_SSL_ENABLE_ALPN:
- data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.ssl_enable_alpn = (0 != va_arg(param, long));
break;
#ifdef USE_UNIX_SOCKETS
case CURLOPT_UNIX_SOCKET_PATH:
@@ -2987,10 +2950,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#endif
case CURLOPT_PATH_AS_IS:
- data->set.path_as_is = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.path_as_is = (0 != va_arg(param, long));
break;
case CURLOPT_PIPEWAIT:
- data->set.pipewait = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.pipewait = (0 != va_arg(param, long));
break;
case CURLOPT_STREAM_WEIGHT:
#if defined(USE_HTTP2) || defined(USE_HTTP3)
@@ -3025,12 +2988,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
#ifndef CURL_DISABLE_SHUFFLE_DNS
case CURLOPT_DNS_SHUFFLE_ADDRESSES:
- data->set.dns_shuffle_addresses = (0 != va_arg(param, long)) ? TRUE:FALSE;
+ data->set.dns_shuffle_addresses = (0 != va_arg(param, long));
break;
#endif
case CURLOPT_DISALLOW_USERNAME_IN_URL:
- data->set.disallow_username_in_url =
- (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.disallow_username_in_url = (0 != va_arg(param, long));
break;
#ifndef CURL_DISABLE_DOH
case CURLOPT_DOH_URL:
@@ -3095,18 +3057,18 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/* this needs to build a list of file names to read from, so that it can
read them later, as we might get a shared HSTS handle to load them
into */
- h = curl_slist_append(data->set.hstslist, argptr);
+ h = curl_slist_append(data->state.hstslist, argptr);
if(!h) {
- curl_slist_free_all(data->set.hstslist);
- data->set.hstslist = NULL;
+ curl_slist_free_all(data->state.hstslist);
+ data->state.hstslist = NULL;
return CURLE_OUT_OF_MEMORY;
}
- data->set.hstslist = h; /* store the list for later use */
+ data->state.hstslist = h; /* store the list for later use */
}
else {
/* clear the list of HSTS files */
- curl_slist_free_all(data->set.hstslist);
- data->set.hstslist = NULL;
+ curl_slist_free_all(data->state.hstslist);
+ data->state.hstslist = NULL;
if(!data->share || !data->share->hsts)
/* throw away the HSTS cache unless shared */
Curl_hsts_cleanup(&data->hsts);
diff --git a/Utilities/cmcurl/lib/setup-win32.h b/Utilities/cmcurl/lib/setup-win32.h
index 1394838..4e034d4 100644
--- a/Utilities/cmcurl/lib/setup-win32.h
+++ b/Utilities/cmcurl/lib/setup-win32.h
@@ -53,14 +53,14 @@
# ifndef NOGDI
# define NOGDI
# endif
-# include <winerror.h>
-# include <windows.h>
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# ifdef HAVE_WS2TCPIP_H
# include <ws2tcpip.h>
# endif
# endif
+# include <windows.h>
+# include <winerror.h>
# include <tchar.h>
# ifdef UNICODE
typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str);
@@ -96,18 +96,12 @@
#ifndef _WIN32_WINNT_WS03
#define _WIN32_WINNT_WS03 0x0502 /* Windows Server 2003 */
#endif
-#ifndef _WIN32_WINNT_WIN6
-#define _WIN32_WINNT_WIN6 0x0600 /* Windows Vista */
-#endif
#ifndef _WIN32_WINNT_VISTA
#define _WIN32_WINNT_VISTA 0x0600 /* Windows Vista */
#endif
#ifndef _WIN32_WINNT_WS08
#define _WIN32_WINNT_WS08 0x0600 /* Windows Server 2008 */
#endif
-#ifndef _WIN32_WINNT_LONGHORN
-#define _WIN32_WINNT_LONGHORN 0x0600 /* Windows Vista */
-#endif
#ifndef _WIN32_WINNT_WIN7
#define _WIN32_WINNT_WIN7 0x0601 /* Windows 7 */
#endif
@@ -117,9 +111,6 @@
#ifndef _WIN32_WINNT_WINBLUE
#define _WIN32_WINNT_WINBLUE 0x0603 /* Windows 8.1 */
#endif
-#ifndef _WIN32_WINNT_WINTHRESHOLD
-#define _WIN32_WINNT_WINTHRESHOLD 0x0A00 /* Windows 10 */
-#endif
#ifndef _WIN32_WINNT_WIN10
#define _WIN32_WINNT_WIN10 0x0A00 /* Windows 10 */
#endif
diff --git a/Utilities/cmcurl/lib/share.h b/Utilities/cmcurl/lib/share.h
index 7f55aac..632d919 100644
--- a/Utilities/cmcurl/lib/share.h
+++ b/Utilities/cmcurl/lib/share.h
@@ -31,14 +31,6 @@
#include "urldata.h"
#include "conncache.h"
-/* SalfordC says "A structure member may not be volatile". Hence:
- */
-#ifdef __SALFORDC__
-#define CURL_VOLATILE
-#else
-#define CURL_VOLATILE volatile
-#endif
-
#define CURL_GOOD_SHARE 0x7e117a1e
#define GOOD_SHARE_HANDLE(x) ((x) && (x)->magic == CURL_GOOD_SHARE)
@@ -46,7 +38,7 @@
struct Curl_share {
unsigned int magic; /* CURL_GOOD_SHARE */
unsigned int specifier;
- CURL_VOLATILE unsigned int dirty;
+ volatile unsigned int dirty;
curl_lock_function lockfunc;
curl_unlock_function unlockfunc;
diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c
index 32c5137..6c8a47c 100644
--- a/Utilities/cmcurl/lib/smb.c
+++ b/Utilities/cmcurl/lib/smb.c
@@ -27,7 +27,7 @@
#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE)
-#ifdef WIN32
+#ifdef _WIN32
#define getpid GetCurrentProcessId
#endif
@@ -1047,14 +1047,7 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done)
break;
}
}
- data->req.bytecount += len;
data->req.offset += len;
- result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
- if(result) {
- req->result = result;
- next_state = SMB_CLOSE;
- break;
- }
next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD;
break;
diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c
index 81a17e3..65fbc5b 100644
--- a/Utilities/cmcurl/lib/smtp.c
+++ b/Utilities/cmcurl/lib/smtp.c
@@ -1320,7 +1320,7 @@ static CURLcode smtp_init(struct Curl_easy *data)
CURLcode result = CURLE_OK;
struct SMTP *smtp;
- smtp = data->req.p.smtp = calloc(sizeof(struct SMTP), 1);
+ smtp = data->req.p.smtp = calloc(1, sizeof(struct SMTP));
if(!smtp)
result = CURLE_OUT_OF_MEMORY;
diff --git a/Utilities/cmcurl/lib/socketpair.c b/Utilities/cmcurl/lib/socketpair.c
index 963e140..e3d40ff 100644
--- a/Utilities/cmcurl/lib/socketpair.c
+++ b/Utilities/cmcurl/lib/socketpair.c
@@ -28,7 +28,7 @@
#include "rand.h"
#if !defined(HAVE_SOCKETPAIR) && !defined(CURL_DISABLE_SOCKETPAIR)
-#ifdef WIN32
+#ifdef _WIN32
/*
* This is a socketpair() implementation for Windows.
*/
@@ -50,7 +50,7 @@
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001
#endif /* !INADDR_LOOPBACK */
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
#include "nonblock.h" /* for curlx_nonblock */
#include "timeval.h" /* needed before select.h */
@@ -87,7 +87,7 @@ int Curl_socketpair(int domain, int type, int protocol,
socks[0] = socks[1] = CURL_SOCKET_BAD;
-#if defined(WIN32) || defined(__CYGWIN__)
+#if defined(_WIN32) || defined(__CYGWIN__)
/* don't set SO_REUSEADDR on Windows */
(void)reuse;
#ifdef SO_EXCLUSIVEADDRUSE
diff --git a/Utilities/cmcurl/lib/socketpair.h b/Utilities/cmcurl/lib/socketpair.h
index 306ab5d..bd499ab 100644
--- a/Utilities/cmcurl/lib/socketpair.h
+++ b/Utilities/cmcurl/lib/socketpair.h
@@ -25,6 +25,23 @@
***************************************************************************/
#include "curl_setup.h"
+
+#ifdef HAVE_PIPE
+
+#define wakeup_write write
+#define wakeup_read read
+#define wakeup_close close
+#define wakeup_create pipe
+
+#else /* HAVE_PIPE */
+
+#define wakeup_write swrite
+#define wakeup_read sread
+#define wakeup_close sclose
+#define wakeup_create(p) Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, p)
+
+#endif /* HAVE_PIPE */
+
#ifndef HAVE_SOCKETPAIR
#include <curl/curl.h>
diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c
index a7b5ab0..3a396de 100644
--- a/Utilities/cmcurl/lib/socks.c
+++ b/Utilities/cmcurl/lib/socks.c
@@ -339,8 +339,8 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
if(dns) {
#ifdef CURLRES_ASYNCH
- data->state.async.dns = dns;
- data->state.async.done = TRUE;
+ conn->resolve_async.dns = dns;
+ conn->resolve_async.done = TRUE;
#endif
infof(data, "Hostname '%s' was found", sx->hostname);
sxstate(sx, data, CONNECT_RESOLVED);
@@ -402,8 +402,11 @@ CONNECT_REQ_INIT:
socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
if(sx->proxy_user) {
size_t plen = strlen(sx->proxy_user);
- if(plen >= (size_t)data->set.buffer_size - 8) {
- failf(data, "Too long SOCKS proxy user name, can't use");
+ if(plen > 255) {
+ /* there is no real size limit to this field in the protocol, but
+ SOCKS5 limits the proxy user field to 255 bytes and it seems likely
+ that a longer field is either a mistake or malicious input */
+ failf(data, "Too long SOCKS proxy user name");
return CURLPX_LONG_USER;
}
/* copy the proxy name WITH trailing zero */
@@ -426,7 +429,8 @@ CONNECT_REQ_INIT:
socksreq[7] = 1;
/* append hostname */
hostnamelen = strlen(sx->hostname) + 1; /* length including NUL */
- if(hostnamelen <= 255)
+ if((hostnamelen <= 255) &&
+ (packetsize + hostnamelen < data->set.buffer_size))
strcpy((char *)socksreq + packetsize, sx->hostname);
else {
failf(data, "SOCKS4: too long host name");
@@ -802,8 +806,8 @@ CONNECT_REQ_INIT:
if(dns) {
#ifdef CURLRES_ASYNCH
- data->state.async.dns = dns;
- data->state.async.done = TRUE;
+ conn->resolve_async.dns = dns;
+ conn->resolve_async.done = TRUE;
#endif
infof(data, "SOCKS5: hostname '%s' found", sx->hostname);
}
@@ -819,10 +823,19 @@ CONNECT_REQ_INIT:
/* FALLTHROUGH */
CONNECT_RESOLVED:
case CONNECT_RESOLVED: {
- char dest[MAX_IPADR_LEN] = "unknown"; /* printable address */
+ char dest[MAX_IPADR_LEN]; /* printable address */
struct Curl_addrinfo *hp = NULL;
if(dns)
hp = dns->addr;
+#ifdef ENABLE_IPV6
+ if(data->set.ipver != CURL_IPRESOLVE_WHATEVER) {
+ int wanted_family = data->set.ipver == CURL_IPRESOLVE_V4 ?
+ AF_INET : AF_INET6;
+ /* scan for the first proper address */
+ while(hp && (hp->ai_family != wanted_family))
+ hp = hp->ai_next;
+ }
+#endif
if(!hp) {
failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
sx->hostname);
@@ -1119,7 +1132,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
return result;
if(!sx) {
- sx = calloc(sizeof(*sx), 1);
+ sx = calloc(1, sizeof(*sx));
if(!sx)
return CURLE_OUT_OF_MEMORY;
cf->ctx = sx;
@@ -1157,32 +1170,29 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
return result;
}
-static int socks_cf_get_select_socks(struct Curl_cfilter *cf,
+static void socks_cf_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
- curl_socket_t *socks)
+ struct easy_pollset *ps)
{
struct socks_state *sx = cf->ctx;
- int fds;
- fds = cf->next->cft->get_select_socks(cf->next, data, socks);
- if(!fds && cf->next->connected && !cf->connected && sx) {
+ if(!cf->connected && sx) {
/* If we are not connected, the filter below is and has nothing
* to wait on, we determine what to wait for. */
- socks[0] = Curl_conn_cf_get_socket(cf, data);
+ curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
switch(sx->state) {
case CONNECT_RESOLVING:
case CONNECT_SOCKS_READ:
case CONNECT_AUTH_READ:
case CONNECT_REQ_READ:
case CONNECT_REQ_READ_MORE:
- fds = GETSOCK_READSOCK(0);
+ Curl_pollset_set_in_only(data, ps, sock);
break;
default:
- fds = GETSOCK_WRITESOCK(0);
+ Curl_pollset_set_out_only(data, ps, sock);
break;
}
}
- return fds;
}
static void socks_proxy_cf_close(struct Curl_cfilter *cf,
@@ -1227,7 +1237,7 @@ struct Curl_cftype Curl_cft_socks_proxy = {
socks_proxy_cf_connect,
socks_proxy_cf_close,
socks_cf_get_host,
- socks_cf_get_select_socks,
+ socks_cf_adjust_pollset,
Curl_cf_def_data_pending,
Curl_cf_def_send,
Curl_cf_def_recv,
diff --git a/Utilities/cmcurl/lib/strdup.c b/Utilities/cmcurl/lib/strdup.c
index 07a6139..2578441 100644
--- a/Utilities/cmcurl/lib/strdup.c
+++ b/Utilities/cmcurl/lib/strdup.c
@@ -26,7 +26,7 @@
#include <curl/curl.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <wchar.h>
#endif
@@ -56,7 +56,7 @@ char *Curl_strdup(const char *str)
}
#endif
-#ifdef WIN32
+#ifdef _WIN32
/***************************************************************************
*
* Curl_wcsdup(source)
@@ -101,6 +101,30 @@ void *Curl_memdup(const void *src, size_t length)
/***************************************************************************
*
+ * Curl_strndup(source, length)
+ *
+ * Copies the 'source' string to a newly allocated buffer (that is returned).
+ * Copies not more than 'length' bytes (up to a null terminator) then adds a
+ * null terminator.
+ *
+ * Returns the new pointer or NULL on failure.
+ *
+ ***************************************************************************/
+void *Curl_strndup(const char *src, size_t length)
+{
+ char *buf = memchr(src, '\0', length);
+ if(buf)
+ length = buf - src;
+ buf = malloc(length + 1);
+ if(!buf)
+ return NULL;
+ memcpy(buf, src, length);
+ buf[length] = 0;
+ return buf;
+}
+
+/***************************************************************************
+ *
* Curl_saferealloc(ptr, size)
*
* Does a normal realloc(), but will free the data pointer if the realloc
diff --git a/Utilities/cmcurl/lib/strdup.h b/Utilities/cmcurl/lib/strdup.h
index c3430b5..9f12b25 100644
--- a/Utilities/cmcurl/lib/strdup.h
+++ b/Utilities/cmcurl/lib/strdup.h
@@ -28,10 +28,11 @@
#ifndef HAVE_STRDUP
char *Curl_strdup(const char *str);
#endif
-#ifdef WIN32
+#ifdef _WIN32
wchar_t* Curl_wcsdup(const wchar_t* src);
#endif
void *Curl_memdup(const void *src, size_t buffer_length);
void *Curl_saferealloc(void *ptr, size_t size);
+void *Curl_strndup(const char *src, size_t length);
#endif /* HEADER_CURL_STRDUP_H */
diff --git a/Utilities/cmcurl/lib/strerror.c b/Utilities/cmcurl/lib/strerror.c
index be41914..0d5f927 100644
--- a/Utilities/cmcurl/lib/strerror.c
+++ b/Utilities/cmcurl/lib/strerror.c
@@ -48,7 +48,7 @@
#include "curl_memory.h"
#include "memdebug.h"
-#if defined(WIN32) || defined(_WIN32_WCE)
+#if defined(_WIN32) || defined(_WIN32_WCE)
#define PRESERVE_WINDOWS_ERROR_CODE
#endif
@@ -762,7 +762,7 @@ get_winsock_error (int err, char *buf, size_t len)
}
#endif /* USE_WINSOCK */
-#if defined(WIN32) || defined(_WIN32_WCE)
+#if defined(_WIN32) || defined(_WIN32_WCE)
/* This is a helper function for Curl_strerror that converts Windows API error
* codes (GetLastError) to error messages.
* Returns NULL if no error message was found for error code.
@@ -804,7 +804,7 @@ get_winapi_error(int err, char *buf, size_t buflen)
return (*buf ? buf : NULL);
}
-#endif /* WIN32 || _WIN32_WCE */
+#endif /* _WIN32 || _WIN32_WCE */
/*
* Our thread-safe and smart strerror() replacement.
@@ -837,15 +837,15 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
if(!buflen)
return NULL;
-#ifndef WIN32
+#ifndef _WIN32
DEBUGASSERT(err >= 0);
#endif
max = buflen - 1;
*buf = '\0';
-#if defined(WIN32) || defined(_WIN32_WCE)
-#if defined(WIN32)
+#if defined(_WIN32) || defined(_WIN32_WCE)
+#if defined(_WIN32)
/* 'sys_nerr' is the maximum errno number, it is not widely portable */
if(err >= 0 && err < sys_nerr)
strncpy(buf, sys_errlist[err], max);
@@ -923,7 +923,7 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
* Curl_winapi_strerror:
* Variant of Curl_strerror if the error code is definitely Windows API.
*/
-#if defined(WIN32) || defined(_WIN32_WCE)
+#if defined(_WIN32) || defined(_WIN32_WCE)
const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen)
{
#ifdef PRESERVE_WINDOWS_ERROR_CODE
@@ -958,7 +958,7 @@ const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen)
return buf;
}
-#endif /* WIN32 || _WIN32_WCE */
+#endif /* _WIN32 || _WIN32_WCE */
#ifdef USE_WINDOWS_SSPI
/*
@@ -986,6 +986,10 @@ const char *Curl_sspi_strerror(int err, char *buf, size_t buflen)
break;
#define SEC2TXT(sec) case sec: txt = #sec; break
SEC2TXT(CRYPT_E_REVOKED);
+ SEC2TXT(CRYPT_E_NO_REVOCATION_DLL);
+ SEC2TXT(CRYPT_E_NO_REVOCATION_CHECK);
+ SEC2TXT(CRYPT_E_REVOCATION_OFFLINE);
+ SEC2TXT(CRYPT_E_NOT_IN_REVOCATION_DATABASE);
SEC2TXT(SEC_E_ALGORITHM_MISMATCH);
SEC2TXT(SEC_E_BAD_BINDINGS);
SEC2TXT(SEC_E_BAD_PKGID);
diff --git a/Utilities/cmcurl/lib/strerror.h b/Utilities/cmcurl/lib/strerror.h
index 399712f..6806867 100644
--- a/Utilities/cmcurl/lib/strerror.h
+++ b/Utilities/cmcurl/lib/strerror.h
@@ -29,7 +29,7 @@
#define STRERROR_LEN 256 /* a suitable length */
const char *Curl_strerror(int err, char *buf, size_t buflen);
-#if defined(WIN32) || defined(_WIN32_WCE)
+#if defined(_WIN32) || defined(_WIN32_WCE)
const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen);
#endif
#ifdef USE_WINDOWS_SSPI
diff --git a/Utilities/cmcurl/lib/system_win32.c b/Utilities/cmcurl/lib/system_win32.c
index 0cdaf3b..9408d02 100644
--- a/Utilities/cmcurl/lib/system_win32.c
+++ b/Utilities/cmcurl/lib/system_win32.c
@@ -24,7 +24,7 @@
#include "curl_setup.h"
-#if defined(WIN32)
+#if defined(_WIN32)
#include <curl/curl.h>
#include "system_win32.h"
@@ -238,4 +238,4 @@ HMODULE Curl_load_library(LPCTSTR filename)
#endif
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
diff --git a/Utilities/cmcurl/lib/system_win32.h b/Utilities/cmcurl/lib/system_win32.h
index 6482643..2566766 100644
--- a/Utilities/cmcurl/lib/system_win32.h
+++ b/Utilities/cmcurl/lib/system_win32.h
@@ -26,7 +26,7 @@
#include "curl_setup.h"
-#if defined(WIN32)
+#if defined(_WIN32)
extern LARGE_INTEGER Curl_freq;
extern bool Curl_isVistaOrGreater;
@@ -42,8 +42,8 @@ extern IF_NAMETOINDEX_FN Curl_if_nametoindex;
/* This is used to dynamically load DLLs */
HMODULE Curl_load_library(LPCTSTR filename);
-#else /* WIN32 */
+#else /* _WIN32 */
#define Curl_win32_init(x) CURLE_OK
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
#endif /* HEADER_CURL_SYSTEM_WIN32_H */
diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c
index e78140d..6630155 100644
--- a/Utilities/cmcurl/lib/tftp.c
+++ b/Utilities/cmcurl/lib/tftp.c
@@ -70,8 +70,6 @@
/* RFC2348 allows the block size to be negotiated */
#define TFTP_BLKSIZE_DEFAULT 512
-#define TFTP_BLKSIZE_MIN 8
-#define TFTP_BLKSIZE_MAX 65464
#define TFTP_OPTION_BLKSIZE "blksize"
/* from RFC2349: */
@@ -978,11 +976,9 @@ static CURLcode tftp_connect(struct Curl_easy *data, bool *done)
return CURLE_OUT_OF_MEMORY;
/* alloc pkt buffers based on specified blksize */
- if(data->set.tftp_blksize) {
+ if(data->set.tftp_blksize)
+ /* range checked when set */
blksize = (int)data->set.tftp_blksize;
- if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN)
- return CURLE_TFTP_ILLEGAL;
- }
need_blksize = blksize;
/* default size is the fallback when no OACK is received */
@@ -1107,7 +1103,6 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data)
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct tftp_state_data *state = conn->proto.tftpc;
- struct SingleRequest *k = &data->req;
/* Receive the packet */
fromlen = sizeof(fromaddr);
@@ -1141,11 +1136,6 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data)
result = Curl_client_write(data, CLIENTWRITE_BODY,
(char *)state->rpacket.data + 4,
state->rbytes-4);
- if(!result) {
- k->bytecount += state->rbytes-4;
- result = Curl_pgrsSetDownloadCounter(data,
- (curl_off_t) k->bytecount);
- }
if(result) {
tftp_state_machine(state, TFTP_EVENT_ERROR);
return result;
diff --git a/Utilities/cmcurl/lib/tftp.h b/Utilities/cmcurl/lib/tftp.h
index 5d2d5da..12404bf 100644
--- a/Utilities/cmcurl/lib/tftp.h
+++ b/Utilities/cmcurl/lib/tftp.h
@@ -25,6 +25,9 @@
***************************************************************************/
#ifndef CURL_DISABLE_TFTP
extern const struct Curl_handler Curl_handler_tftp;
+
+#define TFTP_BLKSIZE_MIN 8
+#define TFTP_BLKSIZE_MAX 65464
#endif
#endif /* HEADER_CURL_TFTP_H */
diff --git a/Utilities/cmcurl/lib/timediff.c b/Utilities/cmcurl/lib/timediff.c
index 1b762bb..d0824d1 100644
--- a/Utilities/cmcurl/lib/timediff.c
+++ b/Utilities/cmcurl/lib/timediff.c
@@ -53,7 +53,7 @@ struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms)
#endif
tv->tv_sec = (time_t)tv_sec;
tv->tv_usec = (suseconds_t)tv_usec;
-#elif defined(WIN32) /* maybe also others in the future */
+#elif defined(_WIN32) /* maybe also others in the future */
#if TIMEDIFF_T_MAX > LONG_MAX
/* tv_sec overflow check on Windows there we know it is long */
if(tv_sec > LONG_MAX)
diff --git a/Utilities/cmcurl/lib/timeval.c b/Utilities/cmcurl/lib/timeval.c
index 026d9d1..5a6727c 100644
--- a/Utilities/cmcurl/lib/timeval.c
+++ b/Utilities/cmcurl/lib/timeval.c
@@ -24,11 +24,10 @@
#include "timeval.h"
-#if defined(WIN32) && !defined(MSDOS)
+#if defined(_WIN32)
-/* set in win32_init() */
-extern LARGE_INTEGER Curl_freq;
-extern bool Curl_isVistaOrGreater;
+#include <curl/curl.h>
+#include "system_win32.h"
/* In case of bug fix this function has a counterpart in tool_util.c */
struct curltime Curl_now(void)
diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c
index 6886764..96f1fde 100644
--- a/Utilities/cmcurl/lib/transfer.c
+++ b/Utilities/cmcurl/lib/transfer.c
@@ -163,9 +163,9 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
{
size_t buffersize = bytes;
size_t nread;
-
curl_read_callback readfunc = NULL;
void *extra_data = NULL;
+ int eof_index = 0;
#ifndef CURL_DISABLE_HTTP
if(data->state.trailers_state == TRAILERS_INITIALIZED) {
@@ -223,6 +223,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
*/
readfunc = trailers_read;
extra_data = (void *)data;
+ eof_index = 1;
}
else
#endif
@@ -231,10 +232,15 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
extra_data = data->state.in;
}
- Curl_set_in_callback(data, true);
- nread = readfunc(data->req.upload_fromhere, 1,
- buffersize, extra_data);
- Curl_set_in_callback(data, false);
+ if(!data->req.fread_eof[eof_index]) {
+ Curl_set_in_callback(data, true);
+ nread = readfunc(data->req.upload_fromhere, 1, buffersize, extra_data);
+ Curl_set_in_callback(data, false);
+ /* make sure the callback is not called again after EOF */
+ data->req.fread_eof[eof_index] = !nread;
+ }
+ else
+ nread = 0;
if(nread == CURL_READFUNC_ABORT) {
failf(data, "operation aborted by callback");
@@ -422,16 +428,15 @@ static CURLcode readwrite_data(struct Curl_easy *data,
bool *comeback)
{
CURLcode result = CURLE_OK;
- ssize_t nread; /* number of bytes read */
- size_t excess = 0; /* excess bytes read */
- bool readmore = FALSE; /* used by RTP to signal for more data */
+ char *buf;
+ size_t blen;
+ size_t consumed;
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;
bool data_eof_handled = FALSE;
- DEBUGASSERT(buf);
+ DEBUGASSERT(data->state.buffer);
*done = FALSE;
*comeback = FALSE;
@@ -439,8 +444,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
read or we get a CURLE_AGAIN */
do {
bool is_empty_data = FALSE;
- size_t buffersize = data->set.buffer_size;
- size_t bytestoread = buffersize;
+ size_t bytestoread = data->set.buffer_size;
/* For HTTP/2 and HTTP/3, read data without caring about the content
length. This is safe because body in HTTP/2 is always segmented
thanks to its framing layer. Meanwhile, we have to call Curl_read
@@ -449,31 +453,38 @@ static CURLcode readwrite_data(struct Curl_easy *data,
bool is_http3 = Curl_conn_is_http3(data, conn, FIRSTSOCKET);
data_eof_handled = is_http3 || Curl_conn_is_http2(data, conn, FIRSTSOCKET);
- if(!data_eof_handled && k->size != -1 && !k->header) {
- /* make sure we don't read too much */
+ /* Each loop iteration starts with a fresh buffer and handles
+ * all data read into it. */
+ buf = data->state.buffer;
+ blen = 0;
+
+ /* If we are reading BODY data and the connection does NOT handle EOF
+ * and we know the size of the BODY data, limit the read amount */
+ if(!k->header && !data_eof_handled && k->size != -1) {
curl_off_t totalleft = k->size - k->bytecount;
- if(totalleft < (curl_off_t)bytestoread)
+ if(totalleft <= 0)
+ bytestoread = 0;
+ else if(totalleft < (curl_off_t)bytestoread)
bytestoread = (size_t)totalleft;
}
if(bytestoread) {
/* receive data from the network! */
+ ssize_t nread; /* number of bytes read */
result = Curl_read(data, conn->sockfd, buf, bytestoread, &nread);
-
- /* read would've blocked */
if(CURLE_AGAIN == result) {
result = CURLE_OK;
break; /* get out of loop */
}
-
- if(result>0)
+ else if(result)
goto out;
+ DEBUGASSERT(nread >= 0);
+ blen = (size_t)nread;
}
else {
/* read nothing but since we wanted nothing we consider this an OK
situation to proceed from */
DEBUGF(infof(data, "readwrite_data: we're done"));
- nread = 0;
}
if(!k->bytecount) {
@@ -485,12 +496,17 @@ static CURLcode readwrite_data(struct Curl_easy *data,
*didwhat |= KEEP_RECV;
/* indicates data of zero size, i.e. empty file */
- is_empty_data = ((nread == 0) && (k->bodywrites == 0)) ? TRUE : FALSE;
-
- if(0 < nread || is_empty_data) {
- buf[nread] = 0;
+ is_empty_data = ((blen == 0) && (k->bodywrites == 0)) ? TRUE : FALSE;
+
+ if(0 < blen || is_empty_data) {
+ /* data->state.buffer is allocated 1 byte larger than
+ * data->set.buffer_size admits. *wink* */
+ /* TODO: we should really not rely on this being 0-terminated, since
+ * the actual data read might contain 0s. */
+ buf[blen] = 0;
}
- if(!nread) {
+
+ if(!blen) {
/* if we receive 0 or less here, either the data transfer is done or the
server closed the connection and we bail out from this! */
if(data_eof_handled)
@@ -502,48 +518,70 @@ static CURLcode readwrite_data(struct Curl_easy *data,
break;
}
- /* Default buffer to use when we write the buffer, it may be changed
- in the flow below before the actual storing is done. */
- k->str = buf;
-
if(conn->handler->readwrite) {
- result = conn->handler->readwrite(data, conn, &nread, &readmore);
+ bool readmore = FALSE; /* indicates data is incomplete, need more */
+ consumed = 0;
+ result = conn->handler->readwrite(data, conn, buf, blen,
+ &consumed, &readmore);
if(result)
goto out;
if(readmore)
break;
+ buf += consumed;
+ blen -= consumed;
+ if(k->download_done) {
+ /* We've stopped dealing with input, get out of the do-while loop */
+ if(blen > 0) {
+ infof(data,
+ "Excess found:"
+ " excess = %zu"
+ " url = %s (zero-length body)",
+ blen, data->state.up.path);
+ }
+
+ /* we make sure that this socket isn't read more now */
+ k->keepon &= ~KEEP_RECV;
+ break;
+ }
}
#ifndef CURL_DISABLE_HTTP
/* Since this is a two-state thing, we check if we are parsing
headers at the moment or not. */
if(k->header) {
- /* we are in parse-the-header-mode */
- bool stop_reading = FALSE;
- result = Curl_http_readwrite_headers(data, conn, &nread, &stop_reading);
+ consumed = 0;
+ result = Curl_http_readwrite_headers(data, conn, buf, blen, &consumed);
if(result)
goto out;
+ buf += consumed;
+ blen -= consumed;
if(conn->handler->readwrite &&
- (k->maxdownload <= 0 && nread > 0)) {
- result = conn->handler->readwrite(data, conn, &nread, &readmore);
+ (k->maxdownload <= 0 && blen > 0)) {
+ bool readmore = FALSE; /* indicates data is incomplete, need more */
+ consumed = 0;
+ result = conn->handler->readwrite(data, conn, buf, blen,
+ &consumed, &readmore);
if(result)
goto out;
if(readmore)
break;
+ buf += consumed;
+ blen -= consumed;
}
- if(stop_reading) {
+ if(k->download_done) {
/* We've stopped dealing with input, get out of the do-while loop */
-
- if(nread > 0) {
+ if(blen > 0) {
infof(data,
"Excess found:"
- " excess = %zd"
+ " excess = %zu"
" url = %s (zero-length body)",
- nread, data->state.up.path);
+ blen, data->state.up.path);
}
+ /* we make sure that this socket isn't read more now */
+ k->keepon &= ~KEEP_RECV;
break;
}
}
@@ -553,11 +591,13 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* This is not an 'else if' since it may be a rest from the header
parsing, where the beginning of the buffer is headers and the end
is non-headers. */
- if(!k->header && (nread > 0 || is_empty_data)) {
+ if(!k->header && (blen > 0 || is_empty_data)) {
- if(data->req.no_body) {
+ if(data->req.no_body && blen > 0) {
/* data arrives although we want none, bail out */
streamclose(conn, "ignoring body");
+ DEBUGF(infof(data, "did not want a BODY, but seeing %zu bytes",
+ blen));
*done = TRUE;
result = CURLE_WEIRD_SERVER_REPLY;
goto out;
@@ -576,34 +616,18 @@ static CURLcode readwrite_data(struct Curl_easy *data,
} /* this is the first time we write a body part */
#endif /* CURL_DISABLE_HTTP */
- k->bodywrites++;
-
- /* pass data to the debug function before it gets "dechunked" */
- if(data->set.verbose) {
- if(k->badheader) {
- Curl_debug(data, CURLINFO_DATA_IN,
- Curl_dyn_ptr(&data->state.headerb),
- Curl_dyn_len(&data->state.headerb));
- if(k->badheader == HEADER_PARTHEADER)
- Curl_debug(data, CURLINFO_DATA_IN,
- k->str, (size_t)nread);
- }
- else
- Curl_debug(data, CURLINFO_DATA_IN,
- k->str, (size_t)nread);
- }
-
#ifndef CURL_DISABLE_HTTP
if(k->chunk) {
/*
* Here comes a chunked transfer flying and we need to decode this
* properly. While the name says read, this function both reads
- * and writes away the data. The returned 'nread' holds the number
- * of actual data it wrote to the client.
+ * and writes away the data.
*/
CURLcode extra;
- CHUNKcode res =
- Curl_httpchunk_read(data, k->str, nread, &nread, &extra);
+ CHUNKcode res;
+
+ consumed = 0;
+ res = Curl_httpchunk_read(data, buf, blen, &consumed, &extra);
if(CHUNKE_OK < res) {
if(CHUNKE_PASSTHRU_ERROR == res) {
@@ -615,9 +639,14 @@ static CURLcode readwrite_data(struct Curl_easy *data,
result = CURLE_RECV_ERROR;
goto out;
}
- if(CHUNKE_STOP == res) {
+
+ buf += consumed;
+ blen -= consumed;
+ if(CHUNKE_STOP == res) {
/* we're done reading chunks! */
k->keepon &= ~KEEP_RECV; /* read no more */
+ /* chunks read successfully, download is complete */
+ k->download_done = TRUE;
/* N number of bytes at the end of the str buffer that weren't
written to the client. */
@@ -631,117 +660,57 @@ static CURLcode readwrite_data(struct Curl_easy *data,
}
#endif /* CURL_DISABLE_HTTP */
- /* Account for body content stored in the header buffer */
- if((k->badheader == HEADER_PARTHEADER) && !k->ignorebody) {
- size_t headlen = Curl_dyn_len(&data->state.headerb);
- DEBUGF(infof(data, "Increasing bytecount by %zu", headlen));
- k->bytecount += headlen;
- }
-
- if((-1 != k->maxdownload) &&
- (k->bytecount + nread >= k->maxdownload)) {
+ max_recv -= blen;
- excess = (size_t)(k->bytecount + nread - k->maxdownload);
- if(excess > 0 && !k->ignorebody) {
- infof(data,
- "Excess found in a read:"
- " excess = %zu"
- ", size = %" CURL_FORMAT_CURL_OFF_T
- ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
- ", bytecount = %" CURL_FORMAT_CURL_OFF_T,
- excess, k->size, k->maxdownload, k->bytecount);
- connclose(conn, "excess found in a read");
- }
-
- nread = (ssize_t) (k->maxdownload - k->bytecount);
- if(nread < 0) /* this should be unusual */
- nread = 0;
-
- /* HTTP/3 over QUIC should keep reading until QUIC connection
- is closed. In contrast to HTTP/2 which can stop reading
- from TCP connection, HTTP/3 over QUIC needs ACK from server
- to ensure stream closure. It should keep reading. */
- if(!is_http3) {
- k->keepon &= ~KEEP_RECV; /* we're done reading */
- }
- }
-
- k->bytecount += nread;
- max_recv -= nread;
-
- result = Curl_pgrsSetDownloadCounter(data, k->bytecount);
- if(result)
- goto out;
-
- if(!k->chunk && (nread || k->badheader || is_empty_data)) {
+ if(!k->chunk && (blen || k->badheader || is_empty_data)) {
/* If this is chunky transfer, it was already written */
- if(k->badheader && !k->ignorebody) {
+ if(k->badheader) {
/* we parsed a piece of data wrongly assuming it was a header
and now we output it as body instead */
size_t headlen = Curl_dyn_len(&data->state.headerb);
/* Don't let excess data pollute body writes */
- if(k->maxdownload == -1 || (curl_off_t)headlen <= k->maxdownload)
- result = Curl_client_write(data, CLIENTWRITE_BODY,
- Curl_dyn_ptr(&data->state.headerb),
- headlen);
- else
- result = Curl_client_write(data, CLIENTWRITE_BODY,
- Curl_dyn_ptr(&data->state.headerb),
- (size_t)k->maxdownload);
+ if(k->maxdownload != -1 && (curl_off_t)headlen > k->maxdownload)
+ headlen = (size_t)k->maxdownload;
+ result = Curl_client_write(data, CLIENTWRITE_BODY,
+ Curl_dyn_ptr(&data->state.headerb),
+ headlen);
if(result)
goto out;
}
- if(k->badheader < HEADER_ALLBAD) {
- /* This switch handles various content encodings. If there's an
- error here, be sure to check over the almost identical code
- in http_chunks.c.
- Make sure that ALL_CONTENT_ENCODINGS contains all the
- encodings handled here. */
- if(!k->ignorebody && nread) {
+
+ if(blen) {
#ifndef CURL_DISABLE_POP3
- if(conn->handler->protocol & PROTO_FAMILY_POP3)
- result = Curl_pop3_write(data, k->str, nread);
- else
-#endif /* CURL_DISABLE_POP3 */
- result = Curl_client_write(data, CLIENTWRITE_BODY, k->str,
- nread);
+ if(conn->handler->protocol & PROTO_FAMILY_POP3) {
+ result = k->ignorebody? CURLE_OK :
+ Curl_pop3_write(data, buf, blen);
}
+ else
+#endif /* CURL_DISABLE_POP3 */
+ result = Curl_client_write(data, CLIENTWRITE_BODY, buf, blen);
}
- k->badheader = HEADER_NORMAL; /* taken care of now */
+ k->badheader = FALSE; /* taken care of now */
if(result)
goto out;
}
- } /* if(!header and data to read) */
-
- if(conn->handler->readwrite && excess) {
- /* Parse the excess data */
- k->str += nread;
-
- if(&k->str[excess] > &buf[data->set.buffer_size]) {
- /* the excess amount was too excessive(!), make sure
- it doesn't read out of buffer */
- excess = &buf[data->set.buffer_size] - k->str;
+ if(k->download_done && !is_http3) {
+ /* HTTP/3 over QUIC should keep reading until QUIC connection
+ is closed. In contrast to HTTP/2 which can stop reading
+ from TCP connection, HTTP/3 over QUIC needs ACK from server
+ to ensure stream closure. It should keep reading. */
+ k->keepon &= ~KEEP_RECV; /* we're done reading */
}
- nread = (ssize_t)excess;
-
- result = conn->handler->readwrite(data, conn, &nread, &readmore);
- if(result)
- goto out;
-
- if(readmore)
- k->keepon |= KEEP_RECV; /* we're not done reading */
- break;
- }
+ } /* if(!header and data to read) */
if(is_empty_data) {
/* if we received nothing, the server closed the connection and we
are done */
k->keepon &= ~KEEP_RECV;
+ k->download_done = TRUE;
}
if((k->keepon & KEEP_RECV_PAUSE) || !(k->keepon & KEEP_RECV)) {
@@ -764,6 +733,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
on from our side, we need to stop that immediately. */
infof(data, "we are done reading and this is set to close, stop send");
k->keepon &= ~KEEP_SEND; /* no writing anymore either */
+ k->keepon &= ~KEEP_SEND_PAUSE; /* no pausing anymore either */
}
out:
@@ -783,7 +753,7 @@ CURLcode Curl_done_sending(struct Curl_easy *data,
return CURLE_OK;
}
-#if defined(WIN32) && defined(USE_WINSOCK)
+#if defined(_WIN32) && defined(USE_WINSOCK)
#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
#endif
@@ -977,7 +947,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
if(result)
return result;
-#if defined(WIN32) && defined(USE_WINSOCK)
+#if defined(_WIN32) && defined(USE_WINSOCK)
{
struct curltime n = Curl_now();
if(Curl_timediff(n, k->last_sndbuf_update) > 1000) {
@@ -1430,8 +1400,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
}
wc = data->wildcard;
- if((wc->state < CURLWC_INIT) ||
- (wc->state >= CURLWC_CLEAN)) {
+ if(wc->state < CURLWC_INIT) {
if(wc->ftpwc)
wc->dtor(wc->ftpwc);
Curl_safefree(wc->pattern);
@@ -1635,7 +1604,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
return Curl_uc_to_curlcode(uc);
}
- p = Curl_builtin_scheme(scheme, CURL_ZERO_TERMINATED);
+ p = Curl_get_scheme_handler(scheme);
if(p && (p->protocol != data->info.conn_protocol)) {
infof(data, "Clear auth, redirects scheme from %s to %s",
data->info.conn_scheme, scheme);
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index 61dad44..b81785f 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/url.c
@@ -168,130 +168,6 @@ static curl_prot_t get_protocol_family(const struct Curl_handler *h)
return h->family;
}
-
-/*
- * Protocol table. Schemes (roughly) in 2019 popularity order:
- *
- * HTTPS, HTTP, FTP, FTPS, SFTP, FILE, SCP, SMTP, LDAP, IMAPS, TELNET, IMAP,
- * LDAPS, SMTPS, TFTP, SMB, POP3, GOPHER POP3S, RTSP, RTMP, SMBS, DICT
- */
-static const struct Curl_handler * const protocols[] = {
-
-#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
- &Curl_handler_https,
-#endif
-
-#ifndef CURL_DISABLE_HTTP
- &Curl_handler_http,
-#endif
-
-#ifdef USE_WEBSOCKETS
-#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
- &Curl_handler_wss,
-#endif
-
-#ifndef CURL_DISABLE_HTTP
- &Curl_handler_ws,
-#endif
-#endif
-
-#ifndef CURL_DISABLE_FTP
- &Curl_handler_ftp,
-#endif
-
-#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
- &Curl_handler_ftps,
-#endif
-
-#if defined(USE_SSH)
- &Curl_handler_sftp,
-#endif
-
-#ifndef CURL_DISABLE_FILE
- &Curl_handler_file,
-#endif
-
-#if defined(USE_SSH) && !defined(USE_WOLFSSH)
- &Curl_handler_scp,
-#endif
-
-#ifndef CURL_DISABLE_SMTP
- &Curl_handler_smtp,
-#ifdef USE_SSL
- &Curl_handler_smtps,
-#endif
-#endif
-
-#ifndef CURL_DISABLE_LDAP
- &Curl_handler_ldap,
-#if !defined(CURL_DISABLE_LDAPS) && \
- ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
- (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
- &Curl_handler_ldaps,
-#endif
-#endif
-
-#ifndef CURL_DISABLE_IMAP
- &Curl_handler_imap,
-#ifdef USE_SSL
- &Curl_handler_imaps,
-#endif
-#endif
-
-#ifndef CURL_DISABLE_TELNET
- &Curl_handler_telnet,
-#endif
-
-#ifndef CURL_DISABLE_TFTP
- &Curl_handler_tftp,
-#endif
-
-#ifndef CURL_DISABLE_POP3
- &Curl_handler_pop3,
-#ifdef USE_SSL
- &Curl_handler_pop3s,
-#endif
-#endif
-
-#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
- (SIZEOF_CURL_OFF_T > 4)
- &Curl_handler_smb,
-#ifdef USE_SSL
- &Curl_handler_smbs,
-#endif
-#endif
-
-#ifndef CURL_DISABLE_RTSP
- &Curl_handler_rtsp,
-#endif
-
-#ifndef CURL_DISABLE_MQTT
- &Curl_handler_mqtt,
-#endif
-
-#ifndef CURL_DISABLE_GOPHER
- &Curl_handler_gopher,
-#ifdef USE_SSL
- &Curl_handler_gophers,
-#endif
-#endif
-
-#ifdef USE_LIBRTMP
- &Curl_handler_rtmp,
- &Curl_handler_rtmpt,
- &Curl_handler_rtmpe,
- &Curl_handler_rtmpte,
- &Curl_handler_rtmps,
- &Curl_handler_rtmpts,
-#endif
-
-#ifndef CURL_DISABLE_DICT
- &Curl_handler_dict,
-#endif
-
- (struct Curl_handler *) NULL
-};
-
void Curl_freeset(struct Curl_easy *data)
{
/* Free all dynamic strings stored in the data->set substructure. */
@@ -320,8 +196,8 @@ void Curl_freeset(struct Curl_easy *data)
Curl_mime_cleanpart(&data->set.mimepost);
#ifndef CURL_DISABLE_COOKIES
- curl_slist_free_all(data->set.cookielist);
- data->set.cookielist = NULL;
+ curl_slist_free_all(data->state.cookielist);
+ data->state.cookielist = NULL;
#endif
}
@@ -363,16 +239,18 @@ CURLcode Curl_close(struct Curl_easy **datap)
/* Detach connection if any is left. This should not be normal, but can be
the case for example with CONNECT_ONLY + recv/send (test 556) */
Curl_detach_connection(data);
- if(data->multi)
- /* This handle is still part of a multi handle, take care of this first
- and detach this handle from there. */
- curl_multi_remove_handle(data->multi, data);
+ if(!data->state.internal) {
+ if(data->multi)
+ /* This handle is still part of a multi handle, take care of this first
+ and detach this handle from there. */
+ curl_multi_remove_handle(data->multi, data);
- if(data->multi_easy) {
- /* when curl_easy_perform() is used, it creates its own multi handle to
- use and this is the one */
- curl_multi_cleanup(data->multi_easy);
- data->multi_easy = NULL;
+ if(data->multi_easy) {
+ /* when curl_easy_perform() is used, it creates its own multi handle to
+ use and this is the one */
+ curl_multi_cleanup(data->multi_easy);
+ data->multi_easy = NULL;
+ }
}
data->magic = 0; /* force a clear AFTER the possibly enforced removal from
@@ -412,7 +290,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
#ifndef CURL_DISABLE_HSTS
if(!data->share || !data->share->hsts)
Curl_hsts_cleanup(&data->hsts);
- curl_slist_free_all(data->set.hstslist); /* clean up list */
+ curl_slist_free_all(data->state.hstslist); /* clean up list */
#endif
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
Curl_http_auth_cleanup_digest(data);
@@ -420,10 +298,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_safefree(data->info.contenttype);
Curl_safefree(data->info.wouldredirect);
- /* this destroys the channel and we cannot use it anymore after this */
- Curl_resolver_cancel(data);
- Curl_resolver_cleanup(data->state.async.resolver);
-
data_priority_cleanup(data);
/* No longer a dirty share, if it exists */
@@ -457,8 +331,8 @@ CURLcode Curl_close(struct Curl_easy **datap)
}
#endif
- Curl_mime_cleanpart(data->state.formp);
#ifndef CURL_DISABLE_HTTP
+ Curl_mime_cleanpart(data->state.formp);
Curl_safefree(data->state.formp);
#endif
@@ -530,26 +404,16 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
Curl_mime_initpart(&set->mimepost);
- /*
- * libcurl 7.10 introduced SSL verification *by default*! This needs to be
- * switched off unless wanted.
- */
+ Curl_ssl_easy_config_init(data);
#ifndef CURL_DISABLE_DOH
set->doh_verifyhost = TRUE;
set->doh_verifypeer = TRUE;
#endif
- set->ssl.primary.verifypeer = TRUE;
- set->ssl.primary.verifyhost = TRUE;
#ifdef USE_SSH
/* defaults to any auth type */
set->ssh_auth_types = CURLSSH_AUTH_DEFAULT;
set->new_directory_perms = 0755; /* Default permissions */
#endif
- set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by
- default */
-#ifndef CURL_DISABLE_PROXY
- set->proxy_ssl = set->ssl;
-#endif
set->new_file_perms = 0644; /* Default permissions */
set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL;
@@ -650,13 +514,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->magic = CURLEASY_MAGIC_NUMBER;
- result = Curl_resolver_init(data, &data->state.async.resolver);
- if(result) {
- DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
- free(data);
- return result;
- }
-
result = Curl_init_userdefined(data);
if(!result) {
Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
@@ -673,7 +530,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
}
if(result) {
- Curl_resolver_cleanup(data->state.async.resolver);
Curl_dyn_free(&data->state.headerb);
Curl_freeset(data);
free(data);
@@ -707,6 +563,7 @@ static void conn_free(struct Curl_easy *data, struct connectdata *conn)
Curl_conn_cf_discard_all(data, conn, (int)i);
}
+ Curl_resolver_cleanup(conn->resolve_async.resolver);
Curl_free_idnconverted_hostname(&conn->host);
Curl_free_idnconverted_hostname(&conn->conn_to_host);
#ifndef CURL_DISABLE_PROXY
@@ -718,7 +575,6 @@ static void conn_free(struct Curl_easy *data, struct connectdata *conn)
Curl_safefree(conn->socks_proxy.passwd);
Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
- Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
#endif
Curl_safefree(conn->user);
Curl_safefree(conn->passwd);
@@ -733,7 +589,7 @@ static void conn_free(struct Curl_easy *data, struct connectdata *conn)
Curl_safefree(conn->hostname_resolve);
Curl_safefree(conn->secondaryhostname);
Curl_safefree(conn->localdev);
- Curl_free_primary_ssl_config(&conn->ssl_config);
+ Curl_ssl_conn_config_cleanup(conn);
#ifdef USE_UNIX_SOCKETS
Curl_safefree(conn->unix_domain_socket);
@@ -807,6 +663,7 @@ void Curl_disconnect(struct Curl_easy *data,
conn->handler->disconnect(data, conn, dead_connection);
conn_shutdown(data);
+ Curl_resolver_cancel(data);
/* detach it again */
Curl_detach_connection(data);
@@ -1059,11 +916,11 @@ ConnectionExists(struct Curl_easy *data,
bool *force_reuse,
bool *waitpipe)
{
- struct connectdata *check;
- struct connectdata *chosen = 0;
+ struct connectdata *chosen = NULL;
bool foundPendingCandidate = FALSE;
- bool canmultiplex = IsMultiplexingPossible(data, needle);
+ bool canmultiplex = FALSE;
struct connectbundle *bundle;
+ struct Curl_llist_element *curr;
#ifdef USE_NTLM
bool wantNTLMhttp = ((data->state.authhost.want &
@@ -1082,395 +939,368 @@ ConnectionExists(struct Curl_easy *data,
bool h2upgrade = (data->state.httpwant == CURL_HTTP_VERSION_2_0) &&
(needle->handler->protocol & CURLPROTO_HTTP);
+ *usethis = NULL;
*force_reuse = FALSE;
*waitpipe = FALSE;
/* Look up the bundle with all the connections to this particular host.
Locks the connection cache, beware of early returns! */
bundle = Curl_conncache_find_bundle(data, needle, data->state.conn_cache);
- if(bundle) {
- /* Max pipe length is zero (unlimited) for multiplexed connections */
- struct Curl_llist_element *curr;
-
- infof(data, "Found bundle for host: %p [%s]",
- (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ?
- "can multiplex" : "serially"));
-
- /* We can't multiplex if we don't know anything about the server */
- if(canmultiplex) {
- if(bundle->multiuse == BUNDLE_UNKNOWN) {
- if(data->set.pipewait) {
- infof(data, "Server doesn't support multiplex yet, wait");
- *waitpipe = TRUE;
- CONNCACHE_UNLOCK(data);
- return FALSE; /* no reuse */
- }
-
- infof(data, "Server doesn't support multiplex (yet)");
- canmultiplex = FALSE;
+ if(!bundle) {
+ CONNCACHE_UNLOCK(data);
+ return FALSE;
+ }
+ infof(data, "Found bundle for host: %p [%s]",
+ (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ?
+ "can multiplex" : "serially"));
+
+ /* We can only multiplex iff the transfer allows it AND we know
+ * that the server we want to talk to supports it as well. */
+ canmultiplex = FALSE;
+ if(IsMultiplexingPossible(data, needle)) {
+ if(bundle->multiuse == BUNDLE_UNKNOWN) {
+ if(data->set.pipewait) {
+ infof(data, "Server doesn't support multiplex yet, wait");
+ *waitpipe = TRUE;
+ CONNCACHE_UNLOCK(data);
+ return FALSE; /* no reuse */
}
- if((bundle->multiuse == BUNDLE_MULTIPLEX) &&
- !Curl_multiplex_wanted(data->multi)) {
+ infof(data, "Server doesn't support multiplex (yet)");
+ }
+ else if(bundle->multiuse == BUNDLE_MULTIPLEX) {
+ if(Curl_multiplex_wanted(data->multi))
+ canmultiplex = TRUE;
+ else
infof(data, "Could multiplex, but not asked to");
- canmultiplex = FALSE;
- }
- if(bundle->multiuse == BUNDLE_NO_MULTIUSE) {
- infof(data, "Can not multiplex, even if we wanted to");
- canmultiplex = FALSE;
- }
}
+ else if(bundle->multiuse == BUNDLE_NO_MULTIUSE) {
+ infof(data, "Can not multiplex, even if we wanted to");
+ }
+ }
- curr = bundle->conn_list.head;
- while(curr) {
- bool match = FALSE;
- size_t multiplexed = 0;
+ curr = bundle->conn_list.head;
+ while(curr) {
+ struct connectdata *check = curr->ptr;
+ /* Get next node now. We might remove a dead `check` connection which
+ * would invalidate `curr` as well. */
+ curr = curr->next;
- /*
- * Note that if we use an HTTP proxy in normal mode (no tunneling), we
- * check connections to that proxy and not to the actual remote server.
- */
- check = curr->ptr;
- curr = curr->next;
+ /* Note that if we use an HTTP proxy in normal mode (no tunneling), we
+ * check connections to that proxy and not to the actual remote server.
+ */
+ if(check->connect_only || check->bits.close)
+ /* connect-only or to-be-closed connections will not be reused */
+ continue;
- if(check->connect_only || check->bits.close)
- /* connect-only or to-be-closed connections will not be reused */
- continue;
+ if(data->set.ipver != CURL_IPRESOLVE_WHATEVER
+ && data->set.ipver != check->ip_version) {
+ /* skip because the connection is not via the requested IP version */
+ continue;
+ }
- if(extract_if_dead(check, data)) {
- /* disconnect it */
- Curl_disconnect(data, check, TRUE);
+ if(!canmultiplex) {
+ if(Curl_resolver_asynch() &&
+ /* primary_ip[0] is NUL only if the resolving of the name hasn't
+ completed yet and until then we don't reuse this connection */
+ !check->primary_ip[0])
continue;
- }
+ }
- if(data->set.ipver != CURL_IPRESOLVE_WHATEVER
- && data->set.ipver != check->ip_version) {
- /* skip because the connection is not via the requested IP version */
+ if(CONN_INUSE(check)) {
+ if(!canmultiplex) {
+ /* transfer can't be multiplexed and check is in use */
continue;
}
-
- if(bundle->multiuse == BUNDLE_MULTIPLEX)
- multiplexed = CONN_INUSE(check);
-
- if(!canmultiplex) {
- if(multiplexed) {
- /* can only happen within multi handles, and means that another easy
- handle is using this connection */
- continue;
- }
-
- if(Curl_resolver_asynch() &&
- /* primary_ip[0] is NUL only if the resolving of the name hasn't
- completed yet and until then we don't reuse this connection */
- !check->primary_ip[0])
+ else {
+ /* Could multiplex, but not when check belongs to another multi */
+ struct Curl_llist_element *e = check->easyq.head;
+ struct Curl_easy *entry = e->ptr;
+ if(entry->multi != data->multi)
continue;
}
+ }
- if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
- foundPendingCandidate = TRUE;
- /* Don't pick a connection that hasn't connected yet */
- infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T
- " isn't open enough, can't reuse", check->connection_id);
- continue;
- }
+ if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
+ foundPendingCandidate = TRUE;
+ /* Don't pick a connection that hasn't connected yet */
+ infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T
+ " isn't open enough, can't reuse", check->connection_id);
+ continue;
+ }
+
+ /* `check` is connected. if it is in use and does not support multiplex,
+ * we cannot use it. */
+ if(!check->bits.multiplex && CONN_INUSE(check))
+ continue;
#ifdef USE_UNIX_SOCKETS
- if(needle->unix_domain_socket) {
- if(!check->unix_domain_socket)
- continue;
- if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
- continue;
- if(needle->bits.abstract_unix_socket !=
- check->bits.abstract_unix_socket)
- continue;
- }
- else if(check->unix_domain_socket)
+ if(needle->unix_domain_socket) {
+ if(!check->unix_domain_socket)
continue;
-#endif
-
- if((needle->handler->flags&PROTOPT_SSL) !=
- (check->handler->flags&PROTOPT_SSL))
- /* don't do mixed SSL and non-SSL connections */
- if(get_protocol_family(check->handler) !=
- needle->handler->protocol || !check->bits.tls_upgraded)
- /* except protocols that have been upgraded via TLS */
- continue;
-
-#ifndef CURL_DISABLE_PROXY
- if(needle->bits.httpproxy != check->bits.httpproxy ||
- needle->bits.socksproxy != check->bits.socksproxy)
+ if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
continue;
-
- if(needle->bits.socksproxy &&
- !socks_proxy_info_matches(&needle->socks_proxy,
- &check->socks_proxy))
+ if(needle->bits.abstract_unix_socket !=
+ check->bits.abstract_unix_socket)
continue;
+ }
+ else if(check->unix_domain_socket)
+ continue;
#endif
- if(needle->bits.conn_to_host != check->bits.conn_to_host)
- /* don't mix connections that use the "connect to host" feature and
- * connections that don't use this feature */
- continue;
- if(needle->bits.conn_to_port != check->bits.conn_to_port)
- /* don't mix connections that use the "connect to port" feature and
- * connections that don't use this feature */
+ if((needle->handler->flags&PROTOPT_SSL) !=
+ (check->handler->flags&PROTOPT_SSL))
+ /* don't do mixed SSL and non-SSL connections */
+ if(get_protocol_family(check->handler) !=
+ needle->handler->protocol || !check->bits.tls_upgraded)
+ /* except protocols that have been upgraded via TLS */
continue;
-#ifndef CURL_DISABLE_PROXY
- if(needle->bits.httpproxy) {
- if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy))
- continue;
+ if(needle->bits.conn_to_host != check->bits.conn_to_host)
+ /* don't mix connections that use the "connect to host" feature and
+ * connections that don't use this feature */
+ continue;
- if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy)
- continue;
+ if(needle->bits.conn_to_port != check->bits.conn_to_port)
+ /* don't mix connections that use the "connect to port" feature and
+ * connections that don't use this feature */
+ continue;
- if(IS_HTTPS_PROXY(needle->http_proxy.proxytype)) {
- /* use https proxy */
- if(needle->http_proxy.proxytype !=
- check->http_proxy.proxytype)
- continue;
- else if(needle->handler->flags&PROTOPT_SSL) {
- /* use double layer ssl */
- if(!Curl_ssl_config_matches(&needle->proxy_ssl_config,
- &check->proxy_ssl_config))
- continue;
- }
- else if(!Curl_ssl_config_matches(&needle->ssl_config,
- &check->ssl_config))
- continue;
- }
- }
-#endif
+#ifndef CURL_DISABLE_PROXY
+ if(needle->bits.httpproxy != check->bits.httpproxy ||
+ needle->bits.socksproxy != check->bits.socksproxy)
+ continue;
- if(h2upgrade && !check->httpversion && canmultiplex) {
- if(data->set.pipewait) {
- infof(data, "Server upgrade doesn't support multiplex yet, wait");
- *waitpipe = TRUE;
- CONNCACHE_UNLOCK(data);
- return FALSE; /* no reuse */
- }
- infof(data, "Server upgrade cannot be used");
- continue; /* can't be used atm */
- }
+ if(needle->bits.socksproxy &&
+ !socks_proxy_info_matches(&needle->socks_proxy,
+ &check->socks_proxy))
+ continue;
- if(!canmultiplex && CONN_INUSE(check))
- /* this request can't be multiplexed but the checked connection is
- already in use so we skip it */
+ if(needle->bits.httpproxy) {
+ if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy)
continue;
- if(CONN_INUSE(check)) {
- /* Subject for multiplex use if 'checks' belongs to the same multi
- handle as 'data' is. */
- struct Curl_llist_element *e = check->easyq.head;
- struct Curl_easy *entry = e->ptr;
- if(entry->multi != data->multi)
- continue;
- }
+ if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy))
+ continue;
- if(needle->localdev || needle->localport) {
- /* If we are bound to a specific local end (IP+port), we must not
- reuse a random other one, although if we didn't ask for a
- particular one we can reuse one that was bound.
-
- This comparison is a bit rough and too strict. Since the input
- parameters can be specified in numerous ways and still end up the
- same it would take a lot of processing to make it really accurate.
- Instead, this matching will assume that reuses of bound connections
- will most likely also reuse the exact same binding parameters and
- missing out a few edge cases shouldn't hurt anyone very much.
- */
- if((check->localport != needle->localport) ||
- (check->localportrange != needle->localportrange) ||
- (needle->localdev &&
- (!check->localdev || strcmp(check->localdev, needle->localdev))))
+ if(IS_HTTPS_PROXY(needle->http_proxy.proxytype)) {
+ /* https proxies come in different types, http/1.1, h2, ... */
+ if(needle->http_proxy.proxytype != check->http_proxy.proxytype)
continue;
- }
-
- if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
- /* This protocol requires credentials per connection,
- so verify that we're using the same name and password as well */
- if(Curl_timestrcmp(needle->user, check->user) ||
- Curl_timestrcmp(needle->passwd, check->passwd) ||
- Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) ||
- Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) {
- /* one of them was different */
+ /* match SSL config to proxy */
+ if(!Curl_ssl_conn_config_match(data, check, TRUE)) {
+ DEBUGF(infof(data,
+ "Connection #%" CURL_FORMAT_CURL_OFF_T
+ " has different SSL proxy parameters, can't reuse",
+ check->connection_id));
continue;
}
+ /* the SSL config to the server, which may apply here is checked
+ * further below */
}
+ }
+#endif
- /* GSS delegation differences do not actually affect every connection
- and auth method, but this check takes precaution before efficiency */
- if(needle->gssapi_delegation != check->gssapi_delegation)
+ if(h2upgrade && !check->httpversion && canmultiplex) {
+ if(data->set.pipewait) {
+ infof(data, "Server upgrade doesn't support multiplex yet, wait");
+ *waitpipe = TRUE;
+ CONNCACHE_UNLOCK(data);
+ return FALSE; /* no reuse */
+ }
+ infof(data, "Server upgrade cannot be used");
+ continue; /* can't be used atm */
+ }
+
+ if(needle->localdev || needle->localport) {
+ /* If we are bound to a specific local end (IP+port), we must not
+ reuse a random other one, although if we didn't ask for a
+ particular one we can reuse one that was bound.
+
+ This comparison is a bit rough and too strict. Since the input
+ parameters can be specified in numerous ways and still end up the
+ same it would take a lot of processing to make it really accurate.
+ Instead, this matching will assume that reuses of bound connections
+ will most likely also reuse the exact same binding parameters and
+ missing out a few edge cases shouldn't hurt anyone very much.
+ */
+ if((check->localport != needle->localport) ||
+ (check->localportrange != needle->localportrange) ||
+ (needle->localdev &&
+ (!check->localdev || strcmp(check->localdev, needle->localdev))))
continue;
+ }
- /* If multiplexing isn't enabled on the h2 connection and h1 is
- explicitly requested, handle it: */
- if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
- (((check->httpversion >= 20) &&
- (data->state.httpwant < CURL_HTTP_VERSION_2_0))
- || ((check->httpversion >= 30) &&
- (data->state.httpwant < CURL_HTTP_VERSION_3))))
+ if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
+ /* This protocol requires credentials per connection,
+ so verify that we're using the same name and password as well */
+ if(Curl_timestrcmp(needle->user, check->user) ||
+ Curl_timestrcmp(needle->passwd, check->passwd) ||
+ Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) ||
+ Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) {
+ /* one of them was different */
continue;
-#ifdef USE_SSH
- else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
- if(!ssh_config_matches(needle, check))
- continue;
}
+ }
+
+ /* GSS delegation differences do not actually affect every connection
+ and auth method, but this check takes precaution before efficiency */
+ if(needle->gssapi_delegation != check->gssapi_delegation)
+ continue;
+
+ /* If looking for HTTP and the HTTP version we want is less
+ * than the HTTP version of the check connection, continue looking */
+ if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
+ (((check->httpversion >= 20) &&
+ (data->state.httpwant < CURL_HTTP_VERSION_2_0))
+ || ((check->httpversion >= 30) &&
+ (data->state.httpwant < CURL_HTTP_VERSION_3))))
+ continue;
+#ifdef USE_SSH
+ else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
+ if(!ssh_config_matches(needle, check))
+ continue;
+ }
#endif
#ifndef CURL_DISABLE_FTP
- else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) {
- /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */
- if(Curl_timestrcmp(needle->proto.ftpc.account,
- check->proto.ftpc.account) ||
- Curl_timestrcmp(needle->proto.ftpc.alternative_to_user,
- check->proto.ftpc.alternative_to_user) ||
- (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) ||
- (needle->proto.ftpc.ccc != check->proto.ftpc.ccc))
- continue;
- }
+ else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) {
+ /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */
+ if(Curl_timestrcmp(needle->proto.ftpc.account,
+ check->proto.ftpc.account) ||
+ Curl_timestrcmp(needle->proto.ftpc.alternative_to_user,
+ check->proto.ftpc.alternative_to_user) ||
+ (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) ||
+ (needle->proto.ftpc.ccc != check->proto.ftpc.ccc))
+ continue;
+ }
#endif
- if((needle->handler->flags&PROTOPT_SSL)
+ /* Additional match requirements if talking TLS OR
+ * not talking to a HTTP proxy OR using a tunnel through a proxy */
+ if((needle->handler->flags&PROTOPT_SSL)
#ifndef CURL_DISABLE_PROXY
- || !needle->bits.httpproxy || needle->bits.tunnel_proxy
-#endif
- ) {
- /* The requested connection does not use an HTTP proxy or it uses SSL
- or it is a non-SSL protocol tunneled or it is a non-SSL protocol
- which is allowed to be upgraded via TLS */
-
- if((strcasecompare(needle->handler->scheme, check->handler->scheme) ||
- (get_protocol_family(check->handler) ==
- needle->handler->protocol && check->bits.tls_upgraded)) &&
- (!needle->bits.conn_to_host || strcasecompare(
- needle->conn_to_host.name, check->conn_to_host.name)) &&
- (!needle->bits.conn_to_port ||
- needle->conn_to_port == check->conn_to_port) &&
- strcasecompare(needle->host.name, check->host.name) &&
- needle->remote_port == check->remote_port) {
- /* The schemes match or the protocol family is the same and the
- previous connection was TLS upgraded, and the hostname and host
- port match */
- if(needle->handler->flags & PROTOPT_SSL) {
- /* This is a SSL connection so verify that we're using the same
- SSL options as well */
- if(!Curl_ssl_config_matches(&needle->ssl_config,
- &check->ssl_config)) {
- DEBUGF(infof(data,
- "Connection #%" CURL_FORMAT_CURL_OFF_T
- " has different SSL parameters, can't reuse",
- check->connection_id));
- continue;
- }
- }
- match = TRUE;
- }
- }
- else {
- /* The requested connection is using the same HTTP proxy in normal
- mode (no tunneling) */
- match = TRUE;
+ || !needle->bits.httpproxy || needle->bits.tunnel_proxy
+#endif
+ ) {
+ /* Talking the same protocol scheme or a TLS upgraded protocol in the
+ * same protocol family? */
+ if(!strcasecompare(needle->handler->scheme, check->handler->scheme) &&
+ (get_protocol_family(check->handler) !=
+ needle->handler->protocol || !check->bits.tls_upgraded))
+ continue;
+
+ /* If needle has "conn_to_*" set, check must match this */
+ if((needle->bits.conn_to_host && !strcasecompare(
+ needle->conn_to_host.name, check->conn_to_host.name)) ||
+ (needle->bits.conn_to_port &&
+ needle->conn_to_port != check->conn_to_port))
+ continue;
+
+ /* hostname and port must match */
+ if(!strcasecompare(needle->host.name, check->host.name) ||
+ needle->remote_port != check->remote_port)
+ continue;
+
+ /* If talking TLS, check needs to use the same SSL options. */
+ if((needle->handler->flags & PROTOPT_SSL) &&
+ !Curl_ssl_conn_config_match(data, check, FALSE)) {
+ DEBUGF(infof(data,
+ "Connection #%" CURL_FORMAT_CURL_OFF_T
+ " has different SSL parameters, can't reuse",
+ check->connection_id));
+ continue;
}
+ }
- if(match) {
#if defined(USE_NTLM)
- /* If we are looking for an HTTP+NTLM connection, check if this is
- already authenticating with the right credentials. If not, keep
- looking so that we can reuse NTLM connections if
- possible. (Especially we must not reuse the same connection if
- partway through a handshake!) */
- if(wantNTLMhttp) {
- if(Curl_timestrcmp(needle->user, check->user) ||
- Curl_timestrcmp(needle->passwd, check->passwd)) {
-
- /* we prefer a credential match, but this is at least a connection
- that can be reused and "upgraded" to NTLM */
- if(check->http_ntlm_state == NTLMSTATE_NONE)
- chosen = check;
- continue;
- }
- }
- else if(check->http_ntlm_state != NTLMSTATE_NONE) {
- /* Connection is using NTLM auth but we don't want NTLM */
- continue;
- }
-
-#ifndef CURL_DISABLE_PROXY
- /* Same for Proxy NTLM authentication */
- if(wantProxyNTLMhttp) {
- /* Both check->http_proxy.user and check->http_proxy.passwd can be
- * NULL */
- if(!check->http_proxy.user || !check->http_proxy.passwd)
- continue;
-
- if(Curl_timestrcmp(needle->http_proxy.user,
- check->http_proxy.user) ||
- Curl_timestrcmp(needle->http_proxy.passwd,
- check->http_proxy.passwd))
- continue;
- }
- else if(check->proxy_ntlm_state != NTLMSTATE_NONE) {
- /* Proxy connection is using NTLM auth but we don't want NTLM */
- continue;
- }
-#endif
- if(wantNTLMhttp || wantProxyNTLMhttp) {
- /* Credentials are already checked, we can use this connection */
+ /* If we are looking for an HTTP+NTLM connection, check if this is
+ already authenticating with the right credentials. If not, keep
+ looking so that we can reuse NTLM connections if
+ possible. (Especially we must not reuse the same connection if
+ partway through a handshake!) */
+ if(wantNTLMhttp) {
+ if(Curl_timestrcmp(needle->user, check->user) ||
+ Curl_timestrcmp(needle->passwd, check->passwd)) {
+
+ /* we prefer a credential match, but this is at least a connection
+ that can be reused and "upgraded" to NTLM */
+ if(check->http_ntlm_state == NTLMSTATE_NONE)
chosen = check;
+ continue;
+ }
+ }
+ else if(check->http_ntlm_state != NTLMSTATE_NONE) {
+ /* Connection is using NTLM auth but we don't want NTLM */
+ continue;
+ }
- if((wantNTLMhttp &&
- (check->http_ntlm_state != NTLMSTATE_NONE)) ||
- (wantProxyNTLMhttp &&
- (check->proxy_ntlm_state != NTLMSTATE_NONE))) {
- /* We must use this connection, no other */
- *force_reuse = TRUE;
- break;
- }
+#ifndef CURL_DISABLE_PROXY
+ /* Same for Proxy NTLM authentication */
+ if(wantProxyNTLMhttp) {
+ /* Both check->http_proxy.user and check->http_proxy.passwd can be
+ * NULL */
+ if(!check->http_proxy.user || !check->http_proxy.passwd)
+ continue;
- /* Continue look up for a better connection */
- continue;
- }
+ if(Curl_timestrcmp(needle->http_proxy.user,
+ check->http_proxy.user) ||
+ Curl_timestrcmp(needle->http_proxy.passwd,
+ check->http_proxy.passwd))
+ continue;
+ }
+ else if(check->proxy_ntlm_state != NTLMSTATE_NONE) {
+ /* Proxy connection is using NTLM auth but we don't want NTLM */
+ continue;
+ }
+#endif
+ if(wantNTLMhttp || wantProxyNTLMhttp) {
+ /* Credentials are already checked, we may use this connection.
+ * With NTLM being weird as it is, we MUST use a
+ * connection where it has already been fully negotiated.
+ * If it has not, we keep on looking for a better one. */
+ chosen = check;
+
+ if((wantNTLMhttp &&
+ (check->http_ntlm_state != NTLMSTATE_NONE)) ||
+ (wantProxyNTLMhttp &&
+ (check->proxy_ntlm_state != NTLMSTATE_NONE))) {
+ /* We must use this connection, no other */
+ *force_reuse = TRUE;
+ break;
+ }
+ /* Continue look up for a better connection */
+ continue;
+ }
#endif
- if(canmultiplex) {
- /* We can multiplex if we want to. Let's continue looking for
- the optimal connection to use. */
-
- if(!multiplexed) {
- /* We have the optimal connection. Let's stop looking. */
- chosen = check;
- break;
- }
-#ifdef USE_NGHTTP2
- /* If multiplexed, make sure we don't go over concurrency limit */
- if(check->bits.multiplex) {
- if(multiplexed >= Curl_conn_get_max_concurrent(data, check,
- FIRSTSOCKET)) {
- infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
- multiplexed);
- continue;
- }
- else if(multiplexed >=
- Curl_multi_max_concurrent_streams(data->multi)) {
- infof(data, "client side MAX_CONCURRENT_STREAMS reached"
- ", skip (%zu)",
- multiplexed);
- continue;
- }
- }
-#endif
- /* When not multiplexed, we have a match here! */
- chosen = check;
- infof(data, "Multiplexed connection found");
- break;
- }
- else {
- /* We have found a connection. Let's stop searching. */
- chosen = check;
- break;
- }
+ if(CONN_INUSE(check)) {
+ DEBUGASSERT(canmultiplex);
+ DEBUGASSERT(check->bits.multiplex);
+ /* If multiplexed, make sure we don't go over concurrency limit */
+ if(CONN_INUSE(check) >=
+ Curl_multi_max_concurrent_streams(data->multi)) {
+ infof(data, "client side MAX_CONCURRENT_STREAMS reached"
+ ", skip (%zu)", CONN_INUSE(check));
+ continue;
}
+ if(CONN_INUSE(check) >=
+ Curl_conn_get_max_concurrent(data, check, FIRSTSOCKET)) {
+ infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
+ CONN_INUSE(check));
+ continue;
+ }
+ /* When not multiplexed, we have a match here! */
+ infof(data, "Multiplexed connection found");
+ }
+ else if(extract_if_dead(check, data)) {
+ /* disconnect it */
+ Curl_disconnect(data, check, TRUE);
+ continue;
}
- }
+
+ /* We have found a connection. Let's stop searching. */
+ chosen = check;
+ break;
+ } /* loop over connection bundle */
if(chosen) {
/* mark it as used before releasing the lock */
@@ -1561,17 +1391,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
#endif
- conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus;
- conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer;
- conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost;
- conn->ssl_config.ssl_options = data->set.ssl.primary.ssl_options;
-#ifndef CURL_DISABLE_PROXY
- conn->proxy_ssl_config.verifystatus =
- data->set.proxy_ssl.primary.verifystatus;
- conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer;
- conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost;
- conn->proxy_ssl_config.ssl_options = data->set.proxy_ssl.primary.ssl_options;
-#endif
conn->ip_version = data->set.ipver;
conn->connect_only = data->set.connect_only;
conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
@@ -1615,30 +1434,231 @@ error:
return NULL;
}
-/* returns the handler if the given scheme is built-in */
-const struct Curl_handler *Curl_builtin_scheme(const char *scheme,
- size_t schemelen)
+const struct Curl_handler *Curl_get_scheme_handler(const char *scheme)
{
- const struct Curl_handler * const *pp;
- const struct Curl_handler *p;
- /* Scan protocol handler table and match against 'scheme'. The handler may
- be changed later when the protocol specific setup function is called. */
- if(schemelen == CURL_ZERO_TERMINATED)
- schemelen = strlen(scheme);
- for(pp = protocols; (p = *pp) != NULL; pp++)
- if(strncasecompare(p->scheme, scheme, schemelen) && !p->scheme[schemelen])
- /* Protocol found in table. */
- return p;
- return NULL; /* not found */
+ return Curl_getn_scheme_handler(scheme, strlen(scheme));
}
+/* returns the handler if the given scheme is built-in */
+const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
+ size_t len)
+{
+ /* table generated by schemetable.c:
+ 1. gcc schemetable.c && ./a.out
+ 2. check how small the table gets
+ 3. tweak the hash algorithm, then rerun from 1
+ 4. when the table is good enough
+ 5. copy the table into this source code
+ 6. make sure this function uses the same hash function that worked for
+ schemetable.c
+ 7. if needed, adjust the #ifdefs in schemetable.c and rerun
+ */
+ static const struct Curl_handler * const protocols[67] = {
+#ifndef CURL_DISABLE_FILE
+ &Curl_handler_file,
+#else
+ NULL,
+#endif
+ NULL, NULL,
+#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)
+ &Curl_handler_gophers,
+#else
+ NULL,
+#endif
+ NULL,
+#ifdef USE_LIBRTMP
+ &Curl_handler_rtmpe,
+#else
+ NULL,
+#endif
+#ifndef CURL_DISABLE_SMTP
+ &Curl_handler_smtp,
+#else
+ NULL,
+#endif
+#if defined(USE_SSH)
+ &Curl_handler_sftp,
+#else
+ NULL,
+#endif
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
+ (SIZEOF_CURL_OFF_T > 4)
+ &Curl_handler_smb,
+#else
+ NULL,
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
+ &Curl_handler_smtps,
+#else
+ NULL,
+#endif
+#ifndef CURL_DISABLE_TELNET
+ &Curl_handler_telnet,
+#else
+ NULL,
+#endif
+#ifndef CURL_DISABLE_GOPHER
+ &Curl_handler_gopher,
+#else
+ NULL,
+#endif
+#ifndef CURL_DISABLE_TFTP
+ &Curl_handler_tftp,
+#else
+ NULL,
+#endif
+ NULL, NULL, NULL,
+#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
+ &Curl_handler_ftps,
+#else
+ NULL,
+#endif
+#ifndef CURL_DISABLE_HTTP
+ &Curl_handler_http,
+#else
+ NULL,
+#endif
+#ifndef CURL_DISABLE_IMAP
+ &Curl_handler_imap,
+#else
+ NULL,
+#endif
+#ifdef USE_LIBRTMP
+ &Curl_handler_rtmps,
+#else
+ NULL,
+#endif
+#ifdef USE_LIBRTMP
+ &Curl_handler_rtmpt,
+#else
+ NULL,
+#endif
+ NULL, NULL, NULL,
+#if !defined(CURL_DISABLE_LDAP) && \
+ !defined(CURL_DISABLE_LDAPS) && \
+ ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
+ (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
+ &Curl_handler_ldaps,
+#else
+ NULL,
+#endif
+#if defined(USE_WEBSOCKETS) && \
+ defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+ &Curl_handler_wss,
+#else
+ NULL,
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+ &Curl_handler_https,
+#else
+ NULL,
+#endif
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+#ifndef CURL_DISABLE_RTSP
+ &Curl_handler_rtsp,
+#else
+ NULL,
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_SMB) && \
+ defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)
+ &Curl_handler_smbs,
+#else
+ NULL,
+#endif
+#if defined(USE_SSH) && !defined(USE_WOLFSSH)
+ &Curl_handler_scp,
+#else
+ NULL,
+#endif
+ NULL, NULL, NULL,
+#ifndef CURL_DISABLE_POP3
+ &Curl_handler_pop3,
+#else
+ NULL,
+#endif
+ NULL, NULL,
+#ifdef USE_LIBRTMP
+ &Curl_handler_rtmp,
+#else
+ NULL,
+#endif
+ NULL, NULL, NULL,
+#ifdef USE_LIBRTMP
+ &Curl_handler_rtmpte,
+#else
+ NULL,
+#endif
+ NULL, NULL, NULL,
+#ifndef CURL_DISABLE_DICT
+ &Curl_handler_dict,
+#else
+ NULL,
+#endif
+ NULL, NULL, NULL,
+#ifndef CURL_DISABLE_MQTT
+ &Curl_handler_mqtt,
+#else
+ NULL,
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
+ &Curl_handler_pop3s,
+#else
+ NULL,
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
+ &Curl_handler_imaps,
+#else
+ NULL,
+#endif
+ NULL,
+#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+ &Curl_handler_ws,
+#else
+ NULL,
+#endif
+ NULL,
+#ifdef USE_LIBRTMP
+ &Curl_handler_rtmpts,
+#else
+ NULL,
+#endif
+#ifndef CURL_DISABLE_LDAP
+ &Curl_handler_ldap,
+#else
+ NULL,
+#endif
+ NULL, NULL,
+#ifndef CURL_DISABLE_FTP
+ &Curl_handler_ftp,
+#else
+ NULL,
+#endif
+ };
+
+ if(len && (len <= 7)) {
+ const char *s = scheme;
+ size_t l = len;
+ const struct Curl_handler *h;
+ unsigned int c = 978;
+ while(l) {
+ c <<= 5;
+ c += Curl_raw_tolower(*s);
+ s++;
+ l--;
+ }
+
+ h = protocols[c % 67];
+ if(h && strncasecompare(scheme, h->scheme, len) && !h->scheme[len])
+ return h;
+ }
+ return NULL;
+}
static CURLcode findprotocol(struct Curl_easy *data,
struct connectdata *conn,
const char *protostr)
{
- const struct Curl_handler *p = Curl_builtin_scheme(protostr,
- CURL_ZERO_TERMINATED);
+ const struct Curl_handler *p = Curl_get_scheme_handler(protostr);
if(p && /* Protocol found in table. Check if allowed */
(data->set.allowed_protocols & p->protocol)) {
@@ -1652,7 +1672,6 @@ static CURLcode findprotocol(struct Curl_easy *data,
else {
/* Perform setup complement if some. */
conn->handler = conn->given = p;
-
/* 'port' and 'remote_port' are set in setup_connection_internals() */
return CURLE_OK;
}
@@ -1705,14 +1724,14 @@ static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
conn->scope_id = (unsigned int)scope;
#if defined(HAVE_IF_NAMETOINDEX)
else {
-#elif defined(WIN32)
+#elif defined(_WIN32)
else if(Curl_if_nametoindex) {
#endif
-#if defined(HAVE_IF_NAMETOINDEX) || defined(WIN32)
+#if defined(HAVE_IF_NAMETOINDEX) || defined(_WIN32)
/* Zone identifier is not numeric */
unsigned int scopeidx = 0;
-#if defined(WIN32)
+#if defined(_WIN32)
scopeidx = Curl_if_nametoindex(zoneid);
#else
scopeidx = if_nametoindex(zoneid);
@@ -1727,7 +1746,7 @@ static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
else
conn->scope_id = scopeidx;
}
-#endif /* HAVE_IF_NAMETOINDEX || WIN32 */
+#endif /* HAVE_IF_NAMETOINDEX || _WIN32 */
free(zoneid);
}
@@ -3596,85 +3615,10 @@ static CURLcode create_conn(struct Curl_easy *data,
conn->send[SECONDARYSOCKET] = Curl_conn_send;
conn->bits.tcp_fastopen = data->set.tcp_fastopen;
- /* Get a cloned copy of the SSL config situation stored in the
- connection struct. But to get this going nicely, we must first make
- sure that the strings in the master copy are pointing to the correct
- strings in the session handle strings array!
-
- Keep in mind that the pointers in the master copy are pointing to strings
- that will be freed as part of the Curl_easy struct, but all cloned
- copies will be separately allocated.
- */
- data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH];
- data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE];
- data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
- data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
- data->set.ssl.primary.cipher_list =
- data->set.str[STRING_SSL_CIPHER_LIST];
- data->set.ssl.primary.cipher_list13 =
- data->set.str[STRING_SSL_CIPHER13_LIST];
- data->set.ssl.primary.pinned_key =
- data->set.str[STRING_SSL_PINNEDPUBLICKEY];
- data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT];
- data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
- data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES];
-
-#ifndef CURL_DISABLE_PROXY
- data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
- data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
- data->set.proxy_ssl.primary.cipher_list =
- data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
- data->set.proxy_ssl.primary.cipher_list13 =
- data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
- data->set.proxy_ssl.primary.pinned_key =
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
- data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
- data->set.proxy_ssl.primary.ca_info_blob =
- data->set.blobs[BLOB_CAINFO_PROXY];
- data->set.proxy_ssl.primary.issuercert =
- data->set.str[STRING_SSL_ISSUERCERT_PROXY];
- data->set.proxy_ssl.primary.issuercert_blob =
- data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
- data->set.proxy_ssl.primary.CRLfile =
- data->set.str[STRING_SSL_CRLFILE_PROXY];
- data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
- data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
- data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
- data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
- data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
- data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
-#endif
- data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE];
- data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE];
- data->set.ssl.key = data->set.str[STRING_KEY];
- data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE];
- data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD];
- data->set.ssl.primary.clientcert = data->set.str[STRING_CERT];
-#ifdef USE_TLS_SRP
- data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME];
- data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD];
-#ifndef CURL_DISABLE_PROXY
- data->set.proxy_ssl.primary.username =
- data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
- data->set.proxy_ssl.primary.password =
- data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
-#endif
-#endif
- data->set.ssl.key_blob = data->set.blobs[BLOB_KEY];
-
- if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary,
- &conn->ssl_config)) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
-
-#ifndef CURL_DISABLE_PROXY
- if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary,
- &conn->proxy_ssl_config)) {
- result = CURLE_OUT_OF_MEMORY;
+ /* Complete the easy's SSL configuration for connection cache matching */
+ result = Curl_ssl_easy_config_complete(data);
+ if(result)
goto out;
- }
-#endif
prune_dead_connections(data);
@@ -3789,7 +3733,41 @@ static CURLcode create_conn(struct Curl_easy *data,
* This is a brand new connection, so let's store it in the connection
* cache of ours!
*/
+ result = Curl_ssl_conn_config_init(data, conn);
+ if(result) {
+ DEBUGF(fprintf(stderr, "Error: init connection ssl config\n"));
+ goto out;
+ }
+
+ result = Curl_resolver_init(data, &conn->resolve_async.resolver);
+ if(result) {
+ DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
+ goto out;
+ }
+
Curl_attach_connection(data, conn);
+
+#ifdef USE_ARES
+ result = Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]);
+ if(result && result != CURLE_NOT_BUILT_IN)
+ goto out;
+
+ result = Curl_set_dns_interface(data,
+ data->set.str[STRING_DNS_INTERFACE]);
+ if(result && result != CURLE_NOT_BUILT_IN)
+ goto out;
+
+ result = Curl_set_dns_local_ip4(data,
+ data->set.str[STRING_DNS_LOCAL_IP4]);
+ if(result && result != CURLE_NOT_BUILT_IN)
+ goto out;
+
+ result = Curl_set_dns_local_ip6(data,
+ data->set.str[STRING_DNS_LOCAL_IP6]);
+ if(result && result != CURLE_NOT_BUILT_IN)
+ goto out;
+#endif /* USE_ARES */
+
result = Curl_conncache_add_conn(data);
if(result)
goto out;
@@ -3976,6 +3954,7 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
k->bytecount = 0;
k->ignorebody = FALSE;
+ Curl_client_cleanup(data);
Curl_speedinit(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
diff --git a/Utilities/cmcurl/lib/url.h b/Utilities/cmcurl/lib/url.h
index f6a5b25..7c1a29b 100644
--- a/Utilities/cmcurl/lib/url.h
+++ b/Utilities/cmcurl/lib/url.h
@@ -46,8 +46,13 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
char **userptr, char **passwdptr,
char **optionsptr);
-const struct Curl_handler *Curl_builtin_scheme(const char *scheme,
- size_t schemelen);
+/* Get protocol handler for a URI scheme
+ * @param scheme URI scheme, case-insensitive
+ * @return NULL of handler not found
+ */
+const struct Curl_handler *Curl_get_scheme_handler(const char *scheme);
+const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
+ size_t len);
#define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */
#define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless
diff --git a/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c
index 4efab61..0d11e48 100644
--- a/Utilities/cmcurl/lib/urlapi.c
+++ b/Utilities/cmcurl/lib/urlapi.c
@@ -206,7 +206,7 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
(void)buflen; /* only used in debug-builds */
if(buf)
buf[0] = 0; /* always leave a defined value in buf */
-#ifdef WIN32
+#ifdef _WIN32
if(guess_scheme && STARTS_WITH_DRIVE_PREFIX(url))
return 0;
#endif
@@ -446,7 +446,7 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
/* if this is a known scheme, get some details */
if(u->scheme)
- h = Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED);
+ h = Curl_get_scheme_handler(u->scheme);
/* We could use the login information in the URL so extract it. Only parse
options if the handler says we should. Note that 'h' might be NULL! */
@@ -1056,7 +1056,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
ptr += 9; /* now points to the slash after the host */
}
else {
-#if defined(WIN32)
+#if defined(_WIN32)
size_t len;
/* the host name, NetBIOS computer name, can not contain disallowed
@@ -1095,7 +1095,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
/* no host for file: URLs by default */
Curl_dyn_reset(&host);
-#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
+#if !defined(_WIN32) && !defined(MSDOS) && !defined(__CYGWIN__)
/* Don't allow Windows drive letters when not in Windows.
* This catches both "file:/c:" and "file:c:" */
if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
@@ -1129,7 +1129,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
}
schemep = schemebuf;
- if(!Curl_builtin_scheme(schemep, CURL_ZERO_TERMINATED) &&
+ if(!Curl_get_scheme_handler(schemep) &&
!(flags & CURLU_NON_SUPPORT_SCHEME)) {
result = CURLUE_UNSUPPORTED_SCHEME;
goto fail;
@@ -1224,14 +1224,14 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
if(flags & CURLU_URLENCODE) {
struct dynbuf enc;
Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
- if(urlencode_str(&enc, fragment + 1, fraglen, TRUE, FALSE)) {
+ if(urlencode_str(&enc, fragment + 1, fraglen - 1, TRUE, FALSE)) {
result = CURLUE_OUT_OF_MEMORY;
goto fail;
}
u->fragment = Curl_dyn_ptr(&enc);
}
else {
- u->fragment = Curl_memdup(fragment + 1, fraglen);
+ u->fragment = Curl_strndup(fragment + 1, fraglen - 1);
if(!u->fragment) {
result = CURLUE_OUT_OF_MEMORY;
goto fail;
@@ -1260,12 +1260,11 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
u->query = Curl_dyn_ptr(&enc);
}
else {
- u->query = Curl_memdup(query + 1, qlen);
+ u->query = Curl_strndup(query + 1, qlen - 1);
if(!u->query) {
result = CURLUE_OUT_OF_MEMORY;
goto fail;
}
- u->query[qlen - 1] = 0;
}
}
else {
@@ -1295,12 +1294,11 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
}
else {
if(!u->path) {
- u->path = Curl_memdup(path, pathlen + 1);
+ u->path = Curl_strndup(path, pathlen);
if(!u->path) {
result = CURLUE_OUT_OF_MEMORY;
goto fail;
}
- u->path[pathlen] = 0;
path = u->path;
}
else if(flags & CURLU_URLENCODE)
@@ -1352,7 +1350,7 @@ static CURLUcode parseurl_and_replace(const char *url, CURLU *u,
*/
CURLU *curl_url(void)
{
- return calloc(sizeof(struct Curl_URL), 1);
+ return calloc(1, sizeof(struct Curl_URL));
}
void curl_url_cleanup(CURLU *u)
@@ -1374,7 +1372,7 @@ void curl_url_cleanup(CURLU *u)
CURLU *curl_url_dup(const CURLU *in)
{
- struct Curl_URL *u = calloc(sizeof(struct Curl_URL), 1);
+ struct Curl_URL *u = calloc(1, sizeof(struct Curl_URL));
if(u) {
DUP(u, in, scheme);
DUP(u, in, user);
@@ -1447,8 +1445,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
if(!ptr && (flags & CURLU_DEFAULT_PORT) && u->scheme) {
/* there's no stored port number, but asked to deliver
a default one for the scheme */
- const struct Curl_handler *h =
- Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED);
+ const struct Curl_handler *h = Curl_get_scheme_handler(u->scheme);
if(h) {
msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
ptr = portbuf;
@@ -1457,8 +1454,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
else if(ptr && u->scheme) {
/* there is a stored port number, but ask to inhibit if
it matches the default one for the scheme */
- const struct Curl_handler *h =
- Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED);
+ const struct Curl_handler *h = Curl_get_scheme_handler(u->scheme);
if(h && (h->defport == u->portnum) &&
(flags & CURLU_NO_DEFAULT_PORT))
ptr = NULL;
@@ -1503,7 +1499,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
else
return CURLUE_NO_SCHEME;
- h = Curl_builtin_scheme(scheme, CURL_ZERO_TERMINATED);
+ h = Curl_get_scheme_handler(scheme);
if(!port && (flags & CURLU_DEFAULT_PORT)) {
/* there's no stored port number, but asked to deliver
a default one for the scheme */
@@ -1596,7 +1592,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
if(ptr) {
size_t partlen = strlen(ptr);
size_t i = 0;
- *part = Curl_memdup(ptr, partlen + 1);
+ *part = Curl_strndup(ptr, partlen);
if(!*part)
return CURLUE_OUT_OF_MEMORY;
if(plusdecode) {
@@ -1743,9 +1739,8 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
if((plen > MAX_SCHEME_LEN) || (plen < 1))
/* too long or too short */
return CURLUE_BAD_SCHEME;
- if(!(flags & CURLU_NON_SUPPORT_SCHEME) &&
- /* verify that it is a fine scheme */
- !Curl_builtin_scheme(part, CURL_ZERO_TERMINATED))
+ /* verify that it is a fine scheme */
+ if(!(flags & CURLU_NON_SUPPORT_SCHEME) && !Curl_get_scheme_handler(part))
return CURLUE_UNSUPPORTED_SCHEME;
storep = &u->scheme;
urlencode = FALSE; /* never */
@@ -1905,7 +1900,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
}
newp = Curl_dyn_ptr(&enc);
- if(appendquery) {
+ if(appendquery && newp) {
/* Append the 'newp' string onto the old query. Add a '&' separator if
none is present at the end of the existing query already */
@@ -1934,8 +1929,8 @@ nomem:
}
}
- if(what == CURLUPART_HOST) {
- size_t n = strlen(newp);
+ else if(what == CURLUPART_HOST) {
+ size_t n = Curl_dyn_len(&enc);
if(!n && (flags & CURLU_NO_AUTHORITY)) {
/* Skip hostname check, it's allowed to be empty. */
}
diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h
index dff26e6..ff66148 100644
--- a/Utilities/cmcurl/lib/urldata.h
+++ b/Utilities/cmcurl/lib/urldata.h
@@ -266,6 +266,13 @@ typedef enum {
/* SSL backend-specific data; declared differently by each SSL backend */
struct ssl_backend_data;
+struct ssl_peer {
+ char *hostname; /* hostname for verification */
+ char *dispname; /* display version of hostname */
+ char *sni; /* SNI version of hostname or NULL if not usable */
+ BIT(is_ip_address); /* if hostname is an IPv4|6 address */
+};
+
struct ssl_primary_config {
char *CApath; /* certificate dir (doesn't work on windows) */
char *CAfile; /* certificate to verify peer against */
@@ -571,6 +578,13 @@ struct hostname {
#define KEEP_RECVBITS (KEEP_RECV | KEEP_RECV_HOLD | KEEP_RECV_PAUSE)
#define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE)
+/* transfer wants to send is not PAUSE or HOLD */
+#define CURL_WANT_SEND(data) \
+ (((data)->req.keepon & KEEP_SENDBITS) == KEEP_SEND)
+/* transfer receive is not on PAUSE or HOLD */
+#define CURL_WANT_RECV(data) \
+ (!((data)->req.keepon & (KEEP_RECV_PAUSE|KEEP_RECV_HOLD)))
+
#if defined(CURLRES_ASYNCH) || !defined(CURL_DISABLE_DOH)
#define USE_CURL_ASYNC
struct Curl_async {
@@ -589,6 +603,15 @@ struct Curl_async {
#define FIRSTSOCKET 0
#define SECONDARYSOCKET 1
+/* Polling requested by an easy handle.
+ * `action` is CURL_POLL_IN, CURL_POLL_OUT or CURL_POLL_INOUT.
+ */
+struct easy_pollset {
+ curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
+ unsigned int num;
+ unsigned char actions[MAX_SOCKSPEREASYHANDLE];
+};
+
enum expect100 {
EXP100_SEND_DATA, /* enough waiting, just send the body now */
EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */
@@ -649,16 +672,8 @@ struct SingleRequest {
counter to make only a 100 reply (without
a following second response code) result
in a CURLE_GOT_NOTHING error code */
- enum {
- HEADER_NORMAL, /* no bad header at all */
- HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest
- is normal data */
- HEADER_ALLBAD /* all was believed to be header */
- } badheader; /* the header was deemed bad and will be
- written as body */
int headerline; /* counts header lines to better track the
first one */
- char *str; /* within buf */
curl_off_t offset; /* possible resume offset read from the
Content-Range: header */
int httpcode; /* error code from the 'HTTP/1.? XXX' or
@@ -669,7 +684,7 @@ struct SingleRequest {
enum upgrade101 upgr101; /* 101 upgrade state */
/* Content unencoding stack. See sec 3.5, RFC2616. */
- struct contenc_writer *writer_stack;
+ struct Curl_cwriter *writer_stack;
time_t timeofdoc;
long bodywrites;
char *location; /* This points to an allocated version of the Location:
@@ -706,16 +721,20 @@ struct SingleRequest {
#ifndef CURL_DISABLE_DOH
struct dohdata *doh; /* DoH specific data for this request */
#endif
-#if defined(WIN32) && defined(USE_WINSOCK)
+#if defined(_WIN32) && defined(USE_WINSOCK)
struct curltime last_sndbuf_update; /* last time readwrite_upload called
win_update_buffer_size */
#endif
+ char fread_eof[2]; /* the body read callback (index 0) returned EOF or
+ the trailer read callback (index 1) returned EOF */
#ifndef CURL_DISABLE_COOKIES
unsigned char setcookies;
#endif
unsigned char writer_stack_depth; /* Unencoding stack depth. */
BIT(header); /* incoming data has HTTP header */
+ BIT(badheader); /* header parsing found sth not a header */
BIT(content_range); /* set TRUE if Content-Range: was found */
+ BIT(download_done); /* set to TRUE when download is complete */
BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding
upload and we're uploading the last chunk */
BIT(ignorebody); /* we read a response-body but we ignore it! */
@@ -799,7 +818,8 @@ struct Curl_handler {
/* If used, this function gets called from transfer.c:readwrite_data() to
allow the protocol to do extra reads/writes */
CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn,
- ssize_t *nread, bool *readmore);
+ const char *buf, size_t blen,
+ size_t *pconsumed, bool *readmore);
/* This function can perform various checks on the connection. See
CONNCHECK_* for more information about the checks that can be performed,
@@ -901,6 +921,9 @@ struct connectdata {
multi_done(). This entry will be NULL if the connection is reused as then
there is no name resolve done. */
struct Curl_dns_entry *dns_entry;
+#ifdef USE_CURL_ASYNC
+ struct Curl_async resolve_async; /* asynchronous name resolver data */
+#endif
/* 'remote_addr' is the particular IP we connected to. it is owned, set
* and NULLed by the connected socket filter (if there is one). */
@@ -1325,7 +1348,8 @@ struct UrlState {
curl_off_t recent_conn_id; /* The most recent connection used, might no
* longer exist */
struct dynbuf headerb; /* buffer to store headers in */
-
+ struct curl_slist *hstslist; /* list of HSTS files set by
+ curl_easy_setopt(HSTS) calls */
char *buffer; /* download buffer */
char *ulbuf; /* allocated upload buffer or NULL */
curl_off_t current_speed; /* the ProgressShow() function sets this,
@@ -1358,9 +1382,6 @@ struct UrlState {
#endif
struct auth authhost; /* auth details for host */
struct auth authproxy; /* auth details for proxy */
-#ifdef USE_CURL_ASYNC
- struct Curl_async async; /* asynchronous name resolver data */
-#endif
#if defined(USE_OPENSSL)
/* void instead of ENGINE to avoid bleeding OpenSSL into this header */
@@ -1373,7 +1394,7 @@ struct UrlState {
/* a place to store the most recently set (S)FTP entrypath */
char *most_recent_ftp_entrypath;
-#if !defined(WIN32) && !defined(MSDOS) && !defined(__EMX__)
+#if !defined(_WIN32) && !defined(MSDOS) && !defined(__EMX__)
/* do FTP line-end conversions on most platforms */
#define CURL_DO_LINEEND_CONV
/* for FTP downloads: track CRLF sequences that span blocks */
@@ -1411,7 +1432,7 @@ struct UrlState {
this should be dealt with in pretransfer */
#ifndef CURL_DISABLE_HTTP
curl_mimepart *mimepost;
- curl_mimepart *formp; /* storage for old API form-posting, alloced on
+ curl_mimepart *formp; /* storage for old API form-posting, allocated on
demand */
size_t trailers_bytes_sent;
struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
@@ -1422,6 +1443,10 @@ struct UrlState {
trailers_state trailers_state; /* whether we are sending trailers
and what stage are we at */
#endif
+#ifndef CURL_DISABLE_COOKIES
+ struct curl_slist *cookielist; /* list of cookie files set by
+ curl_easy_setopt(COOKIEFILE) calls */
+#endif
#ifdef USE_HYPER
bool hconnect; /* set if a CONNECT request */
CURLcode hresult; /* used to pass return codes back from hyper callbacks */
@@ -1498,6 +1523,9 @@ struct UrlState {
though it will be discarded. We must call the data
rewind callback before trying to send again. */
BIT(upload); /* upload request */
+ BIT(internal); /* internal: true if this easy handle was created for
+ internal use and the user does not have ownership of the
+ handle. */
};
/*
@@ -1674,13 +1702,7 @@ struct UserDefined {
void *prereq_userp; /* pre-initial request user data */
void *seek_client; /* pointer to pass to the seek callback */
-#ifndef CURL_DISABLE_COOKIES
- struct curl_slist *cookielist; /* list of cookie files set by
- curl_easy_setopt(COOKIEFILE) calls */
-#endif
#ifndef CURL_DISABLE_HSTS
- struct curl_slist *hstslist; /* list of HSTS files set by
- curl_easy_setopt(HSTS) calls */
curl_hstsread_callback hsts_read;
void *hsts_read_userp;
curl_hstswrite_callback hsts_write;
@@ -1780,9 +1802,6 @@ struct UserDefined {
#endif
curl_prot_t allowed_protocols;
curl_prot_t redir_protocols;
-#ifndef CURL_DISABLE_MIME
- unsigned int mime_options; /* Mime option flags. */
-#endif
#ifndef CURL_DISABLE_RTSP
void *rtp_out; /* write RTP to this if non-NULL */
/* Common RTSP header options */
@@ -1805,8 +1824,6 @@ struct UserDefined {
int tcp_keepidle; /* seconds in idle before sending keepalive probe */
int tcp_keepintvl; /* seconds between TCP keepalive probes */
- size_t maxconnects; /* Max idle connections in the connection cache */
-
long expect_100_timeout; /* in milliseconds */
#if defined(USE_HTTP2) || defined(USE_HTTP3)
struct Curl_data_priority priority;
@@ -1831,10 +1848,14 @@ struct UserDefined {
BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some
recipients */
#endif
+ unsigned int maxconnects; /* Max idle connections in the connection cache */
unsigned char use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or
IMAP or POP3 or others! (type: curl_usessl)*/
unsigned char connect_only; /* make connection/request, then let
application use the socket */
+#ifndef CURL_DISABLE_MIME
+ BIT(mime_formescape);
+#endif
BIT(is_fread_set); /* has read callback been set to non-NULL? */
#ifndef CURL_DISABLE_TFTP
BIT(tftp_no_options); /* do not send TFTP options requests */
@@ -1971,10 +1992,7 @@ struct Curl_easy {
particular order. Note that all sockets are added to the sockhash, where
the state etc are also kept. This array is mostly used to detect when a
socket is to be removed from the hash. See singlesocket(). */
- curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
- unsigned char actions[MAX_SOCKSPEREASYHANDLE]; /* action for each socket in
- sockets[] */
- int numsocks;
+ struct easy_pollset last_poll;
struct Names dns;
struct Curl_multi *multi; /* if non-NULL, points to the multi handle
@@ -2013,10 +2031,6 @@ struct Curl_easy {
#ifdef USE_HYPER
struct hyptransfer hyp;
#endif
-
- /* internal: true if this easy handle was created for internal use and the
- user does not have ownership of the handle. */
- bool internal;
};
#define LIBCURL_NAME "libcurl"
diff --git a/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c
index 12c6f7d..416da0f 100644
--- a/Utilities/cmcurl/lib/vauth/digest.c
+++ b/Utilities/cmcurl/lib/vauth/digest.c
@@ -125,7 +125,6 @@ bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
}
else
return FALSE;
- break;
}
}
diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c
index f99dd38..31bd0a4 100644
--- a/Utilities/cmcurl/lib/version.c
+++ b/Utilities/cmcurl/lib/version.c
@@ -39,7 +39,7 @@
#ifdef USE_ARES
# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
- defined(WIN32)
+ defined(_WIN32)
# define CARES_STATICLIB
# endif
# include <ares.h>
@@ -409,7 +409,8 @@ static int idn_present(curl_version_info_data *info)
#define idn_present NULL
#endif
-#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY)
+#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) && \
+ !defined(CURL_DISABLE_HTTP)
static int https_proxy_present(curl_version_info_data *info)
{
(void) info;
@@ -454,13 +455,14 @@ static const struct feat features_table[] = {
#ifndef CURL_DISABLE_HSTS
FEATURE("HSTS", NULL, CURL_VERSION_HSTS),
#endif
-#if defined(USE_NGHTTP2) || defined(USE_HYPER)
+#if defined(USE_NGHTTP2)
FEATURE("HTTP2", NULL, CURL_VERSION_HTTP2),
#endif
#if defined(ENABLE_QUIC)
FEATURE("HTTP3", NULL, CURL_VERSION_HTTP3),
#endif
-#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY)
+#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) && \
+ !defined(CURL_DISABLE_HTTP)
FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY),
#endif
#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
@@ -510,7 +512,7 @@ static const struct feat features_table[] = {
#ifdef CURLDEBUG
FEATURE("TrackMemory", NULL, CURL_VERSION_CURLDEBUG),
#endif
-#if defined(WIN32) && defined(UNICODE) && defined(_UNICODE)
+#if defined(_WIN32) && defined(UNICODE) && defined(_UNICODE)
FEATURE("Unicode", NULL, CURL_VERSION_UNICODE),
#endif
#ifdef USE_UNIX_SOCKETS
diff --git a/Utilities/cmcurl/lib/version_win32.c b/Utilities/cmcurl/lib/version_win32.c
index 872d5b4..e0f239e 100644
--- a/Utilities/cmcurl/lib/version_win32.c
+++ b/Utilities/cmcurl/lib/version_win32.c
@@ -24,7 +24,7 @@
#include "curl_setup.h"
-#if defined(WIN32)
+#if defined(_WIN32)
#include <curl/curl.h>
#include "version_win32.h"
@@ -316,4 +316,4 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
return matched;
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
diff --git a/Utilities/cmcurl/lib/version_win32.h b/Utilities/cmcurl/lib/version_win32.h
index 3899174..95c0661 100644
--- a/Utilities/cmcurl/lib/version_win32.h
+++ b/Utilities/cmcurl/lib/version_win32.h
@@ -26,7 +26,7 @@
#include "curl_setup.h"
-#if defined(WIN32)
+#if defined(_WIN32)
/* Version condition */
typedef enum {
@@ -51,6 +51,6 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
const PlatformIdentifier platform,
const VersionCondition condition);
-#endif /* WIN32 */
+#endif /* _WIN32 */
#endif /* HEADER_CURL_VERSION_WIN32_H */
diff --git a/Utilities/cmcurl/lib/vquic/curl_msh3.c b/Utilities/cmcurl/lib/vquic/curl_msh3.c
index 6bd0d23..8ae3672 100644
--- a/Utilities/cmcurl/lib/vquic/curl_msh3.c
+++ b/Utilities/cmcurl/lib/vquic/curl_msh3.c
@@ -38,6 +38,7 @@
#include "http1.h"
#include "curl_msh3.h"
#include "socketpair.h"
+#include "vtls/vtls.h"
#include "vquic/vquic.h"
/* The last 3 #include files should be in this order */
@@ -45,6 +46,10 @@
#include "curl_memory.h"
#include "memdebug.h"
+#ifdef CURL_DISABLE_SOCKETPAIR
+#error "MSH3 cannot be build with CURL_DISABLE_SOCKETPAIR set"
+#endif
+
#define H3_STREAM_WINDOW_SIZE (128 * 1024)
#define H3_STREAM_CHUNK_SIZE (16 * 1024)
#define H3_STREAM_RECV_CHUNKS \
@@ -672,31 +677,25 @@ out:
return nwritten;
}
-static int cf_msh3_get_select_socks(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- curl_socket_t *socks)
+static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
{
struct cf_msh3_ctx *ctx = cf->ctx;
struct stream_ctx *stream = H3_STREAM_CTX(data);
- int bitmap = GETSOCK_BLANK;
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
if(stream && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) {
- socks[0] = ctx->sock[SP_LOCAL];
-
if(stream->recv_error) {
- bitmap |= GETSOCK_READSOCK(0);
+ Curl_pollset_add_in(data, ps, ctx->sock[SP_LOCAL]);
drain_stream(cf, data);
}
else if(stream->req) {
- bitmap |= GETSOCK_READSOCK(0);
+ Curl_pollset_add_out(data, ps, ctx->sock[SP_LOCAL]);
drain_stream(cf, data);
}
}
- CURL_TRC_CF(data, cf, "select_sock -> %d", bitmap);
- CF_DATA_RESTORE(cf, save);
- return bitmap;
}
static bool cf_msh3_data_pending(struct Curl_cfilter *cf,
@@ -802,14 +801,20 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- bool verify = !!cf->conn->ssl_config.verifypeer;
+ struct ssl_primary_config *conn_config;
MSH3_ADDR addr = {0};
CURLcode result;
+ bool verify;
+
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config)
+ return CURLE_FAILED_INIT;
+ verify = !!conn_config->verifypeer;
memcpy(&addr, &ctx->addr.sa_addr, ctx->addr.addrlen);
MSH3_SET_PORT(&addr, (uint16_t)cf->conn->remote_port);
- if(verify && (cf->conn->ssl_config.CAfile || cf->conn->ssl_config.CApath)) {
+ if(verify && (conn_config->CAfile || conn_config->CApath)) {
/* TODO: need a way to provide trust anchors to MSH3 */
#ifdef DEBUGBUILD
/* we need this for our test cases to run */
@@ -1025,7 +1030,7 @@ struct Curl_cftype Curl_cft_http3 = {
cf_msh3_connect,
cf_msh3_close,
Curl_cf_def_get_host,
- cf_msh3_get_select_socks,
+ cf_msh3_adjust_pollset,
cf_msh3_data_pending,
cf_msh3_send,
cf_msh3_recv,
@@ -1047,7 +1052,7 @@ CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf,
(void)data;
(void)conn;
(void)ai; /* TODO: msh3 resolves itself? */
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
diff --git a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
index 7d681e5..f09b10b 100644
--- a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
+++ b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
@@ -78,7 +78,6 @@
#define QUIC_MAX_STREAMS (256*1024)
#define QUIC_MAX_DATA (1*1024*1024)
-#define QUIC_IDLE_TIMEOUT (60*NGTCP2_SECONDS)
#define QUIC_HANDSHAKE_TIMEOUT (10*NGTCP2_SECONDS)
/* A stream window is the maximum amount we need to buffer for
@@ -134,6 +133,7 @@ void Curl_ngtcp2_ver(char *p, size_t len)
struct cf_ngtcp2_ctx {
struct cf_quic_ctx q;
+ struct ssl_peer peer;
ngtcp2_path connected_path;
ngtcp2_conn *qconn;
ngtcp2_cid dcid;
@@ -161,6 +161,7 @@ struct cf_ngtcp2_ctx {
struct curltime reconnect_at; /* time the next attempt should start */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
size_t max_stream_window; /* max flow window for one stream */
+ uint64_t max_idle_ms; /* max idle time for QUIC connection */
int qlogfd;
BIT(got_first_byte); /* if first byte was received */
#ifdef USE_OPENSSL
@@ -191,6 +192,7 @@ struct h3_stream_ctx {
bool closed; /* TRUE on stream close */
bool reset; /* TRUE on stream reset */
bool send_closed; /* stream is local closed */
+ BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
};
#define H3_STREAM_CTX(d) ((struct h3_stream_ctx *)(((d) && (d)->req.p.http)? \
@@ -236,11 +238,21 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
{
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
(void)cf;
if(stream) {
CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->id);
+ if(ctx->h3conn && !stream->closed) {
+ nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream->id);
+ nghttp3_conn_close_stream(ctx->h3conn, stream->id,
+ NGHTTP3_H3_REQUEST_CANCELLED);
+ nghttp3_conn_set_stream_user_data(ctx->h3conn, stream->id, NULL);
+ ngtcp2_conn_set_stream_user_data(ctx->qconn, stream->id, NULL);
+ stream->closed = TRUE;
+ }
+
Curl_bufq_free(&stream->sendbuf);
Curl_bufq_free(&stream->recvbuf);
Curl_h1_req_parse_free(&stream->h1);
@@ -249,6 +261,43 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
+static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ int64_t stream_id)
+{
+ struct Curl_easy *sdata;
+
+ (void)cf;
+ if(H3_STREAM_ID(data) == stream_id) {
+ return data;
+ }
+ else {
+ DEBUGASSERT(data->multi);
+ for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+ if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream_id) {
+ return sdata;
+ }
+ }
+ }
+ return NULL;
+}
+
+static void h3_drain_stream(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ unsigned char bits;
+
+ (void)cf;
+ bits = CURL_CSELECT_IN;
+ if(stream && stream->upload_left && !stream->send_closed)
+ bits |= CURL_CSELECT_OUT;
+ if(data->state.dselect_bits != bits) {
+ data->state.dselect_bits = bits;
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+ }
+}
+
/* ngtcp2 default congestion controller does not perform pacing. Limit
the maximum packet burst to MAX_PKT_BURST packets. */
#define MAX_PKT_BURST 10
@@ -261,10 +310,14 @@ struct pkt_io_ctx {
ngtcp2_path_storage ps;
};
-static ngtcp2_tstamp timestamp(void)
+static void pktx_update_time(struct pkt_io_ctx *pktx,
+ struct Curl_cfilter *cf)
{
- struct curltime ct = Curl_now();
- return ct.tv_sec * NGTCP2_SECONDS + ct.tv_usec * NGTCP2_MICROSECONDS;
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+
+ vquic_ctx_update_time(&ctx->q);
+ pktx->ts = ctx->q.last_op.tv_sec * NGTCP2_SECONDS +
+ ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS;
}
static void pktx_init(struct pkt_io_ctx *pktx,
@@ -273,9 +326,9 @@ static void pktx_init(struct pkt_io_ctx *pktx,
{
pktx->cf = cf;
pktx->data = data;
- pktx->ts = timestamp();
pktx->pkt_count = 0;
ngtcp2_path_storage_zero(&pktx->ps);
+ pktx_update_time(pktx, cf);
}
static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
@@ -354,7 +407,7 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx,
t->initial_max_stream_data_uni = ctx->max_stream_window;
t->initial_max_streams_bidi = QUIC_MAX_STREAMS;
t->initial_max_streams_uni = QUIC_MAX_STREAMS;
- t->max_idle_timeout = QUIC_IDLE_TIMEOUT;
+ t->max_idle_timeout = (ctx->max_idle_ms * NGTCP2_MILLISECONDS);
if(ctx->qlogfd != -1) {
s->qlog_write = qlog_callback;
}
@@ -398,14 +451,19 @@ static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx,
struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct connectdata *conn = cf->conn;
+ struct ssl_primary_config *conn_config;
CURLcode result = CURLE_FAILED_INIT;
- SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
+ SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
if(!ssl_ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config) {
+ result = CURLE_FAILED_INIT;
+ goto out;
+ }
#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
if(ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx) != 0) {
@@ -422,8 +480,8 @@ static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx,
SSL_CTX_set_default_verify_paths(ssl_ctx);
{
- const char *curves = conn->ssl_config.curves ?
- conn->ssl_config.curves : QUIC_GROUPS;
+ const char *curves = conn_config->curves ?
+ conn_config->curves : QUIC_GROUPS;
if(!SSL_CTX_set1_curves_list(ssl_ctx, curves)) {
failf(data, "failed setting curves list for QUIC: '%s'", curves);
return CURLE_SSL_CIPHER;
@@ -432,8 +490,8 @@ static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx,
#ifndef OPENSSL_IS_BORINGSSL
{
- const char *ciphers13 = conn->ssl_config.cipher_list13 ?
- conn->ssl_config.cipher_list13 : QUIC_CIPHERS;
+ const char *ciphers13 = conn_config->cipher_list13 ?
+ conn_config->cipher_list13 : QUIC_CIPHERS;
if(SSL_CTX_set_ciphersuites(ssl_ctx, ciphers13) != 1) {
failf(data, "failed setting QUIC cipher suite: %s", ciphers13);
return CURLE_SSL_CIPHER;
@@ -452,7 +510,7 @@ static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx,
* fail to connect if the verification fails, or if it should continue
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
- SSL_CTX_set_verify(ssl_ctx, conn->ssl_config.verifypeer ?
+ SSL_CTX_set_verify(ssl_ctx, conn_config->verifypeer ?
SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
/* give application a chance to interfere with SSL set up. */
@@ -491,7 +549,7 @@ static CURLcode quic_set_client_cert(struct Curl_cfilter *cf,
SSL_CTX *ssl_ctx = ctx->sslctx;
const struct ssl_config_data *ssl_config;
- ssl_config = Curl_ssl_get_config(data, FIRSTSOCKET);
+ ssl_config = Curl_ssl_cf_get_config(cf, data);
DEBUGASSERT(ssl_config);
if(ssl_config->primary.clientcert || ssl_config->primary.cert_blob
@@ -514,7 +572,6 @@ static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
struct cf_ngtcp2_ctx *ctx = cf->ctx;
const uint8_t *alpn = NULL;
size_t alpnlen = 0;
- unsigned char checkip[16];
DEBUGASSERT(!ctx->ssl);
ctx->ssl = SSL_new(ctx->sslctx);
@@ -529,13 +586,8 @@ static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
SSL_set_alpn_protos(ctx->ssl, alpn, (int)alpnlen);
/* set SNI */
- if((0 == Curl_inet_pton(AF_INET, cf->conn->host.name, checkip))
-#ifdef ENABLE_IPV6
- && (0 == Curl_inet_pton(AF_INET6, cf->conn->host.name, checkip))
-#endif
- ) {
- char *snihost = Curl_ssl_snihost(data, cf->conn->host.name, NULL);
- if(!snihost || !SSL_set_tlsext_host_name(ctx->ssl, snihost)) {
+ if(ctx->peer.sni) {
+ if(!SSL_set_tlsext_host_name(ctx->ssl, ctx->peer.sni)) {
failf(data, "Failed set SNI");
SSL_free(ctx->ssl);
ctx->ssl = NULL;
@@ -549,20 +601,24 @@ static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ struct ssl_primary_config *conn_config;
CURLcode result;
gnutls_datum_t alpn[2];
/* this will need some attention when HTTPS proxy over QUIC get fixed */
- const char * const hostname = cf->conn->host.name;
long * const pverifyresult = &data->set.ssl.certverifyresult;
int rc;
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config)
+ return CURLE_FAILED_INIT;
+
DEBUGASSERT(ctx->gtls == NULL);
ctx->gtls = calloc(1, sizeof(*(ctx->gtls)));
if(!ctx->gtls)
return CURLE_OUT_OF_MEMORY;
- result = gtls_client_init(data, &cf->conn->ssl_config, &data->set.ssl,
- hostname, ctx->gtls, pverifyresult);
+ result = gtls_client_init(data, conn_config, &data->set.ssl,
+ &ctx->peer, ctx->gtls, pverifyresult);
if(result)
return result;
@@ -602,10 +658,17 @@ static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx,
struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct connectdata *conn = cf->conn;
CURLcode result = CURLE_FAILED_INIT;
- WOLFSSL_CTX *ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
+ struct ssl_primary_config *conn_config;
+ WOLFSSL_CTX *ssl_ctx = NULL;
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config) {
+ result = CURLE_FAILED_INIT;
+ goto out;
+ }
+
+ ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
if(!ssl_ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -613,13 +676,14 @@ static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx,
if(ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx) != 0) {
failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
+ result = CURLE_FAILED_INIT;
goto out;
}
wolfSSL_CTX_set_default_verify_paths(ssl_ctx);
- if(wolfSSL_CTX_set_cipher_list(ssl_ctx, conn->ssl_config.cipher_list13 ?
- conn->ssl_config.cipher_list13 :
+ if(wolfSSL_CTX_set_cipher_list(ssl_ctx, conn_config->cipher_list13 ?
+ conn_config->cipher_list13 :
QUIC_CIPHERS) != 1) {
char error_buffer[256];
ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
@@ -627,8 +691,8 @@ static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx,
goto out;
}
- if(wolfSSL_CTX_set1_groups_list(ssl_ctx, conn->ssl_config.curves ?
- conn->ssl_config.curves :
+ if(wolfSSL_CTX_set1_groups_list(ssl_ctx, conn_config->curves ?
+ conn_config->curves :
(char *)QUIC_GROUPS) != 1) {
failf(data, "wolfSSL failed to set curves");
goto out;
@@ -645,9 +709,9 @@ static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx,
#endif
}
- if(conn->ssl_config.verifypeer) {
- const char * const ssl_cafile = conn->ssl_config.CAfile;
- const char * const ssl_capath = conn->ssl_config.CApath;
+ if(conn_config->verifypeer) {
+ const char * const ssl_cafile = conn_config->CAfile;
+ const char * const ssl_capath = conn_config->CApath;
wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
if(ssl_cafile || ssl_capath) {
@@ -786,6 +850,12 @@ static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
CURL_TRC_CF(data, cf, "[%" PRId64 "] read_stream(len=%zu) -> %zd",
stream_id, buflen, nconsumed);
if(nconsumed < 0) {
+ if(!data) {
+ struct Curl_easy *cdata = CF_DATA_CURRENT(cf);
+ CURL_TRC_CF(cdata, cf, "[%" PRId64 "] nghttp3 error on stream not "
+ "used by us, ignored", stream_id);
+ return 0;
+ }
ngtcp2_ccerr_set_application_error(
&ctx->last_error,
nghttp3_err_infer_quic_app_error_code((int)nconsumed), NULL, 0);
@@ -816,7 +886,7 @@ cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
(void)stream_user_data;
rv = nghttp3_conn_add_ack_offset(ctx->h3conn, stream_id, datalen);
- if(rv) {
+ if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -844,7 +914,7 @@ static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags,
app_error_code);
CURL_TRC_CF(data, cf, "[%" PRId64 "] quic close(err=%"
PRIu64 ") -> %d", stream3_id, app_error_code, rv);
- if(rv) {
+ if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
ngtcp2_ccerr_set_application_error(
&ctx->last_error, nghttp3_err_infer_quic_app_error_code(rv), NULL, 0);
return NGTCP2_ERR_CALLBACK_FAILURE;
@@ -868,7 +938,7 @@ static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv);
- if(rv) {
+ if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -887,7 +957,7 @@ static int cb_stream_stop_sending(ngtcp2_conn *tconn, int64_t stream_id,
(void)stream_user_data;
rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
- if(rv) {
+ if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -911,16 +981,25 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
{
struct Curl_cfilter *cf = user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ struct Curl_easy *data = CF_DATA_CURRENT(cf);
+ struct Curl_easy *s_data;
+ struct h3_stream_ctx *stream;
int rv;
(void)tconn;
(void)max_data;
(void)stream_user_data;
rv = nghttp3_conn_unblock_stream(ctx->h3conn, stream_id);
- if(rv) {
+ if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
-
+ s_data = get_stream_easy(cf, data, stream_id);
+ stream = H3_STREAM_CTX(s_data);
+ if(stream && stream->quic_flow_blocked) {
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] unblock quic flow", stream_id);
+ stream->quic_flow_blocked = FALSE;
+ h3_drain_stream(cf, data);
+ }
return 0;
}
@@ -1038,7 +1117,7 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
pktx = &local_pktx;
}
else {
- pktx->ts = timestamp();
+ pktx_update_time(pktx, cf);
}
expiry = ngtcp2_conn_get_expiry(ctx->qconn);
@@ -1073,46 +1152,29 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
return CURLE_OK;
}
-static int cf_ngtcp2_get_select_socks(struct Curl_cfilter *cf,
+static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
- curl_socket_t *socks)
+ struct easy_pollset *ps)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct SingleRequest *k = &data->req;
- int rv = GETSOCK_BLANK;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
- socks[0] = ctx->q.sockfd;
+ bool want_recv = CURL_WANT_RECV(data);
+ bool want_send = CURL_WANT_SEND(data);
- /* in HTTP/3 we can always get a frame, so check read */
- rv |= GETSOCK_READSOCK(0);
-
- /* we're still uploading or the HTTP/2 layer wants to send data */
- if((k->keepon & KEEP_SENDBITS) == KEEP_SEND &&
- ngtcp2_conn_get_cwnd_left(ctx->qconn) &&
- ngtcp2_conn_get_max_data_left(ctx->qconn) &&
- stream && nghttp3_conn_is_stream_writable(ctx->h3conn, stream->id))
- rv |= GETSOCK_WRITESOCK(0);
-
- CF_DATA_RESTORE(cf, save);
- return rv;
-}
-
-static void h3_drain_stream(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
- unsigned char bits;
+ if(ctx->qconn && (want_recv || want_send)) {
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_call_data save;
+ bool c_exhaust, s_exhaust;
- (void)cf;
- bits = CURL_CSELECT_IN;
- if(stream && stream->upload_left && !stream->send_closed)
- bits |= CURL_CSELECT_OUT;
- if(data->state.dselect_bits != bits) {
- data->state.dselect_bits = bits;
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
+ CF_DATA_SAVE(save, cf, data);
+ c_exhaust = !ngtcp2_conn_get_cwnd_left(ctx->qconn) ||
+ !ngtcp2_conn_get_max_data_left(ctx->qconn);
+ s_exhaust = stream && stream->id >= 0 && stream->quic_flow_blocked;
+ want_recv = (want_recv || c_exhaust || s_exhaust);
+ want_send = (!s_exhaust && want_send) ||
+ !Curl_bufq_is_empty(&ctx->q.sendbuf);
+
+ Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send);
+ CF_DATA_RESTORE(cf, save);
}
}
@@ -1141,7 +1203,6 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
else {
CURL_TRC_CF(data, cf, "[%" PRId64 "] CLOSED", stream->id);
}
- data->req.keepon &= ~KEEP_SEND_HOLD;
h3_drain_stream(cf, data);
return 0;
}
@@ -1570,15 +1631,9 @@ static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
/* Everything ACKed, we resume upload processing */
if(!stream->sendbuf_len_in_flight) {
int rv = nghttp3_conn_resume_stream(conn, stream_id);
- if(rv) {
+ if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
- if((data->req.keepon & KEEP_SEND_HOLD) &&
- (data->req.keepon & KEEP_SEND)) {
- data->req.keepon &= ~KEEP_SEND_HOLD;
- h3_drain_stream(cf, data);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] unpausing acks", stream_id);
- }
}
return 0;
}
@@ -1676,6 +1731,10 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
goto out;
stream = H3_STREAM_CTX(data);
DEBUGASSERT(stream);
+ if(!stream) {
+ *err = CURLE_FAILED_INIT;
+ goto out;
+ }
nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
if(nwritten < 0)
@@ -1711,7 +1770,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
nva[i].flags = NGHTTP3_NV_FLAG_NONE;
}
- rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &stream->id, NULL);
+ rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &stream->id, data);
if(rc) {
failf(data, "can get bidi streams");
*err = CURLE_SEND_ERROR;
@@ -1860,15 +1919,13 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
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. */
+ * "written" into our various internal connection buffers. */
stream->upload_blocked_len = sent;
CURL_TRC_CF(data, cf, "[%" 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:
@@ -1887,40 +1944,37 @@ static CURLcode qng_verify_peer(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ struct ssl_primary_config *conn_config;
CURLcode result = CURLE_OK;
- const char *hostname, *disp_hostname;
- int port;
- char *snihost;
- Curl_conn_get_host(data, cf->sockindex, &hostname, &disp_hostname, &port);
- snihost = Curl_ssl_snihost(data, hostname, NULL);
- if(!snihost)
- return CURLE_PEER_FAILED_VERIFICATION;
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config)
+ return CURLE_FAILED_INIT;
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
cf->conn->httpversion = 30;
cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
- if(cf->conn->ssl_config.verifyhost) {
+ if(conn_config->verifyhost) {
#ifdef USE_OPENSSL
X509 *server_cert;
- server_cert = SSL_get_peer_certificate(ctx->ssl);
+ server_cert = SSL_get1_peer_certificate(ctx->ssl);
if(!server_cert) {
return CURLE_PEER_FAILED_VERIFICATION;
}
- result = Curl_ossl_verifyhost(data, cf->conn, server_cert);
+ result = Curl_ossl_verifyhost(data, cf->conn, &ctx->peer, server_cert);
X509_free(server_cert);
if(result)
return result;
#elif defined(USE_GNUTLS)
result = Curl_gtls_verifyserver(data, ctx->gtls->session,
- &cf->conn->ssl_config, &data->set.ssl,
- hostname, disp_hostname,
+ conn_config, &data->set.ssl, &ctx->peer,
data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
if(result)
return result;
#elif defined(USE_WOLFSSL)
- if(wolfSSL_check_domain_name(ctx->ssl, snihost) == SSL_FAILURE)
+ if(!ctx->peer.sni ||
+ wolfSSL_check_domain_name(ctx->ssl, ctx->peer.sni) == SSL_FAILURE)
return CURLE_PEER_FAILED_VERIFICATION;
#endif
infof(data, "Verified certificate just fine");
@@ -1955,8 +2009,8 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts);
if(rv) {
- CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s",
- ngtcp2_strerror(rv));
+ CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)",
+ ngtcp2_strerror(rv), rv);
if(!ctx->last_error.error_code) {
if(rv == NGTCP2_ERR_CRYPTO) {
ngtcp2_ccerr_set_tls_alert(&ctx->last_error,
@@ -1993,7 +2047,7 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
pktx = &local_pktx;
}
else {
- pktx->ts = timestamp();
+ pktx_update_time(pktx, cf);
}
#ifdef USE_OPENSSL
@@ -2081,11 +2135,18 @@ static ssize_t read_pkt_to_send(void *userp,
}
else if(n < 0) {
switch(n) {
- case NGTCP2_ERR_STREAM_DATA_BLOCKED:
+ case NGTCP2_ERR_STREAM_DATA_BLOCKED: {
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(x->data);
DEBUGASSERT(ndatalen == -1);
nghttp3_conn_block_stream(ctx->h3conn, stream_id);
+ CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] block quic flow",
+ stream_id);
+ DEBUGASSERT(stream);
+ if(stream)
+ stream->quic_flow_blocked = TRUE;
n = 0;
break;
+ }
case NGTCP2_ERR_STREAM_SHUT_WR:
DEBUGASSERT(ndatalen == -1);
nghttp3_conn_shutdown_stream_write(ctx->h3conn, stream_id);
@@ -2145,7 +2206,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
pktx = &local_pktx;
}
else {
- pktx->ts = timestamp();
+ pktx_update_time(pktx, cf);
ngtcp2_path_storage_zero(&pktx->ps);
}
@@ -2282,10 +2343,12 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
case CF_CTRL_DATA_PAUSE:
result = h3_data_pause(cf, data, (arg1 != 0));
break;
- case CF_CTRL_DATA_DONE: {
+ case CF_CTRL_DATA_DETACH:
+ h3_data_done(cf, data);
+ break;
+ case CF_CTRL_DATA_DONE:
h3_data_done(cf, data);
break;
- }
case CF_CTRL_DATA_DONE_SEND: {
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
if(stream && !stream->send_closed) {
@@ -2344,6 +2407,7 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
if(ctx->qconn)
ngtcp2_conn_del(ctx->qconn);
Curl_bufcp_free(&ctx->stream_bufcp);
+ Curl_ssl_peer_cleanup(&ctx->peer);
memset(ctx, 0, sizeof(*ctx));
ctx->qlogfd = -1;
@@ -2358,15 +2422,15 @@ static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
CF_DATA_SAVE(save, cf, data);
if(ctx && ctx->qconn) {
char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE];
- ngtcp2_tstamp ts;
+ struct pkt_io_ctx pktx;
ngtcp2_ssize rc;
CURL_TRC_CF(data, cf, "close");
- ts = timestamp();
+ pktx_init(&pktx, cf, data);
rc = ngtcp2_conn_write_connection_close(ctx->qconn, NULL, /* path */
NULL, /* pkt_info */
(uint8_t *)buffer, sizeof(buffer),
- &ctx->last_error, ts);
+ &ctx->last_error, pktx.ts);
if(rc > 0) {
while((send(ctx->q.sockfd, buffer, (SEND_TYPE_ARG3)rc, 0) == -1) &&
SOCKERRNO == EINTR);
@@ -2411,9 +2475,14 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
ctx->version = NGTCP2_PROTO_VER_MAX;
ctx->max_stream_window = H3_STREAM_WINDOW_SIZE;
+ ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
H3_STREAM_POOL_SPARES);
+ result = Curl_ssl_peer_init(&ctx->peer, cf);
+ if(result)
+ return result;
+
#ifdef USE_OPENSSL
result = quic_ssl_ctx(&ctx->sslctx, cf, data);
if(result)
@@ -2559,27 +2628,9 @@ out:
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.
- * This may be a stopping of the service or it may be that the server
- * is reloading and a new instance will start serving soon.
- * In any case, we tear down our socket and start over with a new one.
- * We re-open the underlying UDP cf right now, but do not start
- * connecting until called again.
- */
- int reconn_delay_ms = 200;
-
- CURL_TRC_CF(data, cf, "connect, remote closed, reconnect after %dms",
- reconn_delay_ms);
- Curl_conn_cf_close(cf->next, data);
- cf_ngtcp2_ctx_clear(ctx);
- result = Curl_conn_cf_connect(cf->next, data, FALSE, done);
- if(!result && *done) {
- *done = FALSE;
- ctx->reconnect_at = now;
- ctx->reconnect_at.tv_usec += reconn_delay_ms * 1000;
- Curl_expire(data, reconn_delay_ms, EXPIRE_QUIC);
- result = CURLE_OK;
- }
+ * state. The CONNECT may work in the near future again. Indicate
+ * that as a "weird" reply. */
+ result = CURLE_WEIRD_SERVER_REPLY;
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
@@ -2657,24 +2708,51 @@ static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *input_pending)
{
- bool alive = TRUE;
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ bool alive = FALSE;
+ const ngtcp2_transport_params *rp;
+ struct cf_call_data save;
+ CF_DATA_SAVE(save, cf, data);
*input_pending = FALSE;
+ if(!ctx->qconn)
+ goto out;
+
+ /* Both sides of the QUIC connection announce they max idle times in
+ * the transport parameters. Look at the minimum of both and if
+ * we exceed this, regard the connection as dead. The other side
+ * may have completely purged it and will no longer respond
+ * to any packets from us. */
+ rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
+ if(rp) {
+ timediff_t idletime;
+ uint64_t idle_ms = ctx->max_idle_ms;
+
+ if(rp->max_idle_timeout &&
+ (rp->max_idle_timeout / NGTCP2_MILLISECONDS) < idle_ms)
+ idle_ms = (rp->max_idle_timeout / NGTCP2_MILLISECONDS);
+ idletime = Curl_timediff(Curl_now(), ctx->q.last_io);
+ if(idletime > 0 && (uint64_t)idletime > idle_ms)
+ goto out;
+ }
+
if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
- return FALSE;
+ goto out;
+ alive = TRUE;
if(*input_pending) {
+ CURLcode result;
/* 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" */
*input_pending = FALSE;
- if(cf_progress_ingress(cf, data, NULL))
- alive = FALSE;
- else {
- alive = TRUE;
- }
+ result = cf_progress_ingress(cf, data, NULL);
+ CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
+ alive = result? FALSE : TRUE;
}
+out:
+ CF_DATA_RESTORE(cf, save);
return alive;
}
@@ -2686,7 +2764,7 @@ struct Curl_cftype Curl_cft_http3 = {
cf_ngtcp2_connect,
cf_ngtcp2_close,
Curl_cf_def_get_host,
- cf_ngtcp2_get_select_socks,
+ cf_ngtcp2_adjust_pollset,
cf_ngtcp2_data_pending,
cf_ngtcp2_send,
cf_ngtcp2_recv,
@@ -2706,7 +2784,7 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
CURLcode result;
(void)data;
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
diff --git a/Utilities/cmcurl/lib/vquic/curl_quiche.c b/Utilities/cmcurl/lib/vquic/curl_quiche.c
index 3f5d327..7123d63 100644
--- a/Utilities/cmcurl/lib/vquic/curl_quiche.c
+++ b/Utilities/cmcurl/lib/vquic/curl_quiche.c
@@ -55,10 +55,10 @@
#include "curl_memory.h"
#include "memdebug.h"
-/* #define DEBUG_QUICHE */
+/* HTTP/3 error values defined in RFC 9114, ch. 8.1 */
+#define CURL_H3_NO_ERROR (0x0100)
#define QUIC_MAX_STREAMS (100)
-#define QUIC_IDLE_TIMEOUT (60 * 1000) /* milliseconds */
#define H3_STREAM_WINDOW_SIZE (128 * 1024)
#define H3_STREAM_CHUNK_SIZE (16 * 1024)
@@ -92,6 +92,7 @@ static void keylog_callback(const SSL *ssl, const char *line)
struct cf_quiche_ctx {
struct cf_quic_ctx q;
+ struct ssl_peer peer;
quiche_conn *qconn;
quiche_config *cfg;
quiche_h3_conn *h3c;
@@ -105,7 +106,7 @@ struct cf_quiche_ctx {
struct curltime reconnect_at; /* time the next attempt should start */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
curl_off_t data_recvd;
- size_t sends_on_hold; /* # of streams with SEND_HOLD set */
+ uint64_t max_idle_ms; /* max idle time for QUIC conn */
BIT(goaway); /* got GOAWAY from server */
BIT(got_first_byte); /* if first byte was received */
BIT(x509_store_setup); /* if x509 store has been set up */
@@ -132,6 +133,8 @@ static void cf_quiche_ctx_clear(struct cf_quiche_ctx *ctx)
if(ctx->cfg)
quiche_config_free(ctx->cfg);
Curl_bufcp_free(&ctx->stream_bufcp);
+ Curl_ssl_peer_cleanup(&ctx->peer);
+
memset(ctx, 0, sizeof(*ctx));
}
}
@@ -140,11 +143,16 @@ static CURLcode quic_x509_store_setup(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
+ struct ssl_primary_config *conn_config;
+
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config)
+ return CURLE_FAILED_INIT;
if(!ctx->x509_store_setup) {
- if(cf->conn->ssl_config.verifypeer) {
- const char * const ssl_cafile = cf->conn->ssl_config.CAfile;
- const char * const ssl_capath = cf->conn->ssl_config.CApath;
+ if(conn_config->verifypeer) {
+ const char * const ssl_cafile = conn_config->CAfile;
+ const char * const ssl_capath = conn_config->CApath;
if(ssl_cafile || ssl_capath) {
SSL_CTX_set_verify(ctx->sslctx, SSL_VERIFY_PEER, NULL);
/* tell OpenSSL where to find CA certificates that are used to verify
@@ -177,9 +185,16 @@ static CURLcode quic_x509_store_setup(struct Curl_cfilter *cf,
static CURLcode quic_ssl_setup(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- unsigned char checkip[16];
- struct connectdata *conn = data->conn;
- const char *curves = conn->ssl_config.curves;
+ struct ssl_primary_config *conn_config;
+ CURLcode result;
+
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config)
+ return CURLE_FAILED_INIT;
+
+ result = Curl_ssl_peer_init(&ctx->peer, cf);
+ if(result)
+ return result;
DEBUGASSERT(!ctx->sslctx);
ctx->sslctx = SSL_CTX_new(TLS_method());
@@ -198,8 +213,10 @@ static CURLcode quic_ssl_setup(struct Curl_cfilter *cf, struct Curl_easy *data)
SSL_CTX_set_keylog_callback(ctx->sslctx, keylog_callback);
}
- if(curves && !SSL_CTX_set1_curves_list(ctx->sslctx, curves)) {
- failf(data, "failed setting curves list for QUIC: '%s'", curves);
+ if(conn_config->curves &&
+ !SSL_CTX_set1_curves_list(ctx->sslctx, conn_config->curves)) {
+ failf(data, "failed setting curves list for QUIC: '%s'",
+ conn_config->curves);
return CURLE_SSL_CIPHER;
}
@@ -209,13 +226,8 @@ static CURLcode quic_ssl_setup(struct Curl_cfilter *cf, struct Curl_easy *data)
SSL_set_app_data(ctx->ssl, cf);
- if((0 == Curl_inet_pton(AF_INET, cf->conn->host.name, checkip))
-#ifdef ENABLE_IPV6
- && (0 == Curl_inet_pton(AF_INET6, cf->conn->host.name, checkip))
-#endif
- ) {
- char *snihost = Curl_ssl_snihost(data, cf->conn->host.name, NULL);
- if(!snihost || !SSL_set_tlsext_host_name(ctx->ssl, snihost)) {
+ if(ctx->peer.sni) {
+ if(!SSL_set_tlsext_host_name(ctx->ssl, ctx->peer.sni)) {
failf(data, "Failed set SNI");
SSL_free(ctx->ssl);
ctx->ssl = NULL;
@@ -240,6 +252,7 @@ struct stream_ctx {
bool send_closed; /* stream is locally closed */
bool resp_hds_complete; /* complete, final response has been received */
bool resp_got_header; /* TRUE when h3 stream has recvd some HEADER */
+ BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
};
#define H3_STREAM_CTX(d) ((struct stream_ctx *)(((d) && (d)->req.p.http)? \
@@ -249,56 +262,20 @@ struct stream_ctx {
#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \
H3_STREAM_CTX(d)->id : -2)
-static bool stream_send_is_suspended(struct Curl_easy *data)
-{
- return (data->req.keepon & KEEP_SEND_HOLD);
-}
-
-static void stream_send_suspend(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_quiche_ctx *ctx = cf->ctx;
-
- if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) {
- data->req.keepon |= KEEP_SEND_HOLD;
- ++ctx->sends_on_hold;
- if(H3_STREAM_ID(data) >= 0)
- CURL_TRC_CF(data, cf, "[%"PRId64"] suspend sending",
- H3_STREAM_ID(data));
- else
- CURL_TRC_CF(data, cf, "[%s] suspend sending", data->state.url);
- }
-}
-
-static void stream_send_resume(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_quiche_ctx *ctx = cf->ctx;
-
- if(stream_send_is_suspended(data)) {
- data->req.keepon &= ~KEEP_SEND_HOLD;
- --ctx->sends_on_hold;
- if(H3_STREAM_ID(data) >= 0)
- CURL_TRC_CF(data, cf, "[%"PRId64"] resume sending",
- H3_STREAM_ID(data));
- else
- CURL_TRC_CF(data, cf, "[%s] resume sending", data->state.url);
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
- }
-}
-
static void check_resumes(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct cf_quiche_ctx *ctx = cf->ctx;
struct Curl_easy *sdata;
-
- if(ctx->sends_on_hold) {
- DEBUGASSERT(data->multi);
- for(sdata = data->multi->easyp;
- sdata && ctx->sends_on_hold; sdata = sdata->next) {
- if(stream_send_is_suspended(sdata)) {
- stream_send_resume(cf, sdata);
+ struct stream_ctx *stream;
+
+ DEBUGASSERT(data->multi);
+ for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+ if(sdata->conn == data->conn) {
+ stream = H3_STREAM_CTX(sdata);
+ if(stream && stream->quic_flow_blocked) {
+ stream->quic_flow_blocked = FALSE;
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+ CURL_TRC_CF(data, cf, "[%"PRId64"] unblock", stream->id);
}
}
}
@@ -333,9 +310,15 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
(void)cf;
if(stream) {
CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->id);
- if(stream_send_is_suspended(data)) {
- data->req.keepon &= ~KEEP_SEND_HOLD;
- --ctx->sends_on_hold;
+ if(ctx->qconn && !stream->closed) {
+ quiche_conn_stream_shutdown(ctx->qconn, stream->id,
+ QUICHE_SHUTDOWN_READ, CURL_H3_NO_ERROR);
+ if(!stream->send_closed) {
+ quiche_conn_stream_shutdown(ctx->qconn, stream->id,
+ QUICHE_SHUTDOWN_WRITE, CURL_H3_NO_ERROR);
+ stream->send_closed = TRUE;
+ }
+ stream->closed = TRUE;
}
Curl_bufq_free(&stream->recvbuf);
Curl_h1_req_parse_free(&stream->h1);
@@ -590,7 +573,6 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
}
stream->closed = TRUE;
streamclose(cf->conn, "End of stream");
- data->req.keepon &= ~KEEP_SEND_HOLD;
break;
case QUICHE_H3_EVENT_GOAWAY:
@@ -883,6 +865,8 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
ssize_t nread = -1;
CURLcode result;
+ vquic_ctx_update_time(&ctx->q);
+
if(!stream) {
*err = CURLE_RECV_ERROR;
return -1;
@@ -1035,9 +1019,8 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
if(QUICHE_H3_ERR_STREAM_BLOCKED == stream3_id) {
/* quiche seems to report this error if the connection window is
* exhausted. Which happens frequently and intermittent. */
- CURL_TRC_CF(data, cf, "send_request(%s) rejected with BLOCKED",
- data->state.url);
- stream_send_suspend(cf, data);
+ CURL_TRC_CF(data, cf, "[%"PRId64"] blocked", stream->id);
+ stream->quic_flow_blocked = TRUE;
*err = CURLE_AGAIN;
nwritten = -1;
goto out;
@@ -1081,6 +1064,8 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
CURLcode result;
ssize_t nwritten;
+ vquic_ctx_update_time(&ctx->q);
+
*err = cf_process_ingress(cf, data);
if(*err) {
nwritten = -1;
@@ -1104,7 +1089,7 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
if(!quiche_conn_stream_writable(ctx->qconn, stream->id, len)) {
CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
"-> window exhausted", stream->id, len);
- stream_send_suspend(cf, data);
+ stream->quic_flow_blocked = TRUE;
}
*err = CURLE_AGAIN;
nwritten = -1;
@@ -1173,30 +1158,32 @@ static bool stream_is_writeable(struct Curl_cfilter *cf,
struct cf_quiche_ctx *ctx = cf->ctx;
struct stream_ctx *stream = H3_STREAM_CTX(data);
- return stream &&
- quiche_conn_stream_writable(ctx->qconn, (uint64_t)stream->id, 1);
+ return stream && (quiche_conn_stream_writable(ctx->qconn,
+ (uint64_t)stream->id, 1) > 0);
}
-static int cf_quiche_get_select_socks(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- curl_socket_t *socks)
+static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct SingleRequest *k = &data->req;
- int rv = GETSOCK_BLANK;
-
- socks[0] = ctx->q.sockfd;
+ bool want_recv = CURL_WANT_RECV(data);
+ bool want_send = CURL_WANT_SEND(data);
- /* in an HTTP/3 connection we can basically always get a frame so we should
- always be ready for one */
- rv |= GETSOCK_READSOCK(0);
+ if(ctx->qconn && (want_recv || want_send)) {
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
+ bool c_exhaust, s_exhaust;
- /* we're still uploading or the HTTP/3 layer wants to send data */
- if(((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
- && stream_is_writeable(cf, data))
- rv |= GETSOCK_WRITESOCK(0);
+ c_exhaust = FALSE; /* Have not found any call in quiche that tells
+ us if the connection itself is blocked */
+ s_exhaust = stream && stream->id >= 0 &&
+ (stream->quic_flow_blocked || !stream_is_writeable(cf, data));
+ want_recv = (want_recv || c_exhaust || s_exhaust);
+ want_send = (!s_exhaust && want_send) ||
+ !Curl_bufq_is_empty(&ctx->q.sendbuf);
- return rv;
+ Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send);
+ }
}
/*
@@ -1238,10 +1225,12 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
case CF_CTRL_DATA_PAUSE:
result = h3_data_pause(cf, data, (arg1 != 0));
break;
- case CF_CTRL_DATA_DONE: {
+ case CF_CTRL_DATA_DETACH:
+ h3_data_done(cf, data);
+ break;
+ case CF_CTRL_DATA_DONE:
h3_data_done(cf, data);
break;
- }
case CF_CTRL_DATA_DONE_SEND: {
struct stream_ctx *stream = H3_STREAM_CTX(data);
if(stream && !stream->send_closed) {
@@ -1276,20 +1265,25 @@ static CURLcode cf_verify_peer(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
+ struct ssl_primary_config *conn_config;
CURLcode result = CURLE_OK;
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config)
+ return CURLE_FAILED_INIT;
+
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
cf->conn->httpversion = 30;
cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
- if(cf->conn->ssl_config.verifyhost) {
+ if(conn_config->verifyhost) {
X509 *server_cert;
server_cert = SSL_get_peer_certificate(ctx->ssl);
if(!server_cert) {
result = CURLE_PEER_FAILED_VERIFICATION;
goto out;
}
- result = Curl_ossl_verifyhost(data, cf->conn, server_cert);
+ result = Curl_ossl_verifyhost(data, cf->conn, &ctx->peer, server_cert);
X509_free(server_cert);
if(result)
goto out;
@@ -1345,6 +1339,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
debug_log_init = 1;
}
#endif
+ ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
H3_STREAM_POOL_SPARES);
ctx->data_recvd = 0;
@@ -1359,7 +1354,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
return CURLE_FAILED_INIT;
}
quiche_config_enable_pacing(ctx->cfg, false);
- quiche_config_set_max_idle_timeout(ctx->cfg, QUIC_IDLE_TIMEOUT);
+ quiche_config_set_max_idle_timeout(ctx->cfg, ctx->max_idle_ms * 1000);
quiche_config_set_initial_max_data(ctx->cfg, (1 * 1024 * 1024)
/* (QUIC_MAX_STREAMS/2) * H3_STREAM_WINDOW_SIZE */);
quiche_config_set_initial_max_streams_bidi(ctx->cfg, QUIC_MAX_STREAMS);
@@ -1411,7 +1406,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
}
/* Known to not work on Windows */
-#if !defined(WIN32) && defined(HAVE_QUICHE_CONN_SET_QLOG_FD)
+#if !defined(_WIN32) && defined(HAVE_QUICHE_CONN_SET_QLOG_FD)
{
int qfd;
(void)Curl_qlogdir(data, ctx->scid, sizeof(ctx->scid), &qfd);
@@ -1449,7 +1444,6 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
{
struct cf_quiche_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
- struct curltime now;
if(cf->connected) {
*done = TRUE;
@@ -1464,9 +1458,10 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
}
*done = FALSE;
- now = Curl_now();
+ vquic_ctx_update_time(&ctx->q);
- if(ctx->reconnect_at.tv_sec && Curl_timediff(now, ctx->reconnect_at) < 0) {
+ if(ctx->reconnect_at.tv_sec &&
+ Curl_timediff(ctx->q.last_op, ctx->reconnect_at) < 0) {
/* Not time yet to attempt the next connect */
CURL_TRC_CF(data, cf, "waiting for reconnect time");
goto out;
@@ -1476,7 +1471,7 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
result = cf_connect_start(cf, data);
if(result)
goto out;
- ctx->started_at = now;
+ ctx->started_at = ctx->q.last_op;
result = cf_flush_egress(cf, data);
/* we do not expect to be able to recv anything yet */
goto out;
@@ -1491,9 +1486,9 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
goto out;
if(quiche_conn_is_established(ctx->qconn)) {
+ ctx->handshake_at = ctx->q.last_op;
CURL_TRC_CF(data, cf, "handshake complete after %dms",
- (int)Curl_timediff(now, ctx->started_at));
- ctx->handshake_at = now;
+ (int)Curl_timediff(ctx->handshake_at, ctx->started_at));
result = cf_verify_peer(cf, data);
if(!result) {
CURL_TRC_CF(data, cf, "peer verified");
@@ -1506,27 +1501,9 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
else if(quiche_conn_is_draining(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.
- * This may be a stopping of the service or it may be that the server
- * is reloading and a new instance will start serving soon.
- * In any case, we tear down our socket and start over with a new one.
- * We re-open the underlying UDP cf right now, but do not start
- * connecting until called again.
- */
- int reconn_delay_ms = 200;
-
- CURL_TRC_CF(data, cf, "connect, remote closed, reconnect after %dms",
- reconn_delay_ms);
- Curl_conn_cf_close(cf->next, data);
- cf_quiche_ctx_clear(ctx);
- result = Curl_conn_cf_connect(cf->next, data, FALSE, done);
- if(!result && *done) {
- *done = FALSE;
- ctx->reconnect_at = Curl_now();
- ctx->reconnect_at.tv_usec += reconn_delay_ms * 1000;
- Curl_expire(data, reconn_delay_ms, EXPIRE_QUIC);
- result = CURLE_OK;
- }
+ * state. The CONNECT may work in the near future again. Indicate
+ * that as a "weird" reply. */
+ result = CURLE_WEIRD_SERVER_REPLY;
}
out:
@@ -1550,6 +1527,7 @@ static void cf_quiche_close(struct Curl_cfilter *cf, struct Curl_easy *data)
if(ctx) {
if(ctx->qconn) {
+ vquic_ctx_update_time(&ctx->q);
(void)quiche_conn_close(ctx->qconn, TRUE, 0, NULL, 0);
/* flushing the egress is not a failsafe way to deliver all the
outstanding packets, but we also don't want to get stuck here... */
@@ -1617,9 +1595,32 @@ static bool cf_quiche_conn_is_alive(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *input_pending)
{
+ struct cf_quiche_ctx *ctx = cf->ctx;
bool alive = TRUE;
*input_pending = FALSE;
+ if(!ctx->qconn)
+ return FALSE;
+
+ /* Both sides of the QUIC connection announce they max idle times in
+ * the transport parameters. Look at the minimum of both and if
+ * we exceed this, regard the connection as dead. The other side
+ * may have completely purged it and will no longer respond
+ * to any packets from us. */
+ {
+ quiche_transport_params qpeerparams;
+ timediff_t idletime;
+ uint64_t idle_ms = ctx->max_idle_ms;
+
+ if(quiche_conn_peer_transport_params(ctx->qconn, &qpeerparams) &&
+ qpeerparams.peer_max_idle_timeout &&
+ qpeerparams.peer_max_idle_timeout < idle_ms)
+ idle_ms = qpeerparams.peer_max_idle_timeout;
+ idletime = Curl_timediff(Curl_now(), cf->conn->lastused);
+ if(idletime > 0 && (uint64_t)idletime > idle_ms)
+ return FALSE;
+ }
+
if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
return FALSE;
@@ -1646,7 +1647,7 @@ struct Curl_cftype Curl_cft_http3 = {
cf_quiche_connect,
cf_quiche_close,
Curl_cf_def_get_host,
- cf_quiche_get_select_socks,
+ cf_quiche_adjust_pollset,
cf_quiche_data_pending,
cf_quiche_send,
cf_quiche_recv,
@@ -1667,7 +1668,7 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
(void)data;
(void)conn;
- ctx = calloc(sizeof(*ctx), 1);
+ ctx = calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
diff --git a/Utilities/cmcurl/lib/vquic/vquic.c b/Utilities/cmcurl/lib/vquic/vquic.c
index 9a1a1bb..523b807 100644
--- a/Utilities/cmcurl/lib/vquic/vquic.c
+++ b/Utilities/cmcurl/lib/vquic/vquic.c
@@ -100,6 +100,7 @@ CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx)
}
}
#endif
+ vquic_ctx_update_time(qctx);
return CURLE_OK;
}
@@ -109,6 +110,11 @@ void vquic_ctx_free(struct cf_quic_ctx *qctx)
Curl_bufq_free(&qctx->sendbuf);
}
+void vquic_ctx_update_time(struct cf_quic_ctx *qctx)
+{
+ qctx->last_op = Curl_now();
+}
+
static CURLcode send_packet_no_gso(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct cf_quic_ctx *qctx,
@@ -242,6 +248,7 @@ static CURLcode vquic_send_packets(struct Curl_cfilter *cf,
const uint8_t *pkt, size_t pktlen,
size_t gsolen, size_t *psent)
{
+ CURLcode result;
#ifdef DEBUGBUILD
/* simulate network blocking/partial writes */
if(qctx->wblock_percent > 0) {
@@ -254,10 +261,14 @@ static CURLcode vquic_send_packets(struct Curl_cfilter *cf,
}
#endif
if(qctx->no_gso && pktlen > gsolen) {
- return send_packet_no_gso(cf, data, qctx, pkt, pktlen, gsolen, psent);
+ result = send_packet_no_gso(cf, data, qctx, pkt, pktlen, gsolen, psent);
}
-
- return do_sendmsg(cf, data, qctx, pkt, pktlen, gsolen, psent);
+ else {
+ result = do_sendmsg(cf, data, qctx, pkt, pktlen, gsolen, psent);
+ }
+ if(!result)
+ qctx->last_io = qctx->last_op;
+ return result;
}
CURLcode vquic_flush(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -524,13 +535,17 @@ CURLcode vquic_recv_packets(struct Curl_cfilter *cf,
size_t max_pkts,
vquic_recv_pkt_cb *recv_cb, void *userp)
{
+ CURLcode result;
#if defined(HAVE_SENDMMSG)
- return recvmmsg_packets(cf, data, qctx, max_pkts, recv_cb, userp);
+ result = recvmmsg_packets(cf, data, qctx, max_pkts, recv_cb, userp);
#elif defined(HAVE_SENDMSG)
- return recvmsg_packets(cf, data, qctx, max_pkts, recv_cb, userp);
+ result = recvmsg_packets(cf, data, qctx, max_pkts, recv_cb, userp);
#else
- return recvfrom_packets(cf, data, qctx, max_pkts, recv_cb, userp);
+ result = recvfrom_packets(cf, data, qctx, max_pkts, recv_cb, userp);
#endif
+ if(!result)
+ qctx->last_io = qctx->last_op;
+ return result;
}
/*
diff --git a/Utilities/cmcurl/lib/vquic/vquic_int.h b/Utilities/cmcurl/lib/vquic/vquic_int.h
index dbcd009..a820f39 100644
--- a/Utilities/cmcurl/lib/vquic/vquic_int.h
+++ b/Utilities/cmcurl/lib/vquic/vquic_int.h
@@ -31,6 +31,8 @@
#define MAX_PKT_BURST 10
#define MAX_UDP_PAYLOAD_SIZE 1452
+/* Default QUIC connection timeout we announce from our side */
+#define CURL_QUIC_MAX_IDLE_MS (120 * 1000)
struct cf_quic_ctx {
curl_socket_t sockfd; /* connected UDP socket */
@@ -38,6 +40,8 @@ struct cf_quic_ctx {
socklen_t local_addrlen; /* length of local address */
struct bufq sendbuf; /* buffer for sending one or more packets */
+ struct curltime last_op; /* last (attempted) send/recv operation */
+ struct curltime last_io; /* last successful socket IO */
size_t gsolen; /* length of individual packets in send buf */
size_t split_len; /* if != 0, buffer length after which GSO differs */
size_t split_gsolen; /* length of individual packets after split_len */
@@ -50,6 +54,8 @@ struct cf_quic_ctx {
CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx);
void vquic_ctx_free(struct cf_quic_ctx *qctx);
+void vquic_ctx_update_time(struct cf_quic_ctx *qctx);
+
void vquic_push_blocked_pkt(struct Curl_cfilter *cf,
struct cf_quic_ctx *qctx,
const uint8_t *pkt, size_t pktlen, size_t gsolen);
diff --git a/Utilities/cmcurl/lib/vssh/libssh.c b/Utilities/cmcurl/lib/vssh/libssh.c
index b0f49d6..97143c4 100644
--- a/Utilities/cmcurl/lib/vssh/libssh.c
+++ b/Utilities/cmcurl/lib/vssh/libssh.c
@@ -93,6 +93,7 @@
#if defined(__GNUC__) && \
(LIBSSH_VERSION_MINOR >= 10) || \
(LIBSSH_VERSION_MAJOR > 0)
+#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
@@ -1159,13 +1160,23 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
else if(statvfs) {
+ #ifdef _MSC_VER
+ #define LIBSSH_VFS_SIZE_MASK "I64u"
+ #else
+ #define LIBSSH_VFS_SIZE_MASK PRIu64
+ #endif
char *tmp = aprintf("statvfs:\n"
- "f_bsize: %llu\n" "f_frsize: %llu\n"
- "f_blocks: %llu\n" "f_bfree: %llu\n"
- "f_bavail: %llu\n" "f_files: %llu\n"
- "f_ffree: %llu\n" "f_favail: %llu\n"
- "f_fsid: %llu\n" "f_flag: %llu\n"
- "f_namemax: %llu\n",
+ "f_bsize: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_frsize: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_blocks: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_bfree: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_bavail: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_files: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_ffree: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_favail: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_fsid: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_flag: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_namemax: %" LIBSSH_VFS_SIZE_MASK "\n",
statvfs->f_bsize, statvfs->f_frsize,
statvfs->f_blocks, statvfs->f_bfree,
statvfs->f_bavail, statvfs->f_files,
@@ -1466,13 +1477,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
state(data, SSH_STOP);
break;
}
- /* since this counts what we send to the client, we include the
- newline in this counter */
- data->req.bytecount += sshc->readdir_len + 1;
- /* output debug output if that is requested */
- Curl_debug(data, CURLINFO_DATA_OUT, (char *)sshc->readdir_filename,
- sshc->readdir_len);
}
else {
if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
@@ -1564,12 +1569,6 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_dyn_ptr(&sshc->readdir_buf),
Curl_dyn_len(&sshc->readdir_buf));
- if(!result) {
- /* output debug output if that is requested */
- Curl_debug(data, CURLINFO_DATA_OUT, Curl_dyn_ptr(&sshc->readdir_buf),
- Curl_dyn_len(&sshc->readdir_buf));
- data->req.bytecount += Curl_dyn_len(&sshc->readdir_buf);
- }
ssh_string_free_char(sshc->readdir_tmp);
sshc->readdir_tmp = NULL;
@@ -1963,10 +1962,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
ssh_disconnect(sshc->ssh_session);
if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) {
/* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back,
- explicitly mark it as closed with the memdebug macro. This libssh
+ tell the connection to forget about it. This libssh
bug is fixed in 0.10.0. */
- fake_sclose(conn->sock[FIRSTSOCKET]);
- conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;
+ Curl_conn_forget_socket(data, FIRSTSOCKET);
}
SSH_STRING_FREE_CHAR(sshc->homedir);
@@ -2959,4 +2957,10 @@ void Curl_ssh_version(char *buffer, size_t buflen)
(void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
}
+#if defined(__GNUC__) && \
+ (LIBSSH_VERSION_MINOR >= 10) || \
+ (LIBSSH_VERSION_MAJOR > 0)
+#pragma GCC diagnostic pop
+#endif
+
#endif /* USE_LIBSSH */
diff --git a/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c
index f539b39..11f5f4f 100644
--- a/Utilities/cmcurl/lib/vssh/libssh2.c
+++ b/Utilities/cmcurl/lib/vssh/libssh2.c
@@ -1537,139 +1537,137 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
state(data, SSH_SFTP_NEXT_QUOTE);
break;
}
- {
- /*
- * the arguments following the command must be separated from the
- * command with a space so we can check for it unconditionally
- */
- cp = strchr(cmd, ' ');
- if(!cp) {
- failf(data, "Syntax error command '%s', missing parameter",
- cmd);
+
+ /*
+ * the arguments following the command must be separated from the
+ * command with a space so we can check for it unconditionally
+ */
+ cp = strchr(cmd, ' ');
+ if(!cp) {
+ failf(data, "Syntax error command '%s', missing parameter",
+ cmd);
+ state(data, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+
+ /*
+ * also, every command takes at least one argument so we get that
+ * first argument right now
+ */
+ result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data, "Syntax error: Bad first parameter to '%s'", cmd);
+ state(data, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = result;
+ break;
+ }
+
+ /*
+ * SFTP is a binary protocol, so we don't send text commands
+ * to the server. Instead, we scan for commands used by
+ * OpenSSH's sftp program and call the appropriate libssh2
+ * functions.
+ */
+ if(strncasecompare(cmd, "chgrp ", 6) ||
+ strncasecompare(cmd, "chmod ", 6) ||
+ strncasecompare(cmd, "chown ", 6) ||
+ strncasecompare(cmd, "atime ", 6) ||
+ strncasecompare(cmd, "mtime ", 6)) {
+ /* attribute change */
+
+ /* sshc->quote_path1 contains the mode to set */
+ /* get the destination */
+ result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data, "Syntax error in %s: Bad second parameter", cmd);
+ Curl_safefree(sshc->quote_path1);
state(data, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ sshc->actualcode = result;
break;
}
-
- /*
- * also, every command takes at least one argument so we get that
- * first argument right now
- */
- result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
+ memset(&sshp->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+ state(data, SSH_SFTP_QUOTE_STAT);
+ break;
+ }
+ if(strncasecompare(cmd, "ln ", 3) ||
+ strncasecompare(cmd, "symlink ", 8)) {
+ /* symbolic linking */
+ /* sshc->quote_path1 is the source */
+ /* get the destination */
+ result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
if(result) {
if(result == CURLE_OUT_OF_MEMORY)
failf(data, "Out of memory");
else
- failf(data, "Syntax error: Bad first parameter to '%s'", cmd);
+ failf(data,
+ "Syntax error in ln/symlink: Bad second parameter");
+ Curl_safefree(sshc->quote_path1);
state(data, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
break;
}
-
- /*
- * SFTP is a binary protocol, so we don't send text commands
- * to the server. Instead, we scan for commands used by
- * OpenSSH's sftp program and call the appropriate libssh2
- * functions.
- */
- if(strncasecompare(cmd, "chgrp ", 6) ||
- strncasecompare(cmd, "chmod ", 6) ||
- strncasecompare(cmd, "chown ", 6) ||
- strncasecompare(cmd, "atime ", 6) ||
- strncasecompare(cmd, "mtime ", 6)) {
- /* attribute change */
-
- /* sshc->quote_path1 contains the mode to set */
- /* get the destination */
- result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
- if(result) {
- if(result == CURLE_OUT_OF_MEMORY)
- failf(data, "Out of memory");
- else
- failf(data, "Syntax error in %s: Bad second parameter", cmd);
- Curl_safefree(sshc->quote_path1);
- state(data, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = result;
- break;
- }
- memset(&sshp->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
- state(data, SSH_SFTP_QUOTE_STAT);
- break;
- }
- if(strncasecompare(cmd, "ln ", 3) ||
- strncasecompare(cmd, "symlink ", 8)) {
- /* symbolic linking */
- /* sshc->quote_path1 is the source */
- /* get the destination */
- result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
- if(result) {
- if(result == CURLE_OUT_OF_MEMORY)
- failf(data, "Out of memory");
- else
- failf(data,
- "Syntax error in ln/symlink: Bad second parameter");
- Curl_safefree(sshc->quote_path1);
- state(data, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = result;
- break;
- }
- state(data, SSH_SFTP_QUOTE_SYMLINK);
- break;
- }
- else if(strncasecompare(cmd, "mkdir ", 6)) {
- /* create dir */
- state(data, SSH_SFTP_QUOTE_MKDIR);
- break;
- }
- else if(strncasecompare(cmd, "rename ", 7)) {
- /* rename file */
- /* first param is the source path */
- /* second param is the dest. path */
- result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
- if(result) {
- if(result == CURLE_OUT_OF_MEMORY)
- failf(data, "Out of memory");
- else
- failf(data, "Syntax error in rename: Bad second parameter");
- Curl_safefree(sshc->quote_path1);
- state(data, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = result;
- break;
- }
- state(data, SSH_SFTP_QUOTE_RENAME);
- break;
- }
- else if(strncasecompare(cmd, "rmdir ", 6)) {
- /* delete dir */
- state(data, SSH_SFTP_QUOTE_RMDIR);
- break;
- }
- else if(strncasecompare(cmd, "rm ", 3)) {
- state(data, SSH_SFTP_QUOTE_UNLINK);
+ state(data, SSH_SFTP_QUOTE_SYMLINK);
+ break;
+ }
+ else if(strncasecompare(cmd, "mkdir ", 6)) {
+ /* create dir */
+ state(data, SSH_SFTP_QUOTE_MKDIR);
+ break;
+ }
+ else if(strncasecompare(cmd, "rename ", 7)) {
+ /* rename file */
+ /* first param is the source path */
+ /* second param is the dest. path */
+ result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data, "Syntax error in rename: Bad second parameter");
+ Curl_safefree(sshc->quote_path1);
+ state(data, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = result;
break;
}
+ state(data, SSH_SFTP_QUOTE_RENAME);
+ break;
+ }
+ else if(strncasecompare(cmd, "rmdir ", 6)) {
+ /* delete dir */
+ state(data, SSH_SFTP_QUOTE_RMDIR);
+ break;
+ }
+ else if(strncasecompare(cmd, "rm ", 3)) {
+ state(data, SSH_SFTP_QUOTE_UNLINK);
+ break;
+ }
#ifdef HAS_STATVFS_SUPPORT
- else if(strncasecompare(cmd, "statvfs ", 8)) {
- state(data, SSH_SFTP_QUOTE_STATVFS);
- break;
- }
-#endif
-
- failf(data, "Unknown SFTP command");
- Curl_safefree(sshc->quote_path1);
- Curl_safefree(sshc->quote_path2);
- state(data, SSH_SFTP_CLOSE);
- sshc->nextstate = SSH_NO_STATE;
- sshc->actualcode = CURLE_QUOTE_ERROR;
+ else if(strncasecompare(cmd, "statvfs ", 8)) {
+ state(data, SSH_SFTP_QUOTE_STATVFS);
break;
}
+#endif
+
+ failf(data, "Unknown SFTP command");
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ state(data, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
}
- break;
case SSH_SFTP_NEXT_QUOTE:
Curl_safefree(sshc->quote_path1);
@@ -1962,13 +1960,23 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
else if(rc == 0) {
+ #ifdef _MSC_VER
+ #define LIBSSH2_VFS_SIZE_MASK "I64u"
+ #else
+ #define LIBSSH2_VFS_SIZE_MASK "llu"
+ #endif
char *tmp = aprintf("statvfs:\n"
- "f_bsize: %llu\n" "f_frsize: %llu\n"
- "f_blocks: %llu\n" "f_bfree: %llu\n"
- "f_bavail: %llu\n" "f_files: %llu\n"
- "f_ffree: %llu\n" "f_favail: %llu\n"
- "f_fsid: %llu\n" "f_flag: %llu\n"
- "f_namemax: %llu\n",
+ "f_bsize: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_frsize: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_blocks: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_bfree: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_bavail: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_files: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_ffree: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_favail: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_fsid: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_flag: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_namemax: %" LIBSSH2_VFS_SIZE_MASK "\n",
statvfs.f_bsize, statvfs.f_frsize,
statvfs.f_blocks, statvfs.f_bfree,
statvfs.f_bavail, statvfs.f_files,
@@ -2341,14 +2349,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
state(data, SSH_STOP);
break;
}
- /* since this counts what we send to the client, we include the
- newline in this counter */
- data->req.bytecount += readdir_len + 1;
- /* output debug output if that is requested */
- Curl_debug(data, CURLINFO_DATA_IN, sshp->readdir_filename,
- readdir_len);
- Curl_debug(data, CURLINFO_DATA_IN, (char *)"\n", 1);
}
else {
result = Curl_dyn_add(&sshp->readdir, sshp->readdir_longentry);
@@ -2427,13 +2428,6 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_dyn_ptr(&sshp->readdir),
Curl_dyn_len(&sshp->readdir));
- if(!result) {
- /* output debug output if that is requested */
- Curl_debug(data, CURLINFO_DATA_IN,
- Curl_dyn_ptr(&sshp->readdir),
- Curl_dyn_len(&sshp->readdir));
- data->req.bytecount += Curl_dyn_len(&sshp->readdir);
- }
if(result) {
Curl_dyn_free(&sshp->readdir);
state(data, SSH_STOP);
diff --git a/Utilities/cmcurl/lib/vssh/ssh.h b/Utilities/cmcurl/lib/vssh/ssh.h
index 1e1b137..ca0533a 100644
--- a/Utilities/cmcurl/lib/vssh/ssh.h
+++ b/Utilities/cmcurl/lib/vssh/ssh.h
@@ -267,6 +267,7 @@ void Curl_ssh_attach(struct Curl_easy *data,
/* for non-SSH builds */
#define Curl_ssh_cleanup()
#define Curl_ssh_attach(x,y)
+#define Curl_ssh_init() 0
#endif
#endif /* HEADER_CURL_SSH_H */
diff --git a/Utilities/cmcurl/lib/vssh/wolfssh.c b/Utilities/cmcurl/lib/vssh/wolfssh.c
index 39cee50..4da7e9d 100644
--- a/Utilities/cmcurl/lib/vssh/wolfssh.c
+++ b/Utilities/cmcurl/lib/vssh/wolfssh.c
@@ -343,9 +343,6 @@ static CURLcode wssh_setup_connection(struct Curl_easy *data,
return CURLE_OK;
}
-static Curl_recv wscp_recv, wsftp_recv;
-static Curl_send wscp_send, wsftp_send;
-
static int userauth(byte authtype,
WS_UserAuthData* authdata,
void *ctx)
diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c
index 934149c..a6566f4 100644
--- a/Utilities/cmcurl/lib/vtls/bearssl.c
+++ b/Utilities/cmcurl/lib/vtls/bearssl.c
@@ -582,17 +582,12 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
(ca_info_blob ? NULL : conn_config->CAfile);
- const char *hostname = connssl->hostname;
+ const char *hostname = connssl->peer.hostname;
const bool verifypeer = conn_config->verifypeer;
const bool verifyhost = conn_config->verifyhost;
CURLcode ret;
unsigned version_min, version_max;
int session_set = 0;
-#ifdef ENABLE_IPV6
- struct in6_addr addr;
-#else
- struct in_addr addr;
-#endif
DEBUGASSERT(backend);
CURL_TRC_CF(data, cf, "connect_step1");
@@ -706,11 +701,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
- if((1 == Curl_inet_pton(AF_INET, hostname, &addr))
-#ifdef ENABLE_IPV6
- || (1 == Curl_inet_pton(AF_INET6, hostname, &addr))
-#endif
- ) {
+ if(connssl->peer.is_ip_address) {
if(verifyhost) {
failf(data, "BearSSL: "
"host verification of IP address is not supported");
@@ -719,12 +710,11 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
hostname = NULL;
}
else {
- char *snihost = Curl_ssl_snihost(data, hostname, NULL);
- if(!snihost) {
+ if(!connssl->peer.sni) {
failf(data, "Failed to set SNI");
return CURLE_SSL_CONNECT_ERROR;
}
- hostname = snihost;
+ hostname = connssl->peer.sni;
CURL_TRC_CF(data, cf, "connect_step1, SNI set");
}
@@ -749,26 +739,26 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
return CURLE_OK;
}
-static int bearssl_get_select_socks(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- curl_socket_t *socks)
+static void bearssl_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
{
- struct ssl_connect_data *connssl = cf->ctx;
- curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
-
- if(sock == CURL_SOCKET_BAD)
- return GETSOCK_BLANK;
- else {
- struct bearssl_ssl_backend_data *backend =
- (struct bearssl_ssl_backend_data *)connssl->backend;
- unsigned state = br_ssl_engine_current_state(&backend->ctx.eng);
- if(state & BR_SSL_SENDREC) {
- socks[0] = sock;
- return GETSOCK_WRITESOCK(0);
+ if(!cf->connected) {
+ curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
+ if(sock != CURL_SOCKET_BAD) {
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct bearssl_ssl_backend_data *backend =
+ (struct bearssl_ssl_backend_data *)connssl->backend;
+ unsigned state = br_ssl_engine_current_state(&backend->ctx.eng);
+
+ if(state & BR_SSL_SENDREC) {
+ Curl_pollset_set_out_only(data, ps, sock);
+ }
+ else {
+ Curl_pollset_set_in_only(data, ps, sock);
+ }
}
}
- socks[0] = sock;
- return GETSOCK_READSOCK(0);
}
static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
@@ -1210,7 +1200,7 @@ const struct Curl_ssl Curl_ssl_bearssl = {
Curl_none_cert_status_request, /* cert_status_request */
bearssl_connect, /* connect */
bearssl_connect_nonblocking, /* connect_nonblocking */
- bearssl_get_select_socks, /* getsock */
+ bearssl_adjust_pollset, /* adjust_pollset */
bearssl_get_internals, /* get_internals */
bearssl_close, /* close_one */
Curl_none_close_all, /* close_all */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c
index c538a96..4e337f5 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.c
+++ b/Utilities/cmcurl/lib/vtls/gtls.c
@@ -402,18 +402,13 @@ set_ssl_version_min_max(struct Curl_easy *data,
CURLcode gtls_client_init(struct Curl_easy *data,
struct ssl_primary_config *config,
struct ssl_config_data *ssl_config,
- const char *hostname,
+ struct ssl_peer *peer,
struct gtls_instance *gtls,
long *pverifyresult)
{
unsigned int init_flags;
int rc;
bool sni = TRUE; /* default is SNI enabled */
-#ifdef ENABLE_IPV6
- struct in6_addr addr;
-#else
- struct in_addr addr;
-#endif
const char *prioritylist;
const char *err = NULL;
const char *tls13support;
@@ -460,50 +455,60 @@ CURLcode gtls_client_init(struct Curl_easy *data,
}
#endif
- if(config->CAfile) {
- /* set the trusted CA cert bundle file */
- gnutls_certificate_set_verify_flags(gtls->cred,
- GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
+ if(config->verifypeer) {
+ bool imported_native_ca = false;
- rc = gnutls_certificate_set_x509_trust_file(gtls->cred,
- config->CAfile,
- GNUTLS_X509_FMT_PEM);
- if(rc < 0) {
- infof(data, "error reading ca cert file %s (%s)",
- config->CAfile, gnutls_strerror(rc));
- if(config->verifypeer) {
- *pverifyresult = rc;
- return CURLE_SSL_CACERT_BADFILE;
+ if(ssl_config->native_ca_store) {
+ rc = gnutls_certificate_set_x509_system_trust(gtls->cred);
+ if(rc < 0)
+ infof(data, "error reading native ca store (%s), continuing anyway",
+ gnutls_strerror(rc));
+ else {
+ infof(data, "found %d certificates in native ca store", rc);
+ if(rc > 0)
+ imported_native_ca = true;
}
}
- else
- infof(data, "found %d certificates in %s", rc, config->CAfile);
- }
- if(config->CApath) {
- /* set the trusted CA cert directory */
- rc = gnutls_certificate_set_x509_trust_dir(gtls->cred,
- config->CApath,
- GNUTLS_X509_FMT_PEM);
- if(rc < 0) {
- infof(data, "error reading ca cert file %s (%s)",
- config->CApath, gnutls_strerror(rc));
- if(config->verifypeer) {
- *pverifyresult = rc;
- return CURLE_SSL_CACERT_BADFILE;
+ if(config->CAfile) {
+ /* set the trusted CA cert bundle file */
+ gnutls_certificate_set_verify_flags(gtls->cred,
+ GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
+
+ rc = gnutls_certificate_set_x509_trust_file(gtls->cred,
+ config->CAfile,
+ GNUTLS_X509_FMT_PEM);
+ if(rc < 0) {
+ infof(data, "error reading ca cert file %s (%s)%s",
+ config->CAfile, gnutls_strerror(rc),
+ (imported_native_ca ? ", continuing anyway" : ""));
+ if(!imported_native_ca) {
+ *pverifyresult = rc;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
}
+ else
+ infof(data, "found %d certificates in %s", rc, config->CAfile);
}
- else
- infof(data, "found %d certificates in %s", rc, config->CApath);
- }
-#ifdef CURL_CA_FALLBACK
- /* use system ca certificate store as fallback */
- if(config->verifypeer && !(config->CAfile || config->CApath)) {
- /* this ignores errors on purpose */
- gnutls_certificate_set_x509_system_trust(gtls->cred);
+ if(config->CApath) {
+ /* set the trusted CA cert directory */
+ rc = gnutls_certificate_set_x509_trust_dir(gtls->cred,
+ config->CApath,
+ GNUTLS_X509_FMT_PEM);
+ if(rc < 0) {
+ infof(data, "error reading ca cert file %s (%s)%s",
+ config->CApath, gnutls_strerror(rc),
+ (imported_native_ca ? ", continuing anyway" : ""));
+ if(!imported_native_ca) {
+ *pverifyresult = rc;
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+ else
+ infof(data, "found %d certificates in %s", rc, config->CApath);
+ }
}
-#endif
if(config->CRLfile) {
/* set the CRL list file */
@@ -537,15 +542,9 @@ CURLcode gtls_client_init(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
- if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
-#ifdef ENABLE_IPV6
- (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
-#endif
- sni) {
- size_t snilen;
- char *snihost = Curl_ssl_snihost(data, hostname, &snilen);
- if(!snihost || gnutls_server_name_set(gtls->session, GNUTLS_NAME_DNS,
- snihost, snilen) < 0) {
+ if(sni && peer->sni) {
+ if(gnutls_server_name_set(gtls->session, GNUTLS_NAME_DNS,
+ peer->sni, strlen(peer->sni)) < 0) {
failf(data, "Failed to set SNI");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -699,7 +698,7 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_OK;
result = gtls_client_init(data, conn_config, ssl_config,
- connssl->hostname,
+ &connssl->peer,
&backend->gtls, pverifyresult);
if(result)
return result;
@@ -811,8 +810,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
gnutls_session_t session,
struct ssl_primary_config *config,
struct ssl_config_data *ssl_config,
- const char *hostname,
- const char *dispname,
+ struct ssl_peer *peer,
const char *pinned_key)
{
unsigned int cert_list_size;
@@ -1068,7 +1066,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
in RFC2818 (HTTPS), which takes into account wildcards, and the subject
alternative name PKIX extension. Returns non zero on success, and zero on
failure. */
- rc = gnutls_x509_crt_check_hostname(x509_cert, hostname);
+ rc = gnutls_x509_crt_check_hostname(x509_cert, peer->hostname);
#if GNUTLS_VERSION_NUMBER < 0x030306
/* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
addresses. */
@@ -1081,10 +1079,10 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
unsigned char addrbuf[sizeof(struct use_addr)];
size_t addrlen = 0;
- if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0)
+ if(Curl_inet_pton(AF_INET, peer->hostname, addrbuf) > 0)
addrlen = 4;
#ifdef ENABLE_IPV6
- else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0)
+ else if(Curl_inet_pton(AF_INET6, peer->hostname, addrbuf) > 0)
addrlen = 16;
#endif
@@ -1114,13 +1112,13 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
if(!rc) {
if(config->verifyhost) {
failf(data, "SSL: certificate subject name (%s) does not match "
- "target host name '%s'", certname, dispname);
+ "target host name '%s'", certname, peer->dispname);
gnutls_x509_crt_deinit(x509_cert);
return CURLE_PEER_FAILED_VERIFICATION;
}
else
infof(data, " common name: %s (does not match '%s')",
- certname, dispname);
+ certname, peer->dispname);
}
else
infof(data, " common name: %s (matched)", certname);
@@ -1253,8 +1251,7 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
CURLcode result;
result = Curl_gtls_verifyserver(data, session, conn_config, ssl_config,
- connssl->hostname, connssl->dispname,
- pinned_key);
+ &connssl->peer, pinned_key);
if(result)
goto out;
@@ -1662,7 +1659,7 @@ const struct Curl_ssl Curl_ssl_gnutls = {
gtls_cert_status_request, /* cert_status_request */
gtls_connect, /* connect */
gtls_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_get_select_socks, /* getsock */
+ Curl_ssl_adjust_pollset, /* adjust_pollset */
gtls_get_internals, /* get_internals */
gtls_close, /* close_one */
Curl_none_close_all, /* close_all */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h
index ac141e1..1a81c01 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.h
+++ b/Utilities/cmcurl/lib/vtls/gtls.h
@@ -43,6 +43,7 @@ struct Curl_easy;
struct Curl_cfilter;
struct ssl_primary_config;
struct ssl_config_data;
+struct ssl_peer;
struct gtls_instance {
gnutls_session_t session;
@@ -56,7 +57,7 @@ CURLcode
gtls_client_init(struct Curl_easy *data,
struct ssl_primary_config *config,
struct ssl_config_data *ssl_config,
- const char *hostname,
+ struct ssl_peer *peer,
struct gtls_instance *gtls,
long *pverifyresult);
@@ -65,8 +66,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
gnutls_session_t session,
struct ssl_primary_config *config,
struct ssl_config_data *ssl_config,
- const char *hostname,
- const char *dispname,
+ struct ssl_peer *peer,
const char *pinned_key);
extern const struct Curl_ssl Curl_ssl_gnutls;
diff --git a/Utilities/cmcurl/lib/vtls/keylog.c b/Utilities/cmcurl/lib/vtls/keylog.c
index d37bb18..fbcb25c 100644
--- a/Utilities/cmcurl/lib/vtls/keylog.c
+++ b/Utilities/cmcurl/lib/vtls/keylog.c
@@ -23,6 +23,11 @@
***************************************************************************/
#include "curl_setup.h"
+#if defined(USE_OPENSSL) || \
+ defined(USE_WOLFSSL) || \
+ (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \
+ defined(USE_QUICHE)
+
#include "keylog.h"
#include <curl/curl.h>
@@ -55,7 +60,7 @@ Curl_tls_keylog_open(void)
if(keylog_file_name) {
keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT);
if(keylog_file_fp) {
-#ifdef WIN32
+#ifdef _WIN32
if(setvbuf(keylog_file_fp, NULL, _IONBF, 0))
#else
if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096))
@@ -157,3 +162,5 @@ Curl_tls_keylog_write(const char *label,
fputs(line, keylog_file_fp);
return true;
}
+
+#endif /* TLS or QUIC backend */
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c
index 2f994d7..38f7de7 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.c
@@ -322,7 +322,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
char * const ssl_cert = ssl_config->primary.clientcert;
const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
const char * const ssl_crlfile = ssl_config->primary.CRLfile;
- const char *hostname = connssl->hostname;
+ const char *hostname = connssl->peer.hostname;
int ret = -1;
char errorbuf[128];
@@ -639,9 +639,9 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
mbedtls_ssl_conf_own_cert(&backend->config,
&backend->clicert, &backend->pk);
}
- {
- char *snihost = Curl_ssl_snihost(data, hostname, NULL);
- if(!snihost || mbedtls_ssl_set_hostname(&backend->ssl, snihost)) {
+
+ if(connssl->peer.sni) {
+ if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni)) {
/* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and
the name to set in the SNI extension. So even if curl connects to a
host specified as an IP address, this function must be used. */
@@ -1274,7 +1274,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
Curl_none_cert_status_request, /* cert_status_request */
mbedtls_connect, /* connect */
mbedtls_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_get_select_socks, /* getsock */
+ Curl_ssl_adjust_pollset, /* adjust_pollset */
mbedtls_get_internals, /* get_internals */
mbedtls_close, /* close_one */
mbedtls_close_all, /* close_all */
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
index bcb7106..22b1b22 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
@@ -51,7 +51,7 @@ int Curl_mbedtlsthreadlock_thread_setup(void)
{
int i;
- mutex_buf = calloc(NUMT * sizeof(MBEDTLS_MUTEX_T), 1);
+ mutex_buf = calloc(1, NUMT * sizeof(MBEDTLS_MUTEX_T));
if(!mutex_buf)
return 0; /* error, no number of threads defined */
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index 15d84ed..ca6d931 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -79,6 +79,8 @@
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/pkcs12.h>
+#include <openssl/tls1.h>
+#include <openssl/evp.h>
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
#include <openssl/ocsp.h>
@@ -96,6 +98,9 @@
#include "curl_memory.h"
#include "memdebug.h"
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
/* Uncomment the ALLOW_RENEG line to a real #define if you want to allow TLS
renegotiations when built with BoringSSL. Renegotiating is non-compliant
@@ -173,8 +178,6 @@
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
#define HAVE_EVP_PKEY_GET_PARAMS 1
-#else
-#define SSL_get1_peer_certificate SSL_get_peer_certificate
#endif
#ifdef HAVE_EVP_PKEY_GET_PARAMS
@@ -237,7 +240,11 @@
#elif defined(OPENSSL_IS_AWSLC)
#define OSSL_PACKAGE "AWS-LC"
#else
-#define OSSL_PACKAGE "OpenSSL"
+# if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
+# define OSSL_PACKAGE "quictls"
+# else
+# define OSSL_PACKAGE "OpenSSL"
+#endif
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
@@ -546,9 +553,9 @@ CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl)
#else
RSA_get0_key(rsa, &n, &e, NULL);
#endif /* HAVE_EVP_PKEY_GET_PARAMS */
- BIO_printf(mem, "%d", BN_num_bits(n));
+ BIO_printf(mem, "%d", n ? BN_num_bits(n) : 0);
#else
- BIO_printf(mem, "%d", BN_num_bits(rsa->n));
+ BIO_printf(mem, "%d", rsa->n ? BN_num_bits(rsa->n) : 0);
#endif /* HAVE_OPAQUE_RSA_DSA_DH */
push_certinfo("RSA Public Key", i);
print_pubkey_BN(rsa, n, i);
@@ -2106,22 +2113,6 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
return FALSE;
}
-static CURLcode
-ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
- X509 *server_cert, const char *hostname,
- const char *dispname);
-
-CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
- X509 *server_cert)
-{
- const char *hostname, *dispname;
- int port;
-
- (void)conn;
- Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &dispname, &port);
- return ossl_verifyhost(data, conn, server_cert, hostname, dispname);
-}
-
/* Quote from RFC2818 section 3.1 "Server Identity"
If a subjectAltName extension of type dNSName is present, that MUST
@@ -2144,10 +2135,8 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
This function is now used from ngtcp2 (QUIC) as well.
*/
-static CURLcode
-ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
- X509 *server_cert, const char *hostname,
- const char *dispname)
+CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
+ struct ssl_peer *peer, X509 *server_cert)
{
bool matched = FALSE;
int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
@@ -2164,25 +2153,21 @@ ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
size_t hostlen;
(void)conn;
- hostlen = strlen(hostname);
-
-#ifndef ENABLE_IPV6
- /* Silence compiler warnings for unused params */
- (void) conn;
-#endif
-
+ hostlen = strlen(peer->hostname);
+ if(peer->is_ip_address) {
#ifdef ENABLE_IPV6
- if(conn->bits.ipv6_ip &&
- Curl_inet_pton(AF_INET6, hostname, &addr)) {
- target = GEN_IPADD;
- addrlen = sizeof(struct in6_addr);
- }
- else
-#endif
- if(Curl_inet_pton(AF_INET, hostname, &addr)) {
+ if(conn->bits.ipv6_ip &&
+ Curl_inet_pton(AF_INET6, peer->hostname, &addr)) {
target = GEN_IPADD;
- addrlen = sizeof(struct in_addr);
+ addrlen = sizeof(struct in6_addr);
}
+ else
+#endif
+ if(Curl_inet_pton(AF_INET, peer->hostname, &addr)) {
+ target = GEN_IPADD;
+ addrlen = sizeof(struct in_addr);
+ }
+ }
/* get a "list" of alternative names */
altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);
@@ -2232,9 +2217,9 @@ ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
if((altlen == strlen(altptr)) &&
/* if this isn't true, there was an embedded zero in the name
string and we cannot match it. */
- subj_alt_hostcheck(data,
- altptr,
- altlen, hostname, hostlen, dispname)) {
+ subj_alt_hostcheck(data, altptr, altlen,
+ peer->hostname, hostlen,
+ peer->dispname)) {
dnsmatched = TRUE;
}
break;
@@ -2246,7 +2231,7 @@ ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
ipmatched = TRUE;
infof(data,
" subjectAltName: host \"%s\" matched cert's IP address!",
- dispname);
+ peer->dispname);
}
break;
}
@@ -2262,9 +2247,9 @@ ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
/* an alternative name matched */
;
else if(dNSName || iPAddress) {
- infof(data, " subjectAltName does not match %s", dispname);
+ infof(data, " subjectAltName does not match %s", peer->dispname);
failf(data, "SSL: no alternative certificate subject name matches "
- "target host name '%s'", dispname);
+ "target host name '%s'", peer->dispname);
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
@@ -2328,9 +2313,9 @@ ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
result = CURLE_PEER_FAILED_VERIFICATION;
}
else if(!Curl_cert_hostcheck((const char *)peer_CN,
- peerlen, hostname, hostlen)) {
+ peerlen, peer->hostname, hostlen)) {
failf(data, "SSL: certificate subject name '%s' does not match "
- "target host name '%s'", peer_CN, dispname);
+ "target host name '%s'", peer_CN, peer->dispname);
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
@@ -2739,12 +2724,6 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
#ifdef USE_OPENSSL
/* ====================================================== */
-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-# define use_sni(x) sni = (x)
-#else
-# define use_sni(x) Curl_nop_stmt
-#endif
-
/* Check for OpenSSL 1.0.2 which has ALPN support. */
#undef HAS_ALPN
#if OPENSSL_VERSION_NUMBER >= 0x10002000L \
@@ -3048,6 +3027,151 @@ static CURLcode load_cacert_from_memory(X509_STORE *store,
return (count > 0) ? CURLE_OK : CURLE_SSL_CACERT_BADFILE;
}
+#if defined(USE_WIN32_CRYPTO)
+static CURLcode import_windows_cert_store(struct Curl_easy *data,
+ const char *name,
+ X509_STORE *store,
+ bool *imported)
+{
+ CURLcode result = CURLE_OK;
+ HCERTSTORE hStore;
+
+ *imported = false;
+
+ hStore = CertOpenSystemStoreA(0, name);
+ if(hStore) {
+ PCCERT_CONTEXT pContext = NULL;
+ /* The array of enhanced key usage OIDs will vary per certificate and
+ is declared outside of the loop so that rather than malloc/free each
+ iteration we can grow it with realloc, when necessary. */
+ CERT_ENHKEY_USAGE *enhkey_usage = NULL;
+ DWORD enhkey_usage_size = 0;
+
+ /* This loop makes a best effort to import all valid certificates from
+ the MS root store. If a certificate cannot be imported it is
+ skipped. 'result' is used to store only hard-fail conditions (such
+ as out of memory) that cause an early break. */
+ result = CURLE_OK;
+ for(;;) {
+ X509 *x509;
+ FILETIME now;
+ BYTE key_usage[2];
+ DWORD req_size;
+ const unsigned char *encoded_cert;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ char cert_name[256];
+#endif
+
+ pContext = CertEnumCertificatesInStore(hStore, pContext);
+ if(!pContext)
+ break;
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
+ NULL, cert_name, sizeof(cert_name))) {
+ strcpy(cert_name, "Unknown");
+ }
+ infof(data, "SSL: Checking cert \"%s\"", cert_name);
+#endif
+ encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
+ if(!encoded_cert)
+ continue;
+
+ GetSystemTimeAsFileTime(&now);
+ if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 ||
+ CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0)
+ continue;
+
+ /* If key usage exists check for signing attribute */
+ if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType,
+ pContext->pCertInfo,
+ key_usage, sizeof(key_usage))) {
+ if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE))
+ continue;
+ }
+ else if(GetLastError())
+ continue;
+
+ /* If enhanced key usage exists check for server auth attribute.
+ *
+ * Note "In a Microsoft environment, a certificate might also have
+ * EKU extended properties that specify valid uses for the
+ * certificate." The call below checks both, and behavior varies
+ * depending on what is found. For more details see
+ * CertGetEnhancedKeyUsage doc.
+ */
+ if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) {
+ if(req_size && req_size > enhkey_usage_size) {
+ void *tmp = realloc(enhkey_usage, req_size);
+
+ if(!tmp) {
+ failf(data, "SSL: Out of memory allocating for OID list");
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ enhkey_usage = (CERT_ENHKEY_USAGE *)tmp;
+ enhkey_usage_size = req_size;
+ }
+
+ if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) {
+ if(!enhkey_usage->cUsageIdentifier) {
+ /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate
+ is good for all uses. If it returns zero, the certificate
+ has no valid uses." */
+ if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND)
+ continue;
+ }
+ else {
+ DWORD i;
+ bool found = false;
+
+ for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) {
+ if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */,
+ enhkey_usage->rgpszUsageIdentifier[i])) {
+ found = true;
+ break;
+ }
+ }
+
+ if(!found)
+ continue;
+ }
+ }
+ else
+ continue;
+ }
+ else
+ continue;
+
+ x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
+ if(!x509)
+ continue;
+
+ /* Try to import the certificate. This may fail for legitimate
+ reasons such as duplicate certificate, which is allowed by MS but
+ not OpenSSL. */
+ if(X509_STORE_add_cert(store, x509) == 1) {
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ infof(data, "SSL: Imported cert \"%s\"", cert_name);
+#endif
+ *imported = true;
+ }
+ X509_free(x509);
+ }
+
+ free(enhkey_usage);
+ CertFreeCertificateContext(pContext);
+ CertCloseStore(hStore, 0);
+
+ if(result)
+ return result;
+ }
+
+ return result;
+}
+#endif
+
static CURLcode populate_x509_store(struct Curl_cfilter *cf,
struct Curl_easy *data,
X509_STORE *store)
@@ -3077,140 +3201,25 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037
https://datatracker.ietf.org/doc/html/rfc5280 */
if(ssl_config->native_ca_store) {
- HCERTSTORE hStore = CertOpenSystemStore(0, TEXT("ROOT"));
-
- if(hStore) {
- PCCERT_CONTEXT pContext = NULL;
- /* The array of enhanced key usage OIDs will vary per certificate and
- is declared outside of the loop so that rather than malloc/free each
- iteration we can grow it with realloc, when necessary. */
- CERT_ENHKEY_USAGE *enhkey_usage = NULL;
- DWORD enhkey_usage_size = 0;
-
- /* This loop makes a best effort to import all valid certificates from
- the MS root store. If a certificate cannot be imported it is
- skipped. 'result' is used to store only hard-fail conditions (such
- as out of memory) that cause an early break. */
- result = CURLE_OK;
- for(;;) {
- X509 *x509;
- FILETIME now;
- BYTE key_usage[2];
- DWORD req_size;
- const unsigned char *encoded_cert;
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- char cert_name[256];
-#endif
-
- pContext = CertEnumCertificatesInStore(hStore, pContext);
- if(!pContext)
- break;
-
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
- NULL, cert_name, sizeof(cert_name))) {
- strcpy(cert_name, "Unknown");
- }
- infof(data, "SSL: Checking cert \"%s\"", cert_name);
-#endif
- encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
- if(!encoded_cert)
- continue;
-
- GetSystemTimeAsFileTime(&now);
- if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 ||
- CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0)
- continue;
-
- /* If key usage exists check for signing attribute */
- if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType,
- pContext->pCertInfo,
- key_usage, sizeof(key_usage))) {
- if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE))
- continue;
- }
- else if(GetLastError())
- continue;
-
- /* If enhanced key usage exists check for server auth attribute.
- *
- * Note "In a Microsoft environment, a certificate might also have
- * EKU extended properties that specify valid uses for the
- * certificate." The call below checks both, and behavior varies
- * depending on what is found. For more details see
- * CertGetEnhancedKeyUsage doc.
- */
- if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) {
- if(req_size && req_size > enhkey_usage_size) {
- void *tmp = realloc(enhkey_usage, req_size);
-
- if(!tmp) {
- failf(data, "SSL: Out of memory allocating for OID list");
- result = CURLE_OUT_OF_MEMORY;
- break;
- }
-
- enhkey_usage = (CERT_ENHKEY_USAGE *)tmp;
- enhkey_usage_size = req_size;
- }
-
- if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) {
- if(!enhkey_usage->cUsageIdentifier) {
- /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate
- is good for all uses. If it returns zero, the certificate
- has no valid uses." */
- if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND)
- continue;
- }
- else {
- DWORD i;
- bool found = false;
-
- for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) {
- if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */,
- enhkey_usage->rgpszUsageIdentifier[i])) {
- found = true;
- break;
- }
- }
-
- if(!found)
- continue;
- }
- }
- else
- continue;
- }
- else
- continue;
-
- x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
- if(!x509)
- continue;
-
- /* Try to import the certificate. This may fail for legitimate
- reasons such as duplicate certificate, which is allowed by MS but
- not OpenSSL. */
- if(X509_STORE_add_cert(store, x509) == 1) {
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- infof(data, "SSL: Imported cert \"%s\"", cert_name);
-#endif
- imported_native_ca = true;
- }
- X509_free(x509);
- }
-
- free(enhkey_usage);
- CertFreeCertificateContext(pContext);
- CertCloseStore(hStore, 0);
-
+ const char *storeNames[] = {
+ "ROOT", /* Trusted Root Certification Authorities */
+ "CA" /* Intermediate Certification Authorities */
+ };
+ size_t i;
+ for(i = 0; i < ARRAYSIZE(storeNames); ++i) {
+ bool imported = false;
+ result = import_windows_cert_store(data, storeNames[i], store,
+ &imported);
if(result)
return result;
+ if(imported) {
+ infof(data, "successfully imported Windows %s store", storeNames[i]);
+ imported_native_ca = true;
+ }
+ else
+ infof(data, "error importing Windows %s store, continuing anyway",
+ storeNames[i]);
}
- if(imported_native_ca)
- infof(data, "successfully imported Windows CA store");
- else
- infof(data, "error importing Windows CA store, continuing anyway");
}
#endif
if(ca_info_blob) {
@@ -3226,7 +3235,7 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
}
if(ssl_cafile || ssl_capath) {
-#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
/* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
if(ssl_cafile && !X509_STORE_load_file(store, ssl_cafile)) {
if(!imported_native_ca && !imported_ca_info_blob) {
@@ -3355,6 +3364,7 @@ static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
X509_STORE *store = NULL;
+ DEBUGASSERT(multi);
if(multi &&
multi->ssl_backend_data &&
multi->ssl_backend_data->store &&
@@ -3374,6 +3384,7 @@ static void set_cached_x509_store(struct Curl_cfilter *cf,
struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
struct multi_ssl_backend_data *mbackend;
+ DEBUGASSERT(multi);
if(!multi)
return;
@@ -3465,17 +3476,6 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
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);
BIO *bio;
-
-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- bool sni;
- const char *hostname = connssl->hostname;
-
-#ifdef ENABLE_IPV6
- struct in6_addr addr;
-#else
- struct in_addr addr;
-#endif
-#endif
const long int ssl_version = conn_config->version;
char * const ssl_cert = ssl_config->primary.clientcert;
const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
@@ -3510,7 +3510,6 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
#else
req_method = SSLv23_client_method();
#endif
- use_sni(TRUE);
break;
case CURL_SSLVERSION_SSLv2:
failf(data, "No SSLv2 support");
@@ -3803,13 +3802,8 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
backend->server_cert = 0x0;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
-#ifdef ENABLE_IPV6
- (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
-#endif
- sni) {
- char *snihost = Curl_ssl_snihost(data, hostname, NULL);
- if(!snihost || !SSL_set_tlsext_host_name(backend->handle, snihost)) {
+ if(connssl->peer.sni) {
+ if(!SSL_set_tlsext_host_name(backend->handle, connssl->peer.sni)) {
failf(data, "Failed set SNI");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -3818,6 +3812,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
SSL_set_app_data(backend->handle, cf);
+ connssl->reused_session = FALSE;
if(ssl_config->primary.sessionid) {
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
@@ -3831,6 +3826,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
}
/* Informational message */
infof(data, "SSL reusing session ID");
+ connssl->reused_session = TRUE;
}
Curl_ssl_sessionid_unlock(data);
}
@@ -3991,7 +3987,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
Curl_strerror(sockerr, extramsg, sizeof(extramsg));
failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ",
extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
- connssl->hostname, connssl->port);
+ connssl->peer.hostname, connssl->port);
return result;
}
@@ -4002,13 +3998,28 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
}
}
else {
+ int psigtype_nid = NID_undef;
+ const char *negotiated_group_name = NULL;
+
/* we connected fine, we're not waiting for anything else. */
connssl->connecting_state = ssl_connect_3;
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+ SSL_get_peer_signature_type_nid(backend->handle, &psigtype_nid);
+#if (OPENSSL_VERSION_NUMBER >= 0x30200000L)
+ negotiated_group_name = SSL_get0_group_name(backend->handle);
+#else
+ negotiated_group_name =
+ OBJ_nid2sn(SSL_get_negotiated_group(backend->handle) & 0x0000FFFF);
+#endif
+#endif
+
/* Informational message */
- infof(data, "SSL connection using %s / %s",
+ infof(data, "SSL connection using %s / %s / %s / %s",
SSL_get_version(backend->handle),
- SSL_get_cipher(backend->handle));
+ SSL_get_cipher(backend->handle),
+ negotiated_group_name? negotiated_group_name : "[blank]",
+ OBJ_nid2sn(psigtype_nid));
#ifdef HAS_ALPN
/* Sets data and len to negotiated protocol, len is 0 if no protocol was
@@ -4085,6 +4096,75 @@ static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
return result;
}
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
+ !(defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x3060000fL) && \
+ !defined(OPENSSL_IS_BORINGSSL) && \
+ !defined(OPENSSL_IS_AWSLC) && \
+ !defined(CURL_DISABLE_VERBOSE_STRINGS)
+static void infof_certstack(struct Curl_easy *data, const SSL *ssl)
+{
+ STACK_OF(X509) *certstack;
+ long verify_result;
+ int num_cert_levels;
+ int cert_level;
+
+ verify_result = SSL_get_verify_result(ssl);
+ if(verify_result != X509_V_OK)
+ certstack = SSL_get_peer_cert_chain(ssl);
+ else
+ certstack = SSL_get0_verified_chain(ssl);
+ num_cert_levels = sk_X509_num(certstack);
+
+ for(cert_level = 0; cert_level < num_cert_levels; cert_level++) {
+ char cert_algorithm[80] = "";
+ char group_name_final[80] = "";
+ const X509_ALGOR *palg_cert = NULL;
+ const ASN1_OBJECT *paobj_cert = NULL;
+ X509 *current_cert;
+ EVP_PKEY *current_pkey;
+ int key_bits;
+ int key_sec_bits;
+ int get_group_name;
+ const char *type_name;
+
+ current_cert = sk_X509_value(certstack, cert_level);
+
+ X509_get0_signature(NULL, &palg_cert, current_cert);
+ X509_ALGOR_get0(&paobj_cert, NULL, NULL, palg_cert);
+ OBJ_obj2txt(cert_algorithm, sizeof(cert_algorithm), paobj_cert, 0);
+
+ current_pkey = X509_get0_pubkey(current_cert);
+ key_bits = EVP_PKEY_bits(current_pkey);
+#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
+#define EVP_PKEY_get_security_bits EVP_PKEY_security_bits
+#endif
+ key_sec_bits = EVP_PKEY_get_security_bits(current_pkey);
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+ {
+ char group_name[80] = "";
+ get_group_name = EVP_PKEY_get_group_name(current_pkey, group_name,
+ sizeof(group_name), NULL);
+ msnprintf(group_name_final, sizeof(group_name_final), "/%s", group_name);
+ }
+ type_name = EVP_PKEY_get0_type_name(current_pkey);
+#else
+ get_group_name = 0;
+ type_name = NULL;
+#endif
+
+ infof(data,
+ " Certificate level %d: "
+ "Public key type %s%s (%d/%d Bits/secBits), signed using %s",
+ cert_level, type_name ? type_name : "?",
+ get_group_name == 0 ? "" : group_name_final,
+ key_bits, key_sec_bits, cert_algorithm);
+ }
+}
+#else
+#define infof_certstack(data, ssl)
+#endif
+
/*
* Get the server cert, verify it and show it, etc., only call failf() if the
* 'strict' argument is TRUE as otherwise all this is for informational
@@ -4163,8 +4243,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
BIO_free(mem);
if(conn_config->verifyhost) {
- result = ossl_verifyhost(data, conn, backend->server_cert,
- connssl->hostname, connssl->dispname);
+ result = Curl_ossl_verifyhost(data, conn, &connssl->peer,
+ backend->server_cert);
if(result) {
X509_free(backend->server_cert);
backend->server_cert = NULL;
@@ -4274,9 +4354,12 @@ static CURLcode servercert(struct Curl_cfilter *cf,
infof(data, " SSL certificate verify ok.");
}
+ infof_certstack(data, backend->handle);
+
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
- if(conn_config->verifystatus) {
+ if(conn_config->verifystatus && !connssl->reused_session) {
+ /* don't do this after Session ID reuse */
result = verifystatus(cf, data);
if(result) {
X509_free(backend->server_cert);
@@ -4538,22 +4621,9 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
case SSL_ERROR_SSL: {
/* A failure in the SSL library occurred, usually a protocol error.
The OpenSSL error queue contains more information on the error. */
- 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;
sslerror = ERR_get_error();
- if(ERR_GET_LIB(sslerror) == ERR_LIB_SSL &&
- ERR_GET_REASON(sslerror) == SSL_R_BIO_NOT_SET &&
- connssl->state == ssl_connection_complete &&
- (connssl_next && connssl_next->state == ssl_connection_complete)
- ) {
- char ver[120];
- (void)ossl_version(ver, sizeof(ver));
- failf(data, "Error: %s does not support double SSL tunneling.", ver);
- }
- else
- failf(data, "SSL_write() error: %s",
- ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
+ failf(data, "SSL_write() error: %s",
+ ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
*curlcode = CURLE_SEND_ERROR;
rc = -1;
goto out;
@@ -4858,7 +4928,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
ossl_cert_status_request, /* cert_status_request */
ossl_connect, /* connect */
ossl_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_get_select_socks,/* getsock */
+ Curl_ssl_adjust_pollset, /* adjust_pollset */
ossl_get_internals, /* get_internals */
ossl_close, /* close_one */
ossl_close_all, /* close_all */
diff --git a/Utilities/cmcurl/lib/vtls/openssl.h b/Utilities/cmcurl/lib/vtls/openssl.h
index 950faab..e802363 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.h
+++ b/Utilities/cmcurl/lib/vtls/openssl.h
@@ -31,24 +31,21 @@
* This header should only be needed to get included by vtls.c, openssl.c
* and ngtcp2.c
*/
+#include <openssl/ossl_typ.h>
#include <openssl/ssl.h>
#include "urldata.h"
-/*
- * In an effort to avoid using 'X509 *' here, we instead use the struct
- * x509_st version of the type so that we can forward-declare it here without
- * having to include <openssl/x509v3.h>. Including that header causes name
- * conflicts when libcurl is built with both Schannel and OpenSSL support.
- */
-struct x509_st;
+#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
+#define SSL_get1_peer_certificate SSL_get_peer_certificate
+#endif
+
CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
- struct x509_st *server_cert);
+ struct ssl_peer *peer, X509 *server_cert);
extern const struct Curl_ssl Curl_ssl_openssl;
-struct ssl_ctx_st;
CURLcode Curl_ossl_set_client_cert(struct Curl_easy *data,
- struct ssl_ctx_st *ctx, char *cert_file,
+ SSL_CTX *ctx, char *cert_file,
const struct curl_blob *cert_blob,
const char *cert_type, char *key_file,
const struct curl_blob *key_blob,
@@ -65,5 +62,9 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
struct Curl_easy *data,
SSL_CTX *ssl_ctx);
+CURLcode Curl_ossl_ctx_configure(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ SSL_CTX *ssl_ctx);
+
#endif /* USE_OPENSSL */
#endif /* HEADER_CURL_SSLUSE_H */
diff --git a/Utilities/cmcurl/lib/vtls/rustls.c b/Utilities/cmcurl/lib/vtls/rustls.c
index a3e9d96..8751fd9 100644
--- a/Utilities/cmcurl/lib/vtls/rustls.c
+++ b/Utilities/cmcurl/lib/vtls/rustls.c
@@ -39,6 +39,7 @@
#include "select.h"
#include "strerror.h"
#include "multiif.h"
+#include "connect.h" /* for the connect timeout */
struct rustls_ssl_backend_data
{
@@ -75,14 +76,6 @@ cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
return backend->data_pending;
}
-static CURLcode
-cr_connect(struct Curl_cfilter *cf UNUSED_PARAM,
- struct Curl_easy *data UNUSED_PARAM)
-{
- infof(data, "rustls_connect: unimplemented");
- return CURLE_SSL_CONNECT_ERROR;
-}
-
struct io_ctx {
struct Curl_cfilter *cf;
struct Curl_easy *data;
@@ -386,7 +379,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
(ca_info_blob ? NULL : conn_config->CAfile);
const bool verifypeer = conn_config->verifypeer;
- const char *hostname = connssl->hostname;
+ const char *hostname = connssl->peer.hostname;
char errorbuf[256];
size_t errorlen;
int result;
@@ -458,12 +451,11 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
backend->config = rustls_client_config_builder_build(config_builder);
DEBUGASSERT(rconn == NULL);
{
- char *snihost = Curl_ssl_snihost(data, hostname, NULL);
- if(!snihost) {
- failf(data, "rustls: failed to get SNI");
- return CURLE_SSL_CONNECT_ERROR;
- }
- result = rustls_client_connection_new(backend->config, snihost, &rconn);
+ /* rustls claims to manage ip address hostnames as well here. So,
+ * if we have an SNI, we use it, otherwise we pass the hostname */
+ char *server = connssl->peer.sni?
+ connssl->peer.sni : connssl->peer.hostname;
+ result = rustls_client_connection_new(backend->config, server, &rconn);
}
if(result != RUSTLS_RESULT_OK) {
rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
@@ -486,9 +478,20 @@ cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data,
Curl_alpn_set_negotiated(cf, data, protocol, len);
}
+/* Given an established network connection, do a TLS handshake.
+ *
+ * If `blocking` is true, this function will block until the handshake is
+ * complete. Otherwise it will return as soon as I/O would block.
+ *
+ * For the non-blocking I/O case, this function will set `*done` to true
+ * once the handshake is complete. This function never reads the value of
+ * `*done*`.
+ */
static CURLcode
-cr_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data, bool *done)
+cr_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool blocking,
+ bool *done)
{
struct ssl_connect_data *const connssl = cf->ctx;
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
@@ -502,6 +505,8 @@ cr_connect_nonblocking(struct Curl_cfilter *cf,
bool wants_write;
curl_socket_t writefd;
curl_socket_t readfd;
+ timediff_t timeout_ms;
+ timediff_t socket_check_timeout;
DEBUGASSERT(backend);
@@ -539,12 +544,29 @@ cr_connect_nonblocking(struct Curl_cfilter *cf,
writefd = wants_write?sockfd:CURL_SOCKET_BAD;
readfd = wants_read?sockfd:CURL_SOCKET_BAD;
- what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, 0);
+ /* check allowed time left */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "rustls: operation timed out before socket check");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ socket_check_timeout = blocking?timeout_ms:0;
+
+ what = Curl_socket_check(
+ readfd, CURL_SOCKET_BAD, writefd, socket_check_timeout);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
return CURLE_SSL_CONNECT_ERROR;
}
+ if(blocking && 0 == what) {
+ failf(data, "rustls connection timeout after %d ms",
+ socket_check_timeout);
+ return CURLE_OPERATION_TIMEDOUT;
+ }
if(0 == what) {
infof(data, "Curl_socket_check: %s would block",
wants_read&&wants_write ? "writing and reading" :
@@ -589,32 +611,43 @@ cr_connect_nonblocking(struct Curl_cfilter *cf,
DEBUGASSERT(false);
}
-/* returns a bitmap of flags for this connection's first socket indicating
- whether we want to read or write */
-static int
-cr_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
- curl_socket_t *socks)
+static CURLcode
+cr_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data, bool *done)
{
- struct ssl_connect_data *const connssl = cf->ctx;
- curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
- struct rustls_ssl_backend_data *const backend =
- (struct rustls_ssl_backend_data *)connssl->backend;
- struct rustls_connection *rconn = NULL;
+ return cr_connect_common(cf, data, false, done);
+}
- (void)data;
- DEBUGASSERT(backend);
- rconn = backend->conn;
+static CURLcode
+cr_connect_blocking(struct Curl_cfilter *cf UNUSED_PARAM,
+ struct Curl_easy *data UNUSED_PARAM)
+{
+ bool done; /* unused */
+ return cr_connect_common(cf, data, true, &done);
+}
- if(rustls_connection_wants_write(rconn)) {
- socks[0] = sockfd;
- return GETSOCK_WRITESOCK(0);
- }
- if(rustls_connection_wants_read(rconn)) {
- socks[0] = sockfd;
- return GETSOCK_READSOCK(0);
+static void cr_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
+{
+ if(!cf->connected) {
+ curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
+ struct ssl_connect_data *const connssl = cf->ctx;
+ struct rustls_ssl_backend_data *const backend =
+ (struct rustls_ssl_backend_data *)connssl->backend;
+ struct rustls_connection *rconn = NULL;
+
+ (void)data;
+ DEBUGASSERT(backend);
+ rconn = backend->conn;
+
+ if(rustls_connection_wants_write(rconn)) {
+ Curl_pollset_add_out(data, ps, sock);
+ }
+ if(rustls_connection_wants_read(rconn)) {
+ Curl_pollset_add_in(data, ps, sock);
+ }
}
-
- return GETSOCK_BLANK;
}
static void *
@@ -675,9 +708,9 @@ const struct Curl_ssl Curl_ssl_rustls = {
cr_data_pending, /* data_pending */
Curl_none_random, /* random */
Curl_none_cert_status_request, /* cert_status_request */
- cr_connect, /* connect */
+ cr_connect_blocking, /* connect */
cr_connect_nonblocking, /* connect_nonblocking */
- cr_get_select_socks, /* get_select_socks */
+ cr_adjust_pollset, /* adjust_pollset */
cr_get_internals, /* get_internals */
cr_close, /* close_one */
Curl_none_close_all, /* close_all */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index 410a5c4..ae7f295 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -1063,17 +1063,12 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif
SECURITY_STATUS sspi_status = SEC_E_OK;
struct Curl_schannel_cred *old_cred = NULL;
- struct in_addr addr;
-#ifdef ENABLE_IPV6
- struct in6_addr addr6;
-#endif
CURLcode result;
- const char *hostname = connssl->hostname;
DEBUGASSERT(backend);
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 1/3)",
- hostname, connssl->port));
+ connssl->peer.hostname, connssl->port));
if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
VERSION_LESS_THAN_EQUAL)) {
@@ -1154,22 +1149,14 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* A hostname associated with the credential is needed by
InitializeSecurityContext for SNI and other reasons. */
- snihost = Curl_ssl_snihost(data, hostname, NULL);
- if(!snihost) {
- failf(data, "Failed to set SNI");
- return CURLE_SSL_CONNECT_ERROR;
- }
+ snihost = connssl->peer.sni? connssl->peer.sni : connssl->peer.hostname;
backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost);
if(!backend->cred->sni_hostname)
return CURLE_OUT_OF_MEMORY;
}
/* Warn if SNI is disabled due to use of an IP address */
- if(Curl_inet_pton(AF_INET, hostname, &addr)
-#ifdef ENABLE_IPV6
- || Curl_inet_pton(AF_INET6, hostname, &addr6)
-#endif
- ) {
+ if(connssl->peer.is_ip_address) {
infof(data, "schannel: using IP address, SNI is not supported by OS.");
}
@@ -1346,7 +1333,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 2/3)",
- connssl->hostname, connssl->port));
+ connssl->peer.hostname, connssl->port));
if(!backend->cred || !backend->ctxt)
return CURLE_SSL_CONNECT_ERROR;
@@ -1700,7 +1687,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 3/3)",
- connssl->hostname, connssl->port));
+ connssl->peer.hostname, connssl->port));
if(!backend->cred)
return CURLE_SSL_CONNECT_ERROR;
@@ -2498,7 +2485,7 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
if(backend->ctxt) {
infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
- connssl->hostname, connssl->port);
+ connssl->peer.hostname, connssl->port);
}
if(backend->cred && backend->ctxt) {
@@ -2754,6 +2741,151 @@ static void *schannel_get_internals(struct ssl_connect_data *connssl,
return &backend->ctxt->ctxt_handle;
}
+HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+ struct schannel_multi_ssl_backend_data *mbackend;
+ const struct ssl_general_config *cfg = &data->set.general_ssl;
+ timediff_t timeout_ms;
+ timediff_t elapsed_ms;
+ struct curltime now;
+ unsigned char info_blob_digest[CURL_SHA256_DIGEST_LENGTH];
+
+ DEBUGASSERT(multi);
+
+ if(!multi || !multi->ssl_backend_data) {
+ return NULL;
+ }
+
+ mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;
+ if(!mbackend->cert_store) {
+ return NULL;
+ }
+
+ /* zero ca_cache_timeout completely disables caching */
+ if(!cfg->ca_cache_timeout) {
+ return NULL;
+ }
+
+ /* check for cache timeout by using the cached_x509_store_expired timediff
+ calculation pattern from openssl.c.
+ negative timeout means retain forever. */
+ timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
+ if(timeout_ms >= 0) {
+ now = Curl_now();
+ elapsed_ms = Curl_timediff(now, mbackend->time);
+ if(elapsed_ms >= timeout_ms) {
+ return NULL;
+ }
+ }
+
+ if(ca_info_blob) {
+ if(!mbackend->CAinfo_blob_digest) {
+ return NULL;
+ }
+ if(mbackend->CAinfo_blob_size != ca_info_blob->len) {
+ return NULL;
+ }
+ schannel_sha256sum((const unsigned char *)ca_info_blob->data,
+ ca_info_blob->len,
+ info_blob_digest,
+ CURL_SHA256_DIGEST_LENGTH);
+ if(memcmp(mbackend->CAinfo_blob_digest,
+ info_blob_digest,
+ CURL_SHA256_DIGEST_LENGTH)) {
+ return NULL;
+ }
+ }
+ else {
+ if(!conn_config->CAfile || !mbackend->CAfile ||
+ strcmp(mbackend->CAfile, conn_config->CAfile)) {
+ return NULL;
+ }
+ }
+
+ return mbackend->cert_store;
+}
+
+bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data,
+ HCERTSTORE cert_store)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+ struct schannel_multi_ssl_backend_data *mbackend;
+ unsigned char *CAinfo_blob_digest = NULL;
+ size_t CAinfo_blob_size = 0;
+ char *CAfile = NULL;
+
+ DEBUGASSERT(multi);
+
+ if(!multi) {
+ return false;
+ }
+
+ if(!multi->ssl_backend_data) {
+ multi->ssl_backend_data =
+ calloc(1, sizeof(struct schannel_multi_ssl_backend_data));
+ if(!multi->ssl_backend_data) {
+ return false;
+ }
+ }
+
+ mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;
+
+
+ if(ca_info_blob) {
+ CAinfo_blob_digest = malloc(CURL_SHA256_DIGEST_LENGTH);
+ if(!CAinfo_blob_digest) {
+ return false;
+ }
+ schannel_sha256sum((const unsigned char *)ca_info_blob->data,
+ ca_info_blob->len,
+ CAinfo_blob_digest,
+ CURL_SHA256_DIGEST_LENGTH);
+ CAinfo_blob_size = ca_info_blob->len;
+ }
+ else {
+ if(conn_config->CAfile) {
+ CAfile = strdup(conn_config->CAfile);
+ if(!CAfile) {
+ return false;
+ }
+ }
+ }
+
+ /* free old cache data */
+ if(mbackend->cert_store) {
+ CertCloseStore(mbackend->cert_store, 0);
+ }
+ free(mbackend->CAinfo_blob_digest);
+ free(mbackend->CAfile);
+
+ mbackend->time = Curl_now();
+ mbackend->cert_store = cert_store;
+ mbackend->CAinfo_blob_digest = CAinfo_blob_digest;
+ mbackend->CAinfo_blob_size = CAinfo_blob_size;
+ mbackend->CAfile = CAfile;
+ return true;
+}
+
+static void schannel_free_multi_ssl_backend_data(
+ struct multi_ssl_backend_data *msbd)
+{
+ struct schannel_multi_ssl_backend_data *mbackend =
+ (struct schannel_multi_ssl_backend_data*)msbd;
+ if(mbackend->cert_store) {
+ CertCloseStore(mbackend->cert_store, 0);
+ }
+ free(mbackend->CAinfo_blob_digest);
+ free(mbackend->CAfile);
+ free(mbackend);
+}
+
const struct Curl_ssl Curl_ssl_schannel = {
{ CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
@@ -2777,7 +2909,7 @@ const struct Curl_ssl Curl_ssl_schannel = {
Curl_none_cert_status_request, /* cert_status_request */
schannel_connect, /* connect */
schannel_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_get_select_socks, /* getsock */
+ Curl_ssl_adjust_pollset, /* adjust_pollset */
schannel_get_internals, /* get_internals */
schannel_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -2789,7 +2921,7 @@ const struct Curl_ssl Curl_ssl_schannel = {
schannel_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
- NULL, /* free_multi_ssl_backend_data */
+ schannel_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
schannel_recv, /* recv decrypted data */
schannel_send, /* send data to encrypt */
};
diff --git a/Utilities/cmcurl/lib/vtls/schannel_int.h b/Utilities/cmcurl/lib/vtls/schannel_int.h
index a128e04..fe7450d 100644
--- a/Utilities/cmcurl/lib/vtls/schannel_int.h
+++ b/Utilities/cmcurl/lib/vtls/schannel_int.h
@@ -149,5 +149,22 @@ struct schannel_ssl_backend_data {
#endif
};
+struct schannel_multi_ssl_backend_data {
+ unsigned char *CAinfo_blob_digest; /* CA info blob digest */
+ size_t CAinfo_blob_size; /* CA info blob size */
+ char *CAfile; /* CAfile path used to generate
+ certificate store */
+ HCERTSTORE cert_store; /* cached certificate store or
+ NULL if none */
+ struct curltime time; /* when the cached store was created */
+};
+
+HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data);
+
+bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data,
+ HCERTSTORE cert_store);
+
#endif /* USE_SCHANNEL */
#endif /* HEADER_CURL_SCHANNEL_INT_H */
diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c
index a5d5c98..e7c8bc6 100644
--- a/Utilities/cmcurl/lib/vtls/schannel_verify.c
+++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c
@@ -470,7 +470,7 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf,
CERT_CONTEXT *pCertContextServer = NULL;
TCHAR *cert_hostname_buff = NULL;
size_t cert_hostname_buff_index = 0;
- const char *conn_hostname = connssl->hostname;
+ const char *conn_hostname = connssl->peer.hostname;
size_t hostlen = strlen(conn_hostname);
DWORD len = 0;
DWORD actual_len = 0;
@@ -600,6 +600,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
const CERT_CHAIN_CONTEXT *pChainContext = NULL;
HCERTCHAINENGINE cert_chain_engine = NULL;
HCERTSTORE trust_store = NULL;
+ HCERTSTORE own_trust_store = NULL;
DEBUGASSERT(BACKEND);
@@ -630,31 +631,46 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
result = CURLE_SSL_CACERT_BADFILE;
}
else {
- /* Open the certificate store */
- trust_store = CertOpenStore(CERT_STORE_PROV_MEMORY,
- 0,
- (HCRYPTPROV)NULL,
- CERT_STORE_CREATE_NEW_FLAG,
- NULL);
- if(!trust_store) {
- char buffer[STRERROR_LEN];
- failf(data, "schannel: failed to create certificate store: %s",
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
- result = CURLE_SSL_CACERT_BADFILE;
+ /* try cache */
+ trust_store = Curl_schannel_get_cached_cert_store(cf, data);
+
+ if(trust_store) {
+ infof(data, "schannel: reusing certificate store from cache");
}
else {
- const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
- if(ca_info_blob) {
- result = add_certs_data_to_store(trust_store,
- (const char *)ca_info_blob->data,
- ca_info_blob->len,
- "(memory blob)",
- data);
+ /* Open the certificate store */
+ trust_store = CertOpenStore(CERT_STORE_PROV_MEMORY,
+ 0,
+ (HCRYPTPROV)NULL,
+ CERT_STORE_CREATE_NEW_FLAG,
+ NULL);
+ if(!trust_store) {
+ char buffer[STRERROR_LEN];
+ failf(data, "schannel: failed to create certificate store: %s",
+ Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ result = CURLE_SSL_CACERT_BADFILE;
}
else {
- result = add_certs_file_to_store(trust_store,
- conn_config->CAfile,
- data);
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+ own_trust_store = trust_store;
+
+ if(ca_info_blob) {
+ result = add_certs_data_to_store(trust_store,
+ (const char *)ca_info_blob->data,
+ ca_info_blob->len,
+ "(memory blob)",
+ data);
+ }
+ else {
+ result = add_certs_file_to_store(trust_store,
+ conn_config->CAfile,
+ data);
+ }
+ if(result == CURLE_OK) {
+ if(Curl_schannel_set_cached_cert_store(cf, data, trust_store)) {
+ own_trust_store = NULL;
+ }
+ }
}
}
}
@@ -754,8 +770,8 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
CertFreeCertificateChainEngine(cert_chain_engine);
}
- if(trust_store) {
- CertCloseStore(trust_store, 0);
+ if(own_trust_store) {
+ CertCloseStore(own_trust_store, 0);
}
if(pChainContext)
diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c
index 3378f76..0a22ff6 100644
--- a/Utilities/cmcurl/lib/vtls/sectransp.c
+++ b/Utilities/cmcurl/lib/vtls/sectransp.c
@@ -46,8 +46,10 @@
#endif /* __clang__ */
#ifdef __GNUC__
+#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Waddress"
#pragma GCC diagnostic ignored "-Wundef"
+#pragma GCC diagnostic ignored "-Wunreachable-code"
#endif
#include <limits.h>
@@ -1013,7 +1015,7 @@ static CURLcode CopyCertSubject(struct Curl_easy *data,
}
else {
size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1;
- cbuf = calloc(cbuf_size, 1);
+ cbuf = calloc(1, cbuf_size);
if(cbuf) {
if(!CFStringGetCString(c, cbuf, cbuf_size,
kCFStringEncodingUTF8)) {
@@ -1651,11 +1653,6 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
const bool verifypeer = conn_config->verifypeer;
char * const ssl_cert = ssl_config->primary.clientcert;
const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
-#ifdef ENABLE_IPV6
- struct in6_addr addr;
-#else
- struct in_addr addr;
-#endif /* ENABLE_IPV6 */
char *ciphers;
OSStatus err = noErr;
#if CURL_BUILD_MAC
@@ -2003,13 +2000,9 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
* Both hostname check and SNI require SSLSetPeerDomainName().
* Also: the verifyhost setting influences SNI usage */
if(conn_config->verifyhost) {
- size_t snilen;
- char *snihost = Curl_ssl_snihost(data, connssl->hostname, &snilen);
- if(!snihost) {
- failf(data, "Failed to set SNI");
- return CURLE_SSL_CONNECT_ERROR;
- }
- err = SSLSetPeerDomainName(backend->ssl_ctx, snihost, snilen);
+ char *server = connssl->peer.sni?
+ connssl->peer.sni : connssl->peer.hostname;
+ err = SSLSetPeerDomainName(backend->ssl_ctx, server, strlen(server));
if(err != noErr) {
failf(data, "SSL: SSLSetPeerDomainName() failed: OSStatus %d",
@@ -2017,11 +2010,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
- if((Curl_inet_pton(AF_INET, connssl->hostname, &addr))
- #ifdef ENABLE_IPV6
- || (Curl_inet_pton(AF_INET6, connssl->hostname, &addr))
- #endif
- ) {
+ if(connssl->peer.is_ip_address) {
infof(data, "WARNING: using IP address, SNI is being disabled by "
"the OS.");
}
@@ -2079,7 +2068,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
ssl_sessionid =
aprintf("%s:%d:%d:%s:%d",
ssl_cafile ? ssl_cafile : "(blob memory)",
- verifypeer, conn_config->verifyhost, connssl->hostname,
+ verifypeer, conn_config->verifyhost, connssl->peer.hostname,
connssl->port);
ssl_sessionid_len = strlen(ssl_sessionid);
@@ -2665,7 +2654,7 @@ check_handshake:
host name: */
case errSSLHostNameMismatch:
failf(data, "SSL certificate peer verification failed, the "
- "certificate did not match \"%s\"\n", connssl->dispname);
+ "certificate did not match \"%s\"\n", connssl->peer.dispname);
return CURLE_PEER_FAILED_VERIFICATION;
/* Problem with SSL / TLS negotiation */
@@ -2757,7 +2746,7 @@ check_handshake:
default:
/* May also return codes listed in Security Framework Result Codes */
failf(data, "Unknown SSL protocol error in connection to %s:%d",
- connssl->hostname, err);
+ connssl->peer.hostname, err);
break;
}
return CURLE_SSL_CONNECT_ERROR;
@@ -3415,7 +3404,6 @@ again:
}
*curlcode = CURLE_AGAIN;
return -1L;
- break;
/* errSSLClosedGraceful - server gracefully shut down the SSL session
errSSLClosedNoNotify - server hung up on us instead of sending a
@@ -3425,7 +3413,6 @@ again:
case errSSLClosedNoNotify:
*curlcode = CURLE_OK;
return 0;
- break;
/* The below is errSSLPeerAuthCompleted; it's not defined in
Leopard's headers */
@@ -3445,7 +3432,6 @@ again:
failf(data, "SSLRead() return error %d", err);
*curlcode = CURLE_RECV_ERROR;
return -1L;
- break;
}
}
return (ssize_t)processed;
@@ -3483,7 +3469,7 @@ const struct Curl_ssl Curl_ssl_sectransp = {
Curl_none_cert_status_request, /* cert_status_request */
sectransp_connect, /* connect */
sectransp_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_get_select_socks, /* getsock */
+ Curl_ssl_adjust_pollset, /* adjust_pollset */
sectransp_get_internals, /* get_internals */
sectransp_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -3500,6 +3486,10 @@ const struct Curl_ssl Curl_ssl_sectransp = {
sectransp_send, /* send data to encrypt */
};
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
#ifdef __clang__
#pragma clang diagnostic pop
#endif
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
index 494b660..34eda3e 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.c
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -67,6 +67,7 @@
#include "warnless.h"
#include "curl_base64.h"
#include "curl_printf.h"
+#include "inet_pton.h"
#include "strdup.h"
/* The last #include files should be: */
@@ -131,9 +132,6 @@ static bool blobcmp(struct curl_blob *first, struct curl_blob *second)
}
#ifdef USE_SSL
-static const struct alpn_spec ALPN_SPEC_H10 = {
- { ALPN_HTTP_1_0 }, 1
-};
static const struct alpn_spec ALPN_SPEC_H11 = {
{ ALPN_HTTP_1_1 }, 1
};
@@ -147,51 +145,83 @@ static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn)
{
if(!use_alpn)
return NULL;
- if(httpwant == CURL_HTTP_VERSION_1_0)
- return &ALPN_SPEC_H10;
#ifdef USE_HTTP2
if(httpwant >= CURL_HTTP_VERSION_2)
return &ALPN_SPEC_H2_H11;
+#else
+ (void)httpwant;
#endif
+ /* Use the ALPN protocol "http/1.1" for HTTP/1.x.
+ Avoid "http/1.0" because some servers don't support it. */
return &ALPN_SPEC_H11;
}
#endif /* USE_SSL */
-bool
-Curl_ssl_config_matches(struct ssl_primary_config *data,
- struct ssl_primary_config *needle)
-{
- if((data->version == needle->version) &&
- (data->version_max == needle->version_max) &&
- (data->ssl_options == needle->ssl_options) &&
- (data->verifypeer == needle->verifypeer) &&
- (data->verifyhost == needle->verifyhost) &&
- (data->verifystatus == needle->verifystatus) &&
- blobcmp(data->cert_blob, needle->cert_blob) &&
- blobcmp(data->ca_info_blob, needle->ca_info_blob) &&
- blobcmp(data->issuercert_blob, needle->issuercert_blob) &&
- Curl_safecmp(data->CApath, needle->CApath) &&
- Curl_safecmp(data->CAfile, needle->CAfile) &&
- Curl_safecmp(data->issuercert, needle->issuercert) &&
- Curl_safecmp(data->clientcert, needle->clientcert) &&
+void Curl_ssl_easy_config_init(struct Curl_easy *data)
+{
+ /*
+ * libcurl 7.10 introduced SSL verification *by default*! This needs to be
+ * switched off unless wanted.
+ */
+ data->set.ssl.primary.verifypeer = TRUE;
+ data->set.ssl.primary.verifyhost = TRUE;
+ data->set.ssl.primary.sessionid = TRUE; /* session ID caching by default */
+#ifndef CURL_DISABLE_PROXY
+ data->set.proxy_ssl = data->set.ssl;
+#endif
+}
+
+static bool
+match_ssl_primary_config(struct Curl_easy *data,
+ struct ssl_primary_config *c1,
+ struct ssl_primary_config *c2)
+{
+ (void)data;
+ if((c1->version == c2->version) &&
+ (c1->version_max == c2->version_max) &&
+ (c1->ssl_options == c2->ssl_options) &&
+ (c1->verifypeer == c2->verifypeer) &&
+ (c1->verifyhost == c2->verifyhost) &&
+ (c1->verifystatus == c2->verifystatus) &&
+ blobcmp(c1->cert_blob, c2->cert_blob) &&
+ blobcmp(c1->ca_info_blob, c2->ca_info_blob) &&
+ blobcmp(c1->issuercert_blob, c2->issuercert_blob) &&
+ Curl_safecmp(c1->CApath, c2->CApath) &&
+ Curl_safecmp(c1->CAfile, c2->CAfile) &&
+ Curl_safecmp(c1->issuercert, c2->issuercert) &&
+ Curl_safecmp(c1->clientcert, c2->clientcert) &&
#ifdef USE_TLS_SRP
- !Curl_timestrcmp(data->username, needle->username) &&
- !Curl_timestrcmp(data->password, needle->password) &&
+ !Curl_timestrcmp(c1->username, c2->username) &&
+ !Curl_timestrcmp(c1->password, c2->password) &&
#endif
- strcasecompare(data->cipher_list, needle->cipher_list) &&
- strcasecompare(data->cipher_list13, needle->cipher_list13) &&
- strcasecompare(data->curves, needle->curves) &&
- strcasecompare(data->CRLfile, needle->CRLfile) &&
- strcasecompare(data->pinned_key, needle->pinned_key))
+ strcasecompare(c1->cipher_list, c2->cipher_list) &&
+ strcasecompare(c1->cipher_list13, c2->cipher_list13) &&
+ strcasecompare(c1->curves, c2->curves) &&
+ strcasecompare(c1->CRLfile, c2->CRLfile) &&
+ strcasecompare(c1->pinned_key, c2->pinned_key))
return TRUE;
return FALSE;
}
-bool
-Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
- struct ssl_primary_config *dest)
+bool Curl_ssl_conn_config_match(struct Curl_easy *data,
+ struct connectdata *candidate,
+ bool proxy)
+{
+#ifndef CURL_DISABLE_PROXY
+ if(proxy)
+ return match_ssl_primary_config(data, &data->set.proxy_ssl.primary,
+ &candidate->proxy_ssl_config);
+#else
+ (void)proxy;
+#endif
+ return match_ssl_primary_config(data, &data->set.ssl.primary,
+ &candidate->ssl_config);
+}
+
+static bool clone_ssl_primary_config(struct ssl_primary_config *source,
+ struct ssl_primary_config *dest)
{
dest->version = source->version;
dest->version_max = source->version_max;
@@ -221,7 +251,7 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
return TRUE;
}
-void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
+static void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
{
Curl_safefree(sslc->CApath);
Curl_safefree(sslc->CAfile);
@@ -241,6 +271,111 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
#endif
}
+CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data)
+{
+ data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH];
+ data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE];
+ data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE];
+ data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
+ data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
+ data->set.ssl.primary.cipher_list =
+ data->set.str[STRING_SSL_CIPHER_LIST];
+ data->set.ssl.primary.cipher_list13 =
+ data->set.str[STRING_SSL_CIPHER13_LIST];
+ data->set.ssl.primary.pinned_key =
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+ data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT];
+ data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
+ data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES];
+#ifdef USE_TLS_SRP
+ data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME];
+ data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD];
+#endif
+ data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE];
+ data->set.ssl.key = data->set.str[STRING_KEY];
+ data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE];
+ data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD];
+ data->set.ssl.primary.clientcert = data->set.str[STRING_CERT];
+ data->set.ssl.key_blob = data->set.blobs[BLOB_KEY];
+
+#ifndef CURL_DISABLE_PROXY
+ data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
+ data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
+ data->set.proxy_ssl.primary.cipher_list =
+ data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
+ data->set.proxy_ssl.primary.cipher_list13 =
+ data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
+ data->set.proxy_ssl.primary.pinned_key =
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
+ data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
+ data->set.proxy_ssl.primary.ca_info_blob =
+ data->set.blobs[BLOB_CAINFO_PROXY];
+ data->set.proxy_ssl.primary.issuercert =
+ data->set.str[STRING_SSL_ISSUERCERT_PROXY];
+ data->set.proxy_ssl.primary.issuercert_blob =
+ data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
+ data->set.proxy_ssl.primary.CRLfile =
+ data->set.str[STRING_SSL_CRLFILE_PROXY];
+ data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
+ data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
+ data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
+ data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
+ data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
+ data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
+#ifdef USE_TLS_SRP
+ data->set.proxy_ssl.primary.username =
+ data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
+ data->set.proxy_ssl.primary.password =
+ data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
+#endif
+#endif /* CURL_DISABLE_PROXY */
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ /* Clone "primary" SSL configurations from the esay handle to
+ * the connection. They are used for connection cache matching and
+ * probably outlive the easy handle */
+ if(!clone_ssl_primary_config(&data->set.ssl.primary, &conn->ssl_config))
+ return CURLE_OUT_OF_MEMORY;
+#ifndef CURL_DISABLE_PROXY
+ if(!clone_ssl_primary_config(&data->set.proxy_ssl.primary,
+ &conn->proxy_ssl_config))
+ return CURLE_OUT_OF_MEMORY;
+#endif
+ return CURLE_OK;
+}
+
+void Curl_ssl_conn_config_cleanup(struct connectdata *conn)
+{
+ Curl_free_primary_ssl_config(&conn->ssl_config);
+#ifndef CURL_DISABLE_PROXY
+ Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
+#endif
+}
+
+void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy)
+{
+ /* May be called on an easy that has no connection yet */
+ if(data->conn) {
+ struct ssl_primary_config *src, *dest;
+#ifndef CURL_DISABLE_PROXY
+ src = for_proxy? &data->set.proxy_ssl.primary : &data->set.ssl.primary;
+ dest = for_proxy? &data->conn->proxy_ssl_config : &data->conn->ssl_config;
+#else
+ (void)for_proxy;
+ src = &data->set.ssl.primary;
+ dest = &data->conn->ssl_config;
+#endif
+ dest->verifyhost = src->verifyhost;
+ dest->verifypeer = src->verifypeer;
+ dest->verifystatus = src->verifystatus;
+ }
+}
+
#ifdef USE_SSL
static int multissl_setup(const struct Curl_ssl *backend);
#endif
@@ -432,7 +567,7 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
if(!check->sessionid)
/* not session ID means blank entry */
continue;
- if(strcasecompare(connssl->hostname, check->name) &&
+ if(strcasecompare(connssl->peer.hostname, check->name) &&
((!cf->conn->bits.conn_to_host && !check->conn_to_host) ||
(cf->conn->bits.conn_to_host && check->conn_to_host &&
strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) &&
@@ -441,7 +576,7 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
cf->conn->conn_to_port == check->conn_to_port)) &&
(connssl->port == check->remote_port) &&
strcasecompare(cf->conn->handler->scheme, check->scheme) &&
- Curl_ssl_config_matches(conn_config, &check->ssl_config)) {
+ match_ssl_primary_config(data, conn_config, &check->ssl_config)) {
/* yes, we have a session ID! */
(*general_age)++; /* increase general age */
check->age = *general_age; /* set this as used in this age */
@@ -456,7 +591,8 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
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));
+ cf->conn->handler->scheme, connssl->peer.hostname,
+ connssl->port));
return no_match;
}
@@ -532,7 +668,7 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
(void)ssl_config;
DEBUGASSERT(ssl_config->primary.sessionid);
- clone_host = strdup(connssl->hostname);
+ clone_host = strdup(connssl->peer.hostname);
if(!clone_host)
return CURLE_OUT_OF_MEMORY; /* bail out */
@@ -590,7 +726,7 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
store->remote_port = connssl->port;
store->scheme = cf->conn->handler->scheme;
- if(!Curl_clone_primary_ssl_config(conn_config, &store->ssl_config)) {
+ if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) {
Curl_free_primary_ssl_config(&store->ssl_config);
store->sessionid = NULL; /* let caller free sessionid */
free(clone_host);
@@ -629,22 +765,21 @@ void Curl_ssl_close_all(struct Curl_easy *data)
Curl_ssl->close_all(data);
}
-int Curl_ssl_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
- curl_socket_t *socks)
+void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
+ struct easy_pollset *ps)
{
- struct ssl_connect_data *connssl = cf->ctx;
- curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
-
- if(sock == CURL_SOCKET_BAD)
- return GETSOCK_BLANK;
-
- if(connssl->connecting_state == ssl_connect_2_writing) {
- /* we are only interested in writing */
- socks[0] = sock;
- return GETSOCK_WRITESOCK(0);
+ if(!cf->connected) {
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
+ if(sock != CURL_SOCKET_BAD) {
+ if(connssl->connecting_state == ssl_connect_2_writing) {
+ Curl_pollset_set_out_only(data, ps, sock);
+ }
+ else {
+ Curl_pollset_set_in_only(data, ps, sock);
+ }
+ }
}
- socks[0] = sock;
- return GETSOCK_READSOCK(0);
}
/* Selects an SSL crypto engine
@@ -786,32 +921,6 @@ CURLcode Curl_ssl_random(struct Curl_easy *data,
}
/*
- * Curl_ssl_snihost() converts the input host name to a suitable SNI name put
- * in data->state.buffer. Returns a pointer to the name (or NULL if a problem)
- * and stores the new length in 'olen'.
- *
- * SNI fields must not have any trailing dot and while RFC 6066 section 3 says
- * the SNI field is case insensitive, browsers always send the data lowercase
- * and subsequently there are numerous servers out there that don't work
- * unless the name is lowercased.
- */
-
-char *Curl_ssl_snihost(struct Curl_easy *data, const char *host, size_t *olen)
-{
- size_t len = strlen(host);
- if(len && (host[len-1] == '.'))
- len--;
- if(len >= data->set.buffer_size)
- return NULL;
-
- Curl_strntolower(data->state.buffer, host, len);
- data->state.buffer[len] = 0;
- if(olen)
- *olen = len;
- return data->state.buffer;
-}
-
-/*
* Public key pem to der conversion
*/
@@ -1156,13 +1265,13 @@ static CURLcode multissl_connect_nonblocking(struct Curl_cfilter *cf,
return Curl_ssl->connect_nonblocking(cf, data, done);
}
-static int multissl_get_select_socks(struct Curl_cfilter *cf,
+static void multissl_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
- curl_socket_t *socks)
+ struct easy_pollset *ps)
{
if(multissl_setup(NULL))
- return 0;
- return Curl_ssl->get_select_socks(cf, data, socks);
+ return;
+ Curl_ssl->adjust_pollset(cf, data, ps);
}
static void *multissl_get_internals(struct ssl_connect_data *connssl,
@@ -1214,7 +1323,7 @@ static const struct Curl_ssl Curl_ssl_multi = {
Curl_none_cert_status_request, /* cert_status_request */
multissl_connect, /* connect */
multissl_connect_nonblocking, /* connect_nonblocking */
- multissl_get_select_socks, /* getsock */
+ multissl_adjust_pollset, /* adjust_pollset */
multissl_get_internals, /* get_internals */
multissl_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1409,12 +1518,14 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
#ifdef USE_SSL
-static void free_hostname(struct ssl_connect_data *connssl)
+void Curl_ssl_peer_cleanup(struct ssl_peer *peer)
{
- if(connssl->dispname != connssl->hostname)
- free(connssl->dispname);
- free(connssl->hostname);
- connssl->hostname = connssl->dispname = NULL;
+ if(peer->dispname != peer->hostname)
+ free(peer->dispname);
+ free(peer->sni);
+ free(peer->hostname);
+ peer->hostname = peer->sni = peer->dispname = NULL;
+ peer->is_ip_address = FALSE;
}
static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -1423,12 +1534,26 @@ static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
if(connssl) {
Curl_ssl->close(cf, data);
connssl->state = ssl_connection_none;
- free_hostname(connssl);
+ Curl_ssl_peer_cleanup(&connssl->peer);
}
cf->connected = FALSE;
}
-static CURLcode reinit_hostname(struct Curl_cfilter *cf)
+static int is_ip_address(const char *hostname)
+{
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+ return (hostname && hostname[0] && (Curl_inet_pton(AF_INET, hostname, &addr)
+#ifdef ENABLE_IPV6
+ || Curl_inet_pton(AF_INET6, hostname, &addr)
+#endif
+ ));
+}
+
+CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
{
struct ssl_connect_data *connssl = cf->ctx;
const char *ehostname, *edispname;
@@ -1454,23 +1579,43 @@ static CURLcode reinit_hostname(struct Curl_cfilter *cf)
}
/* change if ehostname changed */
- if(ehostname && (!connssl->hostname
- || strcmp(ehostname, connssl->hostname))) {
- free_hostname(connssl);
- connssl->hostname = strdup(ehostname);
- if(!connssl->hostname) {
- free_hostname(connssl);
+ if(ehostname && (!peer->hostname
+ || strcmp(ehostname, peer->hostname))) {
+ Curl_ssl_peer_cleanup(peer);
+ peer->hostname = strdup(ehostname);
+ if(!peer->hostname) {
+ Curl_ssl_peer_cleanup(peer);
return CURLE_OUT_OF_MEMORY;
}
if(!edispname || !strcmp(ehostname, edispname))
- connssl->dispname = connssl->hostname;
+ peer->dispname = peer->hostname;
else {
- connssl->dispname = strdup(edispname);
- if(!connssl->dispname) {
- free_hostname(connssl);
+ peer->dispname = strdup(edispname);
+ if(!peer->dispname) {
+ Curl_ssl_peer_cleanup(peer);
return CURLE_OUT_OF_MEMORY;
}
}
+
+ peer->sni = NULL;
+ peer->is_ip_address = is_ip_address(peer->hostname)? TRUE : FALSE;
+ if(peer->hostname[0] && !peer->is_ip_address) {
+ /* not an IP address, normalize according to RCC 6066 ch. 3,
+ * max len of SNI is 2^16-1, no trailing dot */
+ size_t len = strlen(peer->hostname);
+ if(len && (peer->hostname[len-1] == '.'))
+ len--;
+ if(len < USHRT_MAX) {
+ peer->sni = calloc(1, len + 1);
+ if(!peer->sni) {
+ Curl_ssl_peer_cleanup(peer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ Curl_strntolower(peer->sni, peer->hostname, len);
+ peer->sni[len] = 0;
+ }
+ }
+
}
connssl->port = eport;
return CURLE_OK;
@@ -1525,7 +1670,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
goto out;
*done = FALSE;
- result = reinit_hostname(cf);
+ result = Curl_ssl_peer_init(&connssl->peer, cf);
if(result)
goto out;
@@ -1599,22 +1744,17 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
return nread;
}
-static int ssl_cf_get_select_socks(struct Curl_cfilter *cf,
+static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
- curl_socket_t *socks)
+ struct easy_pollset *ps)
{
struct cf_call_data save;
- int fds = GETSOCK_BLANK;
- if(!cf->next->connected) {
- fds = cf->next->cft->get_select_socks(cf->next, data, socks);
- }
- else if(!cf->connected) {
+ if(!cf->connected) {
CF_DATA_SAVE(save, cf, data);
- fds = Curl_ssl->get_select_socks(cf, data, socks);
+ Curl_ssl->adjust_pollset(cf, data, ps);
CF_DATA_RESTORE(cf, save);
}
- return fds;
}
static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
@@ -1705,7 +1845,7 @@ struct Curl_cftype Curl_cft_ssl = {
ssl_cf_connect,
ssl_cf_close,
Curl_cf_def_get_host,
- ssl_cf_get_select_socks,
+ ssl_cf_adjust_pollset,
ssl_cf_data_pending,
ssl_cf_send,
ssl_cf_recv,
@@ -1723,7 +1863,7 @@ struct Curl_cftype Curl_cft_ssl_proxy = {
ssl_cf_connect,
ssl_cf_close,
Curl_cf_def_get_host,
- ssl_cf_get_select_socks,
+ ssl_cf_adjust_pollset,
ssl_cf_data_pending,
ssl_cf_send,
ssl_cf_recv,
@@ -1837,6 +1977,16 @@ bool Curl_ssl_supports(struct Curl_easy *data, int option)
return (Curl_ssl->supports & option)? TRUE : FALSE;
}
+static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
+{
+ for(; cf; cf = cf->next) {
+ if(cf->cft == &Curl_cft_ssl || cf->cft == &Curl_cft_ssl_proxy)
+ return cf;
+ }
+ return NULL;
+}
+
+
void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
CURLINFO info, int n)
{
@@ -1844,8 +1994,8 @@ void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
(void)n;
if(data->conn) {
struct Curl_cfilter *cf;
- /* get first filter in chain, if any is present */
- cf = Curl_ssl_cf_get_ssl(data->conn->cfilter[sockindex]);
+ /* get first SSL filter in chain, if any is present */
+ cf = get_ssl_filter(data->conn->cfilter[sockindex]);
if(cf) {
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
@@ -1875,23 +2025,6 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
return result;
}
-static struct Curl_cfilter *get_ssl_cf_engaged(struct connectdata *conn,
- int sockindex)
-{
- struct Curl_cfilter *cf, *lowest_ssl_cf = NULL;
-
- for(cf = conn->cfilter[sockindex]; cf; cf = cf->next) {
- if(cf->cft == &Curl_cft_ssl || cf->cft == &Curl_cft_ssl_proxy) {
- lowest_ssl_cf = cf;
- if(cf->connected || (cf->next && cf->next->connected)) {
- /* connected or about to start */
- return cf;
- }
- }
- }
- return lowest_ssl_cf;
-}
-
bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)
{
return (cf->cft == &Curl_cft_ssl_proxy);
@@ -1908,17 +2041,6 @@ Curl_ssl_cf_get_config(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif
}
-struct ssl_config_data *
-Curl_ssl_get_config(struct Curl_easy *data, int sockindex)
-{
- struct Curl_cfilter *cf;
-
- (void)data;
- DEBUGASSERT(data->conn);
- cf = get_ssl_cf_engaged(data->conn, sockindex);
- return cf? Curl_ssl_cf_get_config(cf, data) : &data->set.ssl;
-}
-
struct ssl_primary_config *
Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf)
{
@@ -1930,15 +2052,6 @@ Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf)
#endif
}
-struct Curl_cfilter *Curl_ssl_cf_get_ssl(struct Curl_cfilter *cf)
-{
- for(; cf; cf = cf->next) {
- if(cf->cft == &Curl_cft_ssl || cf->cft == &Curl_cft_ssl_proxy)
- return cf;
- }
- return NULL;
-}
-
CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf,
const struct alpn_spec *spec)
{
@@ -2005,10 +2118,6 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
!memcmp(ALPN_HTTP_1_1, proto, ALPN_HTTP_1_1_LENGTH)) {
*palpn = CURL_HTTP_VERSION_1_1;
}
- else if(proto_len == ALPN_HTTP_1_0_LENGTH &&
- !memcmp(ALPN_HTTP_1_0, proto, ALPN_HTTP_1_0_LENGTH)) {
- *palpn = CURL_HTTP_VERSION_1_0;
- }
#ifdef USE_HTTP2
else if(proto_len == ALPN_H2_LENGTH &&
!memcmp(ALPN_H2, proto, ALPN_H2_LENGTH)) {
diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h
index 8ad1cf6..f1856bd 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.h
+++ b/Utilities/cmcurl/lib/vtls/vtls.h
@@ -65,15 +65,54 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */
#endif
-char *Curl_ssl_snihost(struct Curl_easy *data, const char *host, size_t *olen);
-bool Curl_ssl_config_matches(struct ssl_primary_config *data,
- struct ssl_primary_config *needle);
-bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
- struct ssl_primary_config *dest);
-void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc);
-
curl_sslbackend Curl_ssl_backend(void);
+/**
+ * Init ssl config for a new easy handle.
+ */
+void Curl_ssl_easy_config_init(struct Curl_easy *data);
+
+/**
+ * Init the `data->set.ssl` and `data->set.proxy_ssl` for
+ * connection matching use.
+ */
+CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data);
+
+/**
+ * Init SSL configs (main + proxy) for a new connection from the easy handle.
+ */
+CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
+ struct connectdata *conn);
+
+/**
+ * Free allocated resources in SSL configs (main + proxy) for
+ * the given connection.
+ */
+void Curl_ssl_conn_config_cleanup(struct connectdata *conn);
+
+/**
+ * Return TRUE iff SSL configuration from `conn` is functionally the
+ * same as the one on `candidate`.
+ * @param proxy match the proxy SSL config or the main one
+ */
+bool Curl_ssl_conn_config_match(struct Curl_easy *data,
+ struct connectdata *candidate,
+ bool proxy);
+
+/* Update certain connection SSL config flags after they have
+ * been changed on the easy handle. Will work for `verifypeer`,
+ * `verifyhost` and `verifystatus`. */
+void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy);
+
+/**
+ * Init SSL peer information for filter. Can be called repeatedly.
+ */
+CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf);
+/**
+ * Free all allocated data and reset peer information.
+ */
+void Curl_ssl_peer_cleanup(struct ssl_peer *peer);
+
#ifdef USE_SSL
int Curl_ssl_init(void);
void Curl_ssl_cleanup(void);
@@ -160,18 +199,6 @@ CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
#endif /* !CURL_DISABLE_PROXY */
/**
- * Get the SSL configuration that is used on the connection.
- * This returns NULL if no SSL is configured.
- * Otherwise it returns the config of the first (highest) one that is
- * either connected, in handshake or about to start
- * (e.g. all filters below it are connected). If SSL filters are present,
- * but neither can start operating, return the config of the lowest one
- * that will first come into effect when connecting.
- */
-struct ssl_config_data *Curl_ssl_get_config(struct Curl_easy *data,
- int sockindex);
-
-/**
* True iff the underlying SSL implementation supports the option.
* Option is one of the defined SSLSUPP_* values.
* `data` maybe NULL for the features of the default implementation.
@@ -188,6 +215,18 @@ bool Curl_ssl_supports(struct Curl_easy *data, int ssl_option);
void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
CURLINFO info, int n);
+/**
+ * Get the ssl_config_data in `data` that is relevant for cfilter `cf`.
+ */
+struct ssl_config_data *Curl_ssl_cf_get_config(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+
+/**
+ * Get the primary config relevant for the filter from its connection.
+ */
+struct ssl_primary_config *
+ Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf);
+
extern struct Curl_cftype Curl_cft_ssl;
extern struct Curl_cftype Curl_cft_ssl_proxy;
@@ -209,8 +248,9 @@ extern struct Curl_cftype Curl_cft_ssl_proxy;
#define Curl_ssl_get_internals(a,b,c,d) NULL
#define Curl_ssl_supports(a,b) FALSE
#define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN
-#define Curl_ssl_get_config(a,b) NULL
#define Curl_ssl_cfilter_remove(a,b) CURLE_OK
+#define Curl_ssl_cf_get_config(a,b) NULL
+#define Curl_ssl_cf_get_primary_config(a) NULL
#endif
#endif /* HEADER_CURL_VTLS_H */
diff --git a/Utilities/cmcurl/lib/vtls/vtls_int.h b/Utilities/cmcurl/lib/vtls/vtls_int.h
index a6e4544..af7ae55 100644
--- a/Utilities/cmcurl/lib/vtls/vtls_int.h
+++ b/Utilities/cmcurl/lib/vtls/vtls_int.h
@@ -32,8 +32,6 @@
/* see https://www.iana.org/assignments/tls-extensiontype-values/ */
#define ALPN_HTTP_1_1_LENGTH 8
#define ALPN_HTTP_1_1 "http/1.1"
-#define ALPN_HTTP_1_0_LENGTH 8
-#define ALPN_HTTP_1_0 "http/1.0"
#define ALPN_H2_LENGTH 2
#define ALPN_H2 "h2"
#define ALPN_H3_LENGTH 2
@@ -70,14 +68,14 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
struct ssl_connect_data {
ssl_connection_state state;
ssl_connect_state connecting_state;
- char *hostname; /* hostname for verification */
- char *dispname; /* display version of hostname */
+ struct ssl_peer peer;
const struct alpn_spec *alpn; /* ALPN to use or NULL for none */
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 */
BIT(use_alpn); /* if ALPN shall be used in handshake */
+ BIT(reused_session); /* session-ID was reused for this */
};
@@ -118,14 +116,11 @@ struct Curl_ssl {
struct Curl_easy *data,
bool *done);
- /* If the SSL backend wants to read or write on this connection during a
- handshake, set socks[0] to the connection's FIRSTSOCKET, and return
- a bitmap indicating read or write with GETSOCK_WRITESOCK(0) or
- GETSOCK_READSOCK(0). Otherwise return GETSOCK_BLANK.
- Mandatory. */
- int (*get_select_socks)(struct Curl_cfilter *cf, struct Curl_easy *data,
- curl_socket_t *socks);
-
+ /* During handshake, adjust the pollset to include the socket
+ * for POLLOUT or POLLIN as needed.
+ * Mandatory. */
+ void (*adjust_pollset)(struct Curl_cfilter *cf, struct Curl_easy *data,
+ struct easy_pollset *ps);
void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
void (*close)(struct Curl_cfilter *cf, struct Curl_easy *data);
void (*close_all)(struct Curl_easy *data);
@@ -169,25 +164,8 @@ CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine);
CURLcode Curl_none_set_engine_default(struct Curl_easy *data);
struct curl_slist *Curl_none_engines_list(struct Curl_easy *data);
bool Curl_none_false_start(void);
-int Curl_ssl_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
- curl_socket_t *socks);
-
-/**
- * Get the ssl_config_data in `data` that is relevant for cfilter `cf`.
- */
-struct ssl_config_data *Curl_ssl_cf_get_config(struct Curl_cfilter *cf,
- struct Curl_easy *data);
-
-/**
- * Get the primary config relevant for the filter from its connection.
- */
-struct ssl_primary_config *
- Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf);
-
-/**
- * Get the first SSL filter in the chain starting with `cf`, or NULL.
- */
-struct Curl_cfilter *Curl_ssl_cf_get_ssl(struct Curl_cfilter *cf);
+void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
+ struct easy_pollset *ps);
/**
* Get the SSL filter below the given one or NULL if there is none.
diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c
index b1384a6..5890bb6 100644
--- a/Utilities/cmcurl/lib/vtls/wolfssl.c
+++ b/Utilities/cmcurl/lib/vtls/wolfssl.c
@@ -480,6 +480,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
#endif
+ default:
break;
}
@@ -513,7 +514,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
-#ifndef NO_FILESYSTEM
+#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
/* load native CA certificates */
if(ssl_config->native_ca_store) {
if(wolfSSL_CTX_load_system_CA_certs(backend->ctx) != WOLFSSL_SUCCESS) {
@@ -608,24 +609,12 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
SSL_VERIFY_NONE, NULL);
#ifdef HAVE_SNI
- if(sni) {
- struct in_addr addr4;
-#ifdef ENABLE_IPV6
- struct in6_addr addr6;
-#endif
- size_t hostname_len = strlen(connssl->hostname);
-
- if((hostname_len < USHRT_MAX) &&
- !Curl_inet_pton(AF_INET, connssl->hostname, &addr4)
-#ifdef ENABLE_IPV6
- && !Curl_inet_pton(AF_INET6, connssl->hostname, &addr6)
-#endif
- ) {
- size_t snilen;
- char *snihost = Curl_ssl_snihost(data, connssl->hostname, &snilen);
- if(!snihost ||
- wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, snihost,
- (unsigned short)snilen) != 1) {
+ if(sni && connssl->peer.sni) {
+ size_t sni_len = strlen(connssl->peer.sni);
+ if((sni_len < USHRT_MAX)) {
+ if(wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME,
+ connssl->peer.sni,
+ (unsigned short)sni_len) != 1) {
failf(data, "Failed to set SNI");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -763,9 +752,9 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
/* Enable RFC2818 checks */
if(conn_config->verifyhost) {
- char *snihost = Curl_ssl_snihost(data, connssl->hostname, NULL);
- if(!snihost ||
- (wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE))
+ char *snihost = connssl->peer.sni?
+ connssl->peer.sni : connssl->peer.hostname;
+ if(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE)
return CURLE_SSL_CONNECT_ERROR;
}
@@ -813,7 +802,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
else if(DOMAIN_NAME_MISMATCH == detail) {
#if 1
failf(data, " subject alt name(s) or common name do not match \"%s\"",
- connssl->dispname);
+ connssl->peer.dispname);
return CURLE_PEER_FAILED_VERIFICATION;
#else
/* When the wolfssl_check_domain_name() is used and you desire to
@@ -1398,7 +1387,7 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
Curl_none_cert_status_request, /* cert_status_request */
wolfssl_connect, /* connect */
wolfssl_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_get_select_socks, /* getsock */
+ Curl_ssl_adjust_pollset, /* adjust_pollset */
wolfssl_get_internals, /* get_internals */
wolfssl_close, /* close_one */
Curl_none_close_all, /* close_all */
diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.c b/Utilities/cmcurl/lib/vtls/x509asn1.c
index c3fd3a3..8b1eed6 100644
--- a/Utilities/cmcurl/lib/vtls/x509asn1.c
+++ b/Utilities/cmcurl/lib/vtls/x509asn1.c
@@ -1317,16 +1317,16 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf,
if(Curl_parseX509(&cert, beg, end))
return CURLE_PEER_FAILED_VERIFICATION;
- hostlen = strlen(connssl->hostname);
+ hostlen = strlen(connssl->peer.hostname);
/* Get the server IP address. */
#ifdef ENABLE_IPV6
if(cf->conn->bits.ipv6_ip &&
- Curl_inet_pton(AF_INET6, connssl->hostname, &addr))
+ Curl_inet_pton(AF_INET6, connssl->peer.hostname, &addr))
addrlen = sizeof(struct in6_addr);
else
#endif
- if(Curl_inet_pton(AF_INET, connssl->hostname, &addr))
+ if(Curl_inet_pton(AF_INET, connssl->peer.hostname, &addr))
addrlen = sizeof(struct in_addr);
/* Process extensions. */
@@ -1361,7 +1361,7 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf,
name.beg, name.end);
if(len > 0 && (size_t)len == strlen(dnsname))
matched = Curl_cert_hostcheck(dnsname, (size_t)len,
- connssl->hostname, hostlen);
+ connssl->peer.hostname, hostlen);
else
matched = 0;
free(dnsname);
@@ -1421,7 +1421,7 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf,
if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */
failf(data, "SSL: illegal cert name field");
else if(Curl_cert_hostcheck((const char *) dnsname,
- len, connssl->hostname, hostlen)) {
+ len, connssl->peer.hostname, hostlen)) {
infof(data, " common name: %s (matched)", dnsname);
free(dnsname);
return CURLE_OK;
diff --git a/Utilities/cmcurl/lib/warnless.c b/Utilities/cmcurl/lib/warnless.c
index 7e077f8..c80937b 100644
--- a/Utilities/cmcurl/lib/warnless.c
+++ b/Utilities/cmcurl/lib/warnless.c
@@ -37,7 +37,7 @@
#include "warnless.h"
-#ifdef WIN32
+#ifdef _WIN32
#undef read
#undef write
#endif
@@ -367,7 +367,7 @@ curl_socket_t curlx_sitosk(int i)
#endif /* USE_WINSOCK */
-#if defined(WIN32)
+#if defined(_WIN32)
ssize_t curlx_read(int fd, void *buf, size_t count)
{
@@ -379,8 +379,8 @@ 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 */
+#endif /* _WIN32 */
+/* Ensure that warnless.h redefinitions continue to have an effect
+ in "unity" builds. */
+#undef HEADER_CURL_WARNLESS_H_REDEFS
diff --git a/Utilities/cmcurl/lib/warnless.h b/Utilities/cmcurl/lib/warnless.h
index 2a53016..e5a02c8 100644
--- a/Utilities/cmcurl/lib/warnless.h
+++ b/Utilities/cmcurl/lib/warnless.h
@@ -69,18 +69,13 @@ curl_socket_t curlx_sitosk(int i);
#endif /* USE_WINSOCK */
-#if defined(WIN32)
+#if defined(_WIN32)
ssize_t curlx_read(int fd, void *buf, size_t count);
ssize_t curlx_write(int fd, const void *buf, size_t count);
-#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 */
+#endif /* _WIN32 */
#if defined(__INTEL_COMPILER) && defined(__unix__)
@@ -97,3 +92,15 @@ unsigned short curlx_ntohs(unsigned short usnum);
#endif /* __INTEL_COMPILER && __unix__ */
#endif /* HEADER_CURL_WARNLESS_H */
+
+#ifndef HEADER_CURL_WARNLESS_H_REDEFS
+#define HEADER_CURL_WARNLESS_H_REDEFS
+
+#if defined(_WIN32)
+#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
+
+#endif /* HEADER_CURL_WARNLESS_H_REDEFS */
diff --git a/Utilities/cmcurl/lib/ws.c b/Utilities/cmcurl/lib/ws.c
index 3c1964b..adde531 100644
--- a/Utilities/cmcurl/lib/ws.c
+++ b/Utilities/cmcurl/lib/ws.c
@@ -274,8 +274,8 @@ static CURLcode ws_dec_pass_payload(struct ws_decoder *dec,
dec->payload_offset += (curl_off_t)nwritten;
remain = dec->payload_len - dec->payload_offset;
/* infof(data, "WS-DEC: passed %zd bytes payload, %"
- CURL_FORMAT_CURL_OFF_T " remain",
- nwritten, remain); */
+ CURL_FORMAT_CURL_OFF_T " remain",
+ nwritten, remain); */
}
return remain? CURLE_AGAIN : CURLE_OK;
@@ -925,8 +925,8 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
*metap = &ws->frame;
*nread = ws->frame.len;
/* 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); */
+ CURL_FORMAT_CURL_OFF_T ", %" CURL_FORMAT_CURL_OFF_T " left)",
+ buflen, *nread, ws->frame.offset, ws->frame.bytesleft); */
return CURLE_OK;
}