summaryrefslogtreecommitdiff
path: root/Utilities/cmcurl/lib/url.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/url.c')
-rw-r--r--Utilities/cmcurl/lib/url.c656
1 files changed, 275 insertions, 381 deletions
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index c441ae7165..47fc66aedd 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/url.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -34,10 +34,12 @@
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
+#ifdef HAVE_IPHLPAPI_H
+#include <Iphlpapi.h>
+#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
-
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
@@ -93,6 +95,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "inet_pton.h"
#include "getinfo.h"
#include "urlapi-int.h"
+#include "system_win32.h"
/* And now for the protocols */
#include "ftp.h"
@@ -103,13 +106,12 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "http2.h"
#include "file.h"
#include "curl_ldap.h"
-#include "ssh.h"
+#include "vssh/ssh.h"
#include "imap.h"
#include "url.h"
#include "connect.h"
#include "inet_ntop.h"
#include "http_ntlm.h"
-#include "socks.h"
#include "curl_rtmp.h"
#include "gopher.h"
#include "http_proxy.h"
@@ -126,7 +128,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "memdebug.h"
static void conn_free(struct connectdata *conn);
-static void free_idnconverted_hostname(struct hostname *host);
static unsigned int get_protocol_family(unsigned int protocol);
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
@@ -185,7 +186,7 @@ static const struct Curl_handler * const protocols[] = {
&Curl_handler_tftp,
#endif
-#if defined(USE_SSH)
+#if defined(USE_SSH) && !defined(USE_WOLFSSH)
&Curl_handler_scp,
#endif
@@ -315,13 +316,17 @@ static void up_free(struct Curl_easy *data)
* when curl_easy_perform() is invoked.
*/
-CURLcode Curl_close(struct Curl_easy *data)
+CURLcode Curl_close(struct Curl_easy **datap)
{
struct Curl_multi *m;
+ struct Curl_easy *data;
- if(!data)
+ if(!datap || !*datap)
return CURLE_OK;
+ data = *datap;
+ *datap = NULL;
+
Curl_expire_clear(data); /* shut off timers */
m = data->multi;
@@ -372,9 +377,9 @@ CURLcode Curl_close(struct Curl_easy *data)
Curl_safefree(data->state.buffer);
Curl_safefree(data->state.headerbuff);
Curl_safefree(data->state.ulbuf);
- Curl_flush_cookies(data, 1);
+ Curl_flush_cookies(data, TRUE);
#ifdef USE_ALTSVC
- Curl_altsvc_save(data->asi, data->set.str[STRING_ALTSVC]);
+ Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
Curl_altsvc_cleanup(data->asi);
data->asi = NULL;
#endif
@@ -397,6 +402,12 @@ CURLcode Curl_close(struct Curl_easy *data)
Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
}
+#ifndef CURL_DISABLE_DOH
+ free(data->req.doh.probe[0].serverdoh.memory);
+ free(data->req.doh.probe[1].serverdoh.memory);
+ curl_slist_free_all(data->req.doh.headers);
+#endif
+
/* destruct wildcard structures if it is needed */
Curl_wildcard_dtor(&data->wildcard);
Curl_freeset(data);
@@ -439,7 +450,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->httpreq = HTTPREQ_GET; /* Default HTTP request */
set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
-#ifndef CURL_DISABLE_FILE
+#ifndef CURL_DISABLE_FTP
set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */
@@ -485,9 +496,8 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
define since we internally only use the lower 16 bits for the passed
in bitmask to not conflict with the private bits */
set->allowed_protocols = CURLPROTO_ALL;
- set->redir_protocols = CURLPROTO_ALL & /* All except FILE, SCP and SMB */
- ~(CURLPROTO_FILE | CURLPROTO_SCP | CURLPROTO_SMB |
- CURLPROTO_SMBS);
+ set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP |
+ CURLPROTO_FTPS;
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
/*
@@ -544,7 +554,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
set->maxage_conn = 118;
- set->http09_allowed = TRUE;
+ set->http09_allowed = FALSE;
set->httpversion =
#ifdef USE_NGHTTP2
CURL_HTTP_VERSION_2TLS
@@ -611,8 +621,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->progress.flags |= PGRS_HIDE;
data->state.current_speed = -1; /* init to negative == impossible */
-
- Curl_http2_init_state(&data->state);
}
}
@@ -665,7 +673,7 @@ static void conn_reset_all_postponed_data(struct connectdata *conn)
}
#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
/* Use "do-nothing" macro instead of function when workaround not used */
-#define conn_reset_all_postponed_data(c) do {} WHILE_FALSE
+#define conn_reset_all_postponed_data(c) do {} while(0)
#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
@@ -705,14 +713,14 @@ static void conn_free(struct connectdata *conn)
if(!conn)
return;
- free_idnconverted_hostname(&conn->host);
- free_idnconverted_hostname(&conn->conn_to_host);
- free_idnconverted_hostname(&conn->http_proxy.host);
- free_idnconverted_hostname(&conn->socks_proxy.host);
+ Curl_free_idnconverted_hostname(&conn->host);
+ Curl_free_idnconverted_hostname(&conn->conn_to_host);
+ Curl_free_idnconverted_hostname(&conn->http_proxy.host);
+ Curl_free_idnconverted_hostname(&conn->socks_proxy.host);
Curl_safefree(conn->user);
Curl_safefree(conn->passwd);
- Curl_safefree(conn->oauth_bearer);
+ Curl_safefree(conn->sasl_authzid);
Curl_safefree(conn->options);
Curl_safefree(conn->http_proxy.user);
Curl_safefree(conn->socks_proxy.user);
@@ -873,11 +881,59 @@ proxy_info_matches(const struct proxy_info* data,
return FALSE;
}
+
+static bool
+socks_proxy_info_matches(const struct proxy_info* data,
+ const struct proxy_info* needle)
+{
+ if(!proxy_info_matches(data, needle))
+ return FALSE;
+
+ /* the user information is case-sensitive
+ or at least it is not defined as case-insensitive
+ see https://tools.ietf.org/html/rfc3986#section-3.2.1 */
+ if((data->user == NULL) != (needle->user == NULL))
+ return FALSE;
+ /* curl_strequal does a case insentive comparison, so do not use it here! */
+ if(data->user &&
+ needle->user &&
+ strcmp(data->user, needle->user) != 0)
+ return FALSE;
+ if((data->passwd == NULL) != (needle->passwd == NULL))
+ return FALSE;
+ /* curl_strequal does a case insentive comparison, so do not use it here! */
+ if(data->passwd &&
+ needle->passwd &&
+ strcmp(data->passwd, needle->passwd) != 0)
+ return FALSE;
+ return TRUE;
+}
#else
/* disabled, won't get called */
#define proxy_info_matches(x,y) FALSE
+#define socks_proxy_info_matches(x,y) FALSE
#endif
+/* A connection has to have been idle for a shorter time than 'maxage_conn' to
+ be subject for reuse. The success rate is just too low after this. */
+
+static bool conn_maxage(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct curltime now)
+{
+ if(!conn->data) {
+ timediff_t idletime = Curl_timediff(now, conn->lastused);
+ idletime /= 1000; /* integer seconds is fine */
+
+ if(idletime > data->set.maxage_conn) {
+ infof(data, "Too old connection (%ld seconds), disconnect it\n",
+ idletime);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
/*
* This function checks if the given connection is dead and extracts it from
* the connection cache if so.
@@ -894,7 +950,11 @@ static bool extract_if_dead(struct connectdata *conn,
/* The check for a dead socket makes sense only if the connection isn't in
use */
bool dead;
- if(conn->handler->connection_check) {
+ struct curltime now = Curl_now();
+ if(conn_maxage(data, conn, now)) {
+ dead = TRUE;
+ }
+ else if(conn->handler->connection_check) {
/* The protocol has a special method for checking the state of the
connection. Use it to check if the connection is dead. */
unsigned int state;
@@ -946,7 +1006,8 @@ static int call_extract_if_dead(struct connectdata *conn, void *param)
static void prune_dead_connections(struct Curl_easy *data)
{
struct curltime now = Curl_now();
- time_t elapsed = Curl_timediff(now, data->state.conn_cache->last_cleanup);
+ timediff_t elapsed =
+ Curl_timediff(now, data->state.conn_cache->last_cleanup);
if(elapsed >= 1000L) {
struct prunedead prune;
@@ -961,25 +1022,6 @@ static void prune_dead_connections(struct Curl_easy *data)
}
}
-/* A connection has to have been idle for a shorter time than 'maxage_conn' to
- be subject for reuse. The success rate is just too low after this. */
-
-static bool conn_maxage(struct Curl_easy *data,
- struct connectdata *conn,
- struct curltime now)
-{
- if(!conn->data) {
- timediff_t idletime = Curl_timediff(now, conn->lastused);
- idletime /= 1000; /* integer seconds is fine */
-
- if(idletime/1000 > data->set.maxage_conn) {
- infof(data, "Too old connection (%ld seconds), disconnect it\n",
- idletime);
- return TRUE;
- }
- }
- return FALSE;
-}
/*
* Given one filled in connection struct (named needle), this function should
* detect if there already is one that has all the significant details
@@ -1003,7 +1045,7 @@ ConnectionExists(struct Curl_easy *data,
bool foundPendingCandidate = FALSE;
bool canmultiplex = IsMultiplexingPossible(data, needle);
struct connectbundle *bundle;
- struct curltime now = Curl_now();
+ const char *hostbundle;
#ifdef USE_NTLM
bool wantNTLMhttp = ((data->state.authhost.want &
@@ -1020,21 +1062,20 @@ ConnectionExists(struct Curl_easy *data,
/* Look up the bundle with all the connections to this particular host.
Locks the connection cache, beware of early returns! */
- bundle = Curl_conncache_find_bundle(needle, data->state.conn_cache);
+ bundle = Curl_conncache_find_bundle(needle, data->state.conn_cache,
+ &hostbundle);
if(bundle) {
/* Max pipe length is zero (unlimited) for multiplexed connections */
struct curl_llist_element *curr;
infof(data, "Found bundle for host %s: %p [%s]\n",
- (needle->bits.conn_to_host ? needle->conn_to_host.name :
- needle->host.name), (void *)bundle,
- (bundle->multiuse == BUNDLE_MULTIPLEX ?
- "can multiplex" : "serially"));
+ hostbundle, (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ?
+ "can multiplex" : "serially"));
/* We can't multiplex if we don't know anything about the server */
if(canmultiplex) {
if(bundle->multiuse == BUNDLE_UNKNOWN) {
- if((bundle->multiuse == BUNDLE_UNKNOWN) && data->set.pipewait) {
+ if(data->set.pipewait) {
infof(data, "Server doesn't support multiplex yet, wait\n");
*waitpipe = TRUE;
Curl_conncache_unlock(data);
@@ -1058,7 +1099,7 @@ ConnectionExists(struct Curl_easy *data,
curr = bundle->conn_list.head;
while(curr) {
bool match = FALSE;
- size_t multiplexed;
+ size_t multiplexed = 0;
/*
* Note that if we use a HTTP proxy in normal mode (no tunneling), we
@@ -1067,22 +1108,15 @@ ConnectionExists(struct Curl_easy *data,
check = curr->ptr;
curr = curr->next;
- if(check->bits.connect_only)
- /* connect-only connections will not be reused */
- continue;
-
- if(conn_maxage(data, check, now) || extract_if_dead(check, data)) {
- /* disconnect it */
- (void)Curl_disconnect(data, check, /* dead_connection */TRUE);
+ if(check->bits.connect_only || check->bits.close)
+ /* connect-only or to-be-closed connections will not be reused */
continue;
- }
- multiplexed = CONN_INUSE(check) &&
- (bundle->multiuse == BUNDLE_MULTIPLEX);
+ if(bundle->multiuse == BUNDLE_MULTIPLEX)
+ multiplexed = CONN_INUSE(check);
if(canmultiplex) {
- if(check->bits.protoconnstart && check->bits.close)
- continue;
+ ;
}
else {
if(multiplexed) {
@@ -1102,12 +1136,9 @@ ConnectionExists(struct Curl_easy *data,
}
}
- if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) ||
- check->bits.close) {
- if(!check->bits.close)
- foundPendingCandidate = TRUE;
- /* Don't pick a connection that hasn't connected yet or that is going
- to get closed. */
+ if(check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) {
+ foundPendingCandidate = TRUE;
+ /* Don't pick a connection that hasn't connected yet */
infof(data, "Connection #%ld isn't open enough, can't reuse\n",
check->connection_id);
continue;
@@ -1139,8 +1170,9 @@ ConnectionExists(struct Curl_easy *data,
needle->bits.socksproxy != check->bits.socksproxy)
continue;
- if(needle->bits.socksproxy && !proxy_info_matches(&needle->socks_proxy,
- &check->socks_proxy))
+ if(needle->bits.socksproxy &&
+ !socks_proxy_info_matches(&needle->socks_proxy,
+ &check->socks_proxy))
continue;
if(needle->bits.conn_to_host != check->bits.conn_to_host)
@@ -1180,13 +1212,14 @@ ConnectionExists(struct Curl_easy *data,
}
}
+ DEBUGASSERT(!check->data || GOOD_EASY_HANDLE(check->data));
+
if(!canmultiplex && check->data)
/* this request can't be multiplexed but the checked connection is
already in use so we skip it */
continue;
- if(CONN_INUSE(check) && check->data &&
- (check->data->multi != needle->data->multi))
+ if(check->data && (check->data->multi != needle->data->multi))
/* this could be subject for multiplex use, but only if they belong to
* the same multi handle */
continue;
@@ -1235,7 +1268,7 @@ ConnectionExists(struct Curl_easy *data,
needle->conn_to_port == check->conn_to_port) &&
strcasecompare(needle->host.name, check->host.name) &&
needle->remote_port == check->remote_port) {
- /* The schemes match or the the protocol family is the same and the
+ /* The schemes match or the protocol family is the same and the
previous connection was TLS upgraded, and the hostname and host
port match */
if(needle->handler->flags & PROTOPT_SSL) {
@@ -1276,8 +1309,14 @@ ConnectionExists(struct Curl_easy *data,
partway through a handshake!) */
if(wantNTLMhttp) {
if(strcmp(needle->user, check->user) ||
- strcmp(needle->passwd, check->passwd))
+ strcmp(needle->passwd, check->passwd)) {
+
+ /* we prefer a credential match, but this is at least a connection
+ that can be reused and "upgraded" to NTLM */
+ if(check->http_ntlm_state == NTLMSTATE_NONE)
+ chosen = check;
continue;
+ }
}
else if(check->http_ntlm_state != NTLMSTATE_NONE) {
/* Connection is using NTLM auth but we don't want NTLM */
@@ -1337,6 +1376,13 @@ ConnectionExists(struct Curl_easy *data,
multiplexed);
continue;
}
+ else if(multiplexed >=
+ Curl_multi_max_concurrent_streams(needle->data->multi)) {
+ infof(data, "client side MAX_CONCURRENT_STREAMS reached"
+ ", skip (%zu)\n",
+ multiplexed);
+ continue;
+ }
}
#endif
/* When not multiplexed, we have a match here! */
@@ -1371,58 +1417,6 @@ ConnectionExists(struct Curl_easy *data,
return FALSE; /* no matching connecting exists */
}
-/* after a TCP connection to the proxy has been verified, this function does
- the next magic step.
-
- Note: this function's sub-functions call failf()
-
-*/
-CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex)
-{
- CURLcode result = CURLE_OK;
-
- if(conn->bits.socksproxy) {
-#ifndef CURL_DISABLE_PROXY
- /* for the secondary socket (FTP), use the "connect to host"
- * but ignore the "connect to port" (use the secondary port)
- */
- const char * const host = conn->bits.httpproxy ?
- conn->http_proxy.host.name :
- conn->bits.conn_to_host ?
- conn->conn_to_host.name :
- sockindex == SECONDARYSOCKET ?
- conn->secondaryhostname : conn->host.name;
- const int port = conn->bits.httpproxy ? (int)conn->http_proxy.port :
- sockindex == SECONDARYSOCKET ? conn->secondary_port :
- conn->bits.conn_to_port ? conn->conn_to_port :
- conn->remote_port;
- conn->bits.socksproxy_connecting = TRUE;
- switch(conn->socks_proxy.proxytype) {
- case CURLPROXY_SOCKS5:
- case CURLPROXY_SOCKS5_HOSTNAME:
- result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
- host, port, sockindex, conn);
- break;
-
- case CURLPROXY_SOCKS4:
- case CURLPROXY_SOCKS4A:
- result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
- conn);
- break;
-
- default:
- failf(conn->data, "unknown proxytype option given");
- result = CURLE_COULDNT_CONNECT;
- } /* switch proxytype */
- conn->bits.socksproxy_connecting = FALSE;
-#else
- (void)sockindex;
-#endif /* CURL_DISABLE_PROXY */
- }
-
- return result;
-}
-
/*
* verboseconnect() displays verbose information after a connect
*/
@@ -1439,134 +1433,17 @@ void Curl_verboseconnect(struct connectdata *conn)
}
#endif
-int Curl_protocol_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
-{
- if(conn->handler->proto_getsock)
- return conn->handler->proto_getsock(conn, socks, numsocks);
- /* Backup getsock logic. Since there is a live socket in use, we must wait
- for it or it will be removed from watching when the multi_socket API is
- used. */
- socks[0] = conn->sock[FIRSTSOCKET];
- return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0);
-}
-
-int Curl_doing_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
-{
- if(conn && conn->handler->doing_getsock)
- return conn->handler->doing_getsock(conn, socks, numsocks);
- return GETSOCK_BLANK;
-}
-
-/*
- * We are doing protocol-specific connecting and this is being called over and
- * over from the multi interface until the connection phase is done on
- * protocol layer.
- */
-
-CURLcode Curl_protocol_connecting(struct connectdata *conn,
- bool *done)
-{
- CURLcode result = CURLE_OK;
-
- if(conn && conn->handler->connecting) {
- *done = FALSE;
- result = conn->handler->connecting(conn, done);
- }
- else
- *done = TRUE;
-
- return result;
-}
-
-/*
- * We are DOING this is being called over and over from the multi interface
- * until the DOING phase is done on protocol layer.
- */
-
-CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
-{
- CURLcode result = CURLE_OK;
-
- if(conn && conn->handler->doing) {
- *done = FALSE;
- result = conn->handler->doing(conn, done);
- }
- else
- *done = TRUE;
-
- return result;
-}
-
-/*
- * We have discovered that the TCP connection has been successful, we can now
- * proceed with some action.
- *
- */
-CURLcode Curl_protocol_connect(struct connectdata *conn,
- bool *protocol_done)
-{
- CURLcode result = CURLE_OK;
-
- *protocol_done = FALSE;
-
- if(conn->bits.tcpconnect[FIRSTSOCKET] && conn->bits.protoconnstart) {
- /* We already are connected, get back. This may happen when the connect
- worked fine in the first call, like when we connect to a local server
- or proxy. Note that we don't know if the protocol is actually done.
-
- Unless this protocol doesn't have any protocol-connect callback, as
- then we know we're done. */
- if(!conn->handler->connecting)
- *protocol_done = TRUE;
-
- return CURLE_OK;
- }
-
- if(!conn->bits.protoconnstart) {
-
- result = Curl_proxy_connect(conn, FIRSTSOCKET);
- if(result)
- return result;
-
- if(CONNECT_FIRSTSOCKET_PROXY_SSL())
- /* wait for HTTPS proxy SSL initialization to complete */
- return CURLE_OK;
-
- if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
- Curl_connect_ongoing(conn))
- /* when using an HTTP tunnel proxy, await complete tunnel establishment
- before proceeding further. Return CURLE_OK so we'll be called again */
- return CURLE_OK;
-
- if(conn->handler->connect_it) {
- /* is there a protocol-specific connect() procedure? */
-
- /* Call the protocol-specific connect function */
- result = conn->handler->connect_it(conn, protocol_done);
- }
- else
- *protocol_done = TRUE;
-
- /* it has started, possibly even completed but that knowledge isn't stored
- in this bit! */
- if(!result)
- conn->bits.protoconnstart = TRUE;
- }
-
- return result; /* pass back status */
-}
-
/*
* Helpers for IDNA conversions.
*/
-static bool is_ASCII_name(const char *hostname)
+bool Curl_is_ASCII_name(const char *hostname)
{
+ /* get an UNSIGNED local version of the pointer */
const unsigned char *ch = (const unsigned char *)hostname;
+ if(!hostname) /* bad input, consider it ASCII! */
+ return TRUE;
+
while(*ch) {
if(*ch++ & 0x80)
return FALSE;
@@ -1591,8 +1468,8 @@ static void strip_trailing_dot(struct hostname *host)
/*
* Perform any necessary IDN conversion of hostname
*/
-static CURLcode idnconvert_hostname(struct connectdata *conn,
- struct hostname *host)
+CURLcode Curl_idnconvert_hostname(struct connectdata *conn,
+ struct hostname *host)
{
struct Curl_easy *data = conn->data;
@@ -1607,7 +1484,7 @@ static CURLcode idnconvert_hostname(struct connectdata *conn,
host->dispname = host->name;
/* Check name for non-ASCII and convert hostname to ACE form if we can */
- if(!is_ASCII_name(host->name)) {
+ if(!Curl_is_ASCII_name(host->name)) {
#ifdef USE_LIBIDN2
if(idn2_check_version(IDN2_VERSION)) {
char *ace_hostname = NULL;
@@ -1640,7 +1517,9 @@ static CURLcode idnconvert_hostname(struct connectdata *conn,
host->name = host->encalloc;
}
else {
- failf(data, "Failed to convert %s to ACE;\n", host->name);
+ char buffer[STRERROR_LEN];
+ failf(data, "Failed to convert %s to ACE; %s\n", host->name,
+ Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
return CURLE_URL_MALFORMAT;
}
#else
@@ -1653,7 +1532,7 @@ static CURLcode idnconvert_hostname(struct connectdata *conn,
/*
* Frees data allocated by idnconvert_hostname()
*/
-static void free_idnconverted_hostname(struct hostname *host)
+void Curl_free_idnconverted_hostname(struct hostname *host)
{
#if defined(USE_LIBIDN2)
if(host->encalloc) {
@@ -1670,13 +1549,6 @@ static void free_idnconverted_hostname(struct hostname *host)
#endif
}
-static void llist_dtor(void *user, void *element)
-{
- (void)user;
- (void)element;
- /* Do nothing */
-}
-
/*
* Allocate and initialize a new connectdata object.
*/
@@ -1781,14 +1653,16 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost;
conn->ip_version = data->set.ipver;
conn->bits.connect_only = data->set.connect_only;
+ conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
defined(NTLM_WB_ENABLED)
- conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+ conn->ntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+ conn->proxyntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
#endif
/* Initialize the easy handle list */
- Curl_llist_init(&conn->easyq, (curl_llist_dtor) llist_dtor);
+ Curl_llist_init(&conn->easyq, NULL);
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CLEAR;
@@ -1807,6 +1681,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
it may live on without (this specific) Curl_easy */
conn->fclosesocket = data->set.fclosesocket;
conn->closesocket_client = data->set.closesocket_client;
+ conn->lastused = Curl_now(); /* used now */
return conn;
error:
@@ -1884,6 +1759,50 @@ CURLcode Curl_uc_to_curlcode(CURLUcode uc)
}
/*
+ * If the URL was set with an IPv6 numerical address with a zone id part, set
+ * the scope_id based on that!
+ */
+
+static void zonefrom_url(CURLU *uh, struct connectdata *conn)
+{
+ char *zoneid;
+ CURLUcode uc;
+
+ uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
+
+ if(!uc && zoneid) {
+ char *endp;
+ unsigned long scope = strtoul(zoneid, &endp, 10);
+ if(!*endp && (scope < UINT_MAX))
+ /* A plain number, use it directly as a scope id. */
+ conn->scope_id = (unsigned int)scope;
+#if defined(HAVE_IF_NAMETOINDEX)
+ else {
+#elif defined(WIN32)
+ else if(Curl_if_nametoindex) {
+#endif
+
+#if defined(HAVE_IF_NAMETOINDEX) || defined(WIN32)
+ /* Zone identifier is not numeric */
+ unsigned int scopeidx = 0;
+#if defined(WIN32)
+ scopeidx = Curl_if_nametoindex(zoneid);
+#else
+ scopeidx = if_nametoindex(zoneid);
+#endif
+ if(!scopeidx)
+ infof(conn->data, "Invalid zoneid: %s; %s\n", zoneid,
+ strerror(errno));
+ else
+ conn->scope_id = scopeidx;
+ }
+#endif /* HAVE_IF_NAMETOINDEX || WIN32 */
+
+ free(zoneid);
+ }
+}
+
+/*
* Parse URL and fill in the relevant members of the connection struct.
*/
static CURLcode parseurlandfillconn(struct Curl_easy *data,
@@ -1921,6 +1840,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
}
if(!data->set.uh) {
+ char *newurl;
uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
CURLU_GUESS_SCHEME |
CURLU_NON_SUPPORT_SCHEME |
@@ -1931,6 +1851,15 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
DEBUGF(infof(data, "curl_url_set rejected %s\n", data->change.url));
return Curl_uc_to_curlcode(uc);
}
+
+ /* after it was parsed, get the generated normalized version */
+ uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
+ if(uc)
+ return Curl_uc_to_curlcode(uc);
+ if(data->change.url_alloc)
+ free(data->change.url);
+ data->change.url = newurl;
+ data->change.url_alloc = TRUE;
}
uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
@@ -1991,55 +1920,27 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
}
else {
unsigned long port = strtoul(data->state.up.port, NULL, 10);
- conn->remote_port = curlx_ultous(port);
+ conn->port = conn->remote_port = curlx_ultous(port);
}
(void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
hostname = data->state.up.hostname;
- if(!hostname)
- /* this is for file:// transfers, get a dummy made */
- hostname = (char *)"";
-
- if(hostname[0] == '[') {
+ if(hostname && hostname[0] == '[') {
/* This looks like an IPv6 address literal. See if there is an address
scope. */
- char *zoneid;
size_t hlen;
- uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
conn->bits.ipv6_ip = TRUE;
-
/* cut off the brackets! */
hostname++;
hlen = strlen(hostname);
hostname[hlen - 1] = 0;
- if(!uc && zoneid) {
- char *endp;
- unsigned long scope;
- scope = strtoul(zoneid, &endp, 10);
- if(!*endp && (scope < UINT_MAX)) {
- /* A plain number, use it direcly as a scope id. */
- conn->scope_id = (unsigned int)scope;
- }
-#ifdef HAVE_IF_NAMETOINDEX
- else {
- /* Zone identifier is not numeric */
- unsigned int scopeidx = 0;
- scopeidx = if_nametoindex(zoneid);
- if(!scopeidx)
- infof(data, "Invalid zoneid id: %s; %s\n", zoneid,
- strerror(errno));
- else
- conn->scope_id = scopeidx;
- }
-#endif /* HAVE_IF_NAMETOINDEX */
- free(zoneid);
- }
+ zonefrom_url(uh, conn);
}
/* make sure the connect struct gets its own copy of the host name */
- conn->host.rawalloc = strdup(hostname);
+ conn->host.rawalloc = strdup(hostname ? hostname : "");
if(!conn->host.rawalloc)
return CURLE_OUT_OF_MEMORY;
conn->host.name = conn->host.rawalloc;
@@ -2097,7 +1998,6 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
{
const struct Curl_handler * p;
CURLcode result;
- conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
/* Perform setup complement if some. */
p = conn->handler;
@@ -2128,6 +2028,11 @@ void Curl_free_request_state(struct Curl_easy *data)
{
Curl_safefree(data->req.protop);
Curl_safefree(data->req.newurl);
+
+#ifndef CURL_DISABLE_DOH
+ Curl_close(&data->req.doh.probe[0].easy);
+ Curl_close(&data->req.doh.probe[1].easy);
+#endif
}
@@ -2298,7 +2203,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
struct connectdata *conn, char *proxy,
curl_proxytype proxytype)
{
- char *portptr;
+ char *portptr = NULL;
long port = -1;
char *proxyuser = NULL;
char *proxypasswd = NULL;
@@ -2422,6 +2327,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
size_t len = strlen(host);
host[len-1] = 0; /* clear the trailing bracket */
host++;
+ zonefrom_url(uhp, conn);
}
proxyinfo->host.name = host;
@@ -2846,8 +2752,7 @@ static CURLcode override_login(struct Curl_easy *data,
&netrc_user_changed, &netrc_passwd_changed,
data->set.str[STRING_NETRC_FILE]);
if(ret > 0) {
- infof(data, "Couldn't find host %s in the "
- DOT_CHAR "netrc file; using defaults\n",
+ infof(data, "Couldn't find host %s in the .netrc file; using defaults\n",
conn->host.name);
}
else if(ret < 0) {
@@ -2913,13 +2818,6 @@ static CURLcode set_login(struct connectdata *conn)
result = CURLE_OUT_OF_MEMORY;
}
- /* if there's a user without password, consider password blank */
- if(conn->user && !conn->passwd) {
- conn->passwd = strdup("");
- if(!conn->passwd)
- result = CURLE_OUT_OF_MEMORY;
- }
-
return result;
}
@@ -3144,26 +3042,65 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
if(data->asi && !host && (port == -1) &&
(conn->handler->protocol == CURLPROTO_HTTPS)) {
/* no connect_to match, try alt-svc! */
- const char *nhost;
- int nport;
- enum alpnid nalpnid;
+ enum alpnid srcalpnid;
bool hit;
+ struct altsvc *as;
+ const int allowed_versions = ( ALPN_h1
+#ifdef USE_NGHTTP2
+ | ALPN_h2
+#endif
+#ifdef ENABLE_QUIC
+ | ALPN_h3
+#endif
+ ) & data->asi->flags;
+
host = conn->host.rawalloc;
+#ifdef USE_NGHTTP2
+ /* with h2 support, check that first */
+ srcalpnid = ALPN_h2;
hit = Curl_altsvc_lookup(data->asi,
- ALPN_h1, host, conn->remote_port, /* from */
- &nalpnid, &nhost, &nport /* to */);
+ srcalpnid, host, conn->remote_port, /* from */
+ &as /* to */,
+ allowed_versions);
+ if(!hit)
+#endif
+ {
+ srcalpnid = ALPN_h1;
+ hit = Curl_altsvc_lookup(data->asi,
+ srcalpnid, host, conn->remote_port, /* from */
+ &as /* to */,
+ allowed_versions);
+ }
if(hit) {
- char *hostd = strdup((char *)nhost);
+ char *hostd = strdup((char *)as->dst.host);
if(!hostd)
return CURLE_OUT_OF_MEMORY;
conn->conn_to_host.rawalloc = hostd;
conn->conn_to_host.name = hostd;
conn->bits.conn_to_host = TRUE;
- conn->conn_to_port = nport;
+ conn->conn_to_port = as->dst.port;
conn->bits.conn_to_port = TRUE;
+ conn->bits.altused = TRUE;
infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d\n",
- Curl_alpnid2str(ALPN_h1), host, conn->remote_port,
- Curl_alpnid2str(nalpnid), hostd, nport);
+ Curl_alpnid2str(srcalpnid), host, conn->remote_port,
+ Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
+ if(srcalpnid != as->dst.alpnid) {
+ /* protocol version switch */
+ switch(as->dst.alpnid) {
+ case ALPN_h1:
+ conn->httpversion = 11;
+ break;
+ case ALPN_h2:
+ conn->httpversion = 20;
+ break;
+ case ALPN_h3:
+ conn->transport = TRNSPRT_QUIC;
+ conn->httpversion = 30;
+ break;
+ default: /* shouldn't be possible */
+ break;
+ }
+ }
}
}
#endif
@@ -3300,8 +3237,8 @@ static CURLcode resolve_server(struct Curl_easy *data,
static void reuse_conn(struct connectdata *old_conn,
struct connectdata *conn)
{
- free_idnconverted_hostname(&old_conn->http_proxy.host);
- free_idnconverted_hostname(&old_conn->socks_proxy.host);
+ Curl_free_idnconverted_hostname(&old_conn->http_proxy.host);
+ Curl_free_idnconverted_hostname(&old_conn->socks_proxy.host);
free(old_conn->http_proxy.host.rawalloc);
free(old_conn->socks_proxy.host.rawalloc);
@@ -3345,8 +3282,8 @@ static void reuse_conn(struct connectdata *old_conn,
/* host can change, when doing keepalive with a proxy or if the case is
different this time etc */
- free_idnconverted_hostname(&conn->host);
- free_idnconverted_hostname(&conn->conn_to_host);
+ Curl_free_idnconverted_hostname(&conn->host);
+ Curl_free_idnconverted_hostname(&conn->conn_to_host);
Curl_safefree(conn->host.rawalloc);
Curl_safefree(conn->conn_to_host.rawalloc);
conn->host = old_conn->host;
@@ -3442,9 +3379,9 @@ static CURLcode create_conn(struct Curl_easy *data,
if(result)
goto out;
- if(data->set.str[STRING_BEARER]) {
- conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
- if(!conn->oauth_bearer) {
+ if(data->set.str[STRING_SASL_AUTHZID]) {
+ conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
+ if(!conn->sasl_authzid) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
@@ -3505,21 +3442,21 @@ static CURLcode create_conn(struct Curl_easy *data,
/*************************************************************
* IDN-convert the hostnames
*************************************************************/
- result = idnconvert_hostname(conn, &conn->host);
+ result = Curl_idnconvert_hostname(conn, &conn->host);
if(result)
goto out;
if(conn->bits.conn_to_host) {
- result = idnconvert_hostname(conn, &conn->conn_to_host);
+ result = Curl_idnconvert_hostname(conn, &conn->conn_to_host);
if(result)
goto out;
}
if(conn->bits.httpproxy) {
- result = idnconvert_hostname(conn, &conn->http_proxy.host);
+ result = Curl_idnconvert_hostname(conn, &conn->http_proxy.host);
if(result)
goto out;
}
if(conn->bits.socksproxy) {
- result = idnconvert_hostname(conn, &conn->socks_proxy.host);
+ result = Curl_idnconvert_hostname(conn, &conn->socks_proxy.host);
if(result)
goto out;
}
@@ -3631,6 +3568,10 @@ static CURLcode create_conn(struct Curl_easy *data,
data->set.str[STRING_SSL_CIPHER13_LIST_ORIG];
data->set.proxy_ssl.primary.cipher_list13 =
data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
+ data->set.ssl.primary.pinned_key =
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+ data->set.proxy_ssl.primary.pinned_key =
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG];
data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
@@ -3688,25 +3629,6 @@ static CURLcode create_conn(struct Curl_easy *data,
else
reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe);
- /* If we found a reusable connection that is now marked as in use, we may
- still want to open a new connection if we are multiplexing. */
- if(reuse && !force_reuse && IsMultiplexingPossible(data, conn_temp)) {
- size_t multiplexed = CONN_INUSE(conn_temp);
- if(multiplexed > 0) {
- infof(data, "Found connection %ld, with %zu requests on it\n",
- conn_temp->connection_id, multiplexed);
-
- if(Curl_conncache_bundle_size(conn_temp) < max_host_connections &&
- Curl_conncache_size(data) < max_total_connections) {
- /* We want a new connection anyway */
- reuse = FALSE;
-
- infof(data, "We can reuse, but we want a new connection anyway\n");
- Curl_conncache_return_conn(conn_temp);
- }
- }
- }
-
if(reuse) {
/*
* We already have a connection for this, we got the former connection
@@ -3749,8 +3671,9 @@ static CURLcode create_conn(struct Curl_easy *data,
connections_available = FALSE;
else {
/* this gets a lock on the conncache */
+ const char *bundlehost;
struct connectbundle *bundle =
- Curl_conncache_find_bundle(conn, data->state.conn_cache);
+ Curl_conncache_find_bundle(conn, data->state.conn_cache, &bundlehost);
if(max_host_connections > 0 && bundle &&
(bundle->num_connections >= max_host_connections)) {
@@ -3764,8 +3687,8 @@ static CURLcode create_conn(struct Curl_easy *data,
(void)Curl_disconnect(data, conn_candidate,
/* dead_connection */ FALSE);
else {
- infof(data, "No more connections allowed to host: %zu\n",
- max_host_connections);
+ infof(data, "No more connections allowed to host %s: %zu\n",
+ bundlehost, max_host_connections);
connections_available = FALSE;
}
}
@@ -3926,7 +3849,9 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
}
else {
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
- Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
+ if(conn->ssl[FIRSTSOCKET].use ||
+ (conn->handler->protocol & PROTO_FAMILY_SSH))
+ Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
*protocol_done = TRUE;
Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]);
@@ -4147,34 +4072,3 @@ static unsigned int get_protocol_family(unsigned int protocol)
return family;
}
-
-
-/*
- * Wrapper to call functions in Curl_conncache_foreach()
- *
- * Returns always 0.
- */
-static int conn_upkeep(struct connectdata *conn,
- void *param)
-{
- /* Param is unused. */
- (void)param;
-
- if(conn->handler->connection_check) {
- /* Do a protocol-specific keepalive check on the connection. */
- conn->handler->connection_check(conn, CONNCHECK_KEEPALIVE);
- }
-
- return 0; /* continue iteration */
-}
-
-CURLcode Curl_upkeep(struct conncache *conn_cache,
- void *data)
-{
- /* Loop over every connection and make connection alive. */
- Curl_conncache_foreach(data,
- conn_cache,
- data,
- conn_upkeep);
- return CURLE_OK;
-}