diff options
author | Curl Upstream <curl-library@lists.haxx.se> | 2023-10-11 05:34:19 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2023-10-12 19:28:57 (GMT) |
commit | e6a6c1abc1e6b6e3ca9fa77947279509b55e2b01 (patch) | |
tree | f0d748647eebb0b8ba55e478ea35c8686dbd1485 /lib | |
parent | 017637e40f954e791a895a04855d0411bda61c10 (diff) | |
download | CMake-e6a6c1abc1e6b6e3ca9fa77947279509b55e2b01.zip CMake-e6a6c1abc1e6b6e3ca9fa77947279509b55e2b01.tar.gz CMake-e6a6c1abc1e6b6e3ca9fa77947279509b55e2b01.tar.bz2 |
curl 2023-10-11 (d755a5f7)
Code extracted from:
https://github.com/curl/curl.git
at commit d755a5f7c009dd63a61b2c745180d8ba937cbfeb (curl-8_4_0).
Diffstat (limited to 'lib')
93 files changed, 1360 insertions, 1438 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 9bb8f0b..6f84919 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -56,9 +56,9 @@ add_library( target_compile_definitions(curlu PUBLIC UNITTESTS CURL_STATICLIB) if(ENABLE_CURLDEBUG) - # We must compile memdebug.c separately to avoid memdebug.h redefinitions - # being applied to memdebug.c itself. - set_source_files_properties(memdebug.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON) + # 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}) @@ -85,19 +85,6 @@ else() unset(CMAKESONAME) endif() -if(NOT WIN32 AND NOT CMAKE_CROSSCOMPILING) - # on not-Windows and not-crosscompiling, check for writable argv[] - include(CheckCSourceRuns) - check_c_source_runs(" -int main(int argc, char **argv) -{ - (void)argc; - argv[0][0] = ' '; - return (argv[0][0] == ' ')?0:1; -}" - HAVE_WRITABLE_ARGV) -endif() - ## Library definition # Add "_imp" as a suffix before the extension to avoid conflicting with @@ -122,18 +109,23 @@ if(NOT DEFINED SHARE_LIB_OBJECT) endif() endif() +if(WIN32) + # Define CURL_STATICLIB always, to disable __declspec(dllexport) for exported + # libcurl symbols. We handle exports via libcurl.def instead. Except with + # symbol hiding disabled or debug mode enabled, when we export _all_ symbols + # from libcurl DLL, without using libcurl.def. + add_definitions("-DCURL_STATICLIB") +endif() + if(SHARE_LIB_OBJECT) set(LIB_OBJECT "libcurl_object") add_library(${LIB_OBJECT} OBJECT ${HHEADERS} ${CSOURCES}) target_link_libraries(${LIB_OBJECT} PRIVATE ${CURL_LIBS}) set_target_properties(${LIB_OBJECT} PROPERTIES - COMPILE_DEFINITIONS "BUILDING_LIBCURL" - INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB" POSITION_INDEPENDENT_CODE ON) if(HIDES_CURL_PRIVATE_SYMBOLS) - set_target_properties(${LIB_OBJECT} PROPERTIES - COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS" - COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") endif() if(CURL_HAS_LTO) set_target_properties(${LIB_OBJECT} PROPERTIES @@ -160,12 +152,10 @@ if(BUILD_STATIC_LIBS) set_target_properties(${LIB_STATIC} PROPERTIES PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}" SUFFIX "${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}" - COMPILE_DEFINITIONS "BUILDING_LIBCURL" INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB") if(HIDES_CURL_PRIVATE_SYMBOLS) - set_target_properties(${LIB_STATIC} PROPERTIES - COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS" - COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") endif() if(CURL_HAS_LTO) set_target_properties(${LIB_STATIC} PROPERTIES @@ -187,19 +177,20 @@ if(BUILD_SHARED_LIBS) add_library(${LIB_SHARED} SHARED ${LIB_SOURCE}) add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED}) if(WIN32) - set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc ${CURL_SOURCE_DIR}/libcurl.def) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc) + if(HIDES_CURL_PRIVATE_SYMBOLS) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${CURL_SOURCE_DIR}/libcurl.def") + endif() endif() target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_LIBS}) # Remove the "lib" prefix since the library is already named "libcurl". set_target_properties(${LIB_SHARED} PROPERTIES PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}" IMPORT_PREFIX "" IMPORT_SUFFIX "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}" - COMPILE_DEFINITIONS "BUILDING_LIBCURL" POSITION_INDEPENDENT_CODE ON) if(HIDES_CURL_PRIVATE_SYMBOLS) - set_target_properties(${LIB_SHARED} PROPERTIES - COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS" - COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") endif() if(CURL_HAS_LTO) set_target_properties(${LIB_SHARED} PROPERTIES diff --git a/lib/Makefile.inc b/lib/Makefile.inc index a08180b..e568ef9 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -162,12 +162,12 @@ LIB_CFILES = \ http.c \ http1.c \ http2.c \ + http_aws_sigv4.c \ http_chunks.c \ http_digest.c \ http_negotiate.c \ http_ntlm.c \ http_proxy.c \ - http_aws_sigv4.c \ idn.c \ if2ip.c \ imap.c \ @@ -289,9 +289,9 @@ LIB_HFILES = \ fileinfo.h \ fopen.h \ formdata.h \ - functypes.h \ ftp.h \ ftplistparser.h \ + functypes.h \ getinfo.h \ gopher.h \ hash.h \ @@ -301,12 +301,12 @@ LIB_HFILES = \ http.h \ http1.h \ http2.h \ + http_aws_sigv4.h \ http_chunks.h \ http_digest.h \ http_negotiate.h \ http_ntlm.h \ http_proxy.h \ - http_aws_sigv4.h \ idn.h \ if2ip.h \ imap.h \ diff --git a/lib/base64.c b/lib/base64.c index 30db7e5..2a49b5a 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -31,7 +31,7 @@ !defined(CURL_DISABLE_SMTP) || \ !defined(CURL_DISABLE_POP3) || \ !defined(CURL_DISABLE_IMAP) || \ - !defined(CURL_DISABLE_DOH) || defined(USE_SSL) + !defined(CURL_DISABLE_DOH) || defined(USE_SSL) || defined(BUILDING_CURL) #include "curl/curl.h" #include "warnless.h" #include "curl_base64.h" @@ -144,21 +144,6 @@ static size_t chunk_skip(struct buf_chunk *chunk, size_t amount) return n; } -static void chunk_shift(struct buf_chunk *chunk) -{ - if(chunk->r_offset) { - if(!chunk_is_empty(chunk)) { - size_t n = chunk->w_offset - chunk->r_offset; - memmove(chunk->x.data, chunk->x.data + chunk->r_offset, n); - chunk->w_offset -= chunk->r_offset; - chunk->r_offset = 0; - } - else { - chunk->r_offset = chunk->w_offset = 0; - } - } -} - static void chunk_list_free(struct buf_chunk **anchor) { struct buf_chunk *chunk; @@ -504,13 +489,6 @@ void Curl_bufq_skip(struct bufq *q, size_t amount) } } -void Curl_bufq_skip_and_shift(struct bufq *q, size_t amount) -{ - Curl_bufq_skip(q, amount); - if(q->tail) - chunk_shift(q->tail); -} - ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer, void *writer_ctx, CURLcode *err) { @@ -209,12 +209,6 @@ bool Curl_bufq_peek_at(struct bufq *q, size_t offset, */ void Curl_bufq_skip(struct bufq *q, size_t amount); -/** - * Same as `skip` but shift tail data to the start afterwards, - * so that further writes will find room in tail. - */ -void Curl_bufq_skip_and_shift(struct bufq *q, size_t amount); - typedef ssize_t Curl_bufq_writer(void *writer_ctx, const unsigned char *buf, size_t len, CURLcode *err); diff --git a/lib/c-hyper.c b/lib/c-hyper.c index 61ca29a..5726ff1 100644 --- a/lib/c-hyper.c +++ b/lib/c-hyper.c @@ -174,8 +174,6 @@ static int hyper_each_header(void *userdata, if(!data->state.hconnect || !data->set.suppress_connect_headers) { writetype = CLIENTWRITE_HEADER; - if(data->set.include_header) - writetype |= CLIENTWRITE_BODY; if(data->state.hconnect) writetype |= CLIENTWRITE_CONNECT; if(data->req.httpcode/100 == 1) @@ -248,11 +246,7 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk) if(0 == len) return HYPER_ITER_CONTINUE; Curl_debug(data, CURLINFO_DATA_IN, buf, len); - if(!data->set.http_ce_skip && k->writer_stack) - /* content-encoded data */ - result = Curl_unencode_write(data, k->writer_stack, buf, len); - else - result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len); + result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len); if(result) { data->state.hresult = result; @@ -260,7 +254,11 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk) } data->req.bytecount += len; - Curl_pgrsSetDownloadCounter(data, data->req.bytecount); + result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount); + if(result) { + data->state.hresult = result; + return HYPER_ITER_BREAK; + } return HYPER_ITER_CONTINUE; } @@ -314,8 +312,6 @@ static CURLcode status_line(struct Curl_easy *data, if(!data->state.hconnect || !data->set.suppress_connect_headers) { writetype = CLIENTWRITE_HEADER|CLIENTWRITE_STATUS; - if(data->set.include_header) - writetype |= CLIENTWRITE_BODY; result = Curl_client_write(data, writetype, Curl_dyn_ptr(&data->state.headerb), len); if(result) diff --git a/lib/cf-h1-proxy.c b/lib/cf-h1-proxy.c index e9bc13d..6748021 100644 --- a/lib/cf-h1-proxy.c +++ b/lib/cf-h1-proxy.c @@ -34,6 +34,7 @@ #include "dynbuf.h" #include "sendf.h" #include "http.h" +#include "http1.h" #include "http_proxy.h" #include "url.h" #include "select.h" @@ -64,13 +65,10 @@ typedef enum { /* struct for HTTP CONNECT tunneling */ struct h1_tunnel_state { - int sockindex; - const char *hostname; - int remote_port; struct HTTP CONNECT; struct dynbuf rcvbuf; - struct dynbuf req; - size_t nsend; + struct dynbuf request_data; + size_t nsent; size_t headerlines; enum keeponval { KEEPON_DONE, @@ -94,46 +92,31 @@ static bool tunnel_is_failed(struct h1_tunnel_state *ts) return ts && (ts->tunnel_state == H1_TUNNEL_FAILED); } -static CURLcode tunnel_reinit(struct h1_tunnel_state *ts, - struct connectdata *conn, - struct Curl_easy *data) +static CURLcode tunnel_reinit(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h1_tunnel_state *ts) { (void)data; + (void)cf; DEBUGASSERT(ts); Curl_dyn_reset(&ts->rcvbuf); - Curl_dyn_reset(&ts->req); + Curl_dyn_reset(&ts->request_data); ts->tunnel_state = H1_TUNNEL_INIT; ts->keepon = KEEPON_CONNECT; ts->cl = 0; ts->close_connection = FALSE; - - if(conn->bits.conn_to_host) - ts->hostname = conn->conn_to_host.name; - else if(ts->sockindex == SECONDARYSOCKET) - ts->hostname = conn->secondaryhostname; - else - ts->hostname = conn->host.name; - - if(ts->sockindex == SECONDARYSOCKET) - ts->remote_port = conn->secondary_port; - else if(conn->bits.conn_to_port) - ts->remote_port = conn->conn_to_port; - else - ts->remote_port = conn->remote_port; - return CURLE_OK; } -static CURLcode tunnel_init(struct h1_tunnel_state **pts, +static CURLcode tunnel_init(struct Curl_cfilter *cf, struct Curl_easy *data, - struct connectdata *conn, - int sockindex) + struct h1_tunnel_state **pts) { struct h1_tunnel_state *ts; CURLcode result; - if(conn->handler->flags & PROTOPT_NOTCPPROXY) { - failf(data, "%s cannot be done over CONNECT", conn->handler->scheme); + if(cf->conn->handler->flags & PROTOPT_NOTCPPROXY) { + failf(data, "%s cannot be done over CONNECT", cf->conn->handler->scheme); return CURLE_UNSUPPORTED_PROTOCOL; } @@ -146,15 +129,14 @@ static CURLcode tunnel_init(struct h1_tunnel_state **pts, if(!ts) return CURLE_OUT_OF_MEMORY; - ts->sockindex = sockindex; infof(data, "allocate connect buffer"); Curl_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS); - Curl_dyn_init(&ts->req, DYN_HTTP_REQUEST); + Curl_dyn_init(&ts->request_data, DYN_HTTP_REQUEST); *pts = ts; - connkeep(conn, "HTTP proxy CONNECT"); - return tunnel_reinit(ts, conn, data); + connkeep(cf->conn, "HTTP proxy CONNECT"); + return tunnel_reinit(cf, data, ts); } static void h1_tunnel_go_state(struct Curl_cfilter *cf, @@ -176,7 +158,7 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf, switch(new_state) { case H1_TUNNEL_INIT: CURL_TRC_CF(data, cf, "new tunnel state 'init'"); - tunnel_reinit(ts, cf->conn, data); + tunnel_reinit(cf, data, ts); break; case H1_TUNNEL_CONNECT: @@ -207,7 +189,7 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf, CURL_TRC_CF(data, cf, "new tunnel state 'failed'"); ts->tunnel_state = new_state; Curl_dyn_reset(&ts->rcvbuf); - Curl_dyn_reset(&ts->req); + Curl_dyn_reset(&ts->request_data); /* restore the protocol pointer */ data->info.httpcode = 0; /* clear it as it might've been used for the proxy */ @@ -229,171 +211,80 @@ static void tunnel_free(struct Curl_cfilter *cf, if(ts) { h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data); Curl_dyn_free(&ts->rcvbuf); - Curl_dyn_free(&ts->req); + Curl_dyn_free(&ts->request_data); free(ts); cf->ctx = NULL; } } -static CURLcode CONNECT_host(struct Curl_easy *data, - struct connectdata *conn, - const char *hostname, - int remote_port, - char **connecthostp, - char **hostp) -{ - char *hostheader; /* for CONNECT */ - char *host = NULL; /* Host: */ - bool ipv6_ip = conn->bits.ipv6_ip; - - /* the hostname may be different */ - if(hostname != conn->host.name) - ipv6_ip = (strchr(hostname, ':') != NULL); - hostheader = /* host:port with IPv6 support */ - aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", - remote_port); - if(!hostheader) - return CURLE_OUT_OF_MEMORY; - - if(!Curl_checkProxyheaders(data, conn, STRCONST("Host"))) { - host = aprintf("Host: %s\r\n", hostheader); - if(!host) { - free(hostheader); - return CURLE_OUT_OF_MEMORY; - } - } - *connecthostp = hostheader; - *hostp = host; - return CURLE_OK; -} - #ifndef USE_HYPER static CURLcode start_CONNECT(struct Curl_cfilter *cf, struct Curl_easy *data, struct h1_tunnel_state *ts) { - struct connectdata *conn = cf->conn; - char *hostheader = NULL; - char *host = NULL; - const char *httpv; + struct httpreq *req = NULL; + int http_minor; CURLcode result; - infof(data, "Establish HTTP proxy tunnel to %s:%d", - ts->hostname, ts->remote_port); - /* This only happens if we've looped here due to authentication reasons, and we don't really use the newly cloned URL here then. Just free() it. */ Curl_safefree(data->req.newurl); - result = CONNECT_host(data, conn, - ts->hostname, ts->remote_port, - &hostheader, &host); - if(result) - goto out; - - /* Setup the proxy-authorization header, if any */ - result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET, - hostheader, TRUE); - if(result) - goto out; - - httpv = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1"; - - result = - Curl_dyn_addf(&ts->req, - "CONNECT %s HTTP/%s\r\n" - "%s" /* Host: */ - "%s", /* Proxy-Authorization */ - hostheader, - httpv, - host?host:"", - data->state.aptr.proxyuserpwd? - data->state.aptr.proxyuserpwd:""); + result = Curl_http_proxy_create_CONNECT(&req, cf, data, 1); if(result) goto out; - if(!Curl_checkProxyheaders(data, conn, STRCONST("User-Agent")) - && data->set.str[STRING_USERAGENT]) - result = Curl_dyn_addf(&ts->req, "User-Agent: %s\r\n", - data->set.str[STRING_USERAGENT]); - if(result) - goto out; - - if(!Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) - result = Curl_dyn_addn(&ts->req, - STRCONST("Proxy-Connection: Keep-Alive\r\n")); - if(result) - goto out; - - result = Curl_add_custom_headers(data, TRUE, &ts->req); - if(result) - goto out; + infof(data, "Establish HTTP proxy tunnel to %s", req->authority); - /* CRLF terminate the request */ - result = Curl_dyn_addn(&ts->req, STRCONST("\r\n")); - if(result) - goto out; - - /* Send the connect request to the proxy */ - result = Curl_buffer_send(&ts->req, data, &ts->CONNECT, - &data->info.request_size, 0, - ts->sockindex); + Curl_dyn_reset(&ts->request_data); + ts->nsent = 0; ts->headerlines = 0; + http_minor = (cf->conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? 0 : 1; + + result = Curl_h1_req_write_head(req, http_minor, &ts->request_data); out: if(result) failf(data, "Failed sending CONNECT to proxy"); - free(host); - free(hostheader); + if(req) + Curl_http_req_free(req); return result; } -static CURLcode send_CONNECT(struct Curl_easy *data, - struct connectdata *conn, +static CURLcode send_CONNECT(struct Curl_cfilter *cf, + struct Curl_easy *data, struct h1_tunnel_state *ts, bool *done) { - struct SingleRequest *k = &data->req; - struct HTTP *http = &ts->CONNECT; + char *buf = Curl_dyn_ptr(&ts->request_data); + size_t request_len = Curl_dyn_len(&ts->request_data); + size_t blen = request_len; CURLcode result = CURLE_OK; + ssize_t nwritten; - if(http->sending != HTTPSEND_REQUEST) - goto out; + if(blen <= ts->nsent) + goto out; /* we are done */ - if(!ts->nsend) { - size_t fillcount; - k->upload_fromhere = data->state.ulbuf; - result = Curl_fillreadbuffer(data, data->set.upload_buffer_size, - &fillcount); - if(result) - goto out; - ts->nsend = fillcount; - } - if(ts->nsend) { - ssize_t bytes_written; - /* write to socket (send away data) */ - result = Curl_write(data, - conn->writesockfd, /* socket to send to */ - k->upload_fromhere, /* buffer pointer */ - ts->nsend, /* buffer size */ - &bytes_written); /* actually sent */ - if(result) - goto out; - /* send to debug callback! */ - Curl_debug(data, CURLINFO_HEADER_OUT, - k->upload_fromhere, bytes_written); + blen -= ts->nsent; + buf += ts->nsent; - ts->nsend -= bytes_written; - k->upload_fromhere += bytes_written; + nwritten = cf->next->cft->do_send(cf->next, data, buf, blen, &result); + if(nwritten < 0) { + if(result == CURLE_AGAIN) { + result = CURLE_OK; + } + goto out; } - if(!ts->nsend) - http->sending = HTTPSEND_NADA; + + DEBUGASSERT(blen >= (size_t)nwritten); + ts->nsent += (size_t)nwritten; + Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)nwritten); out: if(result) failf(data, "Failed sending CONNECT to proxy"); - *done = (http->sending != HTTPSEND_REQUEST); + *done = (!result && (ts->nsent >= request_len)); return result; } @@ -491,7 +382,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, error = SELECT_OK; *done = FALSE; - if(!Curl_conn_data_pending(data, ts->sockindex)) + if(!Curl_conn_data_pending(data, cf->sockindex)) return CURLE_OK; while(ts->keepon) { @@ -579,7 +470,6 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, if(!data->set.suppress_connect_headers) { /* send the header to the callback */ int writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT | - (data->set.include_header ? CLIENTWRITE_BODY : 0) | (ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0); result = Curl_client_write(data, writetype, linep, perline); @@ -670,6 +560,41 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, } #else /* USE_HYPER */ + +static CURLcode CONNECT_host(struct Curl_cfilter *cf, + struct Curl_easy *data, + char **pauthority, + char **phost_header) +{ + const char *hostname; + int port; + bool ipv6_ip; + CURLcode result; + char *authority; /* for CONNECT, the destination host + port */ + char *host_header = NULL; /* Host: authority */ + + result = Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip); + if(result) + return result; + + authority = aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", + port); + if(!authority) + return CURLE_OUT_OF_MEMORY; + + /* If user is not overriding the Host header later */ + if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("Host"))) { + host_header = aprintf("Host: %s\r\n", authority); + if(!host_header) { + free(authority); + return CURLE_OUT_OF_MEMORY; + } + } + *pauthority = authority; + *phost_header = host_header; + return CURLE_OK; +} + /* The Hyper version of CONNECT */ static CURLcode start_CONNECT(struct Curl_cfilter *cf, struct Curl_easy *data, @@ -686,9 +611,10 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf, hyper_task *task = NULL; /* for the handshake */ hyper_clientconn *client = NULL; hyper_task *sendtask = NULL; /* for the send */ - char *hostheader = NULL; /* for CONNECT */ - char *host = NULL; /* Host: */ + char *authority = NULL; /* for CONNECT */ + char *host_header = NULL; /* Host: */ CURLcode result = CURLE_OUT_OF_MEMORY; + (void)ts; io = hyper_io_new(); if(!io) { @@ -766,27 +692,25 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf, goto error; } - infof(data, "Establish HTTP proxy tunnel to %s:%d", - ts->hostname, ts->remote_port); - /* This only happens if we've looped here due to authentication reasons, and we don't really use the newly cloned URL here then. Just free() it. */ Curl_safefree(data->req.newurl); - result = CONNECT_host(data, conn, ts->hostname, ts->remote_port, - &hostheader, &host); + result = CONNECT_host(cf, data, &authority, &host_header); if(result) goto error; - if(hyper_request_set_uri(req, (uint8_t *)hostheader, - strlen(hostheader))) { + infof(data, "Establish HTTP proxy tunnel to %s", authority); + + if(hyper_request_set_uri(req, (uint8_t *)authority, + strlen(authority))) { failf(data, "error setting path"); result = CURLE_OUT_OF_MEMORY; goto error; } if(data->set.verbose) { - char *se = aprintf("CONNECT %s HTTP/1.1\r\n", hostheader); + char *se = aprintf("CONNECT %s HTTP/1.1\r\n", authority); if(!se) { result = CURLE_OUT_OF_MEMORY; goto error; @@ -796,10 +720,10 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf, } /* Setup the proxy-authorization header, if any */ result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET, - hostheader, TRUE); + authority, TRUE); if(result) goto error; - Curl_safefree(hostheader); + Curl_safefree(authority); /* default is 1.1 */ if((conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) && @@ -816,11 +740,11 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf, result = CURLE_OUT_OF_MEMORY; goto error; } - if(host) { - result = Curl_hyper_header(data, headers, host); + if(host_header) { + result = Curl_hyper_header(data, headers, host_header); if(result) goto error; - Curl_safefree(host); + Curl_safefree(host_header); } if(data->state.aptr.proxyuserpwd) { @@ -874,8 +798,8 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf, client = NULL; error: - free(host); - free(hostheader); + free(host_header); + free(authority); if(io) hyper_io_free(io); if(options) @@ -890,12 +814,13 @@ error: return result; } -static CURLcode send_CONNECT(struct Curl_easy *data, - struct connectdata *conn, +static CURLcode send_CONNECT(struct Curl_cfilter *cf, + struct Curl_easy *data, struct h1_tunnel_state *ts, bool *done) { struct hyptransfer *h = &data->hyp; + struct connectdata *conn = cf->conn; hyper_task *task = NULL; hyper_error *hypererr = NULL; CURLcode result = CURLE_OK; @@ -995,7 +920,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf, case H1_TUNNEL_CONNECT: /* see that the request is completely sent */ CURL_TRC_CF(data, cf, "CONNECT send"); - result = send_CONNECT(data, cf->conn, ts, &done); + result = send_CONNECT(cf, data, ts, &done); if(result || !done) goto out; h1_tunnel_go_state(cf, ts, H1_TUNNEL_RECEIVE, data); @@ -1090,7 +1015,7 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf, *done = FALSE; if(!ts) { - result = tunnel_init(&ts, data, cf->conn, cf->sockindex); + result = tunnel_init(cf, data, &ts); if(result) return result; cf->ctx = ts; diff --git a/lib/cf-h2-proxy.c b/lib/cf-h2-proxy.c index a3feefc..dbc895d 100644 --- a/lib/cf-h2-proxy.c +++ b/lib/cf-h2-proxy.c @@ -84,7 +84,8 @@ static CURLcode tunnel_stream_init(struct Curl_cfilter *cf, { const char *hostname; int port; - bool ipv6_ip = cf->conn->bits.ipv6_ip; + bool ipv6_ip; + CURLcode result; ts->state = H2_TUNNEL_INIT; ts->stream_id = -1; @@ -92,22 +93,9 @@ static CURLcode tunnel_stream_init(struct Curl_cfilter *cf, BUFQ_OPT_SOFT_LIMIT); Curl_bufq_init(&ts->sendbuf, PROXY_H2_CHUNK_SIZE, H2_TUNNEL_SEND_CHUNKS); - if(cf->conn->bits.conn_to_host) - hostname = cf->conn->conn_to_host.name; - else if(cf->sockindex == SECONDARYSOCKET) - hostname = cf->conn->secondaryhostname; - else - hostname = cf->conn->host.name; - - if(cf->sockindex == SECONDARYSOCKET) - port = cf->conn->secondary_port; - else if(cf->conn->bits.conn_to_port) - port = cf->conn->conn_to_port; - else - port = cf->conn->remote_port; - - if(hostname != cf->conn->host.name) - ipv6_ip = (strchr(hostname, ':') != NULL); + result = Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip); + if(result) + return result; ts->authority = /* host:port with IPv6 support */ aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", port); @@ -233,7 +221,7 @@ static void drain_tunnel(struct Curl_cfilter *cf, bits = CURL_CSELECT_IN; if(!tunnel->closed && !tunnel->reset && tunnel->upload_blocked_len) bits |= CURL_CSELECT_OUT; - if(data->state.dselect_bits != bits || 1) { + if(data->state.dselect_bits != bits) { CURL_TRC_CF(data, cf, "[%d] DRAIN dselect_bits=%x", tunnel->stream_id, bits); data->state.dselect_bits = bits; @@ -309,8 +297,9 @@ static int proxy_h2_on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, void *userp); #ifndef CURL_DISABLE_VERBOSE_STRINGS -static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame, - void *userp); +static int proxy_h2_on_frame_send(nghttp2_session *session, + const nghttp2_frame *frame, + void *userp); #endif static int proxy_h2_on_stream_close(nghttp2_session *session, int32_t stream_id, @@ -355,7 +344,8 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf, nghttp2_session_callbacks_set_on_frame_recv_callback( cbs, proxy_h2_on_frame_recv); #ifndef CURL_DISABLE_VERBOSE_STRINGS - nghttp2_session_callbacks_set_on_frame_send_callback(cbs, on_frame_send); + nghttp2_session_callbacks_set_on_frame_send_callback(cbs, + proxy_h2_on_frame_send); #endif nghttp2_session_callbacks_set_on_data_chunk_recv_callback( cbs, tunnel_recv_callback); @@ -575,7 +565,8 @@ static ssize_t on_session_send(nghttp2_session *h2, } #ifndef CURL_DISABLE_VERBOSE_STRINGS -static int fr_print(const nghttp2_frame *frame, char *buffer, size_t blen) +static int proxy_h2_fr_print(const nghttp2_frame *frame, + char *buffer, size_t blen) { switch(frame->hd.type) { case NGHTTP2_DATA: { @@ -646,8 +637,9 @@ static int fr_print(const nghttp2_frame *frame, char *buffer, size_t blen) } } -static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame, - void *userp) +static int proxy_h2_on_frame_send(nghttp2_session *session, + const nghttp2_frame *frame, + void *userp) { struct Curl_cfilter *cf = userp; struct Curl_easy *data = CF_DATA_CURRENT(cf); @@ -657,7 +649,7 @@ static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame, if(data && Curl_trc_cf_is_verbose(cf, data)) { char buffer[256]; int len; - len = fr_print(frame, buffer, sizeof(buffer)-1); + len = proxy_h2_fr_print(frame, buffer, sizeof(buffer)-1); buffer[len] = 0; CURL_TRC_CF(data, cf, "[%d] -> %s", frame->hd.stream_id, buffer); } @@ -680,7 +672,7 @@ static int proxy_h2_on_frame_recv(nghttp2_session *session, if(Curl_trc_cf_is_verbose(cf, data)) { char buffer[256]; int len; - len = fr_print(frame, buffer, sizeof(buffer)-1); + len = proxy_h2_fr_print(frame, buffer, sizeof(buffer)-1); buffer[len] = 0; CURL_TRC_CF(data, cf, "[%d] <- %s",frame->hd.stream_id, buffer); } @@ -980,38 +972,11 @@ static CURLcode submit_CONNECT(struct Curl_cfilter *cf, CURLcode result; struct httpreq *req = NULL; - infof(data, "Establish HTTP/2 proxy tunnel to %s", ts->authority); - - result = Curl_http_req_make(&req, "CONNECT", sizeof("CONNECT")-1, - NULL, 0, ts->authority, strlen(ts->authority), - NULL, 0); + result = Curl_http_proxy_create_CONNECT(&req, cf, data, 2); if(result) goto out; - /* Setup the proxy-authorization header, if any */ - result = Curl_http_output_auth(data, cf->conn, req->method, HTTPREQ_GET, - req->authority, TRUE); - if(result) - goto out; - - if(data->state.aptr.proxyuserpwd) { - result = Curl_dynhds_h1_cadd_line(&req->headers, - data->state.aptr.proxyuserpwd); - if(result) - goto out; - } - - if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("User-Agent")) - && data->set.str[STRING_USERAGENT]) { - result = Curl_dynhds_cadd(&req->headers, "User-Agent", - data->set.str[STRING_USERAGENT]); - if(result) - goto out; - } - - result = Curl_dynhds_add_custom(data, TRUE, &req->headers); - if(result) - goto out; + infof(data, "Establish HTTP/2 proxy tunnel to %s", req->authority); result = proxy_h2_submit(&ts->stream_id, cf, data, ctx->h2, req, NULL, ts, tunnel_send_callback, cf); @@ -1058,7 +1023,7 @@ static CURLcode inspect_response(struct Curl_cfilter *cf, if(result) return result; if(data->req.newurl) { - /* Inidicator that we should try again */ + /* Indicator that we should try again */ Curl_safefree(data->req.newurl); h2_tunnel_go_state(cf, ts, H2_TUNNEL_INIT, data); return CURLE_OK; @@ -1195,6 +1160,8 @@ static void cf_h2_proxy_close(struct Curl_cfilter *cf, struct Curl_easy *data) cf_h2_proxy_ctx_clear(ctx); CF_DATA_RESTORE(cf, save); } + if(cf->next) + cf->next->cft->do_close(cf->next, data); } static void cf_h2_proxy_destroy(struct Curl_cfilter *cf, diff --git a/lib/cf-socket.c b/lib/cf-socket.c index effe6e6..ce3f9e9 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -781,6 +781,8 @@ struct cf_socket_ctx { #ifdef DEBUGBUILD int wblock_percent; /* percent of writes doing EAGAIN */ int wpartial_percent; /* percent of bytes written in send */ + int rblock_percent; /* percent of reads doing EAGAIN */ + size_t recv_max; /* max enforced read size */ #endif BIT(got_first_byte); /* if first byte was received */ BIT(accepted); /* socket was accepted, not connected */ @@ -811,6 +813,18 @@ static void cf_socket_ctx_init(struct cf_socket_ctx *ctx, if(l >= 0 && l <= 100) ctx->wpartial_percent = (int)l; } + p = getenv("CURL_DBG_SOCK_RBLOCK"); + if(p) { + long l = strtol(p, NULL, 10); + if(l >= 0 && l <= 100) + ctx->rblock_percent = (int)l; + } + p = getenv("CURL_DBG_SOCK_RMAX"); + if(p) { + long l = strtol(p, NULL, 10); + if(l >= 0) + ctx->recv_max = (size_t)l; + } } #endif } @@ -1358,6 +1372,27 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, fdsave = cf->conn->sock[cf->sockindex]; cf->conn->sock[cf->sockindex] = ctx->sock; +#ifdef DEBUGBUILD + /* simulate network blocking/partial reads */ + if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) { + unsigned char c; + Curl_rand(data, &c, 1); + if(c >= ((100-ctx->rblock_percent)*256/100)) { + CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len); + *err = CURLE_AGAIN; + nread = -1; + cf->conn->sock[cf->sockindex] = fdsave; + return nread; + } + } + if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) { + size_t orig_len = len; + len = ctx->recv_max; + CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes", + orig_len, len); + } +#endif + if(ctx->buffer_recv && !Curl_bufq_is_empty(&ctx->recvbuf)) { CURL_TRC_CF(data, cf, "recv from buffer"); nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err); diff --git a/lib/conncache.c b/lib/conncache.c index a21409c..93d8768 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -107,6 +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; Curl_hash_init(&connc->hash, size, Curl_hash_str, Curl_str_key_compare, free_bundle_hash_entry); diff --git a/lib/connect.c b/lib/connect.c index 033fb7b..c7ba3e2 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -634,6 +634,7 @@ evaluate: /* next attempt was started */ CURL_TRC_CF(data, cf, "%s trying next", baller->name); ++ongoing; + Curl_expire(data, 0, EXPIRE_RUN_NOW); } } } @@ -646,7 +647,7 @@ evaluate: /* Nothing connected, check the time before we might * start new ballers or return ok. */ if((ongoing || not_started) && Curl_timeleft(data, &now, TRUE) < 0) { - failf(data, "Connection timeout after %ld ms", + failf(data, "Connection timeout after %" CURL_FORMAT_CURL_OFF_T " ms", Curl_timediff(now, data->progress.t_startsingle)); return CURLE_OPERATION_TIMEDOUT; } @@ -823,11 +824,10 @@ static CURLcode start_connect(struct Curl_cfilter *cf, CURL_TRC_CF(data, cf, "created %s (timeout %" CURL_FORMAT_TIMEDIFF_T "ms)", ctx->baller[1]->name, ctx->baller[1]->timeoutms); + Curl_expire(data, data->set.happy_eyeballs_timeout, + EXPIRE_HAPPY_EYEBALLS); } - Curl_expire(data, data->set.happy_eyeballs_timeout, - EXPIRE_HAPPY_EYEBALLS); - return CURLE_OK; } diff --git a/lib/content_encoding.c b/lib/content_encoding.c index efbe7cb..be7c075 100644 --- a/lib/content_encoding.c +++ b/lib/content_encoding.c @@ -280,9 +280,6 @@ static CURLcode deflate_init_writer(struct Curl_easy *data, struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ - if(!writer->downstream) - return CURLE_WRITE_ERROR; - /* Initialize zlib */ z->zalloc = (alloc_func) zalloc_cb; z->zfree = (free_func) zfree_cb; @@ -337,9 +334,6 @@ static CURLcode gzip_init_writer(struct Curl_easy *data, struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ - if(!writer->downstream) - return CURLE_WRITE_ERROR; - /* Initialize zlib */ z->zalloc = (alloc_func) zalloc_cb; z->zfree = (free_func) zfree_cb; @@ -647,9 +641,6 @@ static CURLcode brotli_init_writer(struct Curl_easy *data, struct brotli_writer *bp = (struct brotli_writer *) writer; (void) data; - if(!writer->downstream) - return CURLE_WRITE_ERROR; - bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL); return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY; } @@ -741,9 +732,6 @@ static CURLcode zstd_init_writer(struct Curl_easy *data, (void)data; - if(!writer->downstream) - return CURLE_WRITE_ERROR; - zp->zds = ZSTD_createDStream(); zp->decomp = NULL; return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY; @@ -822,8 +810,9 @@ static const struct content_encoding zstd_encoding = { static CURLcode identity_init_writer(struct Curl_easy *data, struct contenc_writer *writer) { - (void) data; - return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR; + (void)data; + (void)writer; + return CURLE_OK; } static CURLcode identity_unencode_write(struct Curl_easy *data, @@ -903,51 +892,13 @@ char *Curl_all_content_encodings(void) } -/* Real client writer: no downstream. */ -static CURLcode client_init_writer(struct Curl_easy *data, - struct contenc_writer *writer) -{ - (void) data; - return writer->downstream? CURLE_WRITE_ERROR: CURLE_OK; -} - -static CURLcode client_unencode_write(struct Curl_easy *data, - struct contenc_writer *writer, - const char *buf, size_t nbytes) -{ - struct SingleRequest *k = &data->req; - - (void) writer; - - if(!nbytes || k->ignorebody) - return CURLE_OK; - - return Curl_client_write(data, CLIENTWRITE_BODY, (char *) buf, nbytes); -} - -static void client_close_writer(struct Curl_easy *data, - struct contenc_writer *writer) -{ - (void) data; - (void) writer; -} - -static const struct content_encoding client_encoding = { - NULL, - NULL, - client_init_writer, - client_unencode_write, - client_close_writer, - sizeof(struct contenc_writer) -}; - - /* Deferred error dummy writer. */ static CURLcode error_init_writer(struct Curl_easy *data, struct contenc_writer *writer) { - (void) data; - return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR; + (void)data; + (void)writer; + return CURLE_OK; } static CURLcode error_unencode_write(struct Curl_easy *data, @@ -984,31 +935,6 @@ static const struct content_encoding error_encoding = { sizeof(struct contenc_writer) }; -/* Create an unencoding writer stage using the given handler. */ -static struct contenc_writer * -new_unencoding_writer(struct Curl_easy *data, - const struct content_encoding *handler, - struct contenc_writer *downstream, - int order) -{ - struct contenc_writer *writer; - - DEBUGASSERT(handler->writersize >= sizeof(struct contenc_writer)); - writer = (struct contenc_writer *) calloc(1, handler->writersize); - - if(writer) { - writer->handler = handler; - writer->downstream = downstream; - writer->order = order; - if(handler->init_writer(data, writer)) { - free(writer); - writer = NULL; - } - } - - return writer; -} - /* Write data using an unencoding writer stack. "nbytes" is not allowed to be 0. */ CURLcode Curl_unencode_write(struct Curl_easy *data, @@ -1017,23 +943,11 @@ CURLcode Curl_unencode_write(struct Curl_easy *data, { if(!nbytes) return CURLE_OK; + if(!writer) + return CURLE_WRITE_ERROR; return writer->handler->unencode_write(data, writer, buf, nbytes); } -/* Close and clean-up the connection's writer stack. */ -void Curl_unencode_cleanup(struct Curl_easy *data) -{ - struct SingleRequest *k = &data->req; - struct contenc_writer *writer = k->writer_stack; - - while(writer) { - k->writer_stack = writer->downstream; - writer->handler->close_writer(data, writer); - free(writer); - writer = k->writer_stack; - } -} - /* Find the content encoding by name. */ static const struct content_encoding *find_encoding(const char *name, size_t len) @@ -1049,9 +963,6 @@ static const struct content_encoding *find_encoding(const char *name, return NULL; } -/* allow no more than 5 "chained" compression steps */ -#define MAX_ENCODE_STACK 5 - /* Set-up the unencoding stack from the Content-Encoding header value. * See RFC 7231 section 3.1.2.2. */ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, @@ -1059,6 +970,7 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, { struct SingleRequest *k = &data->req; unsigned int order = is_transfer? 2: 1; + CURLcode result; do { const char *name; @@ -1085,41 +997,19 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, if(is_transfer && !data->set.http_transfer_encoding) /* not requested, ignore */ return CURLE_OK; - encoding = find_encoding(name, namelen); - - if(!k->writer_stack) { - k->writer_stack = new_unencoding_writer(data, &client_encoding, - NULL, 0); - - if(!k->writer_stack) - return CURLE_OUT_OF_MEMORY; - } + encoding = find_encoding(name, namelen); if(!encoding) encoding = &error_encoding; /* Defer error at stack use. */ - if(k->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(order >= k->writer_stack->order) { - writer = new_unencoding_writer(data, encoding, - k->writer_stack, order); - if(!writer) - return CURLE_OUT_OF_MEMORY; - k->writer_stack = writer; - } - else { - struct contenc_writer *w = k->writer_stack; - while(w->downstream && order < w->downstream->order) - w = w->downstream; - writer = new_unencoding_writer(data, encoding, - w->downstream, order); - if(!writer) - return CURLE_OUT_OF_MEMORY; - w->downstream = writer; + result = Curl_client_create_writer(&writer, data, encoding, order); + if(result) + return result; + + result = Curl_client_add_writer(data, writer); + if(result) { + Curl_client_free_writer(data, writer); + return result; } } } while(*enclist); @@ -1149,11 +1039,6 @@ CURLcode Curl_unencode_write(struct Curl_easy *data, return CURLE_NOT_BUILT_IN; } -void Curl_unencode_cleanup(struct Curl_easy *data) -{ - (void) data; -} - char *Curl_all_content_encodings(void) { return strdup(CONTENT_ENCODING_DEFAULT); /* Satisfy caller. */ diff --git a/lib/content_encoding.h b/lib/content_encoding.h index 56e7f97..ef7930c 100644 --- a/lib/content_encoding.h +++ b/lib/content_encoding.h @@ -25,26 +25,9 @@ ***************************************************************************/ #include "curl_setup.h" -struct contenc_writer { - const struct content_encoding *handler; /* Encoding handler. */ - struct contenc_writer *downstream; /* Downstream writer. */ - unsigned int order; /* Ordering within writer stack. */ -}; - -/* 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; -}; +struct contenc_writer; +char *Curl_all_content_encodings(void); CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, const char *enclist, int is_transfer); @@ -52,6 +35,5 @@ 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); -char *Curl_all_content_encodings(void); #endif /* HEADER_CURL_CONTENT_ENCODING_H */ diff --git a/lib/cookie.c b/lib/cookie.c index 4345a84..af01203 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -112,14 +112,11 @@ static void strstore(char **str, const char *newstr, size_t len); static void freecookie(struct Cookie *co) { - free(co->expirestr); free(co->domain); free(co->path); free(co->spath); free(co->name); free(co->value); - free(co->maxage); - free(co->version); free(co); } @@ -487,7 +484,7 @@ Curl_cookie_add(struct Curl_easy *data, struct CookieInfo *c, bool httpheader, /* TRUE if HTTP header-style line */ bool noexpire, /* if TRUE, skip remove_expired() */ - char *lineptr, /* first character of the line */ + const char *lineptr, /* first character of the line */ const char *domain, /* default domain */ const char *path, /* full path used when this cookie is set, used to get default path for the cookie @@ -718,11 +715,7 @@ Curl_cookie_add(struct Curl_easy *data, } } else if((nlen == 7) && strncasecompare("version", namep, 7)) { - strstore(&co->version, valuep, vlen); - if(!co->version) { - badcookie = TRUE; - break; - } + /* just ignore */ } else if((nlen == 7) && strncasecompare("max-age", namep, 7)) { /* @@ -734,17 +727,55 @@ Curl_cookie_add(struct Curl_easy *data, * client should discard the cookie. A value of zero means the * cookie should be discarded immediately. */ - strstore(&co->maxage, valuep, vlen); - if(!co->maxage) { - badcookie = TRUE; + CURLofft offt; + const char *maxage = valuep; + offt = curlx_strtoofft((*maxage == '\"')? + &maxage[1]:&maxage[0], NULL, 10, + &co->expires); + switch(offt) { + case CURL_OFFT_FLOW: + /* overflow, used max value */ + co->expires = CURL_OFF_T_MAX; + break; + case CURL_OFFT_INVAL: + /* negative or otherwise bad, expire */ + co->expires = 1; + break; + case CURL_OFFT_OK: + if(!co->expires) + /* already expired */ + co->expires = 1; + else if(CURL_OFF_T_MAX - now < co->expires) + /* would overflow */ + co->expires = CURL_OFF_T_MAX; + else + co->expires += now; break; } } else if((nlen == 7) && strncasecompare("expires", namep, 7)) { - strstore(&co->expirestr, valuep, vlen); - if(!co->expirestr) { - badcookie = TRUE; - break; + char date[128]; + if(!co->expires && (vlen < sizeof(date))) { + /* copy the date so that it can be null terminated */ + memcpy(date, valuep, vlen); + date[vlen] = 0; + /* + * Let max-age have priority. + * + * If the date cannot get parsed for whatever reason, the cookie + * will be treated as a session cookie + */ + co->expires = Curl_getdate_capped(date); + + /* + * Session cookies have expires set to 0 so if we get that back + * from the date parser let's add a second to make it a + * non-session cookie + */ + if(co->expires == 0) + co->expires = 1; + else if(co->expires < 0) + co->expires = 0; } } @@ -764,49 +795,6 @@ Curl_cookie_add(struct Curl_easy *data, break; } while(1); - if(co->maxage) { - CURLofft offt; - offt = curlx_strtoofft((*co->maxage == '\"')? - &co->maxage[1]:&co->maxage[0], NULL, 10, - &co->expires); - switch(offt) { - case CURL_OFFT_FLOW: - /* overflow, used max value */ - co->expires = CURL_OFF_T_MAX; - break; - case CURL_OFFT_INVAL: - /* negative or otherwise bad, expire */ - co->expires = 1; - break; - case CURL_OFFT_OK: - if(!co->expires) - /* already expired */ - co->expires = 1; - else if(CURL_OFF_T_MAX - now < co->expires) - /* would overflow */ - co->expires = CURL_OFF_T_MAX; - else - co->expires += now; - break; - } - } - else if(co->expirestr) { - /* - * Note that if the date couldn't get parsed for whatever reason, the - * cookie will be treated as a session cookie - */ - co->expires = Curl_getdate_capped(co->expirestr); - - /* - * Session cookies have expires set to 0 so if we get that back from the - * date parser let's add a second to make it a non-session cookie - */ - if(co->expires == 0) - co->expires = 1; - else if(co->expires < 0) - co->expires = 0; - } - if(!badcookie && !co->domain) { if(domain) { /* no domain was given in the header line, set the default */ @@ -894,7 +882,7 @@ Curl_cookie_add(struct Curl_easy *data, if(ptr) *ptr = 0; /* clear it */ - firstptr = strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */ + firstptr = strtok_r((char *)lineptr, "\t", &tok_buf); /* tokenize on TAB */ /* * Now loop through the fields and init the struct we already have @@ -1159,9 +1147,6 @@ Curl_cookie_add(struct Curl_easy *data, free(clist->domain); free(clist->path); free(clist->spath); - free(clist->expirestr); - free(clist->version); - free(clist->maxage); *clist = *co; /* then store all the new data */ @@ -1224,9 +1209,6 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, c = calloc(1, sizeof(struct CookieInfo)); if(!c) return NULL; /* failed to get memory */ - c->filename = strdup(file?file:"none"); /* copy the name just in case */ - if(!c->filename) - goto fail; /* failed to get memory */ /* * Initialize the next_expiration time to signal that we don't have enough * information yet. @@ -1255,24 +1237,20 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, c->running = FALSE; /* this is not running, this is init */ if(fp) { - char *lineptr; - bool headerline; line = malloc(MAX_COOKIE_LINE); if(!line) goto fail; while(Curl_get_line(line, MAX_COOKIE_LINE, fp)) { + char *lineptr = line; + bool headerline = FALSE; if(checkprefix("Set-Cookie:", line)) { /* This is a cookie line, get it! */ lineptr = &line[11]; headerline = TRUE; + while(*lineptr && ISBLANK(*lineptr)) + lineptr++; } - else { - lineptr = line; - headerline = FALSE; - } - while(*lineptr && ISBLANK(*lineptr)) - lineptr++; Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE); } @@ -1288,8 +1266,8 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, fclose(handle); } data->state.cookie_engine = TRUE; - c->running = TRUE; /* now, we're running */ } + c->running = TRUE; /* now, we're running */ return c; @@ -1371,14 +1349,11 @@ static struct Cookie *dup_cookie(struct Cookie *src) { struct Cookie *d = calloc(sizeof(struct Cookie), 1); if(d) { - CLONE(expirestr); CLONE(domain); CLONE(path); CLONE(spath); CLONE(name); CLONE(value); - CLONE(maxage); - CLONE(version); d->expires = src->expires; d->tailmatch = src->tailmatch; d->secure = src->secure; @@ -1595,7 +1570,6 @@ void Curl_cookie_cleanup(struct CookieInfo *c) { if(c) { unsigned int i; - free(c->filename); for(i = 0; i < COOKIE_HASH_SIZE; i++) Curl_cookie_freelist(c->cookies[i]); free(c); /* free the base struct as well */ diff --git a/lib/cookie.h b/lib/cookie.h index b3c0063..012dd89 100644 --- a/lib/cookie.h +++ b/lib/cookie.h @@ -35,12 +35,6 @@ struct Cookie { char *spath; /* sanitized cookie path */ char *domain; /* domain = <this> */ curl_off_t expires; /* expires = <this> */ - char *expirestr; /* the plain text version */ - - /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */ - char *version; /* Version = <value> */ - char *maxage; /* Max-Age = <value> */ - bool tailmatch; /* whether we do tail-matching of the domain name */ bool secure; /* whether the 'secure' keyword was used */ bool livecookie; /* updated from a server, not a stored file */ @@ -56,17 +50,16 @@ struct Cookie { #define COOKIE_PREFIX__SECURE (1<<0) #define COOKIE_PREFIX__HOST (1<<1) -#define COOKIE_HASH_SIZE 256 +#define COOKIE_HASH_SIZE 63 struct CookieInfo { /* linked list of cookies we know of */ struct Cookie *cookies[COOKIE_HASH_SIZE]; - char *filename; /* file we read from/write to */ - long numcookies; /* number of cookies in the "jar" */ + curl_off_t next_expiration; /* the next time at which expiration happens */ + int numcookies; /* number of cookies in the "jar" */ + int lastct; /* last creation-time used in the jar */ bool running; /* state info, for cookie adding information */ bool newsession; /* new session, discard session cookies on load */ - int lastct; /* last creation-time used in the jar */ - curl_off_t next_expiration; /* the next time at which expiration happens */ }; /* The maximum sizes we accept for cookies. RFC 6265 section 6.1 says @@ -75,7 +68,6 @@ struct CookieInfo { - At least 4096 bytes per cookie (as measured by the sum of the length of the cookie's name, value, and attributes). - In the 6265bis draft document section 5.4 it is phrased even stronger: "If the sum of the lengths of the name string and the value string is more than 4096 octets, abort these steps and ignore the set-cookie-string entirely." @@ -116,7 +108,7 @@ struct Curl_easy; struct Cookie *Curl_cookie_add(struct Curl_easy *data, struct CookieInfo *c, bool header, - bool noexpiry, char *lineptr, + bool noexpiry, const char *lineptr, const char *domain, const char *path, bool secure); diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 65901a2..0bfb457 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -159,18 +159,21 @@ /* Define to 1 if you have the alarm function. */ #cmakedefine HAVE_ALARM 1 +/* Define to 1 if you have the arc4random function. */ +#cmakedefine HAVE_ARC4RANDOM 1 + /* Define to 1 if you have the <arpa/inet.h> header file. */ #cmakedefine HAVE_ARPA_INET_H 1 -/* Define to 1 if you have the <arpa/tftp.h> header file. */ -#cmakedefine HAVE_ARPA_TFTP_H 1 - /* 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 + /* Define to 1 if you have the `basename' function. */ #cmakedefine HAVE_BASENAME 1 @@ -183,6 +186,10 @@ /* Define to 1 if you have the clock_gettime function and monotonic timer. */ #cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC 1 +/* Define to 1 if you have the clock_gettime function and raw monotonic timer. + */ +#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC_RAW 1 + /* Define to 1 if you have the `closesocket' function. */ #cmakedefine HAVE_CLOSESOCKET 1 @@ -198,6 +205,12 @@ /* Define to 1 if you have the freeaddrinfo function. */ #cmakedefine HAVE_FREEADDRINFO 1 +/* Define to 1 if you have the fseeko function. */ +#cmakedefine HAVE_FSEEKO 1 + +/* Define to 1 if you have the _fseeki64 function. */ +#cmakedefine HAVE__FSEEKI64 1 + /* Define to 1 if you have the ftruncate function. */ #cmakedefine HAVE_FTRUNCATE 1 @@ -234,9 +247,6 @@ /* Define to 1 if you have the `getpass_r' function. */ #cmakedefine HAVE_GETPASS_R 1 -/* Define to 1 if you have the `getppid' function. */ -#cmakedefine HAVE_GETPPID 1 - /* Define to 1 if you have the `getpeername' function. */ #cmakedefine HAVE_GETPEERNAME 1 @@ -373,6 +383,9 @@ /* Define to 1 if the compiler supports the 'long long' data type. */ #cmakedefine HAVE_LONGLONG 1 +/* Define to 1 if you have the 'suseconds_t' data type. */ +#cmakedefine HAVE_SUSECONDS_T 1 + /* Define to 1 if you have the MSG_NOSIGNAL flag. */ #cmakedefine HAVE_MSG_NOSIGNAL 1 @@ -385,6 +398,9 @@ /* Define to 1 if you have the <netinet/tcp.h> header file. */ #cmakedefine HAVE_NETINET_TCP_H 1 +/* Define to 1 if you have the <netinet/udp.h> header file. */ +#cmakedefine HAVE_NETINET_UDP_H 1 + /* Define to 1 if you have the <linux/tcp.h> header file. */ #cmakedefine HAVE_LINUX_TCP_H 1 @@ -421,9 +437,15 @@ /* Define to 1 if you have the select function. */ #cmakedefine HAVE_SELECT 1 +/* Define to 1 if you have the sched_yield function. */ +#cmakedefine HAVE_SCHED_YIELD 1 + /* Define to 1 if you have the send function. */ #cmakedefine HAVE_SEND 1 +/* Define to 1 if you have the sendmsg function. */ +#cmakedefine HAVE_SENDMSG 1 + /* Define to 1 if you have the 'fsetxattr' function. */ #cmakedefine HAVE_FSETXATTR 1 @@ -433,9 +455,6 @@ /* fsetxattr() takes 6 args */ #cmakedefine HAVE_FSETXATTR_6 1 -/* Define to 1 if you have the <setjmp.h> header file. */ -#cmakedefine HAVE_SETJMP_H 1 - /* Define to 1 if you have the `setlocale' function. */ #cmakedefine HAVE_SETLOCALE 1 @@ -457,14 +476,11 @@ /* Define to 1 if you have the signal function. */ #cmakedefine HAVE_SIGNAL 1 -/* Define to 1 if you have the <signal.h> header file. */ -#cmakedefine HAVE_SIGNAL_H 1 - /* Define to 1 if you have the sigsetjmp function or macro. */ #cmakedefine HAVE_SIGSETJMP 1 /* Define to 1 if you have the `snprintf' function. */ -#cmakedefine HAVE_SNPRINTF +#cmakedefine HAVE_SNPRINTF 1 /* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ #cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 @@ -484,9 +500,6 @@ /* Define to 1 if you have the <stdint.h> header file. */ #cmakedefine HAVE_STDINT_H 1 -/* Define to 1 if you have the <stdlib.h> header file. */ -#cmakedefine HAVE_STDLIB_H 1 - /* Define to 1 if you have the strcasecmp function. */ #cmakedefine HAVE_STRCASECMP 1 @@ -505,9 +518,6 @@ /* Define to 1 if you have the <strings.h> header file. */ #cmakedefine HAVE_STRINGS_H 1 -/* Define to 1 if you have the <string.h> header file. */ -#cmakedefine HAVE_STRING_H 1 - /* Define to 1 if you have the <stropts.h> header file. */ #cmakedefine HAVE_STROPTS_H 1 @@ -517,6 +527,9 @@ /* Define to 1 if you have the strtoll function. */ #cmakedefine HAVE_STRTOLL 1 +/* Define to 1 if you have the memrchr function. */ +#cmakedefine HAVE_MEMRCHR 1 + /* if struct sockaddr_storage is defined */ #cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1 @@ -526,6 +539,9 @@ /* Define to 1 if you have the <sys/filio.h> header file. */ #cmakedefine HAVE_SYS_FILIO_H 1 +/* Define to 1 if you have the <sys/wait.h> header file. */ +#cmakedefine HAVE_SYS_WAIT_H 1 + /* Define to 1 if you have the <sys/ioctl.h> header file. */ #cmakedefine HAVE_SYS_IOCTL_H 1 @@ -568,9 +584,6 @@ /* Define to 1 if you have the <termio.h> header file. */ #cmakedefine HAVE_TERMIO_H 1 -/* Define to 1 if you have the <time.h> header file. */ -#cmakedefine HAVE_TIME_H 1 - /* Define to 1 if you have the <unistd.h> header file. */ #cmakedefine HAVE_UNISTD_H 1 @@ -658,6 +671,9 @@ ${SIZEOF_OFF_T_CODE} /* The size of `curl_off_t', as computed by sizeof. */ ${SIZEOF_CURL_OFF_T_CODE} +/* The size of `curl_socket_t', as computed by sizeof. */ +${SIZEOF_CURL_SOCKET_T_CODE} + /* The size of `size_t', as computed by sizeof. */ ${SIZEOF_SIZE_T_CODE} @@ -667,9 +683,6 @@ ${SIZEOF_TIME_T_CODE} /* Define to 1 if you have the ANSI C header files. */ #cmakedefine STDC_HEADERS 1 -/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ -#cmakedefine TIME_WITH_SYS_TIME 1 - /* Define if you want to enable c-ares support */ #cmakedefine USE_ARES 1 @@ -735,7 +748,7 @@ ${SIZEOF_TIME_T_CODE} #cmakedefine USE_MSH3 1 /* if Unix domain sockets are enabled */ -#cmakedefine USE_UNIX_SOCKETS +#cmakedefine USE_UNIX_SOCKETS 1 /* Define to 1 if you are building a Windows target with large file support. */ #cmakedefine USE_WIN32_LARGE_FILES 1 @@ -792,3 +805,12 @@ ${SIZEOF_TIME_T_CODE} /* Define to 1 to enable websocket support. */ #cmakedefine USE_WEBSOCKETS 1 + +/* Define to 1 if OpenSSL has the SSL_CTX_set_srp_username function. */ +#cmakedefine HAVE_OPENSSL_SRP 1 + +/* Define to 1 if GnuTLS has the gnutls_srp_verifier function. */ +#cmakedefine HAVE_GNUTLS_SRP 1 + +/* Define to 1 to enable TLS-SRP support. */ +#cmakedefine USE_TLS_SRP 1 diff --git a/lib/curl_ctype.h b/lib/curl_ctype.h index 1d1d60c..7f0d0cc 100644 --- a/lib/curl_ctype.h +++ b/lib/curl_ctype.h @@ -43,5 +43,9 @@ #define ISDIGIT(x) (((x) >= '0') && ((x) <= '9')) #define ISBLANK(x) (((x) == ' ') || ((x) == '\t')) #define ISSPACE(x) (ISBLANK(x) || (((x) >= 0xa) && ((x) <= 0x0d))) +#define ISURLPUNTCS(x) (((x) == '-') || ((x) == '.') || ((x) == '_') || \ + ((x) == '~')) +#define ISUNRESERVED(x) (ISALNUM(x) || ISURLPUNTCS(x)) + #endif /* HEADER_CURL_CTYPE_H */ diff --git a/lib/curl_hmac.h b/lib/curl_hmac.h index 9438ca7..2ea03dd 100644 --- a/lib/curl_hmac.h +++ b/lib/curl_hmac.h @@ -24,8 +24,8 @@ * ***************************************************************************/ -#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \ - || !defined(CURL_DISABLE_AWS) +#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \ + || !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) #include <curl/curl.h> diff --git a/lib/curl_memrchr.h b/lib/curl_memrchr.h index a1a4ba0..45bb38c 100644 --- a/lib/curl_memrchr.h +++ b/lib/curl_memrchr.h @@ -28,9 +28,7 @@ #ifdef HAVE_MEMRCHR -#ifdef HAVE_STRING_H -# include <string.h> -#endif +#include <string.h> #ifdef HAVE_STRINGS_H # include <strings.h> #endif diff --git a/lib/curl_ntlm_wb.c b/lib/curl_ntlm_wb.c index a10e2a1..aa7bea7 100644 --- a/lib/curl_ntlm_wb.c +++ b/lib/curl_ntlm_wb.c @@ -39,9 +39,7 @@ #ifdef HAVE_SYS_WAIT_H #include <sys/wait.h> #endif -#ifdef HAVE_SIGNAL_H #include <signal.h> -#endif #ifdef HAVE_PWD_H #include <pwd.h> #endif diff --git a/lib/curl_setup.h b/lib/curl_setup.h index b43714d..ba14972 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -28,11 +28,6 @@ #define CURL_NO_OLDIES #endif -/* define mingw version macros, eg __MINGW{32,64}_{MINOR,MAJOR}_VERSION */ -#ifdef __MINGW32__ -#include <_mingw.h> -#endif - /* * Disable Visual Studio warnings: * 4127 "conditional expression is constant" @@ -830,9 +825,6 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, #endif #if defined(USE_UNIX_SOCKETS) && defined(WIN32) -# if defined(__MINGW32__) && !defined(LUP_SECURE) - typedef u_short ADDRESS_FAMILY; /* Classic mingw, 11y+ old mingw-w64 */ -# endif # if !defined(UNIX_PATH_MAX) /* Replicating logic present in afunix.h (distributed with newer Windows 10 SDK versions only) */ diff --git a/lib/curl_sspi.h b/lib/curl_sspi.h index 9816d59..5af7c24 100644 --- a/lib/curl_sspi.h +++ b/lib/curl_sspi.h @@ -70,227 +70,6 @@ extern PSecurityFunctionTable s_pSecFn; #define ISC_REQ_USE_HTTP_STYLE 0x01000000 #endif -#ifndef ISC_RET_REPLAY_DETECT -#define ISC_RET_REPLAY_DETECT 0x00000004 -#endif - -#ifndef ISC_RET_SEQUENCE_DETECT -#define ISC_RET_SEQUENCE_DETECT 0x00000008 -#endif - -#ifndef ISC_RET_CONFIDENTIALITY -#define ISC_RET_CONFIDENTIALITY 0x00000010 -#endif - -#ifndef ISC_RET_ALLOCATED_MEMORY -#define ISC_RET_ALLOCATED_MEMORY 0x00000100 -#endif - -#ifndef ISC_RET_STREAM -#define ISC_RET_STREAM 0x00008000 -#endif - -#ifndef SEC_E_INSUFFICIENT_MEMORY -# define SEC_E_INSUFFICIENT_MEMORY ((HRESULT)0x80090300L) -#endif -#ifndef SEC_E_INVALID_HANDLE -# define SEC_E_INVALID_HANDLE ((HRESULT)0x80090301L) -#endif -#ifndef SEC_E_UNSUPPORTED_FUNCTION -# define SEC_E_UNSUPPORTED_FUNCTION ((HRESULT)0x80090302L) -#endif -#ifndef SEC_E_TARGET_UNKNOWN -# define SEC_E_TARGET_UNKNOWN ((HRESULT)0x80090303L) -#endif -#ifndef SEC_E_INTERNAL_ERROR -# define SEC_E_INTERNAL_ERROR ((HRESULT)0x80090304L) -#endif -#ifndef SEC_E_SECPKG_NOT_FOUND -# define SEC_E_SECPKG_NOT_FOUND ((HRESULT)0x80090305L) -#endif -#ifndef SEC_E_NOT_OWNER -# define SEC_E_NOT_OWNER ((HRESULT)0x80090306L) -#endif -#ifndef SEC_E_CANNOT_INSTALL -# define SEC_E_CANNOT_INSTALL ((HRESULT)0x80090307L) -#endif -#ifndef SEC_E_INVALID_TOKEN -# define SEC_E_INVALID_TOKEN ((HRESULT)0x80090308L) -#endif -#ifndef SEC_E_CANNOT_PACK -# define SEC_E_CANNOT_PACK ((HRESULT)0x80090309L) -#endif -#ifndef SEC_E_QOP_NOT_SUPPORTED -# define SEC_E_QOP_NOT_SUPPORTED ((HRESULT)0x8009030AL) -#endif -#ifndef SEC_E_NO_IMPERSONATION -# define SEC_E_NO_IMPERSONATION ((HRESULT)0x8009030BL) -#endif -#ifndef SEC_E_LOGON_DENIED -# define SEC_E_LOGON_DENIED ((HRESULT)0x8009030CL) -#endif -#ifndef SEC_E_UNKNOWN_CREDENTIALS -# define SEC_E_UNKNOWN_CREDENTIALS ((HRESULT)0x8009030DL) -#endif -#ifndef SEC_E_NO_CREDENTIALS -# define SEC_E_NO_CREDENTIALS ((HRESULT)0x8009030EL) -#endif -#ifndef SEC_E_MESSAGE_ALTERED -# define SEC_E_MESSAGE_ALTERED ((HRESULT)0x8009030FL) -#endif -#ifndef SEC_E_OUT_OF_SEQUENCE -# define SEC_E_OUT_OF_SEQUENCE ((HRESULT)0x80090310L) -#endif -#ifndef SEC_E_NO_AUTHENTICATING_AUTHORITY -# define SEC_E_NO_AUTHENTICATING_AUTHORITY ((HRESULT)0x80090311L) -#endif -#ifndef SEC_E_BAD_PKGID -# define SEC_E_BAD_PKGID ((HRESULT)0x80090316L) -#endif -#ifndef SEC_E_CONTEXT_EXPIRED -# define SEC_E_CONTEXT_EXPIRED ((HRESULT)0x80090317L) -#endif -#ifndef SEC_E_INCOMPLETE_MESSAGE -# define SEC_E_INCOMPLETE_MESSAGE ((HRESULT)0x80090318L) -#endif -#ifndef SEC_E_INCOMPLETE_CREDENTIALS -# define SEC_E_INCOMPLETE_CREDENTIALS ((HRESULT)0x80090320L) -#endif -#ifndef SEC_E_BUFFER_TOO_SMALL -# define SEC_E_BUFFER_TOO_SMALL ((HRESULT)0x80090321L) -#endif -#ifndef SEC_E_WRONG_PRINCIPAL -# define SEC_E_WRONG_PRINCIPAL ((HRESULT)0x80090322L) -#endif -#ifndef SEC_E_TIME_SKEW -# define SEC_E_TIME_SKEW ((HRESULT)0x80090324L) -#endif -#ifndef SEC_E_UNTRUSTED_ROOT -# define SEC_E_UNTRUSTED_ROOT ((HRESULT)0x80090325L) -#endif -#ifndef SEC_E_ILLEGAL_MESSAGE -# define SEC_E_ILLEGAL_MESSAGE ((HRESULT)0x80090326L) -#endif -#ifndef SEC_E_CERT_UNKNOWN -# define SEC_E_CERT_UNKNOWN ((HRESULT)0x80090327L) -#endif -#ifndef SEC_E_CERT_EXPIRED -# define SEC_E_CERT_EXPIRED ((HRESULT)0x80090328L) -#endif -#ifndef SEC_E_ENCRYPT_FAILURE -# define SEC_E_ENCRYPT_FAILURE ((HRESULT)0x80090329L) -#endif -#ifndef SEC_E_DECRYPT_FAILURE -# define SEC_E_DECRYPT_FAILURE ((HRESULT)0x80090330L) -#endif -#ifndef SEC_E_ALGORITHM_MISMATCH -# define SEC_E_ALGORITHM_MISMATCH ((HRESULT)0x80090331L) -#endif -#ifndef SEC_E_SECURITY_QOS_FAILED -# define SEC_E_SECURITY_QOS_FAILED ((HRESULT)0x80090332L) -#endif -#ifndef SEC_E_UNFINISHED_CONTEXT_DELETED -# define SEC_E_UNFINISHED_CONTEXT_DELETED ((HRESULT)0x80090333L) -#endif -#ifndef SEC_E_NO_TGT_REPLY -# define SEC_E_NO_TGT_REPLY ((HRESULT)0x80090334L) -#endif -#ifndef SEC_E_NO_IP_ADDRESSES -# define SEC_E_NO_IP_ADDRESSES ((HRESULT)0x80090335L) -#endif -#ifndef SEC_E_WRONG_CREDENTIAL_HANDLE -# define SEC_E_WRONG_CREDENTIAL_HANDLE ((HRESULT)0x80090336L) -#endif -#ifndef SEC_E_CRYPTO_SYSTEM_INVALID -# define SEC_E_CRYPTO_SYSTEM_INVALID ((HRESULT)0x80090337L) -#endif -#ifndef SEC_E_MAX_REFERRALS_EXCEEDED -# define SEC_E_MAX_REFERRALS_EXCEEDED ((HRESULT)0x80090338L) -#endif -#ifndef SEC_E_MUST_BE_KDC -# define SEC_E_MUST_BE_KDC ((HRESULT)0x80090339L) -#endif -#ifndef SEC_E_STRONG_CRYPTO_NOT_SUPPORTED -# define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED ((HRESULT)0x8009033AL) -#endif -#ifndef SEC_E_TOO_MANY_PRINCIPALS -# define SEC_E_TOO_MANY_PRINCIPALS ((HRESULT)0x8009033BL) -#endif -#ifndef SEC_E_NO_PA_DATA -# define SEC_E_NO_PA_DATA ((HRESULT)0x8009033CL) -#endif -#ifndef SEC_E_PKINIT_NAME_MISMATCH -# define SEC_E_PKINIT_NAME_MISMATCH ((HRESULT)0x8009033DL) -#endif -#ifndef SEC_E_SMARTCARD_LOGON_REQUIRED -# define SEC_E_SMARTCARD_LOGON_REQUIRED ((HRESULT)0x8009033EL) -#endif -#ifndef SEC_E_SHUTDOWN_IN_PROGRESS -# define SEC_E_SHUTDOWN_IN_PROGRESS ((HRESULT)0x8009033FL) -#endif -#ifndef SEC_E_KDC_INVALID_REQUEST -# define SEC_E_KDC_INVALID_REQUEST ((HRESULT)0x80090340L) -#endif -#ifndef SEC_E_KDC_UNABLE_TO_REFER -# define SEC_E_KDC_UNABLE_TO_REFER ((HRESULT)0x80090341L) -#endif -#ifndef SEC_E_KDC_UNKNOWN_ETYPE -# define SEC_E_KDC_UNKNOWN_ETYPE ((HRESULT)0x80090342L) -#endif -#ifndef SEC_E_UNSUPPORTED_PREAUTH -# define SEC_E_UNSUPPORTED_PREAUTH ((HRESULT)0x80090343L) -#endif -#ifndef SEC_E_DELEGATION_REQUIRED -# define SEC_E_DELEGATION_REQUIRED ((HRESULT)0x80090345L) -#endif -#ifndef SEC_E_BAD_BINDINGS -# define SEC_E_BAD_BINDINGS ((HRESULT)0x80090346L) -#endif -#ifndef SEC_E_MULTIPLE_ACCOUNTS -# define SEC_E_MULTIPLE_ACCOUNTS ((HRESULT)0x80090347L) -#endif -#ifndef SEC_E_NO_KERB_KEY -# define SEC_E_NO_KERB_KEY ((HRESULT)0x80090348L) -#endif -#ifndef SEC_E_CERT_WRONG_USAGE -# define SEC_E_CERT_WRONG_USAGE ((HRESULT)0x80090349L) -#endif -#ifndef SEC_E_DOWNGRADE_DETECTED -# define SEC_E_DOWNGRADE_DETECTED ((HRESULT)0x80090350L) -#endif -#ifndef SEC_E_SMARTCARD_CERT_REVOKED -# define SEC_E_SMARTCARD_CERT_REVOKED ((HRESULT)0x80090351L) -#endif -#ifndef SEC_E_ISSUING_CA_UNTRUSTED -# define SEC_E_ISSUING_CA_UNTRUSTED ((HRESULT)0x80090352L) -#endif -#ifndef SEC_E_REVOCATION_OFFLINE_C -# define SEC_E_REVOCATION_OFFLINE_C ((HRESULT)0x80090353L) -#endif -#ifndef SEC_E_PKINIT_CLIENT_FAILURE -# define SEC_E_PKINIT_CLIENT_FAILURE ((HRESULT)0x80090354L) -#endif -#ifndef SEC_E_SMARTCARD_CERT_EXPIRED -# define SEC_E_SMARTCARD_CERT_EXPIRED ((HRESULT)0x80090355L) -#endif -#ifndef SEC_E_NO_S4U_PROT_SUPPORT -# define SEC_E_NO_S4U_PROT_SUPPORT ((HRESULT)0x80090356L) -#endif -#ifndef SEC_E_CROSSREALM_DELEGATION_FAILURE -# define SEC_E_CROSSREALM_DELEGATION_FAILURE ((HRESULT)0x80090357L) -#endif -#ifndef SEC_E_REVOCATION_OFFLINE_KDC -# define SEC_E_REVOCATION_OFFLINE_KDC ((HRESULT)0x80090358L) -#endif -#ifndef SEC_E_ISSUING_CA_UNTRUSTED_KDC -# define SEC_E_ISSUING_CA_UNTRUSTED_KDC ((HRESULT)0x80090359L) -#endif -#ifndef SEC_E_KDC_CERT_EXPIRED -# define SEC_E_KDC_CERT_EXPIRED ((HRESULT)0x8009035AL) -#endif -#ifndef SEC_E_KDC_CERT_REVOKED -# define SEC_E_KDC_CERT_REVOKED ((HRESULT)0x8009035BL) -#endif #ifndef SEC_E_INVALID_PARAMETER # define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL) #endif @@ -301,30 +80,6 @@ extern PSecurityFunctionTable s_pSecFn; # define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL) #endif -#ifndef SEC_I_CONTINUE_NEEDED -# define SEC_I_CONTINUE_NEEDED ((HRESULT)0x00090312L) -#endif -#ifndef SEC_I_COMPLETE_NEEDED -# define SEC_I_COMPLETE_NEEDED ((HRESULT)0x00090313L) -#endif -#ifndef SEC_I_COMPLETE_AND_CONTINUE -# define SEC_I_COMPLETE_AND_CONTINUE ((HRESULT)0x00090314L) -#endif -#ifndef SEC_I_LOCAL_LOGON -# define SEC_I_LOCAL_LOGON ((HRESULT)0x00090315L) -#endif -#ifndef SEC_I_CONTEXT_EXPIRED -# define SEC_I_CONTEXT_EXPIRED ((HRESULT)0x00090317L) -#endif -#ifndef SEC_I_INCOMPLETE_CREDENTIALS -# define SEC_I_INCOMPLETE_CREDENTIALS ((HRESULT)0x00090320L) -#endif -#ifndef SEC_I_RENEGOTIATE -# define SEC_I_RENEGOTIATE ((HRESULT)0x00090321L) -#endif -#ifndef SEC_I_NO_LSA_CONTEXT -# define SEC_I_NO_LSA_CONTEXT ((HRESULT)0x00090323L) -#endif #ifndef SEC_I_SIGNATURE_NEEDED # define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL) #endif diff --git a/lib/curl_threads.c b/lib/curl_threads.c index e13e294..222d936 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -106,8 +106,6 @@ curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *), { #ifdef _WIN32_WCE typedef HANDLE curl_win_thread_handle_t; -#elif defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) - typedef unsigned long curl_win_thread_handle_t; #else typedef uintptr_t curl_win_thread_handle_t; #endif diff --git a/lib/curl_threads.h b/lib/curl_threads.h index facbc73..27a478d 100644 --- a/lib/curl_threads.h +++ b/lib/curl_threads.h @@ -40,8 +40,7 @@ # define curl_thread_t HANDLE # define curl_thread_t_null (HANDLE)0 # if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ - (_WIN32_WINNT < _WIN32_WINNT_VISTA) || \ - (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) + (_WIN32_WINNT < _WIN32_WINNT_VISTA) # define Curl_mutex_init(m) InitializeCriticalSection(m) # else # define Curl_mutex_init(m) InitializeCriticalSectionEx(m, 0, 1) diff --git a/lib/curl_trc.c b/lib/curl_trc.c index 76c35ba..e53b305 100644 --- a/lib/curl_trc.c +++ b/lib/curl_trc.c @@ -61,6 +61,10 @@ 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); @@ -242,6 +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; ERROR_CHECK_SETOPT(CURLOPT_URL, url); ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https"); ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb); @@ -307,6 +308,10 @@ static CURLcode dohprobe(struct Curl_easy *data, ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx); if(data->set.ssl.fsslctxp) ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp); + if(data->set.fdebug) + ERROR_CHECK_SETOPT(CURLOPT_DEBUGFUNCTION, data->set.fdebug); + if(data->set.debugdata) + ERROR_CHECK_SETOPT(CURLOPT_DEBUGDATA, data->set.debugdata); if(data->set.str[STRING_SSL_EC_CURVES]) { ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES, data->set.str[STRING_SSL_EC_CURVES]); diff --git a/lib/dynbuf.h b/lib/dynbuf.h index 6291eab..31a9130 100644 --- a/lib/dynbuf.h +++ b/lib/dynbuf.h @@ -89,4 +89,5 @@ int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save); #define DYN_H1_TRAILER 4096 #define DYN_PINGPPONG_CMD (64*1024) #define DYN_IMAP_CMD (64*1024) +#define DYN_MQTT_RECV (64*1024) #endif diff --git a/lib/dynhds.c b/lib/dynhds.c index 007dfc5..979b3e8 100644 --- a/lib/dynhds.c +++ b/lib/dynhds.c @@ -344,6 +344,8 @@ size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name) return Curl_dynhds_remove(dynhds, name, strlen(name)); } +#endif + CURLcode Curl_dynhds_h1_dprint(struct dynhds *dynhds, struct dynbuf *dbuf) { CURLcode result = CURLE_OK; @@ -363,4 +365,3 @@ CURLcode Curl_dynhds_h1_dprint(struct dynhds *dynhds, struct dynbuf *dbuf) return result; } -#endif @@ -303,9 +303,6 @@ void curl_global_cleanup(void) Curl_ssh_cleanup(); -#ifdef USE_WOLFSSH - (void)wolfSSH_Cleanup(); -#endif #ifdef DEBUGBUILD free(leakpointer); #endif @@ -925,9 +922,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) if(data->cookies) { /* If cookies are enabled in the parent handle, we enable them in the clone as well! */ - outcurl->cookies = Curl_cookie_init(data, - data->cookies->filename, - outcurl->cookies, + outcurl->cookies = Curl_cookie_init(data, NULL, outcurl->cookies, data->set.cookiesession); if(!outcurl->cookies) goto fail; @@ -1088,11 +1083,14 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) CURLcode result = CURLE_OK; int oldstate; int newstate; + bool recursive = FALSE; if(!GOOD_EASY_HANDLE(data) || !data->conn) /* crazy input, don't continue */ return CURLE_BAD_FUNCTION_ARGUMENT; + if(Curl_is_in_callback(data)) + recursive = TRUE; k = &data->req; oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE); @@ -1120,34 +1118,9 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) if(!(newstate & KEEP_RECV_PAUSE)) { Curl_conn_ev_data_pause(data, FALSE); - - if(data->state.tempcount) { - /* there are buffers for sending that can be delivered as the receive - pausing is lifted! */ - unsigned int i; - unsigned int count = data->state.tempcount; - struct tempbuf writebuf[3]; /* there can only be three */ - - /* copy the structs to allow for immediate re-pausing */ - for(i = 0; i < data->state.tempcount; i++) { - writebuf[i] = data->state.tempwrite[i]; - Curl_dyn_init(&data->state.tempwrite[i].b, DYN_PAUSE_BUFFER); - } - data->state.tempcount = 0; - - for(i = 0; i < count; i++) { - /* even if one function returns error, this loops through and frees - all buffers */ - if(!result) - result = Curl_client_write(data, writebuf[i].type, - Curl_dyn_ptr(&writebuf[i].b), - Curl_dyn_len(&writebuf[i].b)); - Curl_dyn_free(&writebuf[i].b); - } - - if(result) - return result; - } + result = Curl_client_unpause(data); + if(result) + return result; } #ifdef USE_HYPER @@ -1184,6 +1157,11 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) corresponding socket callback, if used */ result = Curl_updatesocket(data); + if(recursive) + /* this might have called a callback recursively which might have set this + to false again on exit */ + Curl_set_in_callback(data, TRUE); + return result; } diff --git a/lib/easy_lock.h b/lib/easy_lock.h index 6399a39..d3fffd0 100644 --- a/lib/easy_lock.h +++ b/lib/easy_lock.h @@ -31,13 +31,6 @@ #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 #ifdef __MINGW32__ -#ifndef __MINGW64_VERSION_MAJOR -#if (__MINGW32_MAJOR_VERSION < 5) || \ - (__MINGW32_MAJOR_VERSION == 5 && __MINGW32_MINOR_VERSION == 0) -/* mingw >= 5.0.1 defines SRWLOCK, and slightly different from MS define */ -typedef PVOID SRWLOCK, *PSRWLOCK; -#endif -#endif #ifndef SRWLOCK_INIT #define SRWLOCK_INIT NULL #endif diff --git a/lib/escape.c b/lib/escape.c index 56aa2b3..5af00c3 100644 --- a/lib/escape.c +++ b/lib/escape.c @@ -38,33 +38,6 @@ #include "curl_memory.h" #include "memdebug.h" -/* Portable character check (remember EBCDIC). Do not use isalnum() because - its behavior is altered by the current locale. - See https://datatracker.ietf.org/doc/html/rfc3986#section-2.3 -*/ -bool Curl_isunreserved(unsigned char in) -{ - switch(in) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'o': - case 'p': case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'L': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': - case '-': case '.': case '_': case '~': - return TRUE; - default: - break; - } - return FALSE; -} - /* for ABI-compatibility with previous versions */ char *curl_escape(const char *string, int inlength) { @@ -99,7 +72,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string, while(length--) { unsigned char in = *string++; /* treat the characters unsigned */ - if(Curl_isunreserved(in)) { + if(ISUNRESERVED(in)) { /* append this */ if(Curl_dyn_addn(&d, &in, 1)) return NULL; @@ -233,3 +206,29 @@ void curl_free(void *p) { free(p); } + +/* + * Curl_hexencode() + * + * Converts binary input to lowercase hex-encoded ASCII output. + * Null-terminated. + */ +void Curl_hexencode(const unsigned char *src, size_t len, /* input length */ + unsigned char *out, size_t olen) /* output buffer size */ +{ + const char *hex = "0123456789abcdef"; + DEBUGASSERT(src && len && (olen >= 3)); + if(src && len && (olen >= 3)) { + while(len-- && (olen >= 3)) { + /* clang-tidy warns on this line without this comment: */ + /* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */ + *out++ = hex[(*src & 0xF0)>>4]; + *out++ = hex[*src & 0x0F]; + ++src; + olen -= 2; + } + *out = 0; + } + else if(olen) + *out = 0; +} diff --git a/lib/escape.h b/lib/escape.h index cdbb712..690e417 100644 --- a/lib/escape.h +++ b/lib/escape.h @@ -26,7 +26,7 @@ /* Escape and unescape URL encoding in strings. The functions return a new * allocated string or NULL if an error occurred. */ -bool Curl_isunreserved(unsigned char in); +#include "curl_ctype.h" enum urlreject { REJECT_NADA = 2, @@ -38,4 +38,7 @@ CURLcode Curl_urldecode(const char *string, size_t length, char **ostring, size_t *olen, enum urlreject ctrl); +void Curl_hexencode(const unsigned char *src, size_t len, /* input length */ + unsigned char *out, size_t olen); /* output buffer size */ + #endif /* HEADER_CURL_ESCAPE_H */ @@ -571,7 +571,9 @@ static CURLcode file_do(struct Curl_easy *data, bool *done) if(result) return result; - Curl_pgrsSetDownloadCounter(data, bytecount); + result = Curl_pgrsSetDownloadCounter(data, bytecount); + if(result) + return result; if(Curl_pgrsUpdate(data)) result = CURLE_ABORTED_BY_CALLBACK; diff --git a/lib/fopen.c b/lib/fopen.c index b6e3cad..75b8a7a 100644 --- a/lib/fopen.c +++ b/lib/fopen.c @@ -64,7 +64,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, fclose(*fh); *fh = NULL; - result = Curl_rand_hex(data, randsuffix, sizeof(randsuffix)); + result = Curl_rand_alnum(data, randsuffix, sizeof(randsuffix)); if(result) goto fail; diff --git a/lib/formdata.c b/lib/formdata.c index 8984b63..e40c4bc 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -789,6 +789,20 @@ static CURLcode setname(curl_mimepart *part, const char *name, size_t len) return res; } +/* 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) + return fseeko(stream, (off_t)offset, whence); +#elif defined(HAVE__FSEEKI64) + return _fseeki64(stream, (__int64)offset, whence); +#else + if(offset > LONG_MAX) + return -1; + return fseek(stream, (long)offset, whence); +#endif +} + /* * Curl_getformdata() converts a linked list of "meta data" into a mime * structure. The input list is in 'post', while the output is stored in @@ -874,8 +888,7 @@ CURLcode Curl_getformdata(struct Curl_easy *data, compatibility: use of "-" pseudo file name should be avoided. */ result = curl_mime_data_cb(part, (curl_off_t) -1, (curl_read_callback) fread, - CURLX_FUNCTION_CAST(curl_seek_callback, - fseek), + fseeko_wrapper, NULL, (void *) stdin); } else @@ -2067,6 +2067,31 @@ static bool ftp_213_date(const char *p, int *year, int *month, int *day, return TRUE; } +static CURLcode client_write_header(struct Curl_easy *data, + char *buf, size_t blen) +{ + /* Some replies from an FTP server are written to the client + * as CLIENTWRITE_HEADER, formatted as if they came from a + * HTTP conversation. + * In all protocols, CLIENTWRITE_HEADER data is only passed to + * the body write callback when data->set.include_header is set + * via CURLOPT_HEADER. + * For historic reasons, FTP never played this game and expects + * all its HEADERs to do that always. Set that flag during the + * call to Curl_client_write() so it does the right thing. + * + * Notice that we cannot enable this flag for FTP in general, + * as an FTP transfer might involve a HTTP proxy connection and + * headers from CONNECT should not automatically be part of the + * output. */ + CURLcode result; + int save = data->set.include_header; + data->set.include_header = TRUE; + result = Curl_client_write(data, CLIENTWRITE_HEADER, buf, blen); + data->set.include_header = save? TRUE:FALSE; + return result; +} + static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, int ftpcode) { @@ -2120,8 +2145,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, tm->tm_hour, tm->tm_min, tm->tm_sec); - result = Curl_client_write(data, CLIENTWRITE_BOTH, headerbuf, - headerbuflen); + result = client_write_header(data, headerbuf, headerbuflen); if(result) return result; } /* end of a ridiculous amount of conditionals */ @@ -2331,7 +2355,7 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data, char clbuf[128]; int clbuflen = msnprintf(clbuf, sizeof(clbuf), "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize); - result = Curl_client_write(data, CLIENTWRITE_BOTH, clbuf, clbuflen); + result = client_write_header(data, clbuf, clbuflen); if(result) return result; } @@ -2365,8 +2389,7 @@ static CURLcode ftp_state_rest_resp(struct Curl_easy *data, #ifdef CURL_FTP_HTTPSTYLE_HEAD if(ftpcode == 350) { char buffer[24]= { "Accept-ranges: bytes\r\n" }; - result = Curl_client_write(data, CLIENTWRITE_BOTH, buffer, - strlen(buffer)); + result = client_write_header(data, buffer, strlen(buffer)); if(result) return result; } @@ -3457,7 +3480,7 @@ CURLcode ftp_sendquote(struct Curl_easy *data, /* if a command starts with an asterisk, which a legal FTP command never can, the command will be allowed to fail without it causing any aborts or cancels etc. It will cause libcurl to act as if the command - is successful, whatever the server reponds. */ + is successful, whatever the server responds. */ if(cmd[0] == '*') { cmd++; diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c index 226d9bc..2a7ca5b 100644 --- a/lib/ftplistparser.c +++ b/lib/ftplistparser.c @@ -379,7 +379,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, /* scenario: * 1. call => OK.. * 2. call => OUT_OF_MEMORY (or other error) - * 3. (last) call => is skipped RIGHT HERE and the error is hadled later + * 3. (last) call => is skipped RIGHT HERE and the error is handled later * in wc_statemach() */ goto fail; @@ -26,8 +26,8 @@ #include "curl_setup.h" -#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \ - || !defined(CURL_DISABLE_AWS) +#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \ + || !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) #include <curl/curl.h> diff --git a/lib/hostip.c b/lib/hostip.c index acb4b51..3cd9a65 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -41,12 +41,8 @@ #include <inet.h> #endif -#ifdef HAVE_SETJMP_H #include <setjmp.h> -#endif -#ifdef HAVE_SIGNAL_H #include <signal.h> -#endif #include "urldata.h" #include "sendf.h" diff --git a/lib/hostip.h b/lib/hostip.h index 06d0867..b68f539 100644 --- a/lib/hostip.h +++ b/lib/hostip.h @@ -30,9 +30,7 @@ #include "timeval.h" /* for timediff_t */ #include "asyn.h" -#ifdef HAVE_SETJMP_H #include <setjmp.h> -#endif /* Allocate enough memory to hold the full name information structs and * everything. OSF1 is known to require at least 8872 bytes. The buffer @@ -1139,6 +1139,8 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy, data->state.authproblem = TRUE; } } +#else + ; #endif /* there may be multiple methods on one line, so keep reading */ @@ -1157,8 +1159,6 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy, * http_should_fail() determines whether an HTTP response has gotten us * into an error state or not. * - * @param conn all information about the current connection - * * @retval FALSE communications should continue * * @retval TRUE communications should not continue @@ -1602,8 +1602,6 @@ CURLcode Curl_http_done(struct Curl_easy *data, data->state.authhost.multipass = FALSE; data->state.authproxy.multipass = FALSE; - Curl_unencode_cleanup(data); - /* set the proper values (possibly modified on POST) */ conn->seek_func = data->set.seek_func; /* restore */ conn->seek_client = data->set.seek_client; /* restore */ @@ -3970,18 +3968,23 @@ CURLcode Curl_bump_headersize(struct Curl_easy *data, bool connect_only) { size_t bad = 0; + unsigned int max = MAX_HTTP_RESP_HEADER_SIZE; if(delta < MAX_HTTP_RESP_HEADER_SIZE) { + data->info.header_size += (unsigned int)delta; + data->req.allheadercount += (unsigned int)delta; if(!connect_only) data->req.headerbytecount += (unsigned int)delta; - data->info.header_size += (unsigned int)delta; - if(data->info.header_size > MAX_HTTP_RESP_HEADER_SIZE) + if(data->req.allheadercount > max) + bad = data->req.allheadercount; + else if(data->info.header_size > (max * 20)) { bad = data->info.header_size; + max *= 20; + } } else - bad = data->info.header_size + delta; + bad = data->req.allheadercount + delta; if(bad) { - failf(data, "Too large response headers: %zu > %u", - bad, MAX_HTTP_RESP_HEADER_SIZE); + failf(data, "Too large response headers: %zu > %u", bad, max); return CURLE_RECV_ERROR; } return CURLE_OK; @@ -4231,7 +4234,6 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* now, only output this if the header AND body are requested: */ writetype = CLIENTWRITE_HEADER | - (data->set.include_header ? CLIENTWRITE_BODY : 0) | ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0); headerlen = Curl_dyn_len(&data->state.headerb); @@ -4563,8 +4565,6 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* * End of header-checks. Write them to the client. */ - if(data->set.include_header) - writetype |= CLIENTWRITE_BODY; if(k->httpcode/100 == 1) writetype |= CLIENTWRITE_1XX; diff --git a/lib/http1.c b/lib/http1.c index 1ca7d41..182234c 100644 --- a/lib/http1.c +++ b/lib/http1.c @@ -318,5 +318,29 @@ out: return nread; } +CURLcode Curl_h1_req_write_head(struct httpreq *req, int http_minor, + struct dynbuf *dbuf) +{ + CURLcode result; + + result = Curl_dyn_addf(dbuf, "%s %s%s%s%s HTTP/1.%d\r\n", + req->method, + req->scheme? req->scheme : "", + req->scheme? "://" : "", + req->authority? req->authority : "", + req->path? req->path : "", + http_minor); + if(result) + goto out; + + result = Curl_dynhds_h1_dprint(&req->headers, dbuf); + if(result) + goto out; + + result = Curl_dyn_addn(dbuf, STRCONST("\r\n")); + +out: + return result; +} #endif /* !CURL_DISABLE_HTTP */ diff --git a/lib/http1.h b/lib/http1.h index b1eaa96..2de302f 100644 --- a/lib/http1.h +++ b/lib/http1.h @@ -56,6 +56,8 @@ ssize_t Curl_h1_req_parse_read(struct h1_req_parser *parser, CURLcode Curl_h1_req_dprint(const struct httpreq *req, struct dynbuf *dbuf); +CURLcode Curl_h1_req_write_head(struct httpreq *req, int http_minor, + struct dynbuf *dbuf); #endif /* !CURL_DISABLE_HTTP */ #endif /* HEADER_CURL_HTTP1_H */ diff --git a/lib/http2.c b/lib/http2.c index e0cda76..c8b0594 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -1688,7 +1688,7 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, "connection", stream->id); connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */ data->state.refused_stream = TRUE; - *err = CURLE_SEND_ERROR; /* trigger Curl_retry_request() later */ + *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */ return -1; } else if(stream->error != NGHTTP2_NO_ERROR) { @@ -2313,7 +2313,7 @@ out: "h2 windows %d-%d (stream-conn), " "buffers %zu-%zu (stream-conn)", stream->id, len, nwritten, *err, - (ssize_t)stream->upload_left, + stream->upload_left, nghttp2_session_get_stream_remote_window_size( ctx->h2, stream->id), nghttp2_session_get_remote_window_size(ctx->h2), @@ -2425,6 +2425,8 @@ static void cf_h2_close(struct Curl_cfilter *cf, struct Curl_easy *data) cf_h2_ctx_clear(ctx); CF_DATA_RESTORE(cf, save); } + if(cf->next) + cf->next->cft->do_close(cf->next, data); } static void cf_h2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) diff --git a/lib/http_aws_sigv4.c b/lib/http_aws_sigv4.c index f39d02c..901c22f 100644 --- a/lib/http_aws_sigv4.c +++ b/lib/http_aws_sigv4.c @@ -34,6 +34,7 @@ #include "transfer.h" #include "parsedate.h" #include "sendf.h" +#include "escape.h" #include <time.h> @@ -63,11 +64,8 @@ static void sha256_to_hex(char *dst, unsigned char *sha) { - int i; - - for(i = 0; i < SHA256_DIGEST_LENGTH; ++i) { - msnprintf(dst + (i * 2), SHA256_HEX_LENGTH - (i * 2), "%02x", sha[i]); - } + Curl_hexencode(sha, SHA256_DIGEST_LENGTH, + (unsigned char *)dst, SHA256_HEX_LENGTH); } static char *find_date_hdr(struct Curl_easy *data, const char *sig_hdr) @@ -409,6 +407,11 @@ static int compare_func(const void *a, const void *b) { const struct pair *aa = a; const struct pair *bb = b; + /* If one element is empty, the other is always sorted higher */ + if(aa->len == 0) + return -1; + if(bb->len == 0) + return 1; return strncmp(aa->p, bb->p, aa->len < bb->len ? aa->len : bb->len); } diff --git a/lib/http_chunks.c b/lib/http_chunks.c index bda00d3..2a401d1 100644 --- a/lib/http_chunks.c +++ b/lib/http_chunks.c @@ -175,10 +175,7 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, /* Write the data portion available */ if(!data->set.http_te_skip && !k->ignorebody) { - if(!data->set.http_ce_skip && k->writer_stack) - result = Curl_unencode_write(data, k->writer_stack, datap, piece); - else - result = Curl_client_write(data, CLIENTWRITE_BODY, datap, piece); + result = Curl_client_write(data, CLIENTWRITE_BODY, datap, piece); if(result) { *extrap = result; diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 60bbfbe..a1d6da9 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -52,6 +52,113 @@ #include "memdebug.h" +CURLcode Curl_http_proxy_get_destination(struct Curl_cfilter *cf, + const char **phostname, + int *pport, bool *pipv6_ip) +{ + DEBUGASSERT(cf); + DEBUGASSERT(cf->conn); + + if(cf->conn->bits.conn_to_host) + *phostname = cf->conn->conn_to_host.name; + else if(cf->sockindex == SECONDARYSOCKET) + *phostname = cf->conn->secondaryhostname; + else + *phostname = cf->conn->host.name; + + if(cf->sockindex == SECONDARYSOCKET) + *pport = cf->conn->secondary_port; + else if(cf->conn->bits.conn_to_port) + *pport = cf->conn->conn_to_port; + else + *pport = cf->conn->remote_port; + + if(*phostname != cf->conn->host.name) + *pipv6_ip = (strchr(*phostname, ':') != NULL); + else + *pipv6_ip = cf->conn->bits.ipv6_ip; + + return CURLE_OK; +} + +CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq, + struct Curl_cfilter *cf, + struct Curl_easy *data, + int http_version_major) +{ + const char *hostname = NULL; + char *authority = NULL; + int port; + bool ipv6_ip; + CURLcode result; + struct httpreq *req = NULL; + + result = Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip); + if(result) + goto out; + + authority = aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, + ipv6_ip?"]":"", port); + if(!authority) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + result = Curl_http_req_make(&req, "CONNECT", sizeof("CONNECT")-1, + NULL, 0, authority, strlen(authority), + NULL, 0); + if(result) + goto out; + + /* Setup the proxy-authorization header, if any */ + result = Curl_http_output_auth(data, cf->conn, req->method, HTTPREQ_GET, + req->authority, TRUE); + if(result) + goto out; + + /* If user is not overriding Host: header, we add for HTTP/1.x */ + if(http_version_major == 1 && + !Curl_checkProxyheaders(data, cf->conn, STRCONST("Host"))) { + result = Curl_dynhds_cadd(&req->headers, "Host", authority); + if(result) + goto out; + } + + if(data->state.aptr.proxyuserpwd) { + result = Curl_dynhds_h1_cadd_line(&req->headers, + data->state.aptr.proxyuserpwd); + if(result) + goto out; + } + + if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("User-Agent")) + && data->set.str[STRING_USERAGENT]) { + result = Curl_dynhds_cadd(&req->headers, "User-Agent", + data->set.str[STRING_USERAGENT]); + if(result) + goto out; + } + + if(http_version_major == 1 && + !Curl_checkProxyheaders(data, cf->conn, STRCONST("Proxy-Connection"))) { + result = Curl_dynhds_cadd(&req->headers, "Proxy-Connection", "Keep-Alive"); + if(result) + goto out; + } + + result = Curl_dynhds_add_custom(data, TRUE, &req->headers); + +out: + if(result && req) { + Curl_http_req_free(req); + req = NULL; + } + free(authority); + *preq = req; + return result; +} + + struct cf_proxy_ctx { /* the protocol specific sub-filter we install during connect */ struct Curl_cfilter *cf_protocol; @@ -105,7 +212,6 @@ connect_sub: break; #endif default: - CURL_TRC_CF(data, cf, "installing subfilter for default HTTP/1.1"); infof(data, "CONNECT tunnel: unsupported ALPN(%d) negotiated", alpn); result = CURLE_COULDNT_CONNECT; goto out; diff --git a/lib/http_proxy.h b/lib/http_proxy.h index a1a0372..2b5f7ae 100644 --- a/lib/http_proxy.h +++ b/lib/http_proxy.h @@ -30,6 +30,15 @@ #include "urldata.h" +CURLcode Curl_http_proxy_get_destination(struct Curl_cfilter *cf, + const char **phostname, + int *pport, bool *pipv6_ip); + +CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq, + struct Curl_cfilter *cf, + struct Curl_easy *data, + int http_version_major); + /* Default proxy timeout in milliseconds */ #define PROXY_TIMEOUT (3600*1000) @@ -91,6 +91,8 @@ static CURLcode win32_idn_to_ascii(const char *in, char **out) else return CURLE_URL_MALFORMAT; } + else + return CURLE_URL_MALFORMAT; return CURLE_OK; } @@ -174,6 +176,9 @@ static CURLcode idn_decode(const char *input, char **output) if(rc != IDN2_OK) result = CURLE_URL_MALFORMAT; } + else + /* a too old libidn2 version */ + result = CURLE_NOT_BUILT_IN; #elif defined(USE_WIN32_IDN) result = win32_idn_to_ascii(input, &decoded); #endif diff --git a/lib/inet_ntop.c b/lib/inet_ntop.c index 135f486..c9cee0c 100644 --- a/lib/inet_ntop.c +++ b/lib/inet_ntop.c @@ -96,10 +96,10 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; char *tp; struct { - long base; - long len; + int base; + int len; } best, cur; - unsigned long words[IN6ADDRSZ / INT16SZ]; + unsigned int words[IN6ADDRSZ / INT16SZ]; int i; /* Preprocess: @@ -108,7 +108,7 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) */ memset(words, '\0', sizeof(words)); for(i = 0; i < IN6ADDRSZ; i++) - words[i/2] |= (src[i] << ((1 - (i % 2)) << 3)); + words[i/2] |= ((unsigned int)src[i] << ((1 - (i % 2)) << 3)); best.base = -1; cur.base = -1; @@ -159,7 +159,7 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) tp += strlen(tp); break; } - tp += msnprintf(tp, 5, "%lx", words[i]); + tp += msnprintf(tp, 5, "%x", words[i]); } /* Was it a trailing run of 0x00's? @@ -735,7 +735,9 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) if(result) goto quit; dlsize++; - Curl_pgrsSetDownloadCounter(data, dlsize); + result = Curl_pgrsSetDownloadCounter(data, dlsize); + if(result) + goto quit; } if(ber) @@ -1289,9 +1289,9 @@ curl_mime *curl_mime_init(struct Curl_easy *easy) mime->lastpart = NULL; memset(mime->boundary, '-', MIME_BOUNDARY_DASHES); - if(Curl_rand_hex(easy, - (unsigned char *) &mime->boundary[MIME_BOUNDARY_DASHES], - MIME_RAND_BOUNDARY_CHARS + 1)) { + if(Curl_rand_alnum(easy, + (unsigned char *) &mime->boundary[MIME_BOUNDARY_DASHES], + MIME_RAND_BOUNDARY_CHARS + 1)) { /* failed to get random separator, bail out */ free(mime); return NULL; @@ -27,7 +27,7 @@ #include "curl_setup.h" #define MIME_BOUNDARY_DASHES 24 /* leading boundary dashes */ -#define MIME_RAND_BOUNDARY_CHARS 16 /* Nb. of random boundary chars. */ +#define MIME_RAND_BOUNDARY_CHARS 22 /* Nb. of random boundary chars. */ #define MAX_ENCODED_LINE_LENGTH 76 /* Maximum encoded line length. */ #define ENCODING_BUFFER_SIZE 256 /* Encoding temp buffers size. */ @@ -109,6 +109,7 @@ static CURLcode mqtt_setup_conn(struct Curl_easy *data, mq = calloc(1, sizeof(struct MQTT)); if(!mq) return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&mq->recvbuf, DYN_MQTT_RECV); data->req.p.mqtt = mq; return CURLE_OK; } @@ -295,12 +296,12 @@ static CURLcode mqtt_connect(struct Curl_easy *data) /* set initial values for the CONNECT packet */ pos = init_connpack(packet, remain, remain_pos); - result = Curl_rand_hex(data, (unsigned char *)&client_id[clen], - MQTT_CLIENTID_LEN - clen + 1); + result = Curl_rand_alnum(data, (unsigned char *)&client_id[clen], + MQTT_CLIENTID_LEN - clen + 1); /* add client id */ rc = add_client_id(client_id, strlen(client_id), packet, pos + 1); if(rc) { - failf(data, "Client ID length mismatched: [%lu]", strlen(client_id)); + failf(data, "Client ID length mismatched: [%zu]", strlen(client_id)); result = CURLE_WEIRD_SERVER_REPLY; goto end; } @@ -317,7 +318,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data) rc = add_user(username, ulen, (unsigned char *)packet, start_user, remain_pos); if(rc) { - failf(data, "Username is too large: [%lu]", ulen); + failf(data, "Username is too large: [%zu]", ulen); result = CURLE_WEIRD_SERVER_REPLY; goto end; } @@ -327,7 +328,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data) if(plen) { rc = add_passwd(passwd, plen, packet, start_pwd, remain_pos); if(rc) { - failf(data, "Password is too large: [%lu]", plen); + failf(data, "Password is too large: [%zu]", plen); result = CURLE_WEIRD_SERVER_REPLY; goto end; } @@ -350,36 +351,66 @@ static CURLcode mqtt_disconnect(struct Curl_easy *data) struct MQTT *mq = data->req.p.mqtt; result = mqtt_send(data, (char *)"\xe0\x00", 2); Curl_safefree(mq->sendleftovers); + Curl_dyn_free(&mq->recvbuf); return result; } -static CURLcode mqtt_verify_connack(struct Curl_easy *data) +static CURLcode mqtt_recv_atleast(struct Curl_easy *data, size_t nbytes) { + struct MQTT *mq = data->req.p.mqtt; + size_t rlen = Curl_dyn_len(&mq->recvbuf); CURLcode result; - struct connectdata *conn = data->conn; - curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; - unsigned char readbuf[MQTT_CONNACK_LEN]; - ssize_t nread; - result = Curl_read(data, sockfd, (char *)readbuf, MQTT_CONNACK_LEN, &nread); - if(result) - goto fail; + if(rlen < nbytes) { + unsigned char readbuf[1024]; + ssize_t nread; - Curl_debug(data, CURLINFO_HEADER_IN, (char *)readbuf, (size_t)nread); + DEBUGASSERT(nbytes - rlen < sizeof(readbuf)); + result = Curl_read(data, data->conn->sock[FIRSTSOCKET], + (char *)readbuf, nbytes - rlen, &nread); + if(result) + return result; + DEBUGASSERT(nread >= 0); + if(Curl_dyn_addn(&mq->recvbuf, readbuf, (size_t)nread)) + return CURLE_OUT_OF_MEMORY; + rlen = Curl_dyn_len(&mq->recvbuf); + } + return (rlen >= nbytes)? CURLE_OK : CURLE_AGAIN; +} - /* fixme */ - if(nread < MQTT_CONNACK_LEN) { - result = CURLE_WEIRD_SERVER_REPLY; +static void mqtt_recv_consume(struct Curl_easy *data, size_t nbytes) +{ + struct MQTT *mq = data->req.p.mqtt; + size_t rlen = Curl_dyn_len(&mq->recvbuf); + if(rlen <= nbytes) + Curl_dyn_reset(&mq->recvbuf); + else + Curl_dyn_tail(&mq->recvbuf, rlen - nbytes); +} + +static CURLcode mqtt_verify_connack(struct Curl_easy *data) +{ + struct MQTT *mq = data->req.p.mqtt; + CURLcode result; + char *ptr; + + result = mqtt_recv_atleast(data, MQTT_CONNACK_LEN); + if(result) goto fail; - } /* verify CONNACK */ - if(readbuf[0] != 0x00 || readbuf[1] != 0x00) { + DEBUGASSERT(Curl_dyn_len(&mq->recvbuf) >= MQTT_CONNACK_LEN); + ptr = Curl_dyn_ptr(&mq->recvbuf); + Curl_debug(data, CURLINFO_HEADER_IN, ptr, MQTT_CONNACK_LEN); + + if(ptr[0] != 0x00 || ptr[1] != 0x00) { failf(data, "Expected %02x%02x but got %02x%02x", - 0x00, 0x00, readbuf[0], readbuf[1]); + 0x00, 0x00, ptr[0], ptr[1]); + Curl_dyn_reset(&mq->recvbuf); result = CURLE_WEIRD_SERVER_REPLY; + goto fail; } - + mqtt_recv_consume(data, MQTT_CONNACK_LEN); fail: return result; } @@ -452,31 +483,29 @@ fail: */ static CURLcode mqtt_verify_suback(struct Curl_easy *data) { - CURLcode result; + struct MQTT *mq = data->req.p.mqtt; struct connectdata *conn = data->conn; - curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; - unsigned char readbuf[MQTT_SUBACK_LEN]; - ssize_t nread; struct mqtt_conn *mqtt = &conn->proto.mqtt; + CURLcode result; + char *ptr; - result = Curl_read(data, sockfd, (char *)readbuf, MQTT_SUBACK_LEN, &nread); + result = mqtt_recv_atleast(data, MQTT_SUBACK_LEN); if(result) goto fail; - Curl_debug(data, CURLINFO_HEADER_IN, (char *)readbuf, (size_t)nread); - - /* fixme */ - if(nread < MQTT_SUBACK_LEN) { + /* verify SUBACK */ + DEBUGASSERT(Curl_dyn_len(&mq->recvbuf) >= MQTT_SUBACK_LEN); + ptr = Curl_dyn_ptr(&mq->recvbuf); + Curl_debug(data, CURLINFO_HEADER_IN, ptr, MQTT_SUBACK_LEN); + + if(((unsigned char)ptr[0]) != ((mqtt->packetid >> 8) & 0xff) || + ((unsigned char)ptr[1]) != (mqtt->packetid & 0xff) || + ptr[2] != 0x00) { + Curl_dyn_reset(&mq->recvbuf); result = CURLE_WEIRD_SERVER_REPLY; goto fail; } - - /* verify SUBACK */ - if(readbuf[0] != ((mqtt->packetid >> 8) & 0xff) || - readbuf[1] != (mqtt->packetid & 0xff) || - readbuf[2] != 0x00) - result = CURLE_WEIRD_SERVER_REPLY; - + mqtt_recv_consume(data, MQTT_SUBACK_LEN); fail: return result; } @@ -668,7 +697,9 @@ MQTT_SUBACK_COMING: mq->npacket -= nread; k->bytecount += nread; - Curl_pgrsSetDownloadCounter(data, k->bytecount); + result = Curl_pgrsSetDownloadCounter(data, k->bytecount); + if(result) + goto end; /* if QoS is set, message contains packet id */ @@ -711,6 +742,7 @@ static CURLcode mqtt_done(struct Curl_easy *data, (void)status; (void)premature; Curl_safefree(mq->sendleftovers); + Curl_dyn_free(&mq->recvbuf); return CURLE_OK; } @@ -56,6 +56,7 @@ struct MQTT { size_t npacket; /* byte counter */ unsigned char firstbyte; size_t remaining_length; + struct dynbuf recvbuf; }; #endif /* HEADER_CURL_MQTT_H */ diff --git a/lib/multi.c b/lib/multi.c index bb57dbc..ff753ac 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -665,7 +665,6 @@ static CURLcode multi_done(struct Curl_easy *data, { CURLcode result; struct connectdata *conn = data->conn; - unsigned int i; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) DEBUGF(infof(data, "multi_done[%s]: status: %d prem: %d done: %d", @@ -721,12 +720,7 @@ static CURLcode multi_done(struct Curl_easy *data, Curl_safefree(data->state.ulbuf); - /* if the transfer was completed in a paused state there can be buffered - data left to free */ - for(i = 0; i < data->state.tempcount; i++) { - Curl_dyn_free(&data->state.tempwrite[i].b); - } - data->state.tempcount = 0; + Curl_client_cleanup(data); CONNCACHE_LOCK(data); Curl_detach_connection(data); @@ -2131,9 +2125,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } if(!result) result = protocol_connect(data, &protocol_connected); - if(!result && !protocol_connected) + if(!result && !protocol_connected) { /* switch to waiting state */ multistate(data, MSTATE_PROTOCONNECTING); + rc = CURLM_CALL_MULTI_PERFORM; + } else if(!result) { /* protocol connect has completed, go WAITDO or DO */ multistate(data, MSTATE_DO); @@ -2220,6 +2216,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* DO was not completed in one function call, we must continue DOING... */ multistate(data, MSTATE_DOING); + rc = CURLM_CALL_MULTI_PERFORM; } /* after DO, go DO_DONE... or DO_MORE */ @@ -2227,6 +2224,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* we're supposed to do more, but we need to sit down, relax and wait a little while first */ multistate(data, MSTATE_DOING_MORE); + rc = CURLM_CALL_MULTI_PERFORM; } else { /* we're done with the DO, now DID */ @@ -3139,7 +3137,7 @@ static CURLMcode add_next_timeout(struct curltime now, struct Curl_llist_element *n = e->next; timediff_t diff; node = (struct time_node *)e->ptr; - diff = Curl_timediff(node->time, now); + diff = Curl_timediff_us(node->time, now); if(diff <= 0) /* remove outdated entry */ Curl_llist_remove(list, e, NULL); @@ -3422,20 +3420,10 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) { /* some time left before expiration */ - timediff_t diff = Curl_timediff(multi->timetree->key, now); - if(diff <= 0) - /* - * Since we only provide millisecond resolution on the returned value - * and the diff might be less than one millisecond here, we don't - * return zero as that may cause short bursts of busyloops on fast - * processors while the diff is still present but less than one - * millisecond! instead we return 1 until the time is ripe. - */ - *timeout_ms = 1; - else - /* this should be safe even on 64 bit archs, as we don't use that - overly long timeouts */ - *timeout_ms = (long)diff; + timediff_t diff = Curl_timediff_ceil(multi->timetree->key, now); + /* this should be safe even on 32 bit archs, as we don't use that + overly long timeouts */ + *timeout_ms = (long)diff; } else /* 0 means immediately */ @@ -3783,41 +3771,26 @@ bool Curl_is_in_callback(struct Curl_easy *easy) (easy->multi_easy && easy->multi_easy->in_callback)); } -#ifdef DEBUGBUILD -void Curl_multi_dump(struct Curl_multi *multi) -{ - struct Curl_easy *data; - int i; - fprintf(stderr, "* Multi status: %d handles, %d alive\n", - multi->num_easy, multi->num_alive); - for(data = multi->easyp; data; data = data->next) { - if(data->mstate < MSTATE_COMPLETED) { - /* only display handles that are not completed */ - fprintf(stderr, "handle %p, state %s, %d sockets\n", - (void *)data, - multi_statename[data->mstate], data->numsocks); - for(i = 0; i < data->numsocks; i++) { - curl_socket_t s = data->sockets[i]; - struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); - - fprintf(stderr, "%d ", (int)s); - if(!entry) { - fprintf(stderr, "INTERNAL CONFUSION\n"); - continue; - } - fprintf(stderr, "[%s %s] ", - (entry->action&CURL_POLL_IN)?"RECVING":"", - (entry->action&CURL_POLL_OUT)?"SENDING":""); - } - if(data->numsocks) - fprintf(stderr, "\n"); - } - } -} -#endif - unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi) { DEBUGASSERT(multi); return multi->max_concurrent_streams; } + +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; + struct Curl_easy *e = multi->easyp; + while(e) { + DEBUGASSERT(i < multi->num_easy); + if(!e->internal) + a[i++] = e; + e = e->next; + } + a[i] = NULL; /* last entry is a NULL */ + } + return a; +} diff --git a/lib/multiif.h b/lib/multiif.h index 7f08ecc..7a344fa 100644 --- a/lib/multiif.h +++ b/lib/multiif.h @@ -62,15 +62,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize, /* mask for checking if read and/or write is set for index x */ #define GETSOCK_MASK_RW(x) (GETSOCK_READSOCK(x)|GETSOCK_WRITESOCK(x)) -#ifdef DEBUGBUILD - /* - * Curl_multi_dump is not a stable public function, this is only meant to - * allow easier tracking of the internal handle's state and what sockets - * they use. Only for research and development DEBUGBUILD enabled builds. - */ -void Curl_multi_dump(struct Curl_multi *multi); -#endif - /* Return the value of the CURLMOPT_MAX_HOST_CONNECTIONS option */ size_t Curl_multi_max_host_connections(struct Curl_multi *multi); diff --git a/lib/openldap.c b/lib/openldap.c index 41fecf9..3aff306 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -199,11 +199,11 @@ struct ldapreqinfo { }; /* - * state() + * oldap_state() * * This is the ONLY way to change LDAP state! */ -static void state(struct Curl_easy *data, ldapstate newstate) +static void oldap_state(struct Curl_easy *data, ldapstate newstate) { struct ldapconninfo *ldapc = data->conn->proto.ldapc; @@ -444,7 +444,7 @@ static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate) rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd, NULL, NULL, &li->msgid); if(rc == LDAP_SUCCESS) - state(data, newstate); + oldap_state(data, newstate); else result = oldap_map_error(rc, data->state.aptr.user? @@ -467,7 +467,7 @@ static CURLcode oldap_perform_mechs(struct Curl_easy *data) (char **) supportedSASLMechanisms, 0, NULL, NULL, NULL, 0, &li->msgid); if(rc == LDAP_SUCCESS) - state(data, OLDAP_MECHS); + oldap_state(data, OLDAP_MECHS); else result = oldap_map_error(rc, CURLE_LOGIN_DENIED); return result; @@ -480,7 +480,7 @@ static CURLcode oldap_perform_sasl(struct Curl_easy *data) struct ldapconninfo *li = data->conn->proto.ldapc; CURLcode result = Curl_sasl_start(&li->sasl, data, TRUE, &progress); - state(data, OLDAP_SASL); + oldap_state(data, OLDAP_SASL); if(!result && progress != SASL_INPROGRESS) result = CURLE_LOGIN_DENIED; return result; @@ -503,7 +503,7 @@ static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate) result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone); if(!result) { - state(data, newstate); + oldap_state(data, newstate); if(ssldone) { Sockbuf *sb; @@ -527,7 +527,7 @@ static CURLcode oldap_perform_starttls(struct Curl_easy *data) int rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid); if(rc == LDAP_SUCCESS) - state(data, OLDAP_STARTTLS); + oldap_state(data, OLDAP_STARTTLS); else result = oldap_map_error(rc, CURLE_USE_SSL_FAILED); return result; @@ -682,7 +682,7 @@ static CURLcode oldap_state_sasl_resp(struct Curl_easy *data, else { result = Curl_sasl_continue(&li->sasl, data, code, &progress); if(!result && progress != SASL_INPROGRESS) - state(data, OLDAP_STOP); + oldap_state(data, OLDAP_STOP); } if(li->servercred) @@ -710,7 +710,7 @@ static CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg, result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND); } else - state(data, OLDAP_STOP); + oldap_state(data, OLDAP_STOP); if(bv) ber_bvfree(bv); @@ -804,7 +804,8 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) else if(data->state.aptr.user) result = oldap_perform_bind(data, OLDAP_BIND); else { - state(data, OLDAP_STOP); /* Version 3 supported: no bind required */ + /* Version 3 supported: no bind required */ + oldap_state(data, OLDAP_STOP); result = CURLE_OK; } } diff --git a/lib/pingpong.c b/lib/pingpong.c index 136985f..0081c9c 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -361,7 +361,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data, * for "headers". The response lines can be seen as a kind of * headers. */ - result = Curl_client_write(data, CLIENTWRITE_HEADER, + result = Curl_client_write(data, CLIENTWRITE_INFO, pp->linestart_resp, perline); if(result) return result; diff --git a/lib/progress.c b/lib/progress.c index 6092b78..e783a9c 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -317,9 +317,16 @@ timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize, /* * Set the number of downloaded bytes so far. */ -void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) +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/lib/progress.h b/lib/progress.h index 0049cd0..fc39e34 100644 --- a/lib/progress.h +++ b/lib/progress.h @@ -46,7 +46,10 @@ int Curl_pgrsDone(struct Curl_easy *data); void Curl_pgrsStartNow(struct Curl_easy *data); void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size); void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size); -void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size); + +/* It is fine to not check the return code if 'size' is set to 0 */ +CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size); + void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size); void Curl_ratelimit(struct Curl_easy *data, struct curltime now); int Curl_pgrsUpdate(struct Curl_easy *data); @@ -24,6 +24,8 @@ #include "curl_setup.h" +#include <limits.h> + #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif @@ -41,6 +43,7 @@ uint32_t arc4random(void); #include "sendf.h" #include "timeval.h" #include "rand.h" +#include "escape.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -49,12 +52,7 @@ uint32_t arc4random(void); #ifdef WIN32 -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -# define HAVE_MINGW_ORIGINAL -#endif - -#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 && \ - !defined(HAVE_MINGW_ORIGINAL) +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 # define HAVE_WIN_BCRYPTGENRANDOM # include <bcrypt.h> # ifdef _MSC_VER @@ -234,9 +232,7 @@ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, size_t num) { CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; - const char *hex = "0123456789abcdef"; unsigned char buffer[128]; - unsigned char *bufp = buffer; DEBUGASSERT(num > 1); #ifdef __clang_analyzer__ @@ -255,13 +251,37 @@ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, if(result) return result; + Curl_hexencode(buffer, num/2, rnd, num + 1); + return result; +} + +/* + * Curl_rand_alnum() fills the 'rnd' buffer with a given 'num' size with random + * alphanumerical chars PLUS a null-terminating byte. + */ + +static const char alnum[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd, + size_t num) +{ + CURLcode result = CURLE_OK; + const int alnumspace = sizeof(alnum) - 1; + unsigned int r; + DEBUGASSERT(num > 1); + + num--; /* save one for null-termination */ + while(num) { - /* clang-tidy warns on this line without this comment: */ - /* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */ - *rnd++ = hex[(*bufp & 0xF0)>>4]; - *rnd++ = hex[*bufp & 0x0F]; - bufp++; - num -= 2; + do { + result = randit(data, &r); + if(result) + return result; + } while(r >= (UINT_MAX - UINT_MAX % alnumspace)); + + *rnd++ = alnum[r % alnumspace]; + num--; } *rnd = 0; @@ -34,6 +34,13 @@ CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num); CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, size_t num); +/* + * Curl_rand_alnum() fills the 'rnd' buffer with a given 'num' size with random + * alphanumerical chars PLUS a null-terminating byte. + */ +CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd, + size_t num); + #ifdef WIN32 /* Random generator shared between the Schannel vtls and Curl_rand*() functions */ diff --git a/lib/sendf.c b/lib/sendf.c index d79ad08..0482c5d 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -40,6 +40,7 @@ #include "sendf.h" #include "cfilters.h" #include "connect.h" +#include "content_encoding.h" #include "vtls/vtls.h" #include "vssh/ssh.h" #include "easyif.h" @@ -213,6 +214,7 @@ CURLcode Curl_write(struct Curl_easy *data, static CURLcode pausewrite(struct Curl_easy *data, int type, /* what type of data */ + bool paused_body, const char *ptr, size_t len) { @@ -228,7 +230,8 @@ static CURLcode pausewrite(struct Curl_easy *data, if(s->tempcount) { for(i = 0; i< s->tempcount; i++) { - if(s->tempwrite[i].type == type) { + if(s->tempwrite[i].type == type && + !!s->tempwrite[i].paused_body == !!paused_body) { /* data for this type exists */ newtype = FALSE; break; @@ -246,6 +249,7 @@ static CURLcode pausewrite(struct Curl_easy *data, /* store this information in the state struct for later use */ Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER); s->tempwrite[i].type = type; + s->tempwrite[i].paused_body = paused_body; s->tempcount++; } @@ -265,6 +269,7 @@ static CURLcode pausewrite(struct Curl_easy *data, */ static CURLcode chop_write(struct Curl_easy *data, int type, + bool skip_body_write, char *optr, size_t olen) { @@ -281,10 +286,12 @@ static CURLcode chop_write(struct Curl_easy *data, /* If reading is paused, append this data to the already held data for this type. */ if(data->req.keepon & KEEP_RECV_PAUSE) - return pausewrite(data, type, ptr, len); + return pausewrite(data, type, !skip_body_write, ptr, len); /* Determine the callback(s) to use. */ - if(type & CLIENTWRITE_BODY) { + if(!skip_body_write && + ((type & CLIENTWRITE_BODY) || + ((type & CLIENTWRITE_HEADER) && data->set.include_header))) { #ifdef USE_WEBSOCKETS if(conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) { writebody = Curl_ws_writecb; @@ -294,7 +301,7 @@ static CURLcode chop_write(struct Curl_easy *data, #endif writebody = data->set.fwrite_func; } - if((type & CLIENTWRITE_HEADER) && + if((type & (CLIENTWRITE_HEADER|CLIENTWRITE_INFO)) && (data->set.fwrite_header || data->set.writeheader)) { /* * Write headers to the same callback or to the especially setup @@ -322,7 +329,7 @@ static CURLcode chop_write(struct Curl_easy *data, failf(data, "Write callback asked for PAUSE when not supported"); return CURLE_WRITE_ERROR; } - return pausewrite(data, type, ptr, len); + return pausewrite(data, type, TRUE, ptr, len); } if(wrote != chunklen) { failf(data, "Failure writing output to destination"); @@ -357,13 +364,7 @@ static CURLcode chop_write(struct Curl_easy *data, Curl_set_in_callback(data, false); if(CURL_WRITEFUNC_PAUSE == wrote) - /* here we pass in the HEADER bit only since if this was body as well - then it was passed already and clearly that didn't trigger the - pause, so this is saved for later with the HEADER bit only */ - return pausewrite(data, CLIENTWRITE_HEADER | - (type & (CLIENTWRITE_STATUS|CLIENTWRITE_CONNECT| - CLIENTWRITE_1XX|CLIENTWRITE_TRAILER)), - optr, olen); + return pausewrite(data, type, FALSE, optr, olen); if(wrote != olen) { failf(data, "Failed writing header"); return CURLE_WRITE_ERROR; @@ -397,9 +398,187 @@ CURLcode Curl_client_write(struct Curl_easy *data, len = convert_lineends(data, ptr, len); } #endif - return chop_write(data, type, ptr, len); + /* it is one of those, at least */ + DEBUGASSERT(type & (CLIENTWRITE_BODY|CLIENTWRITE_HEADER|CLIENTWRITE_INFO)); + /* BODY is only BODY */ + DEBUGASSERT(!(type & CLIENTWRITE_BODY) || (type == CLIENTWRITE_BODY)); + /* 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); + } + return chop_write(data, type, FALSE, ptr, len); +} + +CURLcode Curl_client_unpause(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + + if(data->state.tempcount) { + /* there are buffers for sending that can be delivered as the receive + pausing is lifted! */ + unsigned int i; + unsigned int count = data->state.tempcount; + struct tempbuf writebuf[3]; /* there can only be three */ + + /* copy the structs to allow for immediate re-pausing */ + for(i = 0; i < data->state.tempcount; i++) { + writebuf[i] = data->state.tempwrite[i]; + Curl_dyn_init(&data->state.tempwrite[i].b, DYN_PAUSE_BUFFER); + } + data->state.tempcount = 0; + + for(i = 0; i < count; i++) { + /* even if one function returns error, this loops through and frees + all buffers */ + if(!result) + result = chop_write(data, writebuf[i].type, + !writebuf[i].paused_body, + Curl_dyn_ptr(&writebuf[i].b), + Curl_dyn_len(&writebuf[i].b)); + Curl_dyn_free(&writebuf[i].b); + } + } + return result; } +void Curl_client_cleanup(struct Curl_easy *data) +{ + struct contenc_writer *writer = data->req.writer_stack; + size_t i; + + while(writer) { + data->req.writer_stack = writer->downstream; + writer->handler->close_writer(data, writer); + free(writer); + writer = data->req.writer_stack; + } + + for(i = 0; i < data->state.tempcount; i++) { + Curl_dyn_free(&data->state.tempwrite[i].b); + } + data->state.tempcount = 0; + +} + +/* Real client writer: no downstream. */ +static CURLcode client_cew_init(struct Curl_easy *data, + struct contenc_writer *writer) +{ + (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) +{ + (void)writer; + if(!nbytes || data->req.ignorebody) + return CURLE_OK; + return chop_write(data, CLIENTWRITE_BODY, FALSE, (char *)buf, nbytes); +} + +static void client_cew_close(struct Curl_easy *data, + struct contenc_writer *writer) +{ + (void) data; + (void) writer; +} + +static const struct content_encoding client_cew = { + NULL, + NULL, + client_cew_init, + client_cew_write, + client_cew_close, + sizeof(struct contenc_writer) +}; + +/* Create an unencoding writer stage using the given handler. */ +CURLcode Curl_client_create_writer(struct contenc_writer **pwriter, + struct Curl_easy *data, + const struct content_encoding *ce_handler, + int order) +{ + struct contenc_writer *writer; + CURLcode result = CURLE_OUT_OF_MEMORY; + + DEBUGASSERT(ce_handler->writersize >= sizeof(struct contenc_writer)); + writer = (struct contenc_writer *) calloc(1, ce_handler->writersize); + if(!writer) + goto out; + + writer->handler = ce_handler; + writer->order = order; + result = ce_handler->init_writer(data, writer); + +out: + *pwriter = result? NULL : writer; + if(result) + free(writer); + return result; +} + +void Curl_client_free_writer(struct Curl_easy *data, + struct contenc_writer *writer) +{ + if(writer) { + writer->handler->close_writer(data, writer); + free(writer); + } +} + +/* allow no more than 5 "chained" compression steps */ +#define MAX_ENCODE_STACK 5 + + +static CURLcode init_writer_stack(struct Curl_easy *data) +{ + DEBUGASSERT(!data->req.writer_stack); + return Curl_client_create_writer(&data->req.writer_stack, + data, &client_cew, 0); +} + +CURLcode Curl_client_add_writer(struct Curl_easy *data, + struct contenc_writer *writer) +{ + CURLcode result; + + if(!data->req.writer_stack) { + result = init_writer_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; + } + return CURLE_OK; +} + + /* * Internal read-from-socket function. This is meant to deal with plain * sockets, SSL sockets and kerberos sockets. diff --git a/lib/sendf.h b/lib/sendf.h index 5ef2b91..9ee00bb 100644 --- a/lib/sendf.h +++ b/lib/sendf.h @@ -28,18 +28,67 @@ #include "curl_trc.h" - -#define CLIENTWRITE_BODY (1<<0) -#define CLIENTWRITE_HEADER (1<<1) -#define CLIENTWRITE_STATUS (1<<2) /* the first "header" is the status line */ -#define CLIENTWRITE_CONNECT (1<<3) /* a CONNECT response */ -#define CLIENTWRITE_1XX (1<<4) /* a 1xx response */ -#define CLIENTWRITE_TRAILER (1<<5) /* a trailer header */ -#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER) +/** + * Type of data that is being written to the client (application) + * - data written can be either BODY or META data + * - META data is either INFO or HEADER + * - INFO is meta information, e.g. not BODY, that cannot be interpreted + * as headers of a response. Example FTP/IMAP pingpong answers. + * - HEADER can have additional bits set (more than one) + * - STATUS special "header", e.g. response status line in HTTP + * - CONNECT header was received during proxying the connection + * - 1XX header is part of an intermediate response, e.g. HTTP 1xx code + * - TRAILER header is trailing response data, e.g. HTTP trailers + * BODY, INFO and HEADER should not be mixed, as this would lead to + * confusion on how to interpret/format/convert the data. + */ +#define CLIENTWRITE_BODY (1<<0) /* non-meta information, BODY */ +#define CLIENTWRITE_INFO (1<<1) /* meta information, not a HEADER */ +#define CLIENTWRITE_HEADER (1<<2) /* meta information, HEADER */ +#define CLIENTWRITE_STATUS (1<<3) /* a special status HEADER */ +#define CLIENTWRITE_CONNECT (1<<4) /* a CONNECT related HEADER */ +#define CLIENTWRITE_1XX (1<<5) /* a 1xx response related HEADER */ +#define CLIENTWRITE_TRAILER (1<<6) /* a trailer HEADER */ CURLcode Curl_client_write(struct Curl_easy *data, int type, char *ptr, size_t len) WARN_UNUSED_RESULT; +CURLcode Curl_client_unpause(struct Curl_easy *data); +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. */ +}; + +/* 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; +}; + + +CURLcode Curl_client_create_writer(struct contenc_writer **pwriter, + struct Curl_easy *data, + const struct content_encoding *ce_handler, + int order); + +void Curl_client_free_writer(struct Curl_easy *data, + struct contenc_writer *writer); + +CURLcode Curl_client_add_writer(struct Curl_easy *data, + struct contenc_writer *writer); + + /* internal read-function, does plain socket, SSL and krb4 */ CURLcode Curl_read(struct Curl_easy *data, curl_socket_t sockfd, char *buf, size_t buffersize, diff --git a/lib/setopt.c b/lib/setopt.c index 2cef1b3..0d399ad 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -2076,7 +2076,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) else #endif result = CURLE_NOT_BUILT_IN; - break; + break; case CURLOPT_PINNEDPUBLICKEY: /* * Set pinned public key for SSL connection. diff --git a/lib/sigpipe.h b/lib/sigpipe.h index 48761ad..9b29403 100644 --- a/lib/sigpipe.h +++ b/lib/sigpipe.h @@ -25,7 +25,7 @@ ***************************************************************************/ #include "curl_setup.h" -#if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) && \ +#if defined(HAVE_SIGACTION) && \ (defined(USE_OPENSSL) || defined(USE_MBEDTLS) || defined(USE_WOLFSSL)) #include <signal.h> @@ -1049,7 +1049,12 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done) } data->req.bytecount += len; data->req.offset += len; - Curl_pgrsSetDownloadCounter(data, data->req.bytecount); + 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/lib/socks.c b/lib/socks.c index c492d66..a7b5ab0 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -587,9 +587,9 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ if(!socks5_resolve_local && hostname_len > 255) { - infof(data, "SOCKS5: server resolving disabled for hostnames of " - "length > 255 [actual len=%zu]", hostname_len); - socks5_resolve_local = TRUE; + failf(data, "SOCKS5: the destination hostname is too long to be " + "resolved remotely by the proxy."); + return CURLPX_LONG_HOSTNAME; } if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) @@ -903,7 +903,7 @@ CONNECT_RESOLVE_REMOTE: } else { socksreq[len++] = 3; - socksreq[len++] = (char) hostname_len; /* one byte address length */ + socksreq[len++] = (unsigned char) hostname_len; /* one byte length */ memcpy(&socksreq[len], sx->hostname, hostname_len); /* w/o NULL */ len += hostname_len; } diff --git a/lib/telnet.c b/lib/telnet.c index 850f88c..836e255 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -1570,8 +1570,9 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } total_dl += nread; - Curl_pgrsSetDownloadCounter(data, total_dl); - result = telrcv(data, (unsigned char *)buf, nread); + result = Curl_pgrsSetDownloadCounter(data, total_dl); + if(!result) + result = telrcv(data, (unsigned char *)buf, nread); if(result) { keepon = FALSE; break; @@ -1141,12 +1141,15 @@ 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; } - k->bytecount += state->rbytes-4; - Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount); } break; case TFTP_EVENT_ERROR: diff --git a/lib/timeval.c b/lib/timeval.c index 2de79be..026d9d1 100644 --- a/lib/timeval.c +++ b/lib/timeval.c @@ -210,6 +210,20 @@ timediff_t Curl_timediff(struct curltime newer, struct curltime older) } /* + * Returns: time difference in number of milliseconds, rounded up. + * For too large diffs it returns max value. + */ +timediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older) +{ + timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec; + if(diff >= (TIMEDIFF_T_MAX/1000)) + return TIMEDIFF_T_MAX; + else if(diff <= (TIMEDIFF_T_MIN/1000)) + return TIMEDIFF_T_MIN; + return diff * 1000 + (newer.tv_usec - older.tv_usec + 999)/1000; +} + +/* * Returns: time difference in number of microseconds. For too large diffs it * returns max value. */ diff --git a/lib/timeval.h b/lib/timeval.h index 92e484a..33dfb5b 100644 --- a/lib/timeval.h +++ b/lib/timeval.h @@ -36,16 +36,24 @@ struct curltime { struct curltime Curl_now(void); /* - * Make sure that the first argument (t1) is the more recent time and t2 is - * the older time, as otherwise you get a weird negative time-diff back... + * Make sure that the first argument (newer) is the more recent time and older + * is the older time, as otherwise you get a weird negative time-diff back... * * Returns: the time difference in number of milliseconds. */ -timediff_t Curl_timediff(struct curltime t1, struct curltime t2); +timediff_t Curl_timediff(struct curltime newer, struct curltime older); /* - * Make sure that the first argument (t1) is the more recent time and t2 is - * the older time, as otherwise you get a weird negative time-diff back... + * Make sure that the first argument (newer) is the more recent time and older + * is the older time, as otherwise you get a weird negative time-diff back... + * + * Returns: the time difference in number of milliseconds, rounded up. + */ +timediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older); + +/* + * Make sure that the first argument (newer) is the more recent time and older + * is the older time, as otherwise you get a weird negative time-diff back... * * Returns: the time difference in number of microseconds. */ diff --git a/lib/transfer.c b/lib/transfer.c index d0602b8..6886764 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -40,9 +40,7 @@ #ifdef HAVE_SYS_IOCTL_H #include <sys/ioctl.h> #endif -#ifdef HAVE_SIGNAL_H #include <signal.h> -#endif #ifdef HAVE_SYS_PARAM_H #include <sys/param.h> @@ -671,7 +669,9 @@ static CURLcode readwrite_data(struct Curl_easy *data, k->bytecount += nread; max_recv -= nread; - Curl_pgrsSetDownloadCounter(data, k->bytecount); + result = Curl_pgrsSetDownloadCounter(data, k->bytecount); + if(result) + goto out; if(!k->chunk && (nread || k->badheader || is_empty_data)) { /* If this is chunky transfer, it was already written */ @@ -700,19 +700,15 @@ static CURLcode readwrite_data(struct Curl_easy *data, in http_chunks.c. Make sure that ALL_CONTENT_ENCODINGS contains all the encodings handled here. */ - if(data->set.http_ce_skip || !k->writer_stack) { - if(!k->ignorebody && nread) { + if(!k->ignorebody && nread) { #ifndef CURL_DISABLE_POP3 - if(conn->handler->protocol & PROTO_FAMILY_POP3) - result = Curl_pop3_write(data, k->str, nread); - else + 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); - } + result = Curl_client_write(data, CLIENTWRITE_BODY, k->str, + nread); } - else if(!k->ignorebody && nread) - result = Curl_unencode_write(data, k->writer_stack, k->str, nread); } k->badheader = HEADER_NORMAL; /* taken care of now */ @@ -1050,6 +1046,19 @@ static CURLcode readwrite_upload(struct Curl_easy *data, return CURLE_OK; } +static int select_bits_paused(struct Curl_easy *data, int select_bits) +{ + /* See issue #11982: we really need to be careful not to progress + * a transfer direction when that direction is paused. Not all parts + * of our state machine are handling PAUSED transfers correctly. So, we + * do not want to go there. + * NOTE: we are only interested in PAUSE, not HOLD. */ + return (((select_bits & CURL_CSELECT_IN) && + (data->req.keepon & KEEP_RECV_PAUSE)) || + ((select_bits & CURL_CSELECT_OUT) && + (data->req.keepon & KEEP_SEND_PAUSE))); +} + /* * Curl_readwrite() is the low-level function to be called when data is to * be read and written to/from the connection. @@ -1068,12 +1077,20 @@ CURLcode Curl_readwrite(struct connectdata *conn, int didwhat = 0; int select_bits; - if(data->state.dselect_bits) { + if(select_bits_paused(data, data->state.dselect_bits)) { + /* leave the bits unchanged, so they'll tell us what to do when + * this transfer gets unpaused. */ + DEBUGF(infof(data, "readwrite, dselect_bits, early return on PAUSED")); + result = CURLE_OK; + goto out; + } select_bits = data->state.dselect_bits; data->state.dselect_bits = 0; } else if(conn->cselect_bits) { + /* CAVEAT: adding `select_bits_paused()` check here makes test640 hang + * (among others). Which hints at strange state handling in FTP land... */ select_bits = conn->cselect_bits; conn->cselect_bits = 0; } @@ -888,8 +888,8 @@ static bool conn_maxage(struct Curl_easy *data, idletime /= 1000; /* integer seconds is fine */ if(idletime > data->set.maxage_conn) { - infof(data, "Too old connection (%ld seconds idle), disconnect it", - idletime); + infof(data, "Too old connection (%" CURL_FORMAT_TIMEDIFF_T + " seconds idle), disconnect it", idletime); return TRUE; } @@ -898,8 +898,8 @@ static bool conn_maxage(struct Curl_easy *data, if(data->set.maxlifetime_conn && lifetime > data->set.maxlifetime_conn) { infof(data, - "Too old connection (%ld seconds since creation), disconnect it", - lifetime); + "Too old connection (%" CURL_FORMAT_TIMEDIFF_T + " seconds since creation), disconnect it", lifetime); return TRUE; } @@ -1169,7 +1169,7 @@ ConnectionExists(struct Curl_easy *data, 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); + " isn't open enough, can't reuse", check->connection_id); continue; } @@ -2033,13 +2033,13 @@ void Curl_free_request_state(struct Curl_easy *data) { Curl_safefree(data->req.p.http); Curl_safefree(data->req.newurl); - #ifndef CURL_DISABLE_DOH if(data->req.doh) { Curl_close(&data->req.doh->probe[0].easy); Curl_close(&data->req.doh->probe[1].easy); } #endif + Curl_client_cleanup(data); } @@ -2076,7 +2076,6 @@ static char *detect_proxy(struct Curl_easy *data, char proxy_env[128]; const char *protop = conn->handler->scheme; char *envp = proxy_env; - char *prox; #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)data; #endif @@ -2089,7 +2088,7 @@ static char *detect_proxy(struct Curl_easy *data, strcpy(envp, "_proxy"); /* read the protocol proxy: */ - prox = curl_getenv(proxy_env); + proxy = curl_getenv(proxy_env); /* * We don't try the uppercase version of HTTP_PROXY because of @@ -2103,23 +2102,35 @@ static char *detect_proxy(struct Curl_easy *data, * This can cause 'internal' http/ftp requests to be * arbitrarily redirected by any external attacker. */ - if(!prox && !strcasecompare("http_proxy", proxy_env)) { + if(!proxy && !strcasecompare("http_proxy", proxy_env)) { /* There was no lowercase variable, try the uppercase version: */ Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env)); - prox = curl_getenv(proxy_env); + proxy = curl_getenv(proxy_env); } envp = proxy_env; - if(prox) { - proxy = prox; /* use this */ - } - else { - envp = (char *)"all_proxy"; - proxy = curl_getenv(envp); /* default proxy to use */ + if(!proxy) { +#ifdef USE_WEBSOCKETS + /* websocket proxy fallbacks */ + if(strcasecompare("ws_proxy", proxy_env)) { + proxy = curl_getenv("http_proxy"); + } + else if(strcasecompare("wss_proxy", proxy_env)) { + proxy = curl_getenv("https_proxy"); + if(!proxy) + proxy = curl_getenv("HTTPS_PROXY"); + } if(!proxy) { - envp = (char *)"ALL_PROXY"; - proxy = curl_getenv(envp); +#endif + envp = (char *)"all_proxy"; + proxy = curl_getenv(envp); /* default proxy to use */ + if(!proxy) { + envp = (char *)"ALL_PROXY"; + proxy = curl_getenv(envp); + } +#ifdef USE_WEBSOCKETS } +#endif } if(proxy) infof(data, "Uses proxy env variable %s == '%s'", envp, proxy); @@ -2719,7 +2730,9 @@ static CURLcode override_login(struct Curl_easy *data, data->set.str[STRING_NETRC_FILE]); if(ret > 0) { infof(data, "Couldn't find host %s in the %s file; using defaults", - conn->host.name, data->set.str[STRING_NETRC_FILE]); + conn->host.name, + (data->set.str[STRING_NETRC_FILE] ? + data->set.str[STRING_NETRC_FILE] : ".netrc")); } else if(ret < 0) { failf(data, ".netrc parser error"); @@ -3214,8 +3227,8 @@ static CURLcode resolve_host(struct Curl_easy *data, if(rc == CURLRESOLV_PENDING) *async = TRUE; else if(rc == CURLRESOLV_TIMEDOUT) { - failf(data, "Failed to resolve host '%s' with timeout after %ld ms", - connhost->dispname, + failf(data, "Failed to resolve host '%s' with timeout after %" + CURL_FORMAT_TIMEDIFF_T " ms", connhost->dispname, Curl_timediff(Curl_now(), data->progress.t_startsingle)); return CURLE_OPERATION_TIMEDOUT; } diff --git a/lib/urlapi.c b/lib/urlapi.c index 80299e7..4efab61 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -100,7 +100,7 @@ static void free_urlhandle(struct Curl_URL *u) /* * Find the separator at the end of the host name, or the '?' in cases like - * http://www.url.com?id=2380 + * http://www.example.com?id=2380 */ static const char *find_host_sep(const char *url) { @@ -338,7 +338,7 @@ static char *concat_url(char *base, const char *relurl) pathsep = strchr(protsep, '/'); if(pathsep) { /* When people use badly formatted URLs, such as - "http://www.url.com?dir=/home/daniel" we must not use the first + "http://www.example.com?dir=/home/daniel" we must not use the first slash, if there's a ?-letter before it! */ char *sep = strchr(protsep, '?'); if(sep && (sep < pathsep)) @@ -347,9 +347,9 @@ static char *concat_url(char *base, const char *relurl) } else { /* There was no slash. Now, since we might be operating on a badly - formatted URL, such as "http://www.url.com?id=2380" which doesn't - use a slash separator as it is supposed to, we need to check for a - ?-letter as well! */ + formatted URL, such as "http://www.example.com?id=2380" which + doesn't use a slash separator as it is supposed to, we need to check + for a ?-letter as well! */ pathsep = strchr(protsep, '?'); if(pathsep) *pathsep = 0; @@ -1865,7 +1865,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, if(result) return CURLUE_OUT_OF_MEMORY; } - else if(Curl_isunreserved(*i) || + else if(ISUNRESERVED(*i) || ((*i == '/') && urlskipslash) || ((*i == '=') && equalsencode)) { if((*i == '=') && equalsencode) diff --git a/lib/urldata.h b/lib/urldata.h index 4bfb3b4..dff26e6 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -640,7 +640,9 @@ struct SingleRequest { curl_off_t pendingheader; /* this many bytes left to send is actually header and not body */ struct curltime start; /* transfer started at this time */ - unsigned int headerbytecount; /* only count received headers */ + unsigned int headerbytecount; /* received server headers (not CONNECT + headers) */ + unsigned int allheadercount; /* all received headers (server + CONNECT) */ unsigned int deductheadercount; /* this amount of bytes doesn't count when we check if anything has been transferred at the end of a connection. We use this @@ -1260,6 +1262,7 @@ struct tempbuf { struct dynbuf b; int type; /* type of the 'tempwrite' buffer as a bitmask that is used with Curl_client_write() */ + BIT(paused_body); /* if PAUSE happened before/during BODY write */ }; /* Timers */ @@ -1947,7 +1950,7 @@ struct Curl_easy { other using the same cache. For easier tracking in log output. This may wrap around after LONG_MAX to 0 again, so it - has no uniqueness guarantuee for very large processings. */ + has no uniqueness guarantee for very large processings. */ curl_off_t id; /* first, two fields for the linked list of these */ @@ -2010,6 +2013,10 @@ 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/lib/vauth/cleartext.c b/lib/vauth/cleartext.c index c651fc5..972a874 100644 --- a/lib/vauth/cleartext.c +++ b/lib/vauth/cleartext.c @@ -35,7 +35,6 @@ #include "urldata.h" #include "vauth/vauth.h" -#include "curl_md5.h" #include "warnless.h" #include "strtok.h" #include "sendf.h" diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 03e911d..7d681e5 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -30,7 +30,7 @@ #ifdef USE_OPENSSL #include <openssl/err.h> -#ifdef OPENSSL_IS_BORINGSSL +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) #include <ngtcp2/ngtcp2_crypto_boringssl.h> #else #include <ngtcp2/ngtcp2_crypto_quictls.h> @@ -407,7 +407,7 @@ static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx, goto out; } -#ifdef OPENSSL_IS_BORINGSSL +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) if(ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx) != 0) { failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed"); goto out; @@ -421,22 +421,24 @@ static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx, SSL_CTX_set_default_verify_paths(ssl_ctx); -#ifdef OPENSSL_IS_BORINGSSL - if(SSL_CTX_set1_curves_list(ssl_ctx, QUIC_GROUPS) != 1) { - failf(data, "SSL_CTX_set1_curves_list failed"); - goto out; - } -#else - if(SSL_CTX_set_ciphersuites(ssl_ctx, QUIC_CIPHERS) != 1) { - char error_buffer[256]; - ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer)); - failf(data, "SSL_CTX_set_ciphersuites: %s", error_buffer); - goto out; + { + const char *curves = conn->ssl_config.curves ? + conn->ssl_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; + } } - if(SSL_CTX_set1_groups_list(ssl_ctx, QUIC_GROUPS) != 1) { - failf(data, "SSL_CTX_set1_groups_list failed"); - goto out; +#ifndef OPENSSL_IS_BORINGSSL + { + const char *ciphers13 = conn->ssl_config.cipher_list13 ? + conn->ssl_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; + } + infof(data, "QUIC cipher selection: %s", ciphers13); } #endif @@ -616,15 +618,19 @@ static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx, wolfSSL_CTX_set_default_verify_paths(ssl_ctx); - if(wolfSSL_CTX_set_cipher_list(ssl_ctx, QUIC_CIPHERS) != 1) { + if(wolfSSL_CTX_set_cipher_list(ssl_ctx, conn->ssl_config.cipher_list13 ? + conn->ssl_config.cipher_list13 : + QUIC_CIPHERS) != 1) { char error_buffer[256]; ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer)); - failf(data, "wolfSSL_CTX_set_cipher_list: %s", error_buffer); + failf(data, "wolfSSL failed to set ciphers: %s", error_buffer); goto out; } - if(wolfSSL_CTX_set1_groups_list(ssl_ctx, (char *)QUIC_GROUPS) != 1) { - failf(data, "SSL_CTX_set1_groups_list failed"); + if(wolfSSL_CTX_set1_groups_list(ssl_ctx, conn->ssl_config.curves ? + conn->ssl_config.curves : + (char *)QUIC_GROUPS) != 1) { + failf(data, "wolfSSL failed to set curves"); goto out; } @@ -644,10 +650,13 @@ static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx, const char * const ssl_capath = conn->ssl_config.CApath; wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); - if(conn->ssl_config.CAfile || conn->ssl_config.CApath) { + if(ssl_cafile || ssl_capath) { /* tell wolfSSL where to find CA certificates that are used to verify the server's certificate. */ - if(!wolfSSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) { + int rc = + wolfSSL_CTX_load_verify_locations_ex(ssl_ctx, ssl_cafile, ssl_capath, + WOLFSSL_LOAD_FLAG_IGNORE_ERR); + if(SSL_SUCCESS != rc) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:" " CAfile: %s CApath: %s", diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 3598de1..3f5d327 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -149,8 +149,8 @@ static CURLcode quic_x509_store_setup(struct Curl_cfilter *cf, SSL_CTX_set_verify(ctx->sslctx, SSL_VERIFY_PEER, NULL); /* tell OpenSSL where to find CA certificates that are used to verify the server's certificate. */ - if(!SSL_CTX_load_verify_locations( - ctx->sslctx, ssl_cafile, ssl_capath)) { + if(!SSL_CTX_load_verify_locations(ctx->sslctx, ssl_cafile, + ssl_capath)) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:" " CAfile: %s CApath: %s", @@ -165,7 +165,7 @@ static CURLcode quic_x509_store_setup(struct Curl_cfilter *cf, else { /* verifying the peer without any CA certificates won't work so use openssl's built-in default as fallback */ - SSL_CTX_set_default_verify_paths(ssl_ctx); + SSL_CTX_set_default_verify_paths(ctx->sslctx); } #endif } @@ -178,6 +178,8 @@ 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; DEBUGASSERT(!ctx->sslctx); ctx->sslctx = SSL_CTX_new(TLS_method()); @@ -196,6 +198,11 @@ 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); + return CURLE_SSL_CIPHER; + } + ctx->ssl = SSL_new(ctx->sslctx); if(!ctx->ssl) return CURLE_QUIC_CONNECT_ERROR; diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index dea0084..b0f49d6 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -2567,6 +2567,12 @@ static ssize_t sftp_send(struct Curl_easy *data, int sockindex, struct connectdata *conn = data->conn; (void)sockindex; + /* limit the writes to the maximum specified in Section 3 of + * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02 + */ + if(len > 32768) + len = 32768; + nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len); myssh_block2waitfor(conn, FALSE); @@ -2654,7 +2660,7 @@ static void sftp_quote(struct Curl_easy *data) /* if a command starts with an asterisk, which a legal SFTP command never can, the command will be allowed to fail without it causing any aborts or cancels etc. It will cause libcurl to act as if the command - is successful, whatever the server reponds. */ + is successful, whatever the server responds. */ if(cmd[0] == '*') { cmd++; @@ -2828,7 +2834,7 @@ static void sftp_quote_stat(struct Curl_easy *data) /* if a command starts with an asterisk, which a legal SFTP command never can, the command will be allowed to fail without it causing any aborts or cancels etc. It will cause libcurl to act as if the command - is successful, whatever the server reponds. */ + is successful, whatever the server responds. */ if(cmd[0] == '*') { cmd++; diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 37040b4..f539b39 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1178,8 +1178,16 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) } else { char *err_msg = NULL; - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); + char unknown[] = "Reason unknown (-1)"; + if(rc == -1) { + /* No error message has been set and the last set error message, if + any, is from a previous error so ignore it. #11837 */ + err_msg = unknown; + } + else { + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + } infof(data, "SSH public key authentication failed: %s", err_msg); state(data, SSH_AUTH_PASS_INIT); rc = 0; /* clear rc and continue */ @@ -1495,7 +1503,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) /* if a command starts with an asterisk, which a legal SFTP command never can, the command will be allowed to fail without it causing any aborts or cancels etc. It will cause libcurl to act as if the command - is successful, whatever the server reponds. */ + is successful, whatever the server responds. */ if(cmd[0] == '*') { cmd++; @@ -1691,7 +1699,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) /* if a command starts with an asterisk, which a legal SFTP command never can, the command will be allowed to fail without it causing any aborts or cancels etc. It will cause libcurl to act as if the command - is successful, whatever the server reponds. */ + is successful, whatever the server responds. */ if(cmd[0] == '*') { cmd++; diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c index 306d299..39cee50 100644 --- a/lib/vssh/wolfssh.c +++ b/lib/vssh/wolfssh.c @@ -1168,6 +1168,7 @@ CURLcode Curl_ssh_init(void) } void Curl_ssh_cleanup(void) { + (void)wolfSSH_Cleanup(); } #endif /* USE_WOLFSSH */ diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index e483469..c538a96 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -1473,7 +1473,6 @@ static int gtls_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); struct gtls_ssl_backend_data *backend = (struct gtls_ssl_backend_data *)connssl->backend; int retval = 0; @@ -1536,8 +1535,11 @@ static int gtls_shutdown(struct Curl_cfilter *cf, gnutls_certificate_free_credentials(backend->gtls.cred); #ifdef USE_GNUTLS_SRP - if(ssl_config->primary.username) - gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred); + { + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + if(ssl_config->primary.username) + gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred); + } #endif backend->gtls.cred = NULL; diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index f45636e..2f994d7 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -156,7 +156,8 @@ static void mbed_debug(void *context, int level, const char *f_name, #else #endif -static int bio_cf_write(void *bio, const unsigned char *buf, size_t blen) +static int mbedtls_bio_cf_write(void *bio, + const unsigned char *buf, size_t blen) { struct Curl_cfilter *cf = bio; struct Curl_easy *data = CF_DATA_CURRENT(cf); @@ -165,7 +166,7 @@ static int bio_cf_write(void *bio, const unsigned char *buf, size_t blen) DEBUGASSERT(data); nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result); - CURL_TRC_CF(data, cf, "bio_cf_out_write(len=%zu) -> %zd, err=%d", + CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %zd, err=%d", blen, nwritten, result); if(nwritten < 0 && CURLE_AGAIN == result) { nwritten = MBEDTLS_ERR_SSL_WANT_WRITE; @@ -173,7 +174,7 @@ static int bio_cf_write(void *bio, const unsigned char *buf, size_t blen) return (int)nwritten; } -static int bio_cf_read(void *bio, unsigned char *buf, size_t blen) +static int mbedtls_bio_cf_read(void *bio, unsigned char *buf, size_t blen) { struct Curl_cfilter *cf = bio; struct Curl_easy *data = CF_DATA_CURRENT(cf); @@ -186,7 +187,7 @@ static int bio_cf_read(void *bio, unsigned char *buf, size_t blen) return 0; nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &result); - CURL_TRC_CF(data, cf, "bio_cf_in_read(len=%zu) -> %zd, err=%d", + CURL_TRC_CF(data, cf, "mbedtls_bio_cf_in_read(len=%zu) -> %zd, err=%d", blen, nread, result); if(nread < 0 && CURLE_AGAIN == result) { nread = MBEDTLS_ERR_SSL_WANT_READ; @@ -591,7 +592,9 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random, &backend->ctr_drbg); - mbedtls_ssl_set_bio(&backend->ssl, cf, bio_cf_write, bio_cf_read, + mbedtls_ssl_set_bio(&backend->ssl, cf, + mbedtls_bio_cf_write, + mbedtls_bio_cf_read, NULL /* rev_timeout() */); mbedtls_ssl_conf_ciphersuites(&backend->config, diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index a12e712..9f9c8d1 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -466,7 +466,9 @@ CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl) X509_get0_signature(&psig, &sigalg, x); if(sigalg) { - i2a_ASN1_OBJECT(mem, sigalg->algorithm); + const ASN1_OBJECT *sigalgoid = NULL; + X509_ALGOR_get0(&sigalgoid, NULL, NULL, sigalg); + i2a_ASN1_OBJECT(mem, sigalgoid); push_certinfo("Signature Algorithm", i); } @@ -661,7 +663,7 @@ CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl) #define BIO_set_shutdown(x,v) ((x)->shutdown=(v)) #endif /* USE_PRE_1_1_API */ -static int bio_cf_create(BIO *bio) +static int ossl_bio_cf_create(BIO *bio) { BIO_set_shutdown(bio, 1); BIO_set_init(bio, 1); @@ -672,14 +674,14 @@ static int bio_cf_create(BIO *bio) return 1; } -static int bio_cf_destroy(BIO *bio) +static int ossl_bio_cf_destroy(BIO *bio) { if(!bio) return 0; return 1; } -static long bio_cf_ctrl(BIO *bio, int cmd, long num, void *ptr) +static long ossl_bio_cf_ctrl(BIO *bio, int cmd, long num, void *ptr) { struct Curl_cfilter *cf = BIO_get_data(bio); long ret = 1; @@ -713,7 +715,7 @@ static long bio_cf_ctrl(BIO *bio, int cmd, long num, void *ptr) return ret; } -static int bio_cf_out_write(BIO *bio, const char *buf, int blen) +static int ossl_bio_cf_out_write(BIO *bio, const char *buf, int blen) { struct Curl_cfilter *cf = BIO_get_data(bio); struct ssl_connect_data *connssl = cf->ctx; @@ -725,7 +727,7 @@ static int bio_cf_out_write(BIO *bio, const char *buf, int blen) DEBUGASSERT(data); nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result); - CURL_TRC_CF(data, cf, "bio_cf_out_write(len=%d) -> %d, err=%d", + CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, err=%d", blen, (int)nwritten, result); BIO_clear_retry_flags(bio); backend->io_result = result; @@ -736,7 +738,7 @@ static int bio_cf_out_write(BIO *bio, const char *buf, int blen) return (int)nwritten; } -static int bio_cf_in_read(BIO *bio, char *buf, int blen) +static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen) { struct Curl_cfilter *cf = BIO_get_data(bio); struct ssl_connect_data *connssl = cf->ctx; @@ -752,7 +754,7 @@ static int bio_cf_in_read(BIO *bio, char *buf, int blen) return 0; nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); - CURL_TRC_CF(data, cf, "bio_cf_in_read(len=%d) -> %d, err=%d", + CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, err=%d", blen, (int)nread, result); BIO_clear_retry_flags(bio); backend->io_result = result; @@ -777,42 +779,42 @@ static int bio_cf_in_read(BIO *bio, char *buf, int blen) #if USE_PRE_1_1_API -static BIO_METHOD bio_cf_meth_1_0 = { +static BIO_METHOD ossl_bio_cf_meth_1_0 = { BIO_TYPE_MEM, "OpenSSL CF BIO", - bio_cf_out_write, - bio_cf_in_read, + ossl_bio_cf_out_write, + ossl_bio_cf_in_read, NULL, /* puts is never called */ NULL, /* gets is never called */ - bio_cf_ctrl, - bio_cf_create, - bio_cf_destroy, + ossl_bio_cf_ctrl, + ossl_bio_cf_create, + ossl_bio_cf_destroy, NULL }; -static BIO_METHOD *bio_cf_method_create(void) +static BIO_METHOD *ossl_bio_cf_method_create(void) { - return &bio_cf_meth_1_0; + return &ossl_bio_cf_meth_1_0; } -#define bio_cf_method_free(m) Curl_nop_stmt +#define ossl_bio_cf_method_free(m) Curl_nop_stmt #else -static BIO_METHOD *bio_cf_method_create(void) +static BIO_METHOD *ossl_bio_cf_method_create(void) { BIO_METHOD *m = BIO_meth_new(BIO_TYPE_MEM, "OpenSSL CF BIO"); if(m) { - BIO_meth_set_write(m, &bio_cf_out_write); - BIO_meth_set_read(m, &bio_cf_in_read); - BIO_meth_set_ctrl(m, &bio_cf_ctrl); - BIO_meth_set_create(m, &bio_cf_create); - BIO_meth_set_destroy(m, &bio_cf_destroy); + BIO_meth_set_write(m, &ossl_bio_cf_out_write); + BIO_meth_set_read(m, &ossl_bio_cf_in_read); + BIO_meth_set_ctrl(m, &ossl_bio_cf_ctrl); + BIO_meth_set_create(m, &ossl_bio_cf_create); + BIO_meth_set_destroy(m, &ossl_bio_cf_destroy); } return m; } -static void bio_cf_method_free(BIO_METHOD *m) +static void ossl_bio_cf_method_free(BIO_METHOD *m) { if(m) BIO_meth_free(m); @@ -1551,11 +1553,9 @@ fail: UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL())); UI_method_set_reader(ui_method, ssl_ui_reader); UI_method_set_writer(ui_method, ssl_ui_writer); - /* the typecast below was added to please mingw32 */ - priv_key = (EVP_PKEY *) - ENGINE_load_private_key(data->state.engine, key_file, - ui_method, - key_passwd); + priv_key = ENGINE_load_private_key(data->state.engine, key_file, + ui_method, + key_passwd); UI_destroy_method(ui_method); if(!priv_key) { failf(data, "failed to load private key from crypto engine"); @@ -1878,15 +1878,45 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data) if(backend->handle) { if(cf->next && cf->next->connected) { - char buf[32]; + char buf[1024]; + int nread, err; + long sslerr; + /* Maybe the server has already sent a close notify alert. Read it to avoid an RST on the TCP connection. */ (void)SSL_read(backend->handle, buf, (int)sizeof(buf)); - - (void)SSL_shutdown(backend->handle); - ERR_clear_error(); + if(SSL_shutdown(backend->handle) == 1) { + CURL_TRC_CF(data, cf, "SSL shutdown finished"); + } + else { + nread = SSL_read(backend->handle, buf, (int)sizeof(buf)); + err = SSL_get_error(backend->handle, nread); + switch(err) { + case SSL_ERROR_NONE: /* this is not an error */ + case SSL_ERROR_ZERO_RETURN: /* no more data */ + CURL_TRC_CF(data, cf, "SSL shutdown, EOF from server"); + break; + case SSL_ERROR_WANT_READ: + /* SSL has send its notify and now wants to read the reply + * from the server. We are not really interested in that. */ + CURL_TRC_CF(data, cf, "SSL shutdown sent"); + break; + case SSL_ERROR_WANT_WRITE: + CURL_TRC_CF(data, cf, "SSL shutdown send blocked"); + break; + default: + sslerr = ERR_get_error(); + CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s', errno %d", + (sslerr ? + ossl_strerror(sslerr, buf, sizeof(buf)) : + SSL_ERROR_to_str(err)), + SOCKERRNO); + break; + } + } + ERR_clear_error(); SSL_set_connect_state(backend->handle); } @@ -1899,7 +1929,7 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data) backend->x509_store_setup = FALSE; } if(backend->bio_method) { - bio_cf_method_free(backend->bio_method); + ossl_bio_cf_method_free(backend->bio_method); backend->bio_method = NULL; } } @@ -3789,7 +3819,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, Curl_ssl_sessionid_unlock(data); } - backend->bio_method = bio_cf_method_create(); + backend->bio_method = ossl_bio_cf_method_create(); if(!backend->bio_method) return CURLE_OUT_OF_MEMORY; bio = BIO_new(backend->bio_method); diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index f6a5d44..410a5c4 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -68,22 +68,6 @@ # define HAS_ALPN 1 #endif -#ifndef UNISP_NAME_A -#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider" -#endif - -#ifndef UNISP_NAME_W -#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider" -#endif - -#ifndef UNISP_NAME -#ifdef UNICODE -#define UNISP_NAME UNISP_NAME_W -#else -#define UNISP_NAME UNISP_NAME_A -#endif -#endif - #ifndef BCRYPT_CHACHA20_POLY1305_ALGORITHM #define BCRYPT_CHACHA20_POLY1305_ALGORITHM L"CHACHA20_POLY1305" #endif @@ -108,13 +92,6 @@ #define BCRYPT_SHA384_ALGORITHM L"SHA384" #endif -/* Workaround broken compilers like MinGW. - Return the number of elements in a statically sized array. -*/ -#ifndef ARRAYSIZE -#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) -#endif - #ifdef HAS_CLIENT_CERT_PATH #ifdef UNICODE #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W @@ -123,18 +100,6 @@ #endif #endif -#ifndef SP_PROT_SSL2_CLIENT -#define SP_PROT_SSL2_CLIENT 0x00000008 -#endif - -#ifndef SP_PROT_SSL3_CLIENT -#define SP_PROT_SSL3_CLIENT 0x00000008 -#endif - -#ifndef SP_PROT_TLS1_CLIENT -#define SP_PROT_TLS1_CLIENT 0x00000080 -#endif - #ifndef SP_PROT_TLS1_0_CLIENT #define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT #endif @@ -175,12 +140,6 @@ # define CALG_SHA_256 0x0000800c #endif -/* Work around typo in classic MinGW's w32api up to version 5.0, - see https://osdn.net/projects/mingw/ticket/38391 */ -#if !defined(ALG_CLASS_DHASH) && defined(ALG_CLASS_HASH) -#define ALG_CLASS_DHASH ALG_CLASS_HASH -#endif - #ifndef PKCS12_NO_PERSIST_KEY #define PKCS12_NO_PERSIST_KEY 0x00008000 #endif @@ -769,7 +728,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, } #endif - /* allocate memory for the re-usable credential handle */ + /* allocate memory for the reusable credential handle */ backend->cred = (struct Curl_schannel_cred *) calloc(1, sizeof(struct Curl_schannel_cred)); if(!backend->cred) { @@ -1169,7 +1128,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) backend->cred = NULL; - /* check for an existing re-usable credential handle */ + /* check for an existing reusable credential handle */ if(ssl_config->primary.sessionid) { Curl_ssl_sessionid_lock(data); if(!Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)) { @@ -2752,8 +2711,7 @@ static void schannel_checksum(const unsigned char *input, if(!CryptCreateHash(hProv, algId, 0, 0, &hHash)) break; /* failed */ - /* workaround for original MinGW, should be (const BYTE*) */ - if(!CryptHashData(hHash, (BYTE*)input, (DWORD)inputlen, 0)) + if(!CryptHashData(hHash, input, (DWORD)inputlen, 0)) break; /* failed */ /* get hash size */ diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h index be23567..b26334b 100644 --- a/lib/vtls/schannel.h +++ b/lib/vtls/schannel.h @@ -68,7 +68,7 @@ * BoringSSL's <openssl/x509.h>: So just undefine those defines here * (and only here). */ -#if defined(HAVE_BORINGSSL) || defined(OPENSSL_IS_BORINGSSL) +#if defined(OPENSSL_IS_BORINGSSL) # undef X509_NAME # undef X509_CERT_PAIR # undef X509_EXTENSIONS diff --git a/lib/vtls/schannel_int.h b/lib/vtls/schannel_int.h index edb20bc..a128e04 100644 --- a/lib/vtls/schannel_int.h +++ b/lib/vtls/schannel_int.h @@ -28,15 +28,9 @@ #ifdef USE_SCHANNEL -#ifdef __MINGW32__ -#ifdef __MINGW64_VERSION_MAJOR +#if defined(__MINGW32__) || defined(CERT_CHAIN_REVOCATION_CHECK_CHAIN) #define HAS_MANUAL_VERIFY_API #endif -#else -#ifdef CERT_CHAIN_REVOCATION_CHECK_CHAIN -#define HAS_MANUAL_VERIFY_API -#endif -#endif #if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) \ && !defined(DISABLE_SCHANNEL_CLIENT_CERT) @@ -60,41 +54,6 @@ #endif -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -/* Original mingw is missing CERT structs or they're disabled. - Refer to w32api-5.0.2-mingw32-dev\include\wincrypt.h. */ - -/* !checksrc! disable TYPEDEFSTRUCT 4 */ -typedef struct _CERT_OTHER_NAME { - LPSTR pszObjId; - CRYPT_OBJID_BLOB Value; -} CERT_OTHER_NAME, *PCERT_OTHER_NAME; - -typedef struct _CERT_ALT_NAME_ENTRY { - DWORD dwAltNameChoice; - union { - PCERT_OTHER_NAME pOtherName; - LPWSTR pwszRfc822Name; - LPWSTR pwszDNSName; - CERT_NAME_BLOB DirectoryName; - LPWSTR pwszURL; - CRYPT_DATA_BLOB IPAddress; - LPSTR pszRegisteredID; - }; -} CERT_ALT_NAME_ENTRY, *PCERT_ALT_NAME_ENTRY; - -typedef struct _CERT_ALT_NAME_INFO { - DWORD cAltEntry; - PCERT_ALT_NAME_ENTRY rgAltEntry; -} CERT_ALT_NAME_INFO, *PCERT_ALT_NAME_INFO; - -typedef struct _CRYPT_DECODE_PARA { - DWORD cbSize; - PFN_CRYPT_ALLOC pfnAlloc; - PFN_CRYPT_FREE pfnFree; -} CRYPT_DECODE_PARA, *PCRYPT_DECODE_PARA; -#endif - #ifndef SCH_CREDENTIALS_VERSION #define SCH_CREDENTIALS_VERSION 0x00000005 diff --git a/lib/vtls/sectransp.c b/lib/vtls/sectransp.c index e6a114a..3378f76 100644 --- a/lib/vtls/sectransp.c +++ b/lib/vtls/sectransp.c @@ -830,9 +830,9 @@ static const unsigned char ecDsaSecp384r1SpkiHeader[] = { #endif /* SECTRANSP_PINNEDPUBKEY_V1 */ #endif /* SECTRANSP_PINNEDPUBKEY */ -static OSStatus bio_cf_in_read(SSLConnectionRef connection, - void *buf, - size_t *dataLength) /* IN/OUT */ +static OSStatus sectransp_bio_cf_in_read(SSLConnectionRef connection, + void *buf, + size_t *dataLength) /* IN/OUT */ { struct Curl_cfilter *cf = (struct Curl_cfilter *)connection; struct ssl_connect_data *connssl = cf->ctx; @@ -870,9 +870,9 @@ static OSStatus bio_cf_in_read(SSLConnectionRef connection, return rtn; } -static OSStatus bio_cf_out_write(SSLConnectionRef connection, - const void *buf, - size_t *dataLength) /* IN/OUT */ +static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection, + const void *buf, + size_t *dataLength) /* IN/OUT */ { struct Curl_cfilter *cf = (struct Curl_cfilter *)connection; struct ssl_connect_data *connssl = cf->ctx; @@ -2100,7 +2100,9 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, } } - err = SSLSetIOFuncs(backend->ssl_ctx, bio_cf_in_read, bio_cf_out_write); + err = SSLSetIOFuncs(backend->ssl_ctx, + sectransp_bio_cf_in_read, + sectransp_bio_cf_out_write); if(err != noErr) { failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 38a20e8..494b660 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1494,7 +1494,8 @@ static void ssl_cf_close(struct Curl_cfilter *cf, CF_DATA_SAVE(save, cf, data); cf_close(cf, data); - cf->next->cft->do_close(cf->next, data); + if(cf->next) + cf->next->cft->do_close(cf->next, data); CF_DATA_RESTORE(cf, save); } diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 5f15720..b1384a6 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -229,7 +229,7 @@ static const struct group_name_map gnm[] = { #ifdef USE_BIO_CHAIN -static int bio_cf_create(WOLFSSL_BIO *bio) +static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio) { wolfSSL_BIO_set_shutdown(bio, 1); wolfSSL_BIO_set_init(bio, 1); @@ -237,14 +237,14 @@ static int bio_cf_create(WOLFSSL_BIO *bio) return 1; } -static int bio_cf_destroy(WOLFSSL_BIO *bio) +static int wolfssl_bio_cf_destroy(WOLFSSL_BIO *bio) { if(!bio) return 0; return 1; } -static long bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr) +static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr) { struct Curl_cfilter *cf = BIO_get_data(bio); long ret = 1; @@ -278,7 +278,8 @@ static long bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr) return ret; } -static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen) +static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio, + const char *buf, int blen) { struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio); struct ssl_connect_data *connssl = cf->ctx; @@ -299,7 +300,7 @@ static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen) return (int)nwritten; } -static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) +static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) { struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio); struct ssl_connect_data *connssl = cf->ctx; @@ -323,27 +324,27 @@ static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) return (int)nread; } -static WOLFSSL_BIO_METHOD *bio_cf_method = NULL; +static WOLFSSL_BIO_METHOD *wolfssl_bio_cf_method = NULL; -static void bio_cf_init_methods(void) +static void wolfssl_bio_cf_init_methods(void) { - bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO"); - wolfSSL_BIO_meth_set_write(bio_cf_method, &bio_cf_out_write); - wolfSSL_BIO_meth_set_read(bio_cf_method, &bio_cf_in_read); - wolfSSL_BIO_meth_set_ctrl(bio_cf_method, &bio_cf_ctrl); - wolfSSL_BIO_meth_set_create(bio_cf_method, &bio_cf_create); - wolfSSL_BIO_meth_set_destroy(bio_cf_method, &bio_cf_destroy); + wolfssl_bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO"); + wolfSSL_BIO_meth_set_write(wolfssl_bio_cf_method, &wolfssl_bio_cf_out_write); + wolfSSL_BIO_meth_set_read(wolfssl_bio_cf_method, &wolfssl_bio_cf_in_read); + wolfSSL_BIO_meth_set_ctrl(wolfssl_bio_cf_method, &wolfssl_bio_cf_ctrl); + wolfSSL_BIO_meth_set_create(wolfssl_bio_cf_method, &wolfssl_bio_cf_create); + wolfSSL_BIO_meth_set_destroy(wolfssl_bio_cf_method, &wolfssl_bio_cf_destroy); } -static void bio_cf_free_methods(void) +static void wolfssl_bio_cf_free_methods(void) { - wolfSSL_BIO_meth_free(bio_cf_method); + wolfSSL_BIO_meth_free(wolfssl_bio_cf_method); } #else /* USE_BIO_CHAIN */ -#define bio_cf_init_methods() Curl_nop_stmt -#define bio_cf_free_methods() Curl_nop_stmt +#define wolfssl_bio_cf_init_methods() Curl_nop_stmt +#define wolfssl_bio_cf_free_methods() Curl_nop_stmt #endif /* !USE_BIO_CHAIN */ @@ -361,6 +362,10 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : conn_config->CAfile); + const char * const ssl_capath = conn_config->CApath; WOLFSSL_METHOD* req_method = NULL; #ifdef HAVE_LIBOQS word16 oqsAlg = 0; @@ -541,20 +546,21 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) } #ifndef NO_FILESYSTEM - /* load trusted cacert */ - if(conn_config->CAfile) { - if(1 != wolfSSL_CTX_load_verify_locations(backend->ctx, - conn_config->CAfile, - conn_config->CApath)) { + /* load trusted cacert from file if not blob */ + if(ssl_cafile || ssl_capath) { + int rc = + wolfSSL_CTX_load_verify_locations_ex(backend->ctx, + ssl_cafile, + ssl_capath, + WOLFSSL_LOAD_FLAG_IGNORE_ERR); + if(SSL_SUCCESS != rc) { if(conn_config->verifypeer && !imported_ca_info_blob && !imported_native_ca) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:" " CAfile: %s CApath: %s", - conn_config->CAfile? - conn_config->CAfile: "none", - conn_config->CApath? - conn_config->CApath : "none"); + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); return CURLE_SSL_CACERT_BADFILE; } else { @@ -568,10 +574,8 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) /* Everything is fine. */ infof(data, "successfully set certificate verify locations:"); } - infof(data, " CAfile: %s", - conn_config->CAfile ? conn_config->CAfile : "none"); - infof(data, " CApath: %s", - conn_config->CApath ? conn_config->CApath : "none"); + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); } /* Load the client certificate, and private key */ @@ -720,7 +724,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) { WOLFSSL_BIO *bio; - bio = BIO_new(bio_cf_method); + bio = BIO_new(wolfssl_bio_cf_method); if(!bio) return CURLE_OUT_OF_MEMORY; @@ -1140,14 +1144,14 @@ static int wolfssl_init(void) Curl_tls_keylog_open(); #endif ret = (wolfSSL_Init() == SSL_SUCCESS); - bio_cf_init_methods(); + wolfssl_bio_cf_init_methods(); return ret; } static void wolfssl_cleanup(void) { - bio_cf_free_methods(); + wolfssl_bio_cf_free_methods(); wolfSSL_Cleanup(); #ifdef OPENSSL_EXTRA Curl_tls_keylog_close(); @@ -1378,6 +1382,7 @@ const struct Curl_ssl Curl_ssl_wolfssl = { #ifdef USE_BIO_CHAIN SSLSUPP_HTTPS_PROXY | #endif + SSLSUPP_CA_PATH | SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX, diff --git a/lib/warnless.c b/lib/warnless.c index 65c5ec5..7e077f8 100644 --- a/lib/warnless.c +++ b/lib/warnless.c @@ -384,54 +384,3 @@ ssize_t curlx_write(int fd, const void *buf, size_t count) #endif /* WIN32 */ -#if defined(__INTEL_COMPILER) && defined(__unix__) - -int curlx_FD_ISSET(int fd, fd_set *fdset) -{ - #pragma warning(push) - #pragma warning(disable:1469) /* clobber ignored */ - return FD_ISSET(fd, fdset); - #pragma warning(pop) -} - -void curlx_FD_SET(int fd, fd_set *fdset) -{ - #pragma warning(push) - #pragma warning(disable:1469) /* clobber ignored */ - FD_SET(fd, fdset); - #pragma warning(pop) -} - -void curlx_FD_ZERO(fd_set *fdset) -{ - #pragma warning(push) - #pragma warning(disable:593) /* variable was set but never used */ - FD_ZERO(fdset); - #pragma warning(pop) -} - -unsigned short curlx_htons(unsigned short usnum) -{ -#if (__INTEL_COMPILER == 910) && defined(__i386__) - return (unsigned short)(((usnum << 8) & 0xFF00) | ((usnum >> 8) & 0x00FF)); -#else - #pragma warning(push) - #pragma warning(disable:810) /* conversion may lose significant bits */ - return htons(usnum); - #pragma warning(pop) -#endif -} - -unsigned short curlx_ntohs(unsigned short usnum) -{ -#if (__INTEL_COMPILER == 910) && defined(__i386__) - return (unsigned short)(((usnum << 8) & 0xFF00) | ((usnum >> 8) & 0x00FF)); -#else - #pragma warning(push) - #pragma warning(disable:810) /* conversion may lose significant bits */ - return ntohs(usnum); - #pragma warning(pop) -#endif -} - -#endif /* __INTEL_COMPILER && __unix__ */ |