diff options
Diffstat (limited to 'libs/libcurl/src/url.c')
-rw-r--r-- | libs/libcurl/src/url.c | 136 |
1 files changed, 93 insertions, 43 deletions
diff --git a/libs/libcurl/src/url.c b/libs/libcurl/src/url.c index d5a982008e..eb09a24be2 100644 --- a/libs/libcurl/src/url.c +++ b/libs/libcurl/src/url.c @@ -120,6 +120,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "dotdot.h" #include "strdup.h" #include "setopt.h" +#include "altsvc.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -292,7 +293,7 @@ void Curl_freeset(struct Curl_easy *data) } /* free the URL pieces */ -void Curl_up_free(struct Curl_easy *data) +static void up_free(struct Curl_easy *data) { struct urlpieces *up = &data->state.up; Curl_safefree(up->scheme); @@ -303,7 +304,8 @@ void Curl_up_free(struct Curl_easy *data) Curl_safefree(up->options); Curl_safefree(up->path); Curl_safefree(up->query); - curl_url_cleanup(data->state.uh); + if(data->set.uh != data->state.uh) + curl_url_cleanup(data->state.uh); data->state.uh = NULL; } @@ -369,11 +371,16 @@ CURLcode Curl_close(struct Curl_easy *data) } data->change.referer = NULL; - Curl_up_free(data); + up_free(data); Curl_safefree(data->state.buffer); Curl_safefree(data->state.headerbuff); Curl_safefree(data->state.ulbuf); Curl_flush_cookies(data, 1); +#ifdef USE_ALTSVC + Curl_altsvc_save(data->asi, data->set.str[STRING_ALTSVC]); + Curl_altsvc_cleanup(data->asi); + data->asi = NULL; +#endif Curl_digest_cleanup(data); Curl_safefree(data->info.contenttype); Curl_safefree(data->info.wouldredirect); @@ -660,11 +667,15 @@ static void conn_reset_all_postponed_data(struct connectdata *conn) #define conn_reset_all_postponed_data(c) do {} WHILE_FALSE #endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ -static void conn_free(struct connectdata *conn) + +static void conn_shutdown(struct connectdata *conn) { if(!conn) return; + infof(conn->data, "Closing connection %ld\n", conn->connection_id); + DEBUGASSERT(conn->data); + /* possible left-overs from the async name resolvers */ Curl_resolver_cancel(conn); @@ -688,6 +699,21 @@ static void conn_free(struct connectdata *conn) Curl_ntlm_wb_cleanup(conn); #endif + /* unlink ourselves. this should be called last since other shutdown + procedures need a valid conn->data and this may clear it. */ + Curl_conncache_remove_conn(conn->data, conn, TRUE); +} + +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_safefree(conn->user); Curl_safefree(conn->passwd); Curl_safefree(conn->oauth_bearer); @@ -780,27 +806,20 @@ CURLcode Curl_disconnect(struct Curl_easy *data, /* Cleanup NTLM connection-related data */ Curl_http_ntlm_cleanup(conn); #endif +#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) + /* Cleanup NEGOTIATE connection-related data */ + Curl_cleanup_negotiate(conn); +#endif - /* the protocol specific disconnect handler needs a transfer for its - connection! */ + /* the protocol specific disconnect handler and conn_shutdown need a transfer + for the connection! */ conn->data = data; + if(conn->handler->disconnect) /* This is set if protocol-specific cleanups should be made */ conn->handler->disconnect(conn, dead_connection); - /* unlink ourselves! */ - infof(data, "Closing connection %ld\n", conn->connection_id); - Curl_conncache_remove_conn(data, conn, TRUE); - - 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); - - /* this assumes that the pointer is still there after the connection was - detected from the cache */ - Curl_ssl_close(conn, FIRSTSOCKET); - + conn_shutdown(conn); conn_free(conn); return CURLE_OK; } @@ -956,7 +975,7 @@ static bool extract_if_dead(struct connectdata *conn, struct Curl_easy *data) { size_t pipeLen = conn->send_pipe.size + conn->recv_pipe.size; - if(!pipeLen && !CONN_INUSE(conn)) { + if(!pipeLen && !CONN_INUSE(conn) && !conn->data) { /* The check for a dead socket makes sense only if there are no handles in pipeline and the connection isn't already marked in use */ @@ -965,7 +984,10 @@ static bool extract_if_dead(struct connectdata *conn, /* 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; + struct Curl_easy *olddata = conn->data; + conn->data = data; /* use this transfer for now */ state = conn->handler->connection_check(conn, CONNCHECK_ISDEAD); + conn->data = olddata; dead = (state & CONNRESULT_DEAD); } else { @@ -994,7 +1016,6 @@ struct prunedead { static int call_extract_if_dead(struct connectdata *conn, void *param) { struct prunedead *p = (struct prunedead *)param; - conn->data = p->data; /* transfer to use for this check */ if(extract_if_dead(conn, p->data)) { /* stop the iteration here, pass back the connection that was extracted */ p->extracted = conn; @@ -1132,6 +1153,10 @@ 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(extract_if_dead(check, data)) { /* disconnect it */ (void)Curl_disconnect(data, check, /* dead_connection */TRUE); @@ -1262,14 +1287,15 @@ ConnectionExists(struct Curl_easy *data, } } - if(!canpipe && CONN_INUSE(check)) + if(!canpipe && check->data) /* this request can't be pipelined but the checked connection is already in use so we skip it */ continue; - if(CONN_INUSE(check) && (check->data->multi != needle->data->multi)) - /* this could be subject for pipeline/multiplex use, but only - if they belong to the same multi handle */ + if(CONN_INUSE(check) && check->data && + (check->data->multi != needle->data->multi)) + /* this could be subject for pipeline/multiplex use, but only if they + belong to the same multi handle */ continue; if(needle->localdev || needle->localport) { @@ -1685,6 +1711,8 @@ static bool is_ASCII_name(const char *hostname) static void strip_trailing_dot(struct hostname *host) { size_t len; + if(!host || !host->name) + return; len = strlen(host->name); if(len && (host->name[len-1] == '.')) host->name[len-1] = 0; @@ -1749,15 +1777,6 @@ static CURLcode idnconvert_hostname(struct connectdata *conn, infof(data, "IDN support not present, can't parse Unicode domains\n"); #endif } - { - char *hostp; - for(hostp = host->name; *hostp; hostp++) { - if(*hostp <= 32) { - failf(data, "Host name '%s' contains bad letter", host->name); - return CURLE_URL_MALFORMAT; - } - } - } return CURLE_OK; } @@ -1899,8 +1918,8 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) data->set.proxy_ssl.primary.verifystatus; conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; - conn->ip_version = data->set.ipver; + conn->bits.connect_only = data->set.connect_only; #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ defined(NTLM_WB_ENABLED) @@ -2029,11 +2048,11 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, CURLUcode uc; char *hostname; - Curl_up_free(data); /* cleanup previous leftovers first */ + up_free(data); /* cleanup previous leftovers first */ /* parse the URL */ if(data->set.uh) { - uh = data->set.uh; + uh = data->state.uh = data->set.uh; } else { uh = data->state.uh = curl_url(); @@ -3361,6 +3380,34 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data, conn_to_host = conn_to_host->next; } +#ifdef USE_ALTSVC + 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; + bool hit; + host = conn->host.rawalloc; + hit = Curl_altsvc_lookup(data->asi, + ALPN_h1, host, conn->remote_port, /* from */ + &nalpnid, &nhost, &nport /* to */); + if(hit) { + char *hostd = strdup((char *)nhost); + 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->bits.conn_to_port = 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); + } + } +#endif + return result; } @@ -3374,6 +3421,8 @@ static CURLcode resolve_server(struct Curl_easy *data, CURLcode result = CURLE_OK; timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + DEBUGASSERT(conn); + DEBUGASSERT(data); /************************************************************* * Resolve the name of the server or proxy *************************************************************/ @@ -3789,9 +3838,8 @@ static CURLcode create_conn(struct Curl_easy *data, (void)conn->handler->done(conn, result, FALSE); goto out; } - - Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ - -1, NULL); /* no upload */ + Curl_attach_connnection(data, conn); + Curl_setup_transfer(data, -1, -1, FALSE, -1); } /* since we skip do_init() */ @@ -3877,8 +3925,9 @@ static CURLcode create_conn(struct Curl_easy *data, /* reuse_fresh is TRUE if we are told to use a new connection by force, but we only acknowledge this option if this is not a re-used connection already (which happens due to follow-location or during a HTTP - authentication phase). */ - if(data->set.reuse_fresh && !data->state.this_is_a_follow) + authentication phase). CONNECT_ONLY transfers also refuse reuse. */ + if((data->set.reuse_fresh && !data->state.this_is_a_follow) || + data->set.connect_only) reuse = FALSE; else reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe); @@ -4170,7 +4219,8 @@ CURLcode Curl_connect(struct Curl_easy *data, connectdata struct, free those here */ Curl_disconnect(data, conn, TRUE); } - else + else if(!data->conn) + /* FILE: transfers already have the connection attached */ Curl_attach_connnection(data, conn); return result; |