xref: /curl/lib/url.c (revision 926fb004)
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 #include "curl_setup.h"
26 
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
29 #endif
30 #ifdef HAVE_NETDB_H
31 #include <netdb.h>
32 #endif
33 #ifdef HAVE_ARPA_INET_H
34 #include <arpa/inet.h>
35 #endif
36 #ifdef HAVE_NET_IF_H
37 #include <net/if.h>
38 #endif
39 #ifdef HAVE_IPHLPAPI_H
40 #include <Iphlpapi.h>
41 #endif
42 #ifdef HAVE_SYS_IOCTL_H
43 #include <sys/ioctl.h>
44 #endif
45 #ifdef HAVE_SYS_PARAM_H
46 #include <sys/param.h>
47 #endif
48 
49 #ifdef __VMS
50 #include <in.h>
51 #include <inet.h>
52 #endif
53 
54 #ifdef HAVE_SYS_UN_H
55 #include <sys/un.h>
56 #endif
57 
58 #ifndef HAVE_SOCKET
59 #error "We can't compile without socket() support!"
60 #endif
61 
62 #include <limits.h>
63 
64 #include "doh.h"
65 #include "urldata.h"
66 #include "netrc.h"
67 #include "formdata.h"
68 #include "mime.h"
69 #include "vtls/vtls.h"
70 #include "hostip.h"
71 #include "transfer.h"
72 #include "sendf.h"
73 #include "progress.h"
74 #include "cookie.h"
75 #include "strcase.h"
76 #include "strerror.h"
77 #include "escape.h"
78 #include "strtok.h"
79 #include "share.h"
80 #include "content_encoding.h"
81 #include "http_digest.h"
82 #include "http_negotiate.h"
83 #include "select.h"
84 #include "multiif.h"
85 #include "easyif.h"
86 #include "speedcheck.h"
87 #include "warnless.h"
88 #include "getinfo.h"
89 #include "urlapi-int.h"
90 #include "system_win32.h"
91 #include "hsts.h"
92 #include "noproxy.h"
93 #include "cfilters.h"
94 #include "idn.h"
95 
96 /* And now for the protocols */
97 #include "ftp.h"
98 #include "dict.h"
99 #include "telnet.h"
100 #include "tftp.h"
101 #include "http.h"
102 #include "http2.h"
103 #include "file.h"
104 #include "curl_ldap.h"
105 #include "vssh/ssh.h"
106 #include "imap.h"
107 #include "url.h"
108 #include "connect.h"
109 #include "inet_ntop.h"
110 #include "http_ntlm.h"
111 #include "curl_rtmp.h"
112 #include "gopher.h"
113 #include "mqtt.h"
114 #include "http_proxy.h"
115 #include "conncache.h"
116 #include "multihandle.h"
117 #include "strdup.h"
118 #include "setopt.h"
119 #include "altsvc.h"
120 #include "dynbuf.h"
121 #include "headers.h"
122 
123 /* The last 3 #include files should be in this order */
124 #include "curl_printf.h"
125 #include "curl_memory.h"
126 #include "memdebug.h"
127 
128 #ifndef ARRAYSIZE
129 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
130 #endif
131 
132 #ifdef USE_NGHTTP2
133 static void data_priority_cleanup(struct Curl_easy *data);
134 #else
135 #define data_priority_cleanup(x)
136 #endif
137 
138 /* Some parts of the code (e.g. chunked encoding) assume this buffer has at
139  * more than just a few bytes to play with. Don't let it become too small or
140  * bad things will happen.
141  */
142 #if READBUFFER_SIZE < READBUFFER_MIN
143 # error READBUFFER_SIZE is too small
144 #endif
145 
146 #ifdef USE_UNIX_SOCKETS
147 #define UNIX_SOCKET_PREFIX "localhost"
148 #endif
149 
150 /* Reject URLs exceeding this length */
151 #define MAX_URL_LEN 0xffff
152 
153 /*
154 * get_protocol_family()
155 *
156 * This is used to return the protocol family for a given protocol.
157 *
158 * Parameters:
159 *
160 * 'h'  [in]  - struct Curl_handler pointer.
161 *
162 * Returns the family as a single bit protocol identifier.
163 */
get_protocol_family(const struct Curl_handler * h)164 static curl_prot_t get_protocol_family(const struct Curl_handler *h)
165 {
166   DEBUGASSERT(h);
167   DEBUGASSERT(h->family);
168   return h->family;
169 }
170 
Curl_freeset(struct Curl_easy * data)171 void Curl_freeset(struct Curl_easy *data)
172 {
173   /* Free all dynamic strings stored in the data->set substructure. */
174   enum dupstring i;
175   enum dupblob j;
176 
177   for(i = (enum dupstring)0; i < STRING_LAST; i++) {
178     Curl_safefree(data->set.str[i]);
179   }
180 
181   for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
182     Curl_safefree(data->set.blobs[j]);
183   }
184 
185   if(data->state.referer_alloc) {
186     Curl_safefree(data->state.referer);
187     data->state.referer_alloc = FALSE;
188   }
189   data->state.referer = NULL;
190   if(data->state.url_alloc) {
191     Curl_safefree(data->state.url);
192     data->state.url_alloc = FALSE;
193   }
194   data->state.url = NULL;
195 
196   Curl_mime_cleanpart(&data->set.mimepost);
197 
198 #ifndef CURL_DISABLE_COOKIES
199   curl_slist_free_all(data->state.cookielist);
200   data->state.cookielist = NULL;
201 #endif
202 }
203 
204 /* free the URL pieces */
up_free(struct Curl_easy * data)205 static void up_free(struct Curl_easy *data)
206 {
207   struct urlpieces *up = &data->state.up;
208   Curl_safefree(up->scheme);
209   Curl_safefree(up->hostname);
210   Curl_safefree(up->port);
211   Curl_safefree(up->user);
212   Curl_safefree(up->password);
213   Curl_safefree(up->options);
214   Curl_safefree(up->path);
215   Curl_safefree(up->query);
216   curl_url_cleanup(data->state.uh);
217   data->state.uh = NULL;
218 }
219 
220 /*
221  * This is the internal function curl_easy_cleanup() calls. This should
222  * cleanup and free all resources associated with this sessionhandle.
223  *
224  * We ignore SIGPIPE when this is called from curl_easy_cleanup.
225  */
226 
Curl_close(struct Curl_easy ** datap)227 CURLcode Curl_close(struct Curl_easy **datap)
228 {
229   struct Curl_easy *data;
230 
231   if(!datap || !*datap)
232     return CURLE_OK;
233 
234   data = *datap;
235   *datap = NULL;
236 
237   Curl_expire_clear(data); /* shut off timers */
238 
239   /* Detach connection if any is left. This should not be normal, but can be
240      the case for example with CONNECT_ONLY + recv/send (test 556) */
241   Curl_detach_connection(data);
242   if(!data->state.internal) {
243     if(data->multi)
244       /* This handle is still part of a multi handle, take care of this first
245          and detach this handle from there. */
246       curl_multi_remove_handle(data->multi, data);
247 
248     if(data->multi_easy) {
249       /* when curl_easy_perform() is used, it creates its own multi handle to
250          use and this is the one */
251       curl_multi_cleanup(data->multi_easy);
252       data->multi_easy = NULL;
253     }
254   }
255 
256   data->magic = 0; /* force a clear AFTER the possibly enforced removal from
257                       the multi handle, since that function uses the magic
258                       field! */
259 
260   if(data->state.rangestringalloc)
261     free(data->state.range);
262 
263   /* freed here just in case DONE wasn't called */
264   Curl_req_free(&data->req, data);
265 
266   /* Close down all open SSL info and sessions */
267   Curl_ssl_close_all(data);
268   Curl_safefree(data->state.first_host);
269   Curl_safefree(data->state.scratch);
270   Curl_ssl_free_certinfo(data);
271 
272   if(data->state.referer_alloc) {
273     Curl_safefree(data->state.referer);
274     data->state.referer_alloc = FALSE;
275   }
276   data->state.referer = NULL;
277 
278   up_free(data);
279   Curl_dyn_free(&data->state.headerb);
280   Curl_flush_cookies(data, TRUE);
281 #ifndef CURL_DISABLE_ALTSVC
282   Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
283   Curl_altsvc_cleanup(&data->asi);
284 #endif
285 #ifndef CURL_DISABLE_HSTS
286   Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
287   if(!data->share || !data->share->hsts)
288     Curl_hsts_cleanup(&data->hsts);
289   curl_slist_free_all(data->state.hstslist); /* clean up list */
290 #endif
291 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
292   Curl_http_auth_cleanup_digest(data);
293 #endif
294   Curl_safefree(data->info.contenttype);
295   Curl_safefree(data->info.wouldredirect);
296 
297   /* this destroys the channel and we cannot use it anymore after this */
298   Curl_resolver_cancel(data);
299   Curl_resolver_cleanup(data->state.async.resolver);
300 
301   data_priority_cleanup(data);
302 
303   /* No longer a dirty share, if it exists */
304   if(data->share) {
305     Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
306     data->share->dirty--;
307     Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
308   }
309 
310 #ifndef CURL_DISABLE_PROXY
311   Curl_safefree(data->state.aptr.proxyuserpwd);
312 #endif
313   Curl_safefree(data->state.aptr.uagent);
314   Curl_safefree(data->state.aptr.userpwd);
315   Curl_safefree(data->state.aptr.accept_encoding);
316   Curl_safefree(data->state.aptr.te);
317   Curl_safefree(data->state.aptr.rangeline);
318   Curl_safefree(data->state.aptr.ref);
319   Curl_safefree(data->state.aptr.host);
320 #ifndef CURL_DISABLE_COOKIES
321   Curl_safefree(data->state.aptr.cookiehost);
322 #endif
323 #ifndef CURL_DISABLE_RTSP
324   Curl_safefree(data->state.aptr.rtsp_transport);
325 #endif
326   Curl_safefree(data->state.aptr.user);
327   Curl_safefree(data->state.aptr.passwd);
328 #ifndef CURL_DISABLE_PROXY
329   Curl_safefree(data->state.aptr.proxyuser);
330   Curl_safefree(data->state.aptr.proxypasswd);
331 #endif
332 
333 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
334   Curl_mime_cleanpart(data->state.formp);
335   Curl_safefree(data->state.formp);
336 #endif
337 
338   /* destruct wildcard structures if it is needed */
339   Curl_wildcard_dtor(&data->wildcard);
340   Curl_freeset(data);
341   Curl_headers_cleanup(data);
342   free(data);
343   return CURLE_OK;
344 }
345 
346 /*
347  * Initialize the UserDefined fields within a Curl_easy.
348  * This may be safely called on a new or existing Curl_easy.
349  */
Curl_init_userdefined(struct Curl_easy * data)350 CURLcode Curl_init_userdefined(struct Curl_easy *data)
351 {
352   struct UserDefined *set = &data->set;
353   CURLcode result = CURLE_OK;
354 
355   set->out = stdout; /* default output to stdout */
356   set->in_set = stdin;  /* default input from stdin */
357   set->err  = stderr;  /* default stderr to stderr */
358 
359   /* use fwrite as default function to store output */
360   set->fwrite_func = (curl_write_callback)fwrite;
361 
362   /* use fread as default function to read input */
363   set->fread_func_set = (curl_read_callback)fread;
364   set->is_fread_set = 0;
365 
366   set->seek_client = ZERO_NULL;
367 
368   set->filesize = -1;        /* we don't know the size */
369   set->postfieldsize = -1;   /* unknown size */
370   set->maxredirs = 30;       /* sensible default */
371 
372   set->method = HTTPREQ_GET; /* Default HTTP request */
373 #ifndef CURL_DISABLE_RTSP
374   set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
375 #endif
376 #ifndef CURL_DISABLE_FTP
377   set->ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
378   set->ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
379   set->ftp_use_pret = FALSE;  /* mainly useful for drftpd servers */
380   set->ftp_filemethod = FTPFILE_MULTICWD;
381   set->ftp_skip_ip = TRUE;    /* skip PASV IP by default */
382 #endif
383   set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
384 
385   /* Set the default size of the SSL session ID cache */
386   set->general_ssl.max_ssl_sessions = 5;
387   /* Timeout every 24 hours by default */
388   set->general_ssl.ca_cache_timeout = 24 * 60 * 60;
389 
390   set->httpauth = CURLAUTH_BASIC;  /* defaults to basic */
391 
392 #ifndef CURL_DISABLE_PROXY
393   set->proxyport = 0;
394   set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
395   set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
396   /* SOCKS5 proxy auth defaults to username/password + GSS-API */
397   set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI;
398 #endif
399 
400   /* make libcurl quiet by default: */
401   set->hide_progress = TRUE;  /* CURLOPT_NOPROGRESS changes these */
402 
403   Curl_mime_initpart(&set->mimepost);
404 
405   Curl_ssl_easy_config_init(data);
406 #ifndef CURL_DISABLE_DOH
407   set->doh_verifyhost = TRUE;
408   set->doh_verifypeer = TRUE;
409 #endif
410 #ifdef USE_SSH
411   /* defaults to any auth type */
412   set->ssh_auth_types = CURLSSH_AUTH_DEFAULT;
413   set->new_directory_perms = 0755; /* Default permissions */
414 #endif
415 
416   set->new_file_perms = 0644;    /* Default permissions */
417   set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL;
418   set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP |
419                          CURLPROTO_FTPS;
420 
421 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
422   /*
423    * disallow unprotected protection negotiation NEC reference implementation
424    * seem not to follow rfc1961 section 4.3/4.4
425    */
426   set->socks5_gssapi_nec = FALSE;
427 #endif
428 
429   /* Set the default CA cert bundle/path detected/specified at build time.
430    *
431    * If Schannel or SecureTransport is the selected SSL backend then these
432    * locations are ignored. We allow setting CA location for schannel and
433    * securetransport when explicitly specified by the user via
434    *  CURLOPT_CAINFO / --cacert.
435    */
436   if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL &&
437      Curl_ssl_backend() != CURLSSLBACKEND_SECURETRANSPORT) {
438 #if defined(CURL_CA_BUNDLE)
439     result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
440     if(result)
441       return result;
442 #ifndef CURL_DISABLE_PROXY
443     result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
444                             CURL_CA_BUNDLE);
445     if(result)
446       return result;
447 #endif
448 #endif
449 #if defined(CURL_CA_PATH)
450     result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
451     if(result)
452       return result;
453 #ifndef CURL_DISABLE_PROXY
454     result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
455     if(result)
456       return result;
457 #endif
458 #endif
459   }
460 
461 #ifndef CURL_DISABLE_FTP
462   set->wildcard_enabled = FALSE;
463   set->chunk_bgn      = ZERO_NULL;
464   set->chunk_end      = ZERO_NULL;
465   set->fnmatch = ZERO_NULL;
466 #endif
467   set->tcp_keepalive = FALSE;
468   set->tcp_keepintvl = 60;
469   set->tcp_keepidle = 60;
470   set->tcp_fastopen = FALSE;
471   set->tcp_nodelay = TRUE;
472   set->ssl_enable_alpn = TRUE;
473   set->expect_100_timeout = 1000L; /* Wait for a second by default. */
474   set->sep_headers = TRUE; /* separated header lists by default */
475   set->buffer_size = READBUFFER_SIZE;
476   set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
477   set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
478   set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
479   set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
480   set->maxage_conn = 118;
481   set->maxlifetime_conn = 0;
482   set->http09_allowed = FALSE;
483 #ifdef USE_HTTP2
484   set->httpwant = CURL_HTTP_VERSION_2TLS
485 #else
486   set->httpwant = CURL_HTTP_VERSION_1_1
487 #endif
488     ;
489 #if defined(USE_HTTP2) || defined(USE_HTTP3)
490   memset(&set->priority, 0, sizeof(set->priority));
491 #endif
492   set->quick_exit = 0L;
493   return result;
494 }
495 
496 /**
497  * Curl_open()
498  *
499  * @param curl is a pointer to a sessionhandle pointer that gets set by this
500  * function.
501  * @return CURLcode
502  */
503 
Curl_open(struct Curl_easy ** curl)504 CURLcode Curl_open(struct Curl_easy **curl)
505 {
506   CURLcode result;
507   struct Curl_easy *data;
508 
509   /* Very simple start-up: alloc the struct, init it with zeroes and return */
510   data = calloc(1, sizeof(struct Curl_easy));
511   if(!data) {
512     /* this is a very serious error */
513     DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n"));
514     return CURLE_OUT_OF_MEMORY;
515   }
516 
517   data->magic = CURLEASY_MAGIC_NUMBER;
518 
519   Curl_req_init(&data->req);
520 
521   result = Curl_resolver_init(data, &data->state.async.resolver);
522   if(result) {
523     DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
524     Curl_req_free(&data->req, data);
525     free(data);
526     return result;
527   }
528 
529   result = Curl_init_userdefined(data);
530   if(!result) {
531     Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
532     Curl_initinfo(data);
533 
534     /* most recent connection is not yet defined */
535     data->state.lastconnect_id = -1;
536     data->state.recent_conn_id = -1;
537     /* and not assigned an id yet */
538     data->id = -1;
539 
540     data->progress.flags |= PGRS_HIDE;
541     data->state.current_speed = -1; /* init to negative == impossible */
542   }
543 
544   if(result) {
545     Curl_resolver_cleanup(data->state.async.resolver);
546     Curl_dyn_free(&data->state.headerb);
547     Curl_freeset(data);
548     Curl_req_free(&data->req, data);
549     free(data);
550     data = NULL;
551   }
552   else
553     *curl = data;
554 
555   return result;
556 }
557 
conn_shutdown(struct Curl_easy * data)558 static void conn_shutdown(struct Curl_easy *data)
559 {
560   DEBUGASSERT(data);
561   infof(data, "Closing connection");
562 
563   /* possible left-overs from the async name resolvers */
564   Curl_resolver_cancel(data);
565 
566   Curl_conn_close(data, SECONDARYSOCKET);
567   Curl_conn_close(data, FIRSTSOCKET);
568 }
569 
conn_free(struct Curl_easy * data,struct connectdata * conn)570 static void conn_free(struct Curl_easy *data, struct connectdata *conn)
571 {
572   size_t i;
573 
574   DEBUGASSERT(conn);
575 
576   for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
577     Curl_conn_cf_discard_all(data, conn, (int)i);
578   }
579 
580   Curl_free_idnconverted_hostname(&conn->host);
581   Curl_free_idnconverted_hostname(&conn->conn_to_host);
582 #ifndef CURL_DISABLE_PROXY
583   Curl_free_idnconverted_hostname(&conn->http_proxy.host);
584   Curl_free_idnconverted_hostname(&conn->socks_proxy.host);
585   Curl_safefree(conn->http_proxy.user);
586   Curl_safefree(conn->socks_proxy.user);
587   Curl_safefree(conn->http_proxy.passwd);
588   Curl_safefree(conn->socks_proxy.passwd);
589   Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
590   Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
591 #endif
592   Curl_safefree(conn->user);
593   Curl_safefree(conn->passwd);
594   Curl_safefree(conn->sasl_authzid);
595   Curl_safefree(conn->options);
596   Curl_safefree(conn->oauth_bearer);
597   Curl_safefree(conn->host.rawalloc); /* host name buffer */
598   Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
599   Curl_safefree(conn->hostname_resolve);
600   Curl_safefree(conn->secondaryhostname);
601   Curl_safefree(conn->localdev);
602   Curl_ssl_conn_config_cleanup(conn);
603 
604 #ifdef USE_UNIX_SOCKETS
605   Curl_safefree(conn->unix_domain_socket);
606 #endif
607 
608   free(conn); /* free all the connection oriented data */
609 }
610 
611 /*
612  * Disconnects the given connection. Note the connection may not be the
613  * primary connection, like when freeing room in the connection cache or
614  * killing of a dead old connection.
615  *
616  * A connection needs an easy handle when closing down. We support this passed
617  * in separately since the connection to get closed here is often already
618  * disassociated from an easy handle.
619  *
620  * This function MUST NOT reset state in the Curl_easy struct if that
621  * isn't strictly bound to the life-time of *this* particular connection.
622  *
623  */
624 
Curl_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)625 void Curl_disconnect(struct Curl_easy *data,
626                      struct connectdata *conn, bool dead_connection)
627 {
628   /* there must be a connection to close */
629   DEBUGASSERT(conn);
630 
631   /* it must be removed from the connection cache */
632   DEBUGASSERT(!conn->bundle);
633 
634   /* there must be an associated transfer */
635   DEBUGASSERT(data);
636 
637   /* the transfer must be detached from the connection */
638   DEBUGASSERT(!data->conn);
639 
640   DEBUGF(infof(data, "Curl_disconnect(conn #%"
641          CURL_FORMAT_CURL_OFF_T ", dead=%d)",
642          conn->connection_id, dead_connection));
643   /*
644    * If this connection isn't marked to force-close, leave it open if there
645    * are other users of it
646    */
647   if(CONN_INUSE(conn) && !dead_connection) {
648     DEBUGF(infof(data, "Curl_disconnect when inuse: %zu", CONN_INUSE(conn)));
649     return;
650   }
651 
652   if(conn->dns_entry) {
653     Curl_resolv_unlock(data, conn->dns_entry);
654     conn->dns_entry = NULL;
655   }
656 
657   /* Cleanup NTLM connection-related data */
658   Curl_http_auth_cleanup_ntlm(conn);
659 
660   /* Cleanup NEGOTIATE connection-related data */
661   Curl_http_auth_cleanup_negotiate(conn);
662 
663   if(conn->connect_only)
664     /* treat the connection as dead in CONNECT_ONLY situations */
665     dead_connection = TRUE;
666 
667   /* temporarily attach the connection to this transfer handle for the
668      disconnect and shutdown */
669   Curl_attach_connection(data, conn);
670 
671   if(conn->handler && conn->handler->disconnect)
672     /* This is set if protocol-specific cleanups should be made */
673     conn->handler->disconnect(data, conn, dead_connection);
674 
675   conn_shutdown(data);
676 
677   /* detach it again */
678   Curl_detach_connection(data);
679 
680   conn_free(data, conn);
681 }
682 
683 /*
684  * IsMultiplexingPossible()
685  *
686  * Return a bitmask with the available multiplexing options for the given
687  * requested connection.
688  */
IsMultiplexingPossible(const struct Curl_easy * handle,const struct connectdata * conn)689 static int IsMultiplexingPossible(const struct Curl_easy *handle,
690                                   const struct connectdata *conn)
691 {
692   int avail = 0;
693 
694   /* If an HTTP protocol and multiplexing is enabled */
695   if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
696      (!conn->bits.protoconnstart || !conn->bits.close)) {
697 
698     if(Curl_multiplex_wanted(handle->multi) &&
699        (handle->state.httpwant >= CURL_HTTP_VERSION_2))
700       /* allows HTTP/2 */
701       avail |= CURLPIPE_MULTIPLEX;
702   }
703   return avail;
704 }
705 
706 #ifndef CURL_DISABLE_PROXY
707 static bool
proxy_info_matches(const struct proxy_info * data,const struct proxy_info * needle)708 proxy_info_matches(const struct proxy_info *data,
709                    const struct proxy_info *needle)
710 {
711   if((data->proxytype == needle->proxytype) &&
712      (data->port == needle->port) &&
713      strcasecompare(data->host.name, needle->host.name))
714     return TRUE;
715 
716   return FALSE;
717 }
718 
719 static bool
socks_proxy_info_matches(const struct proxy_info * data,const struct proxy_info * needle)720 socks_proxy_info_matches(const struct proxy_info *data,
721                          const struct proxy_info *needle)
722 {
723   if(!proxy_info_matches(data, needle))
724     return FALSE;
725 
726   /* the user information is case-sensitive
727      or at least it is not defined as case-insensitive
728      see https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1 */
729 
730   /* curl_strequal does a case insensitive comparison,
731      so do not use it here! */
732   if(Curl_timestrcmp(data->user, needle->user) ||
733      Curl_timestrcmp(data->passwd, needle->passwd))
734     return FALSE;
735   return TRUE;
736 }
737 #else
738 /* disabled, won't get called */
739 #define proxy_info_matches(x,y) FALSE
740 #define socks_proxy_info_matches(x,y) FALSE
741 #endif
742 
743 /* A connection has to have been idle for a shorter time than 'maxage_conn'
744    (the success rate is just too low after this), or created less than
745    'maxlifetime_conn' ago, to be subject for reuse. */
746 
conn_maxage(struct Curl_easy * data,struct connectdata * conn,struct curltime now)747 static bool conn_maxage(struct Curl_easy *data,
748                         struct connectdata *conn,
749                         struct curltime now)
750 {
751   timediff_t idletime, lifetime;
752 
753   idletime = Curl_timediff(now, conn->lastused);
754   idletime /= 1000; /* integer seconds is fine */
755 
756   if(idletime > data->set.maxage_conn) {
757     infof(data, "Too old connection (%" CURL_FORMAT_TIMEDIFF_T
758           " seconds idle), disconnect it", idletime);
759     return TRUE;
760   }
761 
762   lifetime = Curl_timediff(now, conn->created);
763   lifetime /= 1000; /* integer seconds is fine */
764 
765   if(data->set.maxlifetime_conn && lifetime > data->set.maxlifetime_conn) {
766     infof(data,
767           "Too old connection (%" CURL_FORMAT_TIMEDIFF_T
768           " seconds since creation), disconnect it", lifetime);
769     return TRUE;
770   }
771 
772 
773   return FALSE;
774 }
775 
776 /*
777  * This function checks if the given connection is dead and extracts it from
778  * the connection cache if so.
779  *
780  * When this is called as a Curl_conncache_foreach() callback, the connection
781  * cache lock is held!
782  *
783  * Returns TRUE if the connection was dead and extracted.
784  */
extract_if_dead(struct connectdata * conn,struct Curl_easy * data)785 static bool extract_if_dead(struct connectdata *conn,
786                             struct Curl_easy *data)
787 {
788   if(!CONN_INUSE(conn)) {
789     /* The check for a dead socket makes sense only if the connection isn't in
790        use */
791     bool dead;
792     struct curltime now = Curl_now();
793     if(conn_maxage(data, conn, now)) {
794       /* avoid check if already too old */
795       dead = TRUE;
796     }
797     else if(conn->handler->connection_check) {
798       /* The protocol has a special method for checking the state of the
799          connection. Use it to check if the connection is dead. */
800       unsigned int state;
801 
802       /* briefly attach the connection to this transfer for the purpose of
803          checking it */
804       Curl_attach_connection(data, conn);
805 
806       state = conn->handler->connection_check(data, conn, CONNCHECK_ISDEAD);
807       dead = (state & CONNRESULT_DEAD);
808       /* detach the connection again */
809       Curl_detach_connection(data);
810 
811     }
812     else {
813       bool input_pending = FALSE;
814 
815       Curl_attach_connection(data, conn);
816       dead = !Curl_conn_is_alive(data, conn, &input_pending);
817       if(input_pending) {
818         /* For reuse, we want a "clean" connection state. The includes
819          * that we expect - in general - no waiting input data. Input
820          * waiting might be a TLS Notify Close, for example. We reject
821          * that.
822          * For protocols where data from other end may arrive at
823          * any time (HTTP/2 PING for example), the protocol handler needs
824          * to install its own `connection_check` callback.
825          */
826         dead = TRUE;
827       }
828       Curl_detach_connection(data);
829     }
830 
831     if(dead) {
832       infof(data, "Connection %" CURL_FORMAT_CURL_OFF_T " seems to be dead",
833             conn->connection_id);
834       Curl_conncache_remove_conn(data, conn, FALSE);
835       return TRUE;
836     }
837   }
838   return FALSE;
839 }
840 
841 struct prunedead {
842   struct Curl_easy *data;
843   struct connectdata *extracted;
844 };
845 
846 /*
847  * Wrapper to use extract_if_dead() function in Curl_conncache_foreach()
848  *
849  */
call_extract_if_dead(struct Curl_easy * data,struct connectdata * conn,void * param)850 static int call_extract_if_dead(struct Curl_easy *data,
851                                 struct connectdata *conn, void *param)
852 {
853   struct prunedead *p = (struct prunedead *)param;
854   if(extract_if_dead(conn, data)) {
855     /* stop the iteration here, pass back the connection that was extracted */
856     p->extracted = conn;
857     return 1;
858   }
859   return 0; /* continue iteration */
860 }
861 
862 /*
863  * This function scans the connection cache for half-open/dead connections,
864  * closes and removes them. The cleanup is done at most once per second.
865  *
866  * When called, this transfer has no connection attached.
867  */
prune_dead_connections(struct Curl_easy * data)868 static void prune_dead_connections(struct Curl_easy *data)
869 {
870   struct curltime now = Curl_now();
871   timediff_t elapsed;
872 
873   DEBUGASSERT(!data->conn); /* no connection */
874   CONNCACHE_LOCK(data);
875   elapsed =
876     Curl_timediff(now, data->state.conn_cache->last_cleanup);
877   CONNCACHE_UNLOCK(data);
878 
879   if(elapsed >= 1000L) {
880     struct prunedead prune;
881     prune.data = data;
882     prune.extracted = NULL;
883     while(Curl_conncache_foreach(data, data->state.conn_cache, &prune,
884                                  call_extract_if_dead)) {
885       /* unlocked */
886 
887       /* remove connection from cache */
888       Curl_conncache_remove_conn(data, prune.extracted, TRUE);
889 
890       /* disconnect it */
891       Curl_disconnect(data, prune.extracted, TRUE);
892     }
893     CONNCACHE_LOCK(data);
894     data->state.conn_cache->last_cleanup = now;
895     CONNCACHE_UNLOCK(data);
896   }
897 }
898 
899 #ifdef USE_SSH
ssh_config_matches(struct connectdata * one,struct connectdata * two)900 static bool ssh_config_matches(struct connectdata *one,
901                                struct connectdata *two)
902 {
903   return (Curl_safecmp(one->proto.sshc.rsa, two->proto.sshc.rsa) &&
904           Curl_safecmp(one->proto.sshc.rsa_pub, two->proto.sshc.rsa_pub));
905 }
906 #else
907 #define ssh_config_matches(x,y) FALSE
908 #endif
909 
910 /*
911  * Given one filled in connection struct (named needle), this function should
912  * detect if there already is one that has all the significant details
913  * exactly the same and thus should be used instead.
914  *
915  * If there is a match, this function returns TRUE - and has marked the
916  * connection as 'in-use'. It must later be called with ConnectionDone() to
917  * return back to 'idle' (unused) state.
918  *
919  * The force_reuse flag is set if the connection must be used.
920  */
921 static bool
ConnectionExists(struct Curl_easy * data,struct connectdata * needle,struct connectdata ** usethis,bool * force_reuse,bool * waitpipe)922 ConnectionExists(struct Curl_easy *data,
923                  struct connectdata *needle,
924                  struct connectdata **usethis,
925                  bool *force_reuse,
926                  bool *waitpipe)
927 {
928   struct connectdata *chosen = NULL;
929   bool foundPendingCandidate = FALSE;
930   bool canmultiplex = FALSE;
931   struct connectbundle *bundle;
932   struct Curl_llist_element *curr;
933 
934 #ifdef USE_NTLM
935   bool wantNTLMhttp = ((data->state.authhost.want & CURLAUTH_NTLM) &&
936                        (needle->handler->protocol & PROTO_FAMILY_HTTP));
937 #ifndef CURL_DISABLE_PROXY
938   bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd &&
939                             ((data->state.authproxy.want &
940                               CURLAUTH_NTLM) &&
941                              (needle->handler->protocol & PROTO_FAMILY_HTTP)));
942 #else
943   bool wantProxyNTLMhttp = FALSE;
944 #endif
945 #endif
946   /* plain HTTP with upgrade */
947   bool h2upgrade = (data->state.httpwant == CURL_HTTP_VERSION_2_0) &&
948     (needle->handler->protocol & CURLPROTO_HTTP);
949 
950   *usethis = NULL;
951   *force_reuse = FALSE;
952   *waitpipe = FALSE;
953 
954   /* Look up the bundle with all the connections to this particular host.
955      Locks the connection cache, beware of early returns! */
956   bundle = Curl_conncache_find_bundle(data, needle, data->state.conn_cache);
957   if(!bundle) {
958     CONNCACHE_UNLOCK(data);
959     return FALSE;
960   }
961   infof(data, "Found bundle for host: %p [%s]",
962         (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ?
963                          "can multiplex" : "serially"));
964 
965   /* We can only multiplex iff the transfer allows it AND we know
966    * that the server we want to talk to supports it as well. */
967   canmultiplex = FALSE;
968   if(IsMultiplexingPossible(data, needle)) {
969     if(bundle->multiuse == BUNDLE_UNKNOWN) {
970       if(data->set.pipewait) {
971         infof(data, "Server doesn't support multiplex yet, wait");
972         *waitpipe = TRUE;
973         CONNCACHE_UNLOCK(data);
974         return FALSE; /* no reuse */
975       }
976       infof(data, "Server doesn't support multiplex (yet)");
977     }
978     else if(bundle->multiuse == BUNDLE_MULTIPLEX) {
979       if(Curl_multiplex_wanted(data->multi))
980         canmultiplex = TRUE;
981       else
982         infof(data, "Could multiplex, but not asked to");
983     }
984     else if(bundle->multiuse == BUNDLE_NO_MULTIUSE) {
985       infof(data, "Can not multiplex, even if we wanted to");
986     }
987   }
988 
989   curr = bundle->conn_list.head;
990   while(curr) {
991     struct connectdata *check = curr->ptr;
992     /* Get next node now. We might remove a dead `check` connection which
993      * would invalidate `curr` as well. */
994     curr = curr->next;
995 
996     /* Note that if we use an HTTP proxy in normal mode (no tunneling), we
997      * check connections to that proxy and not to the actual remote server.
998      */
999     if(check->connect_only || check->bits.close)
1000       /* connect-only or to-be-closed connections will not be reused */
1001       continue;
1002 
1003     if(data->set.ipver != CURL_IPRESOLVE_WHATEVER
1004        && data->set.ipver != check->ip_version) {
1005       /* skip because the connection is not via the requested IP version */
1006       continue;
1007     }
1008 
1009     if(!canmultiplex) {
1010       if(Curl_resolver_asynch() &&
1011          /* remote_ip[0] is NUL only if the resolving of the name hasn't
1012             completed yet and until then we don't reuse this connection */
1013          !check->primary.remote_ip[0])
1014         continue;
1015     }
1016 
1017     if(CONN_INUSE(check)) {
1018       if(!canmultiplex) {
1019         /* transfer can't be multiplexed and check is in use */
1020         continue;
1021       }
1022       else {
1023         /* Could multiplex, but not when check belongs to another multi */
1024         struct Curl_llist_element *e = check->easyq.head;
1025         struct Curl_easy *entry = e->ptr;
1026         if(entry->multi != data->multi)
1027           continue;
1028       }
1029     }
1030 
1031     if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
1032       foundPendingCandidate = TRUE;
1033       /* Don't pick a connection that hasn't connected yet */
1034       infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T
1035             " isn't open enough, can't reuse", check->connection_id);
1036       continue;
1037     }
1038 
1039     /* `check` is connected. if it is in use and does not support multiplex,
1040      * we cannot use it. */
1041     if(!check->bits.multiplex && CONN_INUSE(check))
1042       continue;
1043 
1044 #ifdef USE_UNIX_SOCKETS
1045     if(needle->unix_domain_socket) {
1046       if(!check->unix_domain_socket)
1047         continue;
1048       if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
1049         continue;
1050       if(needle->bits.abstract_unix_socket !=
1051          check->bits.abstract_unix_socket)
1052         continue;
1053     }
1054     else if(check->unix_domain_socket)
1055       continue;
1056 #endif
1057 
1058     if((needle->handler->flags&PROTOPT_SSL) !=
1059        (check->handler->flags&PROTOPT_SSL))
1060       /* don't do mixed SSL and non-SSL connections */
1061       if(get_protocol_family(check->handler) !=
1062          needle->handler->protocol || !check->bits.tls_upgraded)
1063         /* except protocols that have been upgraded via TLS */
1064         continue;
1065 
1066     if(needle->bits.conn_to_host != check->bits.conn_to_host)
1067       /* don't mix connections that use the "connect to host" feature and
1068        * connections that don't use this feature */
1069       continue;
1070 
1071     if(needle->bits.conn_to_port != check->bits.conn_to_port)
1072       /* don't mix connections that use the "connect to port" feature and
1073        * connections that don't use this feature */
1074       continue;
1075 
1076 #ifndef CURL_DISABLE_PROXY
1077     if(needle->bits.httpproxy != check->bits.httpproxy ||
1078        needle->bits.socksproxy != check->bits.socksproxy)
1079       continue;
1080 
1081     if(needle->bits.socksproxy &&
1082       !socks_proxy_info_matches(&needle->socks_proxy,
1083                                 &check->socks_proxy))
1084       continue;
1085 
1086     if(needle->bits.httpproxy) {
1087       if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy)
1088         continue;
1089 
1090       if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy))
1091         continue;
1092 
1093       if(IS_HTTPS_PROXY(needle->http_proxy.proxytype)) {
1094         /* https proxies come in different types, http/1.1, h2, ... */
1095         if(needle->http_proxy.proxytype != check->http_proxy.proxytype)
1096           continue;
1097         /* match SSL config to proxy */
1098         if(!Curl_ssl_conn_config_match(data, check, TRUE)) {
1099           DEBUGF(infof(data,
1100             "Connection #%" CURL_FORMAT_CURL_OFF_T
1101             " has different SSL proxy parameters, can't reuse",
1102             check->connection_id));
1103           continue;
1104         }
1105         /* the SSL config to the server, which may apply here is checked
1106          * further below */
1107       }
1108     }
1109 #endif
1110 
1111     if(h2upgrade && !check->httpversion && canmultiplex) {
1112       if(data->set.pipewait) {
1113         infof(data, "Server upgrade doesn't support multiplex yet, wait");
1114         *waitpipe = TRUE;
1115         CONNCACHE_UNLOCK(data);
1116         return FALSE; /* no reuse */
1117       }
1118       infof(data, "Server upgrade cannot be used");
1119       continue; /* can't be used atm */
1120     }
1121 
1122     if(needle->localdev || needle->localport) {
1123       /* If we are bound to a specific local end (IP+port), we must not
1124          reuse a random other one, although if we didn't ask for a
1125          particular one we can reuse one that was bound.
1126 
1127          This comparison is a bit rough and too strict. Since the input
1128          parameters can be specified in numerous ways and still end up the
1129          same it would take a lot of processing to make it really accurate.
1130          Instead, this matching will assume that reuses of bound connections
1131          will most likely also reuse the exact same binding parameters and
1132          missing out a few edge cases shouldn't hurt anyone very much.
1133       */
1134       if((check->localport != needle->localport) ||
1135          (check->localportrange != needle->localportrange) ||
1136          (needle->localdev &&
1137           (!check->localdev || strcmp(check->localdev, needle->localdev))))
1138         continue;
1139     }
1140 
1141     if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
1142       /* This protocol requires credentials per connection,
1143          so verify that we're using the same name and password as well */
1144       if(Curl_timestrcmp(needle->user, check->user) ||
1145          Curl_timestrcmp(needle->passwd, check->passwd) ||
1146          Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) ||
1147          Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) {
1148         /* one of them was different */
1149         continue;
1150       }
1151     }
1152 
1153     /* GSS delegation differences do not actually affect every connection
1154        and auth method, but this check takes precaution before efficiency */
1155     if(needle->gssapi_delegation != check->gssapi_delegation)
1156       continue;
1157 
1158     /* If looking for HTTP and the HTTP version  we want is less
1159      * than the HTTP version of the check connection, continue looking */
1160     if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
1161        (((check->httpversion >= 20) &&
1162          (data->state.httpwant < CURL_HTTP_VERSION_2_0))
1163         || ((check->httpversion >= 30) &&
1164             (data->state.httpwant < CURL_HTTP_VERSION_3))))
1165       continue;
1166 #ifdef USE_SSH
1167     else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
1168       if(!ssh_config_matches(needle, check))
1169         continue;
1170     }
1171 #endif
1172 #ifndef CURL_DISABLE_FTP
1173     else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) {
1174       /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */
1175       if(Curl_timestrcmp(needle->proto.ftpc.account,
1176                          check->proto.ftpc.account) ||
1177          Curl_timestrcmp(needle->proto.ftpc.alternative_to_user,
1178                          check->proto.ftpc.alternative_to_user) ||
1179          (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) ||
1180          (needle->proto.ftpc.ccc != check->proto.ftpc.ccc))
1181         continue;
1182     }
1183 #endif
1184 
1185     /* Additional match requirements if talking TLS OR
1186      * not talking to a HTTP proxy OR using a tunnel through a proxy */
1187     if((needle->handler->flags&PROTOPT_SSL)
1188 #ifndef CURL_DISABLE_PROXY
1189        || !needle->bits.httpproxy || needle->bits.tunnel_proxy
1190 #endif
1191       ) {
1192       /* Talking the same protocol scheme or a TLS upgraded protocol in the
1193        * same protocol family? */
1194       if(!strcasecompare(needle->handler->scheme, check->handler->scheme) &&
1195          (get_protocol_family(check->handler) !=
1196           needle->handler->protocol || !check->bits.tls_upgraded))
1197         continue;
1198 
1199       /* If needle has "conn_to_*" set, check must match this */
1200       if((needle->bits.conn_to_host && !strcasecompare(
1201           needle->conn_to_host.name, check->conn_to_host.name)) ||
1202          (needle->bits.conn_to_port &&
1203            needle->conn_to_port != check->conn_to_port))
1204         continue;
1205 
1206       /* hostname and port must match */
1207       if(!strcasecompare(needle->host.name, check->host.name) ||
1208          needle->remote_port != check->remote_port)
1209         continue;
1210 
1211       /* If talking TLS, check needs to use the same SSL options. */
1212       if((needle->handler->flags & PROTOPT_SSL) &&
1213          !Curl_ssl_conn_config_match(data, check, FALSE)) {
1214         DEBUGF(infof(data,
1215                      "Connection #%" CURL_FORMAT_CURL_OFF_T
1216                      " has different SSL parameters, can't reuse",
1217                      check->connection_id));
1218         continue;
1219       }
1220     }
1221 
1222 #if defined(USE_NTLM)
1223     /* If we are looking for an HTTP+NTLM connection, check if this is
1224        already authenticating with the right credentials. If not, keep
1225        looking so that we can reuse NTLM connections if
1226        possible. (Especially we must not reuse the same connection if
1227        partway through a handshake!) */
1228     if(wantNTLMhttp) {
1229       if(Curl_timestrcmp(needle->user, check->user) ||
1230          Curl_timestrcmp(needle->passwd, check->passwd)) {
1231 
1232         /* we prefer a credential match, but this is at least a connection
1233            that can be reused and "upgraded" to NTLM */
1234         if(check->http_ntlm_state == NTLMSTATE_NONE)
1235           chosen = check;
1236         continue;
1237       }
1238     }
1239     else if(check->http_ntlm_state != NTLMSTATE_NONE) {
1240       /* Connection is using NTLM auth but we don't want NTLM */
1241       continue;
1242     }
1243 
1244 #ifndef CURL_DISABLE_PROXY
1245     /* Same for Proxy NTLM authentication */
1246     if(wantProxyNTLMhttp) {
1247       /* Both check->http_proxy.user and check->http_proxy.passwd can be
1248        * NULL */
1249       if(!check->http_proxy.user || !check->http_proxy.passwd)
1250         continue;
1251 
1252       if(Curl_timestrcmp(needle->http_proxy.user,
1253                          check->http_proxy.user) ||
1254          Curl_timestrcmp(needle->http_proxy.passwd,
1255                          check->http_proxy.passwd))
1256         continue;
1257     }
1258     else if(check->proxy_ntlm_state != NTLMSTATE_NONE) {
1259       /* Proxy connection is using NTLM auth but we don't want NTLM */
1260       continue;
1261     }
1262 #endif
1263     if(wantNTLMhttp || wantProxyNTLMhttp) {
1264       /* Credentials are already checked, we may use this connection.
1265        * With NTLM being weird as it is, we MUST use a
1266        * connection where it has already been fully negotiated.
1267        * If it has not, we keep on looking for a better one. */
1268       chosen = check;
1269 
1270       if((wantNTLMhttp &&
1271          (check->http_ntlm_state != NTLMSTATE_NONE)) ||
1272           (wantProxyNTLMhttp &&
1273            (check->proxy_ntlm_state != NTLMSTATE_NONE))) {
1274         /* We must use this connection, no other */
1275         *force_reuse = TRUE;
1276         break;
1277       }
1278       /* Continue look up for a better connection */
1279       continue;
1280     }
1281 #endif
1282 
1283     if(CONN_INUSE(check)) {
1284       DEBUGASSERT(canmultiplex);
1285       DEBUGASSERT(check->bits.multiplex);
1286       /* If multiplexed, make sure we don't go over concurrency limit */
1287       if(CONN_INUSE(check) >=
1288               Curl_multi_max_concurrent_streams(data->multi)) {
1289         infof(data, "client side MAX_CONCURRENT_STREAMS reached"
1290               ", skip (%zu)", CONN_INUSE(check));
1291         continue;
1292       }
1293       if(CONN_INUSE(check) >=
1294               Curl_conn_get_max_concurrent(data, check, FIRSTSOCKET)) {
1295         infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
1296               CONN_INUSE(check));
1297         continue;
1298       }
1299       /* When not multiplexed, we have a match here! */
1300       infof(data, "Multiplexed connection found");
1301     }
1302     else if(extract_if_dead(check, data)) {
1303       /* disconnect it */
1304       Curl_disconnect(data, check, TRUE);
1305       continue;
1306     }
1307 
1308     /* We have found a connection. Let's stop searching. */
1309     chosen = check;
1310     break;
1311   } /* loop over connection bundle */
1312 
1313   if(chosen) {
1314     /* mark it as used before releasing the lock */
1315     Curl_attach_connection(data, chosen);
1316     CONNCACHE_UNLOCK(data);
1317     *usethis = chosen;
1318     return TRUE; /* yes, we found one to use! */
1319   }
1320   CONNCACHE_UNLOCK(data);
1321 
1322   if(foundPendingCandidate && data->set.pipewait) {
1323     infof(data,
1324           "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
1325     *waitpipe = TRUE;
1326   }
1327 
1328   return FALSE; /* no matching connecting exists */
1329 }
1330 
1331 /*
1332  * verboseconnect() displays verbose information after a connect
1333  */
1334 #ifndef CURL_DISABLE_VERBOSE_STRINGS
Curl_verboseconnect(struct Curl_easy * data,struct connectdata * conn,int sockindex)1335 void Curl_verboseconnect(struct Curl_easy *data,
1336                          struct connectdata *conn, int sockindex)
1337 {
1338   if(data->set.verbose && sockindex == SECONDARYSOCKET)
1339     infof(data, "Connected 2nd connection to %s port %u",
1340           conn->secondary.remote_ip, conn->secondary.remote_port);
1341   else
1342     infof(data, "Connected to %s (%s) port %u",
1343           CURL_CONN_HOST_DISPNAME(conn), conn->primary.remote_ip,
1344           conn->primary.remote_port);
1345 }
1346 #endif
1347 
1348 /*
1349  * Allocate and initialize a new connectdata object.
1350  */
allocate_conn(struct Curl_easy * data)1351 static struct connectdata *allocate_conn(struct Curl_easy *data)
1352 {
1353   struct connectdata *conn = calloc(1, sizeof(struct connectdata));
1354   if(!conn)
1355     return NULL;
1356 
1357   /* and we setup a few fields in case we end up actually using this struct */
1358 
1359   conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
1360   conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
1361   conn->sockfd = CURL_SOCKET_BAD;
1362   conn->writesockfd = CURL_SOCKET_BAD;
1363   conn->connection_id = -1;    /* no ID */
1364   conn->primary.remote_port = -1; /* unknown at this point */
1365   conn->remote_port = -1; /* unknown at this point */
1366 
1367   /* Default protocol-independent behavior doesn't support persistent
1368      connections, so we set this to force-close. Protocols that support
1369      this need to set this to FALSE in their "curl_do" functions. */
1370   connclose(conn, "Default to force-close");
1371 
1372   /* Store creation time to help future close decision making */
1373   conn->created = Curl_now();
1374 
1375   /* Store current time to give a baseline to keepalive connection times. */
1376   conn->keepalive = conn->created;
1377 
1378 #ifndef CURL_DISABLE_PROXY
1379   conn->http_proxy.proxytype = data->set.proxytype;
1380   conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
1381 
1382   /* note that these two proxy bits are now just on what looks to be
1383      requested, they may be altered down the road */
1384   conn->bits.proxy = (data->set.str[STRING_PROXY] &&
1385                       *data->set.str[STRING_PROXY]) ? TRUE : FALSE;
1386   conn->bits.httpproxy = (conn->bits.proxy &&
1387                           (conn->http_proxy.proxytype == CURLPROXY_HTTP ||
1388                            conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
1389                            IS_HTTPS_PROXY(conn->http_proxy.proxytype))) ?
1390     TRUE : FALSE;
1391   conn->bits.socksproxy = (conn->bits.proxy &&
1392                            !conn->bits.httpproxy) ? TRUE : FALSE;
1393 
1394   if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
1395     conn->bits.proxy = TRUE;
1396     conn->bits.socksproxy = TRUE;
1397   }
1398 
1399   conn->bits.proxy_user_passwd =
1400     (data->state.aptr.proxyuser) ? TRUE : FALSE;
1401   conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
1402 #endif /* CURL_DISABLE_PROXY */
1403 
1404 #ifndef CURL_DISABLE_FTP
1405   conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
1406   conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
1407 #endif
1408   conn->ip_version = data->set.ipver;
1409   conn->connect_only = data->set.connect_only;
1410   conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
1411 
1412   /* Initialize the easy handle list */
1413   Curl_llist_init(&conn->easyq, NULL);
1414 
1415 #ifdef HAVE_GSSAPI
1416   conn->data_prot = PROT_CLEAR;
1417 #endif
1418 
1419   /* Store the local bind parameters that will be used for this connection */
1420   if(data->set.str[STRING_DEVICE]) {
1421     conn->localdev = strdup(data->set.str[STRING_DEVICE]);
1422     if(!conn->localdev)
1423       goto error;
1424   }
1425 #ifndef CURL_DISABLE_BINDLOCAL
1426   conn->localportrange = data->set.localportrange;
1427   conn->localport = data->set.localport;
1428 #endif
1429 
1430   /* the close socket stuff needs to be copied to the connection struct as
1431      it may live on without (this specific) Curl_easy */
1432   conn->fclosesocket = data->set.fclosesocket;
1433   conn->closesocket_client = data->set.closesocket_client;
1434   conn->lastused = conn->created;
1435   conn->gssapi_delegation = data->set.gssapi_delegation;
1436 
1437   return conn;
1438 error:
1439 
1440   free(conn->localdev);
1441   free(conn);
1442   return NULL;
1443 }
1444 
Curl_get_scheme_handler(const char * scheme)1445 const struct Curl_handler *Curl_get_scheme_handler(const char *scheme)
1446 {
1447   return Curl_getn_scheme_handler(scheme, strlen(scheme));
1448 }
1449 
1450 /* returns the handler if the given scheme is built-in */
Curl_getn_scheme_handler(const char * scheme,size_t len)1451 const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
1452                                                     size_t len)
1453 {
1454   /* table generated by schemetable.c:
1455      1. gcc schemetable.c && ./a.out
1456      2. check how small the table gets
1457      3. tweak the hash algorithm, then rerun from 1
1458      4. when the table is good enough
1459      5. copy the table into this source code
1460      6. make sure this function uses the same hash function that worked for
1461      schemetable.c
1462      7. if needed, adjust the #ifdefs in schemetable.c and rerun
1463      */
1464   static const struct Curl_handler * const protocols[67] = {
1465 #ifndef CURL_DISABLE_FILE
1466     &Curl_handler_file,
1467 #else
1468     NULL,
1469 #endif
1470     NULL, NULL,
1471 #if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)
1472     &Curl_handler_gophers,
1473 #else
1474     NULL,
1475 #endif
1476     NULL,
1477 #ifdef USE_LIBRTMP
1478     &Curl_handler_rtmpe,
1479 #else
1480     NULL,
1481 #endif
1482 #ifndef CURL_DISABLE_SMTP
1483     &Curl_handler_smtp,
1484 #else
1485     NULL,
1486 #endif
1487 #if defined(USE_SSH)
1488     &Curl_handler_sftp,
1489 #else
1490     NULL,
1491 #endif
1492 #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
1493   (SIZEOF_CURL_OFF_T > 4)
1494     &Curl_handler_smb,
1495 #else
1496     NULL,
1497 #endif
1498 #if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
1499     &Curl_handler_smtps,
1500 #else
1501     NULL,
1502 #endif
1503 #ifndef CURL_DISABLE_TELNET
1504     &Curl_handler_telnet,
1505 #else
1506     NULL,
1507 #endif
1508 #ifndef CURL_DISABLE_GOPHER
1509     &Curl_handler_gopher,
1510 #else
1511     NULL,
1512 #endif
1513 #ifndef CURL_DISABLE_TFTP
1514     &Curl_handler_tftp,
1515 #else
1516     NULL,
1517 #endif
1518     NULL, NULL, NULL,
1519 #if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
1520     &Curl_handler_ftps,
1521 #else
1522     NULL,
1523 #endif
1524 #ifndef CURL_DISABLE_HTTP
1525     &Curl_handler_http,
1526 #else
1527     NULL,
1528 #endif
1529 #ifndef CURL_DISABLE_IMAP
1530     &Curl_handler_imap,
1531 #else
1532     NULL,
1533 #endif
1534 #ifdef USE_LIBRTMP
1535     &Curl_handler_rtmps,
1536 #else
1537     NULL,
1538 #endif
1539 #ifdef USE_LIBRTMP
1540     &Curl_handler_rtmpt,
1541 #else
1542     NULL,
1543 #endif
1544     NULL, NULL, NULL,
1545 #if !defined(CURL_DISABLE_LDAP) && \
1546   !defined(CURL_DISABLE_LDAPS) && \
1547   ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
1548    (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
1549     &Curl_handler_ldaps,
1550 #else
1551     NULL,
1552 #endif
1553 #if defined(USE_WEBSOCKETS) && \
1554   defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
1555     &Curl_handler_wss,
1556 #else
1557     NULL,
1558 #endif
1559 #if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
1560     &Curl_handler_https,
1561 #else
1562     NULL,
1563 #endif
1564     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1565 #ifndef CURL_DISABLE_RTSP
1566     &Curl_handler_rtsp,
1567 #else
1568     NULL,
1569 #endif
1570 #if defined(USE_SSL) && !defined(CURL_DISABLE_SMB) && \
1571   defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)
1572     &Curl_handler_smbs,
1573 #else
1574     NULL,
1575 #endif
1576 #if defined(USE_SSH) && !defined(USE_WOLFSSH)
1577     &Curl_handler_scp,
1578 #else
1579     NULL,
1580 #endif
1581     NULL, NULL, NULL,
1582 #ifndef CURL_DISABLE_POP3
1583     &Curl_handler_pop3,
1584 #else
1585     NULL,
1586 #endif
1587     NULL, NULL,
1588 #ifdef USE_LIBRTMP
1589     &Curl_handler_rtmp,
1590 #else
1591     NULL,
1592 #endif
1593     NULL, NULL, NULL,
1594 #ifdef USE_LIBRTMP
1595     &Curl_handler_rtmpte,
1596 #else
1597     NULL,
1598 #endif
1599     NULL, NULL, NULL,
1600 #ifndef CURL_DISABLE_DICT
1601     &Curl_handler_dict,
1602 #else
1603     NULL,
1604 #endif
1605     NULL, NULL, NULL,
1606 #ifndef CURL_DISABLE_MQTT
1607     &Curl_handler_mqtt,
1608 #else
1609     NULL,
1610 #endif
1611 #if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
1612     &Curl_handler_pop3s,
1613 #else
1614     NULL,
1615 #endif
1616 #if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
1617     &Curl_handler_imaps,
1618 #else
1619     NULL,
1620 #endif
1621     NULL,
1622 #if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
1623     &Curl_handler_ws,
1624 #else
1625     NULL,
1626 #endif
1627     NULL,
1628 #ifdef USE_LIBRTMP
1629     &Curl_handler_rtmpts,
1630 #else
1631     NULL,
1632 #endif
1633 #ifndef CURL_DISABLE_LDAP
1634     &Curl_handler_ldap,
1635 #else
1636     NULL,
1637 #endif
1638     NULL, NULL,
1639 #ifndef CURL_DISABLE_FTP
1640     &Curl_handler_ftp,
1641 #else
1642     NULL,
1643 #endif
1644   };
1645 
1646   if(len && (len <= 7)) {
1647     const char *s = scheme;
1648     size_t l = len;
1649     const struct Curl_handler *h;
1650     unsigned int c = 978;
1651     while(l) {
1652       c <<= 5;
1653       c += Curl_raw_tolower(*s);
1654       s++;
1655       l--;
1656     }
1657 
1658     h = protocols[c % 67];
1659     if(h && strncasecompare(scheme, h->scheme, len) && !h->scheme[len])
1660       return h;
1661   }
1662   return NULL;
1663 }
1664 
findprotocol(struct Curl_easy * data,struct connectdata * conn,const char * protostr)1665 static CURLcode findprotocol(struct Curl_easy *data,
1666                              struct connectdata *conn,
1667                              const char *protostr)
1668 {
1669   const struct Curl_handler *p = Curl_get_scheme_handler(protostr);
1670 
1671   if(p && /* Protocol found in table. Check if allowed */
1672      (data->set.allowed_protocols & p->protocol)) {
1673 
1674     /* it is allowed for "normal" request, now do an extra check if this is
1675        the result of a redirect */
1676     if(data->state.this_is_a_follow &&
1677        !(data->set.redir_protocols & p->protocol))
1678       /* nope, get out */
1679       ;
1680     else {
1681       /* Perform setup complement if some. */
1682       conn->handler = conn->given = p;
1683       /* 'port' and 'remote_port' are set in setup_connection_internals() */
1684       return CURLE_OK;
1685     }
1686   }
1687 
1688   /* The protocol was not found in the table, but we don't have to assign it
1689      to anything since it is already assigned to a dummy-struct in the
1690      create_conn() function when the connectdata struct is allocated. */
1691   failf(data, "Protocol \"%s\" %s%s", protostr,
1692         p ? "disabled" : "not supported",
1693         data->state.this_is_a_follow ? " (in redirect)":"");
1694 
1695   return CURLE_UNSUPPORTED_PROTOCOL;
1696 }
1697 
1698 
Curl_uc_to_curlcode(CURLUcode uc)1699 CURLcode Curl_uc_to_curlcode(CURLUcode uc)
1700 {
1701   switch(uc) {
1702   default:
1703     return CURLE_URL_MALFORMAT;
1704   case CURLUE_UNSUPPORTED_SCHEME:
1705     return CURLE_UNSUPPORTED_PROTOCOL;
1706   case CURLUE_OUT_OF_MEMORY:
1707     return CURLE_OUT_OF_MEMORY;
1708   case CURLUE_USER_NOT_ALLOWED:
1709     return CURLE_LOGIN_DENIED;
1710   }
1711 }
1712 
1713 #ifdef USE_IPV6
1714 /*
1715  * If the URL was set with an IPv6 numerical address with a zone id part, set
1716  * the scope_id based on that!
1717  */
1718 
zonefrom_url(CURLU * uh,struct Curl_easy * data,struct connectdata * conn)1719 static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
1720                          struct connectdata *conn)
1721 {
1722   char *zoneid;
1723   CURLUcode uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
1724 #ifdef CURL_DISABLE_VERBOSE_STRINGS
1725   (void)data;
1726 #endif
1727 
1728   if(!uc && zoneid) {
1729     char *endp;
1730     unsigned long scope = strtoul(zoneid, &endp, 10);
1731     if(!*endp && (scope < UINT_MAX))
1732       /* A plain number, use it directly as a scope id. */
1733       conn->scope_id = (unsigned int)scope;
1734 #if defined(HAVE_IF_NAMETOINDEX)
1735     else {
1736 #elif defined(_WIN32)
1737     else if(Curl_if_nametoindex) {
1738 #endif
1739 
1740 #if defined(HAVE_IF_NAMETOINDEX) || defined(_WIN32)
1741       /* Zone identifier is not numeric */
1742       unsigned int scopeidx = 0;
1743 #if defined(_WIN32)
1744       scopeidx = Curl_if_nametoindex(zoneid);
1745 #else
1746       scopeidx = if_nametoindex(zoneid);
1747 #endif
1748       if(!scopeidx) {
1749 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1750         char buffer[STRERROR_LEN];
1751         infof(data, "Invalid zoneid: %s; %s", zoneid,
1752               Curl_strerror(errno, buffer, sizeof(buffer)));
1753 #endif
1754       }
1755       else
1756         conn->scope_id = scopeidx;
1757     }
1758 #endif /* HAVE_IF_NAMETOINDEX || _WIN32 */
1759 
1760     free(zoneid);
1761   }
1762 }
1763 #else
1764 #define zonefrom_url(a,b,c) Curl_nop_stmt
1765 #endif
1766 
1767 /*
1768  * Parse URL and fill in the relevant members of the connection struct.
1769  */
1770 static CURLcode parseurlandfillconn(struct Curl_easy *data,
1771                                     struct connectdata *conn)
1772 {
1773   CURLcode result;
1774   CURLU *uh;
1775   CURLUcode uc;
1776   char *hostname;
1777   bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
1778 
1779   up_free(data); /* cleanup previous leftovers first */
1780 
1781   /* parse the URL */
1782   if(use_set_uh) {
1783     uh = data->state.uh = curl_url_dup(data->set.uh);
1784   }
1785   else {
1786     uh = data->state.uh = curl_url();
1787   }
1788 
1789   if(!uh)
1790     return CURLE_OUT_OF_MEMORY;
1791 
1792   if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
1793      !Curl_is_absolute_url(data->state.url, NULL, 0, TRUE)) {
1794     char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL],
1795                         data->state.url);
1796     if(!url)
1797       return CURLE_OUT_OF_MEMORY;
1798     if(data->state.url_alloc)
1799       free(data->state.url);
1800     data->state.url = url;
1801     data->state.url_alloc = TRUE;
1802   }
1803 
1804   if(!use_set_uh) {
1805     char *newurl;
1806     uc = curl_url_set(uh, CURLUPART_URL, data->state.url,
1807                       CURLU_GUESS_SCHEME |
1808                       CURLU_NON_SUPPORT_SCHEME |
1809                       (data->set.disallow_username_in_url ?
1810                        CURLU_DISALLOW_USER : 0) |
1811                       (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
1812     if(uc) {
1813       failf(data, "URL rejected: %s", curl_url_strerror(uc));
1814       return Curl_uc_to_curlcode(uc);
1815     }
1816 
1817     /* after it was parsed, get the generated normalized version */
1818     uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
1819     if(uc)
1820       return Curl_uc_to_curlcode(uc);
1821     if(data->state.url_alloc)
1822       free(data->state.url);
1823     data->state.url = newurl;
1824     data->state.url_alloc = TRUE;
1825   }
1826 
1827   uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
1828   if(uc)
1829     return Curl_uc_to_curlcode(uc);
1830 
1831   uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
1832   if(uc) {
1833     if(!strcasecompare("file", data->state.up.scheme))
1834       return CURLE_OUT_OF_MEMORY;
1835   }
1836   else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
1837     failf(data, "Too long host name (maximum is %d)", MAX_URL_LEN);
1838     return CURLE_URL_MALFORMAT;
1839   }
1840   hostname = data->state.up.hostname;
1841 
1842   if(hostname && hostname[0] == '[') {
1843     /* This looks like an IPv6 address literal. See if there is an address
1844        scope. */
1845     size_t hlen;
1846     conn->bits.ipv6_ip = TRUE;
1847     /* cut off the brackets! */
1848     hostname++;
1849     hlen = strlen(hostname);
1850     hostname[hlen - 1] = 0;
1851 
1852     zonefrom_url(uh, data, conn);
1853   }
1854 
1855   /* make sure the connect struct gets its own copy of the host name */
1856   conn->host.rawalloc = strdup(hostname ? hostname : "");
1857   if(!conn->host.rawalloc)
1858     return CURLE_OUT_OF_MEMORY;
1859   conn->host.name = conn->host.rawalloc;
1860 
1861   /*************************************************************
1862    * IDN-convert the hostnames
1863    *************************************************************/
1864   result = Curl_idnconvert_hostname(&conn->host);
1865   if(result)
1866     return result;
1867 
1868 #ifndef CURL_DISABLE_HSTS
1869   /* HSTS upgrade */
1870   if(data->hsts && strcasecompare("http", data->state.up.scheme)) {
1871     /* This MUST use the IDN decoded name */
1872     if(Curl_hsts(data->hsts, conn->host.name, TRUE)) {
1873       char *url;
1874       Curl_safefree(data->state.up.scheme);
1875       uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0);
1876       if(uc)
1877         return Curl_uc_to_curlcode(uc);
1878       if(data->state.url_alloc)
1879         Curl_safefree(data->state.url);
1880       /* after update, get the updated version */
1881       uc = curl_url_get(uh, CURLUPART_URL, &url, 0);
1882       if(uc)
1883         return Curl_uc_to_curlcode(uc);
1884       uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
1885       if(uc) {
1886         free(url);
1887         return Curl_uc_to_curlcode(uc);
1888       }
1889       data->state.url = url;
1890       data->state.url_alloc = TRUE;
1891       infof(data, "Switched from HTTP to HTTPS due to HSTS => %s",
1892             data->state.url);
1893     }
1894   }
1895 #endif
1896 
1897   result = findprotocol(data, conn, data->state.up.scheme);
1898   if(result)
1899     return result;
1900 
1901   /*
1902    * User name and password set with their own options override the
1903    * credentials possibly set in the URL.
1904    */
1905   if(!data->set.str[STRING_PASSWORD]) {
1906     uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
1907     if(!uc) {
1908       char *decoded;
1909       result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL,
1910                               conn->handler->flags&PROTOPT_USERPWDCTRL ?
1911                               REJECT_ZERO : REJECT_CTRL);
1912       if(result)
1913         return result;
1914       conn->passwd = decoded;
1915       result = Curl_setstropt(&data->state.aptr.passwd, decoded);
1916       if(result)
1917         return result;
1918     }
1919     else if(uc != CURLUE_NO_PASSWORD)
1920       return Curl_uc_to_curlcode(uc);
1921   }
1922 
1923   if(!data->set.str[STRING_USERNAME]) {
1924     /* we don't use the URL API's URL decoder option here since it rejects
1925        control codes and we want to allow them for some schemes in the user
1926        and password fields */
1927     uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
1928     if(!uc) {
1929       char *decoded;
1930       result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL,
1931                               conn->handler->flags&PROTOPT_USERPWDCTRL ?
1932                               REJECT_ZERO : REJECT_CTRL);
1933       if(result)
1934         return result;
1935       conn->user = decoded;
1936       result = Curl_setstropt(&data->state.aptr.user, decoded);
1937     }
1938     else if(uc != CURLUE_NO_USER)
1939       return Curl_uc_to_curlcode(uc);
1940     else if(data->state.aptr.passwd) {
1941       /* no user was set but a password, set a blank user */
1942       result = Curl_setstropt(&data->state.aptr.user, "");
1943     }
1944     if(result)
1945       return result;
1946   }
1947 
1948   uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
1949                     CURLU_URLDECODE);
1950   if(!uc) {
1951     conn->options = strdup(data->state.up.options);
1952     if(!conn->options)
1953       return CURLE_OUT_OF_MEMORY;
1954   }
1955   else if(uc != CURLUE_NO_OPTIONS)
1956     return Curl_uc_to_curlcode(uc);
1957 
1958   uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path,
1959                     CURLU_URLENCODE);
1960   if(uc)
1961     return Curl_uc_to_curlcode(uc);
1962 
1963   uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port,
1964                     CURLU_DEFAULT_PORT);
1965   if(uc) {
1966     if(!strcasecompare("file", data->state.up.scheme))
1967       return CURLE_OUT_OF_MEMORY;
1968   }
1969   else {
1970     unsigned long port = strtoul(data->state.up.port, NULL, 10);
1971     conn->primary.remote_port = conn->remote_port =
1972       (data->set.use_port && data->state.allow_port) ?
1973       data->set.use_port : curlx_ultous(port);
1974   }
1975 
1976   (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
1977 
1978 #ifdef USE_IPV6
1979   if(data->set.scope_id)
1980     /* Override any scope that was set above.  */
1981     conn->scope_id = data->set.scope_id;
1982 #endif
1983 
1984   return CURLE_OK;
1985 }
1986 
1987 
1988 /*
1989  * If we're doing a resumed transfer, we need to setup our stuff
1990  * properly.
1991  */
1992 static CURLcode setup_range(struct Curl_easy *data)
1993 {
1994   struct UrlState *s = &data->state;
1995   s->resume_from = data->set.set_resume_from;
1996   if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
1997     if(s->rangestringalloc)
1998       free(s->range);
1999 
2000     if(s->resume_from)
2001       s->range = aprintf("%" CURL_FORMAT_CURL_OFF_T "-", s->resume_from);
2002     else
2003       s->range = strdup(data->set.str[STRING_SET_RANGE]);
2004 
2005     s->rangestringalloc = (s->range) ? TRUE : FALSE;
2006 
2007     if(!s->range)
2008       return CURLE_OUT_OF_MEMORY;
2009 
2010     /* tell ourselves to fetch this range */
2011     s->use_range = TRUE;        /* enable range download */
2012   }
2013   else
2014     s->use_range = FALSE; /* disable range download */
2015 
2016   return CURLE_OK;
2017 }
2018 
2019 
2020 /*
2021  * setup_connection_internals() -
2022  *
2023  * Setup connection internals specific to the requested protocol in the
2024  * Curl_easy. This is inited and setup before the connection is made but
2025  * is about the particular protocol that is to be used.
2026  *
2027  * This MUST get called after proxy magic has been figured out.
2028  */
2029 static CURLcode setup_connection_internals(struct Curl_easy *data,
2030                                            struct connectdata *conn)
2031 {
2032   const struct Curl_handler *p;
2033   CURLcode result;
2034 
2035   /* Perform setup complement if some. */
2036   p = conn->handler;
2037 
2038   if(p->setup_connection) {
2039     result = (*p->setup_connection)(data, conn);
2040 
2041     if(result)
2042       return result;
2043 
2044     p = conn->handler;              /* May have changed. */
2045   }
2046 
2047   if(conn->primary.remote_port < 0)
2048     /* we check for -1 here since if proxy was detected already, this
2049        was very likely already set to the proxy port */
2050     conn->primary.remote_port = p->defport;
2051 
2052   return CURLE_OK;
2053 }
2054 
2055 
2056 #ifndef CURL_DISABLE_PROXY
2057 
2058 #ifndef CURL_DISABLE_HTTP
2059 /****************************************************************
2060 * Detect what (if any) proxy to use. Remember that this selects a host
2061 * name and is not limited to HTTP proxies only.
2062 * The returned pointer must be freed by the caller (unless NULL)
2063 ****************************************************************/
2064 static char *detect_proxy(struct Curl_easy *data,
2065                           struct connectdata *conn)
2066 {
2067   char *proxy = NULL;
2068 
2069   /* If proxy was not specified, we check for default proxy environment
2070    * variables, to enable i.e Lynx compliance:
2071    *
2072    * http_proxy=http://some.server.dom:port/
2073    * https_proxy=http://some.server.dom:port/
2074    * ftp_proxy=http://some.server.dom:port/
2075    * no_proxy=domain1.dom,host.domain2.dom
2076    *   (a comma-separated list of hosts which should
2077    *   not be proxied, or an asterisk to override
2078    *   all proxy variables)
2079    * all_proxy=http://some.server.dom:port/
2080    *   (seems to exist for the CERN www lib. Probably
2081    *   the first to check for.)
2082    *
2083    * For compatibility, the all-uppercase versions of these variables are
2084    * checked if the lowercase versions don't exist.
2085    */
2086   char proxy_env[128];
2087   const char *protop = conn->handler->scheme;
2088   char *envp = proxy_env;
2089 #ifdef CURL_DISABLE_VERBOSE_STRINGS
2090   (void)data;
2091 #endif
2092 
2093   /* Now, build <protocol>_proxy and check for such a one to use */
2094   while(*protop)
2095     *envp++ = Curl_raw_tolower(*protop++);
2096 
2097   /* append _proxy */
2098   strcpy(envp, "_proxy");
2099 
2100   /* read the protocol proxy: */
2101   proxy = curl_getenv(proxy_env);
2102 
2103   /*
2104    * We don't try the uppercase version of HTTP_PROXY because of
2105    * security reasons:
2106    *
2107    * When curl is used in a webserver application
2108    * environment (cgi or php), this environment variable can
2109    * be controlled by the web server user by setting the
2110    * http header 'Proxy:' to some value.
2111    *
2112    * This can cause 'internal' http/ftp requests to be
2113    * arbitrarily redirected by any external attacker.
2114    */
2115   if(!proxy && !strcasecompare("http_proxy", proxy_env)) {
2116     /* There was no lowercase variable, try the uppercase version: */
2117     Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
2118     proxy = curl_getenv(proxy_env);
2119   }
2120 
2121   envp = proxy_env;
2122   if(!proxy) {
2123 #ifdef USE_WEBSOCKETS
2124     /* websocket proxy fallbacks */
2125     if(strcasecompare("ws_proxy", proxy_env)) {
2126       proxy = curl_getenv("http_proxy");
2127     }
2128     else if(strcasecompare("wss_proxy", proxy_env)) {
2129       proxy = curl_getenv("https_proxy");
2130       if(!proxy)
2131         proxy = curl_getenv("HTTPS_PROXY");
2132     }
2133     if(!proxy) {
2134 #endif
2135       envp = (char *)"all_proxy";
2136       proxy = curl_getenv(envp); /* default proxy to use */
2137       if(!proxy) {
2138         envp = (char *)"ALL_PROXY";
2139         proxy = curl_getenv(envp);
2140       }
2141 #ifdef USE_WEBSOCKETS
2142     }
2143 #endif
2144   }
2145   if(proxy)
2146     infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
2147 
2148   return proxy;
2149 }
2150 #endif /* CURL_DISABLE_HTTP */
2151 
2152 /*
2153  * If this is supposed to use a proxy, we need to figure out the proxy
2154  * host name, so that we can reuse an existing connection
2155  * that may exist registered to the same proxy host.
2156  */
2157 static CURLcode parse_proxy(struct Curl_easy *data,
2158                             struct connectdata *conn, char *proxy,
2159                             curl_proxytype proxytype)
2160 {
2161   char *portptr = NULL;
2162   int port = -1;
2163   char *proxyuser = NULL;
2164   char *proxypasswd = NULL;
2165   char *host = NULL;
2166   bool sockstype;
2167   CURLUcode uc;
2168   struct proxy_info *proxyinfo;
2169   CURLU *uhp = curl_url();
2170   CURLcode result = CURLE_OK;
2171   char *scheme = NULL;
2172 #ifdef USE_UNIX_SOCKETS
2173   char *path = NULL;
2174   bool is_unix_proxy = FALSE;
2175 #endif
2176 
2177 
2178   if(!uhp) {
2179     result = CURLE_OUT_OF_MEMORY;
2180     goto error;
2181   }
2182 
2183   /* When parsing the proxy, allowing non-supported schemes since we have
2184      these made up ones for proxies. Guess scheme for URLs without it. */
2185   uc = curl_url_set(uhp, CURLUPART_URL, proxy,
2186                     CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
2187   if(!uc) {
2188     /* parsed okay as a URL */
2189     uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, 0);
2190     if(uc) {
2191       result = CURLE_OUT_OF_MEMORY;
2192       goto error;
2193     }
2194 
2195     if(strcasecompare("https", scheme)) {
2196       if(proxytype != CURLPROXY_HTTPS2)
2197         proxytype = CURLPROXY_HTTPS;
2198       else
2199         proxytype = CURLPROXY_HTTPS2;
2200     }
2201     else if(strcasecompare("socks5h", scheme))
2202       proxytype = CURLPROXY_SOCKS5_HOSTNAME;
2203     else if(strcasecompare("socks5", scheme))
2204       proxytype = CURLPROXY_SOCKS5;
2205     else if(strcasecompare("socks4a", scheme))
2206       proxytype = CURLPROXY_SOCKS4A;
2207     else if(strcasecompare("socks4", scheme) ||
2208             strcasecompare("socks", scheme))
2209       proxytype = CURLPROXY_SOCKS4;
2210     else if(strcasecompare("http", scheme))
2211       ; /* leave it as HTTP or HTTP/1.0 */
2212     else {
2213       /* Any other xxx:// reject! */
2214       failf(data, "Unsupported proxy scheme for \'%s\'", proxy);
2215       result = CURLE_COULDNT_CONNECT;
2216       goto error;
2217     }
2218   }
2219   else {
2220     failf(data, "Unsupported proxy syntax in \'%s\': %s", proxy,
2221           curl_url_strerror(uc));
2222     result = CURLE_COULDNT_RESOLVE_PROXY;
2223     goto error;
2224   }
2225 
2226 #ifdef USE_SSL
2227   if(!Curl_ssl_supports(data, SSLSUPP_HTTPS_PROXY))
2228 #endif
2229     if(IS_HTTPS_PROXY(proxytype)) {
2230       failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
2231             "HTTPS-proxy support.", proxy);
2232       result = CURLE_NOT_BUILT_IN;
2233       goto error;
2234     }
2235 
2236   sockstype =
2237     proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
2238     proxytype == CURLPROXY_SOCKS5 ||
2239     proxytype == CURLPROXY_SOCKS4A ||
2240     proxytype == CURLPROXY_SOCKS4;
2241 
2242   proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy;
2243   proxyinfo->proxytype = (unsigned char)proxytype;
2244 
2245   /* Is there a username and password given in this proxy url? */
2246   uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
2247   if(uc && (uc != CURLUE_NO_USER))
2248     goto error;
2249   uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
2250   if(uc && (uc != CURLUE_NO_PASSWORD))
2251     goto error;
2252 
2253   if(proxyuser || proxypasswd) {
2254     Curl_safefree(proxyinfo->user);
2255     proxyinfo->user = proxyuser;
2256     result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser);
2257     proxyuser = NULL;
2258     if(result)
2259       goto error;
2260     Curl_safefree(proxyinfo->passwd);
2261     if(!proxypasswd) {
2262       proxypasswd = strdup("");
2263       if(!proxypasswd) {
2264         result = CURLE_OUT_OF_MEMORY;
2265         goto error;
2266       }
2267     }
2268     proxyinfo->passwd = proxypasswd;
2269     result = Curl_setstropt(&data->state.aptr.proxypasswd, proxypasswd);
2270     proxypasswd = NULL;
2271     if(result)
2272       goto error;
2273     conn->bits.proxy_user_passwd = TRUE; /* enable it */
2274   }
2275 
2276   (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
2277 
2278   if(portptr) {
2279     port = (int)strtol(portptr, NULL, 10);
2280     free(portptr);
2281   }
2282   else {
2283     if(data->set.proxyport)
2284       /* None given in the proxy string, then get the default one if it is
2285          given */
2286       port = (int)data->set.proxyport;
2287     else {
2288       if(IS_HTTPS_PROXY(proxytype))
2289         port = CURL_DEFAULT_HTTPS_PROXY_PORT;
2290       else
2291         port = CURL_DEFAULT_PROXY_PORT;
2292     }
2293   }
2294   if(port >= 0) {
2295     proxyinfo->port = port;
2296     if(conn->primary.remote_port < 0 || sockstype ||
2297        !conn->socks_proxy.host.rawalloc)
2298       conn->primary.remote_port = port;
2299   }
2300 
2301   /* now, clone the proxy host name */
2302   uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
2303   if(uc) {
2304     result = CURLE_OUT_OF_MEMORY;
2305     goto error;
2306   }
2307 #ifdef USE_UNIX_SOCKETS
2308   if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) {
2309     uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE);
2310     if(uc) {
2311       result = CURLE_OUT_OF_MEMORY;
2312       goto error;
2313     }
2314     /* path will be "/", if no path was found */
2315     if(strcmp("/", path)) {
2316       is_unix_proxy = TRUE;
2317       free(host);
2318       host = aprintf(UNIX_SOCKET_PREFIX"%s", path);
2319       if(!host) {
2320         result = CURLE_OUT_OF_MEMORY;
2321         goto error;
2322       }
2323       Curl_safefree(proxyinfo->host.rawalloc);
2324       proxyinfo->host.rawalloc = host;
2325       proxyinfo->host.name = host;
2326       host = NULL;
2327     }
2328   }
2329 
2330   if(!is_unix_proxy) {
2331 #endif
2332     Curl_safefree(proxyinfo->host.rawalloc);
2333     proxyinfo->host.rawalloc = host;
2334     if(host[0] == '[') {
2335       /* this is a numerical IPv6, strip off the brackets */
2336       size_t len = strlen(host);
2337       host[len-1] = 0; /* clear the trailing bracket */
2338       host++;
2339       zonefrom_url(uhp, data, conn);
2340     }
2341     proxyinfo->host.name = host;
2342     host = NULL;
2343 #ifdef USE_UNIX_SOCKETS
2344   }
2345 #endif
2346 
2347 error:
2348   free(proxyuser);
2349   free(proxypasswd);
2350   free(host);
2351   free(scheme);
2352 #ifdef USE_UNIX_SOCKETS
2353   free(path);
2354 #endif
2355   curl_url_cleanup(uhp);
2356   return result;
2357 }
2358 
2359 /*
2360  * Extract the user and password from the authentication string
2361  */
2362 static CURLcode parse_proxy_auth(struct Curl_easy *data,
2363                                  struct connectdata *conn)
2364 {
2365   const char *proxyuser = data->state.aptr.proxyuser ?
2366     data->state.aptr.proxyuser : "";
2367   const char *proxypasswd = data->state.aptr.proxypasswd ?
2368     data->state.aptr.proxypasswd : "";
2369   CURLcode result = CURLE_OUT_OF_MEMORY;
2370 
2371   conn->http_proxy.user = strdup(proxyuser);
2372   if(conn->http_proxy.user) {
2373     conn->http_proxy.passwd = strdup(proxypasswd);
2374     if(conn->http_proxy.passwd)
2375       result = CURLE_OK;
2376     else
2377       Curl_safefree(conn->http_proxy.user);
2378   }
2379   return result;
2380 }
2381 
2382 /* create_conn helper to parse and init proxy values. to be called after unix
2383    socket init but before any proxy vars are evaluated. */
2384 static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
2385                                               struct connectdata *conn)
2386 {
2387   char *proxy = NULL;
2388   char *socksproxy = NULL;
2389   char *no_proxy = NULL;
2390   CURLcode result = CURLE_OK;
2391   bool spacesep = FALSE;
2392 
2393   /*************************************************************
2394    * Extract the user and password from the authentication string
2395    *************************************************************/
2396   if(conn->bits.proxy_user_passwd) {
2397     result = parse_proxy_auth(data, conn);
2398     if(result)
2399       goto out;
2400   }
2401 
2402   /*************************************************************
2403    * Detect what (if any) proxy to use
2404    *************************************************************/
2405   if(data->set.str[STRING_PROXY]) {
2406     proxy = strdup(data->set.str[STRING_PROXY]);
2407     /* if global proxy is set, this is it */
2408     if(!proxy) {
2409       failf(data, "memory shortage");
2410       result = CURLE_OUT_OF_MEMORY;
2411       goto out;
2412     }
2413   }
2414 
2415   if(data->set.str[STRING_PRE_PROXY]) {
2416     socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
2417     /* if global socks proxy is set, this is it */
2418     if(!socksproxy) {
2419       failf(data, "memory shortage");
2420       result = CURLE_OUT_OF_MEMORY;
2421       goto out;
2422     }
2423   }
2424 
2425   if(!data->set.str[STRING_NOPROXY]) {
2426     const char *p = "no_proxy";
2427     no_proxy = curl_getenv(p);
2428     if(!no_proxy) {
2429       p = "NO_PROXY";
2430       no_proxy = curl_getenv(p);
2431     }
2432     if(no_proxy) {
2433       infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
2434     }
2435   }
2436 
2437   if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
2438                         data->set.str[STRING_NOPROXY] : no_proxy,
2439                         &spacesep)) {
2440     Curl_safefree(proxy);
2441     Curl_safefree(socksproxy);
2442   }
2443 #ifndef CURL_DISABLE_HTTP
2444   else if(!proxy && !socksproxy)
2445     /* if the host is not in the noproxy list, detect proxy. */
2446     proxy = detect_proxy(data, conn);
2447 #endif /* CURL_DISABLE_HTTP */
2448   if(spacesep)
2449     infof(data, "space-separated NOPROXY patterns are deprecated");
2450 
2451   Curl_safefree(no_proxy);
2452 
2453 #ifdef USE_UNIX_SOCKETS
2454   /* For the time being do not mix proxy and unix domain sockets. See #1274 */
2455   if(proxy && conn->unix_domain_socket) {
2456     free(proxy);
2457     proxy = NULL;
2458   }
2459 #endif
2460 
2461   if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
2462     free(proxy);  /* Don't bother with an empty proxy string or if the
2463                      protocol doesn't work with network */
2464     proxy = NULL;
2465   }
2466   if(socksproxy && (!*socksproxy ||
2467                     (conn->handler->flags & PROTOPT_NONETWORK))) {
2468     free(socksproxy);  /* Don't bother with an empty socks proxy string or if
2469                           the protocol doesn't work with network */
2470     socksproxy = NULL;
2471   }
2472 
2473   /***********************************************************************
2474    * If this is supposed to use a proxy, we need to figure out the proxy host
2475    * name, proxy type and port number, so that we can reuse an existing
2476    * connection that may exist registered to the same proxy host.
2477    ***********************************************************************/
2478   if(proxy || socksproxy) {
2479     curl_proxytype ptype = (curl_proxytype)conn->http_proxy.proxytype;
2480     if(proxy) {
2481       result = parse_proxy(data, conn, proxy, ptype);
2482       Curl_safefree(proxy); /* parse_proxy copies the proxy string */
2483       if(result)
2484         goto out;
2485     }
2486 
2487     if(socksproxy) {
2488       result = parse_proxy(data, conn, socksproxy, ptype);
2489       /* parse_proxy copies the socks proxy string */
2490       Curl_safefree(socksproxy);
2491       if(result)
2492         goto out;
2493     }
2494 
2495     if(conn->http_proxy.host.rawalloc) {
2496 #ifdef CURL_DISABLE_HTTP
2497       /* asking for an HTTP proxy is a bit funny when HTTP is disabled... */
2498       result = CURLE_UNSUPPORTED_PROTOCOL;
2499       goto out;
2500 #else
2501       /* force this connection's protocol to become HTTP if compatible */
2502       if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) {
2503         if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) &&
2504            !conn->bits.tunnel_proxy)
2505           conn->handler = &Curl_handler_http;
2506         else
2507           /* if not converting to HTTP over the proxy, enforce tunneling */
2508           conn->bits.tunnel_proxy = TRUE;
2509       }
2510       conn->bits.httpproxy = TRUE;
2511 #endif
2512     }
2513     else {
2514       conn->bits.httpproxy = FALSE; /* not an HTTP proxy */
2515       conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
2516     }
2517 
2518     if(conn->socks_proxy.host.rawalloc) {
2519       if(!conn->http_proxy.host.rawalloc) {
2520         /* once a socks proxy */
2521         if(!conn->socks_proxy.user) {
2522           conn->socks_proxy.user = conn->http_proxy.user;
2523           conn->http_proxy.user = NULL;
2524           Curl_safefree(conn->socks_proxy.passwd);
2525           conn->socks_proxy.passwd = conn->http_proxy.passwd;
2526           conn->http_proxy.passwd = NULL;
2527         }
2528       }
2529       conn->bits.socksproxy = TRUE;
2530     }
2531     else
2532       conn->bits.socksproxy = FALSE; /* not a socks proxy */
2533   }
2534   else {
2535     conn->bits.socksproxy = FALSE;
2536     conn->bits.httpproxy = FALSE;
2537   }
2538   conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
2539 
2540   if(!conn->bits.proxy) {
2541     /* we aren't using the proxy after all... */
2542     conn->bits.proxy = FALSE;
2543     conn->bits.httpproxy = FALSE;
2544     conn->bits.socksproxy = FALSE;
2545     conn->bits.proxy_user_passwd = FALSE;
2546     conn->bits.tunnel_proxy = FALSE;
2547     /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
2548        to signal that CURLPROXY_HTTPS is not used for this connection */
2549     conn->http_proxy.proxytype = CURLPROXY_HTTP;
2550   }
2551 
2552 out:
2553 
2554   free(socksproxy);
2555   free(proxy);
2556   return result;
2557 }
2558 #endif /* CURL_DISABLE_PROXY */
2559 
2560 /*
2561  * Curl_parse_login_details()
2562  *
2563  * This is used to parse a login string for user name, password and options in
2564  * the following formats:
2565  *
2566  *   user
2567  *   user:password
2568  *   user:password;options
2569  *   user;options
2570  *   user;options:password
2571  *   :password
2572  *   :password;options
2573  *   ;options
2574  *   ;options:password
2575  *
2576  * Parameters:
2577  *
2578  * login    [in]     - The login string.
2579  * len      [in]     - The length of the login string.
2580  * userp    [in/out] - The address where a pointer to newly allocated memory
2581  *                     holding the user will be stored upon completion.
2582  * passwdp  [in/out] - The address where a pointer to newly allocated memory
2583  *                     holding the password will be stored upon completion.
2584  * optionsp [in/out] - The address where a pointer to newly allocated memory
2585  *                     holding the options will be stored upon completion.
2586  *
2587  * Returns CURLE_OK on success.
2588  */
2589 CURLcode Curl_parse_login_details(const char *login, const size_t len,
2590                                   char **userp, char **passwdp,
2591                                   char **optionsp)
2592 {
2593   CURLcode result = CURLE_OK;
2594   char *ubuf = NULL;
2595   char *pbuf = NULL;
2596   char *obuf = NULL;
2597   const char *psep = NULL;
2598   const char *osep = NULL;
2599   size_t ulen;
2600   size_t plen;
2601   size_t olen;
2602 
2603   /* Attempt to find the password separator */
2604   if(passwdp)
2605     psep = memchr(login, ':', len);
2606 
2607   /* Attempt to find the options separator */
2608   if(optionsp)
2609     osep = memchr(login, ';', len);
2610 
2611   /* Calculate the portion lengths */
2612   ulen = (psep ?
2613           (size_t)(osep && psep > osep ? osep - login : psep - login) :
2614           (osep ? (size_t)(osep - login) : len));
2615   plen = (psep ?
2616           (osep && osep > psep ? (size_t)(osep - psep) :
2617                                  (size_t)(login + len - psep)) - 1 : 0);
2618   olen = (osep ?
2619           (psep && psep > osep ? (size_t)(psep - osep) :
2620                                  (size_t)(login + len - osep)) - 1 : 0);
2621 
2622   /* Allocate the user portion buffer, which can be zero length */
2623   if(userp) {
2624     ubuf = malloc(ulen + 1);
2625     if(!ubuf)
2626       result = CURLE_OUT_OF_MEMORY;
2627   }
2628 
2629   /* Allocate the password portion buffer */
2630   if(!result && passwdp && psep) {
2631     pbuf = malloc(plen + 1);
2632     if(!pbuf) {
2633       free(ubuf);
2634       result = CURLE_OUT_OF_MEMORY;
2635     }
2636   }
2637 
2638   /* Allocate the options portion buffer */
2639   if(!result && optionsp && olen) {
2640     obuf = malloc(olen + 1);
2641     if(!obuf) {
2642       free(pbuf);
2643       free(ubuf);
2644       result = CURLE_OUT_OF_MEMORY;
2645     }
2646   }
2647 
2648   if(!result) {
2649     /* Store the user portion if necessary */
2650     if(ubuf) {
2651       memcpy(ubuf, login, ulen);
2652       ubuf[ulen] = '\0';
2653       Curl_safefree(*userp);
2654       *userp = ubuf;
2655     }
2656 
2657     /* Store the password portion if necessary */
2658     if(pbuf) {
2659       memcpy(pbuf, psep + 1, plen);
2660       pbuf[plen] = '\0';
2661       Curl_safefree(*passwdp);
2662       *passwdp = pbuf;
2663     }
2664 
2665     /* Store the options portion if necessary */
2666     if(obuf) {
2667       memcpy(obuf, osep + 1, olen);
2668       obuf[olen] = '\0';
2669       Curl_safefree(*optionsp);
2670       *optionsp = obuf;
2671     }
2672   }
2673 
2674   return result;
2675 }
2676 
2677 /*************************************************************
2678  * Figure out the remote port number and fix it in the URL
2679  *
2680  * No matter if we use a proxy or not, we have to figure out the remote
2681  * port number of various reasons.
2682  *
2683  * The port number embedded in the URL is replaced, if necessary.
2684  *************************************************************/
2685 static CURLcode parse_remote_port(struct Curl_easy *data,
2686                                   struct connectdata *conn)
2687 {
2688 
2689   if(data->set.use_port && data->state.allow_port) {
2690     /* if set, we use this instead of the port possibly given in the URL */
2691     char portbuf[16];
2692     CURLUcode uc;
2693     conn->remote_port = data->set.use_port;
2694     msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port);
2695     uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
2696     if(uc)
2697       return CURLE_OUT_OF_MEMORY;
2698   }
2699 
2700   return CURLE_OK;
2701 }
2702 
2703 /*
2704  * Override the login details from the URL with that in the CURLOPT_USERPWD
2705  * option or a .netrc file, if applicable.
2706  */
2707 static CURLcode override_login(struct Curl_easy *data,
2708                                struct connectdata *conn)
2709 {
2710   CURLUcode uc;
2711   char **userp = &conn->user;
2712   char **passwdp = &conn->passwd;
2713   char **optionsp = &conn->options;
2714 
2715   if(data->set.str[STRING_OPTIONS]) {
2716     free(*optionsp);
2717     *optionsp = strdup(data->set.str[STRING_OPTIONS]);
2718     if(!*optionsp)
2719       return CURLE_OUT_OF_MEMORY;
2720   }
2721 
2722 #ifndef CURL_DISABLE_NETRC
2723   if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
2724     Curl_safefree(*userp);
2725     Curl_safefree(*passwdp);
2726   }
2727   conn->bits.netrc = FALSE;
2728   if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
2729     int ret;
2730     bool url_provided = FALSE;
2731 
2732     if(data->state.aptr.user) {
2733       /* there was a user name in the URL. Use the URL decoded version */
2734       userp = &data->state.aptr.user;
2735       url_provided = TRUE;
2736     }
2737 
2738     ret = Curl_parsenetrc(conn->host.name,
2739                           userp, passwdp,
2740                           data->set.str[STRING_NETRC_FILE]);
2741     if(ret > 0) {
2742       infof(data, "Couldn't find host %s in the %s file; using defaults",
2743             conn->host.name,
2744             (data->set.str[STRING_NETRC_FILE] ?
2745              data->set.str[STRING_NETRC_FILE] : ".netrc"));
2746     }
2747     else if(ret < 0) {
2748       failf(data, ".netrc parser error");
2749       return CURLE_READ_ERROR;
2750     }
2751     else {
2752       /* set bits.netrc TRUE to remember that we got the name from a .netrc
2753          file, so that it is safe to use even if we followed a Location: to a
2754          different host or similar. */
2755       conn->bits.netrc = TRUE;
2756     }
2757     if(url_provided) {
2758       Curl_safefree(conn->user);
2759       conn->user = strdup(*userp);
2760       if(!conn->user)
2761         return CURLE_OUT_OF_MEMORY;
2762     }
2763     /* no user was set but a password, set a blank user */
2764     if(!*userp && *passwdp) {
2765       *userp = strdup("");
2766       if(!*userp)
2767         return CURLE_OUT_OF_MEMORY;
2768     }
2769   }
2770 #endif
2771 
2772   /* for updated strings, we update them in the URL */
2773   if(*userp) {
2774     CURLcode result;
2775     if(data->state.aptr.user != *userp) {
2776       /* nothing to do then */
2777       result = Curl_setstropt(&data->state.aptr.user, *userp);
2778       if(result)
2779         return result;
2780     }
2781   }
2782   if(data->state.aptr.user) {
2783     uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
2784                       CURLU_URLENCODE);
2785     if(uc)
2786       return Curl_uc_to_curlcode(uc);
2787     if(!*userp) {
2788       *userp = strdup(data->state.aptr.user);
2789       if(!*userp)
2790         return CURLE_OUT_OF_MEMORY;
2791     }
2792   }
2793   if(*passwdp) {
2794     CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
2795     if(result)
2796       return result;
2797   }
2798   if(data->state.aptr.passwd) {
2799     uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
2800                       data->state.aptr.passwd, CURLU_URLENCODE);
2801     if(uc)
2802       return Curl_uc_to_curlcode(uc);
2803     if(!*passwdp) {
2804       *passwdp = strdup(data->state.aptr.passwd);
2805       if(!*passwdp)
2806         return CURLE_OUT_OF_MEMORY;
2807     }
2808   }
2809 
2810   return CURLE_OK;
2811 }
2812 
2813 /*
2814  * Set the login details so they're available in the connection
2815  */
2816 static CURLcode set_login(struct Curl_easy *data,
2817                           struct connectdata *conn)
2818 {
2819   CURLcode result = CURLE_OK;
2820   const char *setuser = CURL_DEFAULT_USER;
2821   const char *setpasswd = CURL_DEFAULT_PASSWORD;
2822 
2823   /* If our protocol needs a password and we have none, use the defaults */
2824   if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user)
2825     ;
2826   else {
2827     setuser = "";
2828     setpasswd = "";
2829   }
2830   /* Store the default user */
2831   if(!conn->user) {
2832     conn->user = strdup(setuser);
2833     if(!conn->user)
2834       return CURLE_OUT_OF_MEMORY;
2835   }
2836 
2837   /* Store the default password */
2838   if(!conn->passwd) {
2839     conn->passwd = strdup(setpasswd);
2840     if(!conn->passwd)
2841       result = CURLE_OUT_OF_MEMORY;
2842   }
2843 
2844   return result;
2845 }
2846 
2847 /*
2848  * Parses a "host:port" string to connect to.
2849  * The hostname and the port may be empty; in this case, NULL is returned for
2850  * the hostname and -1 for the port.
2851  */
2852 static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
2853                                            const char *host,
2854                                            char **hostname_result,
2855                                            int *port_result)
2856 {
2857   char *host_dup;
2858   char *hostptr;
2859   char *host_portno;
2860   char *portptr;
2861   int port = -1;
2862   CURLcode result = CURLE_OK;
2863 
2864 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
2865   (void) data;
2866 #endif
2867 
2868   *hostname_result = NULL;
2869   *port_result = -1;
2870 
2871   if(!host || !*host)
2872     return CURLE_OK;
2873 
2874   host_dup = strdup(host);
2875   if(!host_dup)
2876     return CURLE_OUT_OF_MEMORY;
2877 
2878   hostptr = host_dup;
2879 
2880   /* start scanning for port number at this point */
2881   portptr = hostptr;
2882 
2883   /* detect and extract RFC6874-style IPv6-addresses */
2884   if(*hostptr == '[') {
2885 #ifdef USE_IPV6
2886     char *ptr = ++hostptr; /* advance beyond the initial bracket */
2887     while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
2888       ptr++;
2889     if(*ptr == '%') {
2890       /* There might be a zone identifier */
2891       if(strncmp("%25", ptr, 3))
2892         infof(data, "Please URL encode %% as %%25, see RFC 6874.");
2893       ptr++;
2894       /* Allow unreserved characters as defined in RFC 3986 */
2895       while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
2896                      (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
2897         ptr++;
2898     }
2899     if(*ptr == ']')
2900       /* yeps, it ended nicely with a bracket as well */
2901       *ptr++ = '\0';
2902     else
2903       infof(data, "Invalid IPv6 address format");
2904     portptr = ptr;
2905     /* Note that if this didn't end with a bracket, we still advanced the
2906      * hostptr first, but I can't see anything wrong with that as no host
2907      * name nor a numeric can legally start with a bracket.
2908      */
2909 #else
2910     failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
2911     result = CURLE_NOT_BUILT_IN;
2912     goto error;
2913 #endif
2914   }
2915 
2916   /* Get port number off server.com:1080 */
2917   host_portno = strchr(portptr, ':');
2918   if(host_portno) {
2919     char *endp = NULL;
2920     *host_portno = '\0'; /* cut off number from host name */
2921     host_portno++;
2922     if(*host_portno) {
2923       long portparse = strtol(host_portno, &endp, 10);
2924       if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
2925         failf(data, "No valid port number in connect to host string (%s)",
2926               host_portno);
2927         result = CURLE_SETOPT_OPTION_SYNTAX;
2928         goto error;
2929       }
2930       else
2931         port = (int)portparse; /* we know it will fit */
2932     }
2933   }
2934 
2935   /* now, clone the cleaned host name */
2936   DEBUGASSERT(hostptr);
2937   *hostname_result = strdup(hostptr);
2938   if(!*hostname_result) {
2939     result = CURLE_OUT_OF_MEMORY;
2940     goto error;
2941   }
2942 
2943   *port_result = port;
2944 
2945 error:
2946   free(host_dup);
2947   return result;
2948 }
2949 
2950 /*
2951  * Parses one "connect to" string in the form:
2952  * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
2953  */
2954 static CURLcode parse_connect_to_string(struct Curl_easy *data,
2955                                         struct connectdata *conn,
2956                                         const char *conn_to_host,
2957                                         char **host_result,
2958                                         int *port_result)
2959 {
2960   CURLcode result = CURLE_OK;
2961   const char *ptr = conn_to_host;
2962   int host_match = FALSE;
2963   int port_match = FALSE;
2964 
2965   *host_result = NULL;
2966   *port_result = -1;
2967 
2968   if(*ptr == ':') {
2969     /* an empty hostname always matches */
2970     host_match = TRUE;
2971     ptr++;
2972   }
2973   else {
2974     /* check whether the URL's hostname matches */
2975     size_t hostname_to_match_len;
2976     char *hostname_to_match = aprintf("%s%s%s",
2977                                       conn->bits.ipv6_ip ? "[" : "",
2978                                       conn->host.name,
2979                                       conn->bits.ipv6_ip ? "]" : "");
2980     if(!hostname_to_match)
2981       return CURLE_OUT_OF_MEMORY;
2982     hostname_to_match_len = strlen(hostname_to_match);
2983     host_match = strncasecompare(ptr, hostname_to_match,
2984                                  hostname_to_match_len);
2985     free(hostname_to_match);
2986     ptr += hostname_to_match_len;
2987 
2988     host_match = host_match && *ptr == ':';
2989     ptr++;
2990   }
2991 
2992   if(host_match) {
2993     if(*ptr == ':') {
2994       /* an empty port always matches */
2995       port_match = TRUE;
2996       ptr++;
2997     }
2998     else {
2999       /* check whether the URL's port matches */
3000       char *ptr_next = strchr(ptr, ':');
3001       if(ptr_next) {
3002         char *endp = NULL;
3003         long port_to_match = strtol(ptr, &endp, 10);
3004         if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
3005           port_match = TRUE;
3006           ptr = ptr_next + 1;
3007         }
3008       }
3009     }
3010   }
3011 
3012   if(host_match && port_match) {
3013     /* parse the hostname and port to connect to */
3014     result = parse_connect_to_host_port(data, ptr, host_result, port_result);
3015   }
3016 
3017   return result;
3018 }
3019 
3020 /*
3021  * Processes all strings in the "connect to" slist, and uses the "connect
3022  * to host" and "connect to port" of the first string that matches.
3023  */
3024 static CURLcode parse_connect_to_slist(struct Curl_easy *data,
3025                                        struct connectdata *conn,
3026                                        struct curl_slist *conn_to_host)
3027 {
3028   CURLcode result = CURLE_OK;
3029   char *host = NULL;
3030   int port = -1;
3031 
3032   while(conn_to_host && !host && port == -1) {
3033     result = parse_connect_to_string(data, conn, conn_to_host->data,
3034                                      &host, &port);
3035     if(result)
3036       return result;
3037 
3038     if(host && *host) {
3039       conn->conn_to_host.rawalloc = host;
3040       conn->conn_to_host.name = host;
3041       conn->bits.conn_to_host = TRUE;
3042 
3043       infof(data, "Connecting to hostname: %s", host);
3044     }
3045     else {
3046       /* no "connect to host" */
3047       conn->bits.conn_to_host = FALSE;
3048       Curl_safefree(host);
3049     }
3050 
3051     if(port >= 0) {
3052       conn->conn_to_port = port;
3053       conn->bits.conn_to_port = TRUE;
3054       infof(data, "Connecting to port: %d", port);
3055     }
3056     else {
3057       /* no "connect to port" */
3058       conn->bits.conn_to_port = FALSE;
3059       port = -1;
3060     }
3061 
3062     conn_to_host = conn_to_host->next;
3063   }
3064 
3065 #ifndef CURL_DISABLE_ALTSVC
3066   if(data->asi && !host && (port == -1) &&
3067      ((conn->handler->protocol == CURLPROTO_HTTPS) ||
3068 #ifdef CURLDEBUG
3069       /* allow debug builds to circumvent the HTTPS restriction */
3070       getenv("CURL_ALTSVC_HTTP")
3071 #else
3072       0
3073 #endif
3074        )) {
3075     /* no connect_to match, try alt-svc! */
3076     enum alpnid srcalpnid;
3077     bool hit;
3078     struct altsvc *as;
3079     const int allowed_versions = ( ALPN_h1
3080 #ifdef USE_HTTP2
3081                                    | ALPN_h2
3082 #endif
3083 #ifdef USE_HTTP3
3084                                    | ALPN_h3
3085 #endif
3086       ) & data->asi->flags;
3087 
3088     host = conn->host.rawalloc;
3089 #ifdef USE_HTTP2
3090     /* with h2 support, check that first */
3091     srcalpnid = ALPN_h2;
3092     hit = Curl_altsvc_lookup(data->asi,
3093                              srcalpnid, host, conn->remote_port, /* from */
3094                              &as /* to */,
3095                              allowed_versions);
3096     if(!hit)
3097 #endif
3098     {
3099       srcalpnid = ALPN_h1;
3100       hit = Curl_altsvc_lookup(data->asi,
3101                                srcalpnid, host, conn->remote_port, /* from */
3102                                &as /* to */,
3103                                allowed_versions);
3104     }
3105     if(hit) {
3106       char *hostd = strdup((char *)as->dst.host);
3107       if(!hostd)
3108         return CURLE_OUT_OF_MEMORY;
3109       conn->conn_to_host.rawalloc = hostd;
3110       conn->conn_to_host.name = hostd;
3111       conn->bits.conn_to_host = TRUE;
3112       conn->conn_to_port = as->dst.port;
3113       conn->bits.conn_to_port = TRUE;
3114       conn->bits.altused = TRUE;
3115       infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d",
3116             Curl_alpnid2str(srcalpnid), host, conn->remote_port,
3117             Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
3118       if(srcalpnid != as->dst.alpnid) {
3119         /* protocol version switch */
3120         switch(as->dst.alpnid) {
3121         case ALPN_h1:
3122           conn->httpversion = 11;
3123           break;
3124         case ALPN_h2:
3125           conn->httpversion = 20;
3126           break;
3127         case ALPN_h3:
3128           conn->transport = TRNSPRT_QUIC;
3129           conn->httpversion = 30;
3130           break;
3131         default: /* shouldn't be possible */
3132           break;
3133         }
3134       }
3135     }
3136   }
3137 #endif
3138 
3139   return result;
3140 }
3141 
3142 #ifdef USE_UNIX_SOCKETS
3143 static CURLcode resolve_unix(struct Curl_easy *data,
3144                              struct connectdata *conn,
3145                              char *unix_path)
3146 {
3147   struct Curl_dns_entry *hostaddr = NULL;
3148   bool longpath = FALSE;
3149 
3150   DEBUGASSERT(unix_path);
3151   DEBUGASSERT(conn->dns_entry == NULL);
3152 
3153   /* Unix domain sockets are local. The host gets ignored, just use the
3154    * specified domain socket address. Do not cache "DNS entries". There is
3155    * no DNS involved and we already have the filesystem path available. */
3156   hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
3157   if(!hostaddr)
3158     return CURLE_OUT_OF_MEMORY;
3159 
3160   hostaddr->addr = Curl_unix2addr(unix_path, &longpath,
3161                                   conn->bits.abstract_unix_socket);
3162   if(!hostaddr->addr) {
3163     if(longpath)
3164       /* Long paths are not supported for now */
3165       failf(data, "Unix socket path too long: '%s'", unix_path);
3166     free(hostaddr);
3167     return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY;
3168   }
3169 
3170   hostaddr->inuse++;
3171   conn->dns_entry = hostaddr;
3172   return CURLE_OK;
3173 }
3174 #endif
3175 
3176 #ifndef CURL_DISABLE_PROXY
3177 static CURLcode resolve_proxy(struct Curl_easy *data,
3178                               struct connectdata *conn,
3179                               bool *async)
3180 {
3181   struct Curl_dns_entry *hostaddr = NULL;
3182   struct hostname *host;
3183   timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
3184   int rc;
3185 
3186   DEBUGASSERT(conn->dns_entry == NULL);
3187 
3188   host = conn->bits.socksproxy ? &conn->socks_proxy.host :
3189     &conn->http_proxy.host;
3190 
3191   conn->hostname_resolve = strdup(host->name);
3192   if(!conn->hostname_resolve)
3193     return CURLE_OUT_OF_MEMORY;
3194 
3195   rc = Curl_resolv_timeout(data, conn->hostname_resolve,
3196                            conn->primary.remote_port, &hostaddr, timeout_ms);
3197   conn->dns_entry = hostaddr;
3198   if(rc == CURLRESOLV_PENDING)
3199     *async = TRUE;
3200   else if(rc == CURLRESOLV_TIMEDOUT)
3201     return CURLE_OPERATION_TIMEDOUT;
3202   else if(!hostaddr) {
3203     failf(data, "Couldn't resolve proxy '%s'", host->dispname);
3204     return CURLE_COULDNT_RESOLVE_PROXY;
3205   }
3206 
3207   return CURLE_OK;
3208 }
3209 #endif
3210 
3211 static CURLcode resolve_host(struct Curl_easy *data,
3212                              struct connectdata *conn,
3213                              bool *async)
3214 {
3215   struct Curl_dns_entry *hostaddr = NULL;
3216   struct hostname *connhost;
3217   timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
3218   int rc;
3219 
3220   DEBUGASSERT(conn->dns_entry == NULL);
3221 
3222   connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
3223 
3224   /* If not connecting via a proxy, extract the port from the URL, if it is
3225    * there, thus overriding any defaults that might have been set above. */
3226   conn->primary.remote_port = conn->bits.conn_to_port ? conn->conn_to_port :
3227     conn->remote_port;
3228 
3229   /* Resolve target host right on */
3230   conn->hostname_resolve = strdup(connhost->name);
3231   if(!conn->hostname_resolve)
3232     return CURLE_OUT_OF_MEMORY;
3233 
3234   rc = Curl_resolv_timeout(data, conn->hostname_resolve,
3235                            conn->primary.remote_port, &hostaddr, timeout_ms);
3236   conn->dns_entry = hostaddr;
3237   if(rc == CURLRESOLV_PENDING)
3238     *async = TRUE;
3239   else if(rc == CURLRESOLV_TIMEDOUT) {
3240     failf(data, "Failed to resolve host '%s' with timeout after %"
3241           CURL_FORMAT_TIMEDIFF_T " ms", connhost->dispname,
3242           Curl_timediff(Curl_now(), data->progress.t_startsingle));
3243     return CURLE_OPERATION_TIMEDOUT;
3244   }
3245   else if(!hostaddr) {
3246     failf(data, "Could not resolve host: %s", connhost->dispname);
3247     return CURLE_COULDNT_RESOLVE_HOST;
3248   }
3249 
3250   return CURLE_OK;
3251 }
3252 
3253 /* Perform a fresh resolve */
3254 static CURLcode resolve_fresh(struct Curl_easy *data,
3255                               struct connectdata *conn,
3256                               bool *async)
3257 {
3258 #ifdef USE_UNIX_SOCKETS
3259   char *unix_path = conn->unix_domain_socket;
3260 
3261 #ifndef CURL_DISABLE_PROXY
3262   if(!unix_path && conn->socks_proxy.host.name &&
3263      !strncmp(UNIX_SOCKET_PREFIX"/",
3264               conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
3265     unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
3266 #endif
3267 
3268   if(unix_path) {
3269     conn->transport = TRNSPRT_UNIX;
3270     return resolve_unix(data, conn, unix_path);
3271   }
3272 #endif
3273 
3274 #ifndef CURL_DISABLE_PROXY
3275   if(CONN_IS_PROXIED(conn))
3276     return resolve_proxy(data, conn, async);
3277 #endif
3278 
3279   return resolve_host(data, conn, async);
3280 }
3281 
3282 /*************************************************************
3283  * Resolve the address of the server or proxy
3284  *************************************************************/
3285 static CURLcode resolve_server(struct Curl_easy *data,
3286                                struct connectdata *conn,
3287                                bool *async)
3288 {
3289   DEBUGASSERT(conn);
3290   DEBUGASSERT(data);
3291 
3292   /* Resolve the name of the server or proxy */
3293   if(conn->bits.reuse) {
3294     /* We're reusing the connection - no need to resolve anything, and
3295        idnconvert_hostname() was called already in create_conn() for the reuse
3296        case. */
3297     *async = FALSE;
3298     return CURLE_OK;
3299   }
3300 
3301   return resolve_fresh(data, conn, async);
3302 }
3303 
3304 /*
3305  * Cleanup the connection `temp`, just allocated for `data`, before using the
3306  * previously `existing` one for `data`.  All relevant info is copied over
3307  * and `temp` is freed.
3308  */
3309 static void reuse_conn(struct Curl_easy *data,
3310                        struct connectdata *temp,
3311                        struct connectdata *existing)
3312 {
3313   /* get the user+password information from the temp struct since it may
3314    * be new for this request even when we reuse an existing connection */
3315   if(temp->user) {
3316     /* use the new user name and password though */
3317     Curl_safefree(existing->user);
3318     Curl_safefree(existing->passwd);
3319     existing->user = temp->user;
3320     existing->passwd = temp->passwd;
3321     temp->user = NULL;
3322     temp->passwd = NULL;
3323   }
3324 
3325 #ifndef CURL_DISABLE_PROXY
3326   existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
3327   if(existing->bits.proxy_user_passwd) {
3328     /* use the new proxy user name and proxy password though */
3329     Curl_safefree(existing->http_proxy.user);
3330     Curl_safefree(existing->socks_proxy.user);
3331     Curl_safefree(existing->http_proxy.passwd);
3332     Curl_safefree(existing->socks_proxy.passwd);
3333     existing->http_proxy.user = temp->http_proxy.user;
3334     existing->socks_proxy.user = temp->socks_proxy.user;
3335     existing->http_proxy.passwd = temp->http_proxy.passwd;
3336     existing->socks_proxy.passwd = temp->socks_proxy.passwd;
3337     temp->http_proxy.user = NULL;
3338     temp->socks_proxy.user = NULL;
3339     temp->http_proxy.passwd = NULL;
3340     temp->socks_proxy.passwd = NULL;
3341   }
3342 #endif
3343 
3344   /* Finding a connection for reuse in the cache matches, among other
3345    * things on the "remote-relevant" hostname. This is not necessarily
3346    * the authority of the URL, e.g. conn->host. For example:
3347    * - we use a proxy (not tunneling). we want to send all requests
3348    *   that use the same proxy on this connection.
3349    * - we have a "connect-to" setting that may redirect the hostname of
3350    *   a new request to the same remote endpoint of an existing conn.
3351    *   We want to reuse an existing conn to the remote endpoint.
3352    * Since connection reuse does not match on conn->host necessarily, we
3353    * switch `existing` conn to `temp` conn's host settings.
3354    * TODO: is this correct in the case of TLS connections that have
3355    *       used the original hostname in SNI to negotiate? Do we send
3356    *       requests for another host through the different SNI?
3357    */
3358   Curl_free_idnconverted_hostname(&existing->host);
3359   Curl_free_idnconverted_hostname(&existing->conn_to_host);
3360   Curl_safefree(existing->host.rawalloc);
3361   Curl_safefree(existing->conn_to_host.rawalloc);
3362   existing->host = temp->host;
3363   temp->host.rawalloc = NULL;
3364   temp->host.encalloc = NULL;
3365   existing->conn_to_host = temp->conn_to_host;
3366   temp->conn_to_host.rawalloc = NULL;
3367   existing->conn_to_port = temp->conn_to_port;
3368   existing->remote_port = temp->remote_port;
3369   Curl_safefree(existing->hostname_resolve);
3370 
3371   existing->hostname_resolve = temp->hostname_resolve;
3372   temp->hostname_resolve = NULL;
3373 
3374   /* reuse init */
3375   existing->bits.reuse = TRUE; /* yes, we're reusing here */
3376 
3377   conn_free(data, temp);
3378 }
3379 
3380 /**
3381  * create_conn() sets up a new connectdata struct, or reuses an already
3382  * existing one, and resolves host name.
3383  *
3384  * if this function returns CURLE_OK and *async is set to TRUE, the resolve
3385  * response will be coming asynchronously. If *async is FALSE, the name is
3386  * already resolved.
3387  *
3388  * @param data The sessionhandle pointer
3389  * @param in_connect is set to the next connection data pointer
3390  * @param async is set TRUE when an async DNS resolution is pending
3391  * @see Curl_setup_conn()
3392  *
3393  */
3394 
3395 static CURLcode create_conn(struct Curl_easy *data,
3396                             struct connectdata **in_connect,
3397                             bool *async)
3398 {
3399   CURLcode result = CURLE_OK;
3400   struct connectdata *conn;
3401   struct connectdata *existing = NULL;
3402   bool reuse;
3403   bool connections_available = TRUE;
3404   bool force_reuse = FALSE;
3405   bool waitpipe = FALSE;
3406   size_t max_host_connections = Curl_multi_max_host_connections(data->multi);
3407   size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
3408 
3409   *async = FALSE;
3410   *in_connect = NULL;
3411 
3412   /*************************************************************
3413    * Check input data
3414    *************************************************************/
3415   if(!data->state.url) {
3416     result = CURLE_URL_MALFORMAT;
3417     goto out;
3418   }
3419 
3420   /* First, split up the current URL in parts so that we can use the
3421      parts for checking against the already present connections. In order
3422      to not have to modify everything at once, we allocate a temporary
3423      connection data struct and fill in for comparison purposes. */
3424   conn = allocate_conn(data);
3425 
3426   if(!conn) {
3427     result = CURLE_OUT_OF_MEMORY;
3428     goto out;
3429   }
3430 
3431   /* We must set the return variable as soon as possible, so that our
3432      parent can cleanup any possible allocs we may have done before
3433      any failure */
3434   *in_connect = conn;
3435 
3436   result = parseurlandfillconn(data, conn);
3437   if(result)
3438     goto out;
3439 
3440   if(data->set.str[STRING_SASL_AUTHZID]) {
3441     conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
3442     if(!conn->sasl_authzid) {
3443       result = CURLE_OUT_OF_MEMORY;
3444       goto out;
3445     }
3446   }
3447 
3448   if(data->set.str[STRING_BEARER]) {
3449     conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
3450     if(!conn->oauth_bearer) {
3451       result = CURLE_OUT_OF_MEMORY;
3452       goto out;
3453     }
3454   }
3455 
3456 #ifdef USE_UNIX_SOCKETS
3457   if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
3458     conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
3459     if(!conn->unix_domain_socket) {
3460       result = CURLE_OUT_OF_MEMORY;
3461       goto out;
3462     }
3463     conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
3464   }
3465 #endif
3466 
3467   /* After the unix socket init but before the proxy vars are used, parse and
3468      initialize the proxy vars */
3469 #ifndef CURL_DISABLE_PROXY
3470   result = create_conn_helper_init_proxy(data, conn);
3471   if(result)
3472     goto out;
3473 
3474   /*************************************************************
3475    * If the protocol is using SSL and HTTP proxy is used, we set
3476    * the tunnel_proxy bit.
3477    *************************************************************/
3478   if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
3479     conn->bits.tunnel_proxy = TRUE;
3480 #endif
3481 
3482   /*************************************************************
3483    * Figure out the remote port number and fix it in the URL
3484    *************************************************************/
3485   result = parse_remote_port(data, conn);
3486   if(result)
3487     goto out;
3488 
3489   /* Check for overridden login details and set them accordingly so that
3490      they are known when protocol->setup_connection is called! */
3491   result = override_login(data, conn);
3492   if(result)
3493     goto out;
3494 
3495   result = set_login(data, conn); /* default credentials */
3496   if(result)
3497     goto out;
3498 
3499   /*************************************************************
3500    * Process the "connect to" linked list of hostname/port mappings.
3501    * Do this after the remote port number has been fixed in the URL.
3502    *************************************************************/
3503   result = parse_connect_to_slist(data, conn, data->set.connect_to);
3504   if(result)
3505     goto out;
3506 
3507   /*************************************************************
3508    * IDN-convert the proxy hostnames
3509    *************************************************************/
3510 #ifndef CURL_DISABLE_PROXY
3511   if(conn->bits.httpproxy) {
3512     result = Curl_idnconvert_hostname(&conn->http_proxy.host);
3513     if(result)
3514       return result;
3515   }
3516   if(conn->bits.socksproxy) {
3517     result = Curl_idnconvert_hostname(&conn->socks_proxy.host);
3518     if(result)
3519       return result;
3520   }
3521 #endif
3522   if(conn->bits.conn_to_host) {
3523     result = Curl_idnconvert_hostname(&conn->conn_to_host);
3524     if(result)
3525       return result;
3526   }
3527 
3528   /*************************************************************
3529    * Check whether the host and the "connect to host" are equal.
3530    * Do this after the hostnames have been IDN-converted.
3531    *************************************************************/
3532   if(conn->bits.conn_to_host &&
3533      strcasecompare(conn->conn_to_host.name, conn->host.name)) {
3534     conn->bits.conn_to_host = FALSE;
3535   }
3536 
3537   /*************************************************************
3538    * Check whether the port and the "connect to port" are equal.
3539    * Do this after the remote port number has been fixed in the URL.
3540    *************************************************************/
3541   if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
3542     conn->bits.conn_to_port = FALSE;
3543   }
3544 
3545 #ifndef CURL_DISABLE_PROXY
3546   /*************************************************************
3547    * If the "connect to" feature is used with an HTTP proxy,
3548    * we set the tunnel_proxy bit.
3549    *************************************************************/
3550   if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
3551       conn->bits.httpproxy)
3552     conn->bits.tunnel_proxy = TRUE;
3553 #endif
3554 
3555   /*************************************************************
3556    * Setup internals depending on protocol. Needs to be done after
3557    * we figured out what/if proxy to use.
3558    *************************************************************/
3559   result = setup_connection_internals(data, conn);
3560   if(result)
3561     goto out;
3562 
3563   /***********************************************************************
3564    * file: is a special case in that it doesn't need a network connection
3565    ***********************************************************************/
3566 #ifndef CURL_DISABLE_FILE
3567   if(conn->handler->flags & PROTOPT_NONETWORK) {
3568     bool done;
3569     /* this is supposed to be the connect function so we better at least check
3570        that the file is present here! */
3571     DEBUGASSERT(conn->handler->connect_it);
3572     Curl_persistconninfo(data, conn, NULL);
3573     result = conn->handler->connect_it(data, &done);
3574 
3575     /* Setup a "faked" transfer that'll do nothing */
3576     if(!result) {
3577       Curl_attach_connection(data, conn);
3578       result = Curl_conncache_add_conn(data);
3579       if(result)
3580         goto out;
3581 
3582       /*
3583        * Setup whatever necessary for a resumed transfer
3584        */
3585       result = setup_range(data);
3586       if(result) {
3587         DEBUGASSERT(conn->handler->done);
3588         /* we ignore the return code for the protocol-specific DONE */
3589         (void)conn->handler->done(data, result, FALSE);
3590         goto out;
3591       }
3592       Curl_xfer_setup(data, -1, -1, FALSE, -1);
3593     }
3594 
3595     /* since we skip do_init() */
3596     Curl_init_do(data, conn);
3597 
3598     goto out;
3599   }
3600 #endif
3601 
3602   /* Setup filter for network connections */
3603   conn->recv[FIRSTSOCKET] = Curl_cf_recv;
3604   conn->send[FIRSTSOCKET] = Curl_cf_send;
3605   conn->recv[SECONDARYSOCKET] = Curl_cf_recv;
3606   conn->send[SECONDARYSOCKET] = Curl_cf_send;
3607   conn->bits.tcp_fastopen = data->set.tcp_fastopen;
3608 
3609   /* Complete the easy's SSL configuration for connection cache matching */
3610   result = Curl_ssl_easy_config_complete(data);
3611   if(result)
3612     goto out;
3613 
3614   prune_dead_connections(data);
3615 
3616   /*************************************************************
3617    * Check the current list of connections to see if we can
3618    * reuse an already existing one or if we have to create a
3619    * new one.
3620    *************************************************************/
3621 
3622   DEBUGASSERT(conn->user);
3623   DEBUGASSERT(conn->passwd);
3624 
3625   /* reuse_fresh is TRUE if we are told to use a new connection by force, but
3626      we only acknowledge this option if this is not a reused connection
3627      already (which happens due to follow-location or during an HTTP
3628      authentication phase). CONNECT_ONLY transfers also refuse reuse. */
3629   if((data->set.reuse_fresh && !data->state.followlocation) ||
3630      data->set.connect_only)
3631     reuse = FALSE;
3632   else
3633     reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
3634 
3635   if(reuse) {
3636     /*
3637      * We already have a connection for this, we got the former connection in
3638      * `existing` and thus we need to cleanup the one we just
3639      * allocated before we can move along and use `existing`.
3640      */
3641     reuse_conn(data, conn, existing);
3642     conn = existing;
3643     *in_connect = conn;
3644 
3645 #ifndef CURL_DISABLE_PROXY
3646     infof(data, "Re-using existing connection with %s %s",
3647           conn->bits.proxy?"proxy":"host",
3648           conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
3649           conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
3650           conn->host.dispname);
3651 #else
3652     infof(data, "Re-using existing connection with host %s",
3653           conn->host.dispname);
3654 #endif
3655   }
3656   else {
3657     /* We have decided that we want a new connection. However, we may not
3658        be able to do that if we have reached the limit of how many
3659        connections we are allowed to open. */
3660 
3661     if(conn->handler->flags & PROTOPT_ALPN) {
3662       /* The protocol wants it, so set the bits if enabled in the easy handle
3663          (default) */
3664       if(data->set.ssl_enable_alpn)
3665         conn->bits.tls_enable_alpn = TRUE;
3666     }
3667 
3668     if(waitpipe)
3669       /* There is a connection that *might* become usable for multiplexing
3670          "soon", and we wait for that */
3671       connections_available = FALSE;
3672     else {
3673       /* this gets a lock on the conncache */
3674       struct connectbundle *bundle =
3675         Curl_conncache_find_bundle(data, conn, data->state.conn_cache);
3676 
3677       if(max_host_connections > 0 && bundle &&
3678          (bundle->num_connections >= max_host_connections)) {
3679         struct connectdata *conn_candidate;
3680 
3681         /* The bundle is full. Extract the oldest connection. */
3682         conn_candidate = Curl_conncache_extract_bundle(data, bundle);
3683         CONNCACHE_UNLOCK(data);
3684 
3685         if(conn_candidate)
3686           Curl_disconnect(data, conn_candidate, FALSE);
3687         else {
3688           infof(data, "No more connections allowed to host: %zu",
3689                 max_host_connections);
3690           connections_available = FALSE;
3691         }
3692       }
3693       else
3694         CONNCACHE_UNLOCK(data);
3695 
3696     }
3697 
3698     if(connections_available &&
3699        (max_total_connections > 0) &&
3700        (Curl_conncache_size(data) >= max_total_connections)) {
3701       struct connectdata *conn_candidate;
3702 
3703       /* The cache is full. Let's see if we can kill a connection. */
3704       conn_candidate = Curl_conncache_extract_oldest(data);
3705       if(conn_candidate)
3706         Curl_disconnect(data, conn_candidate, FALSE);
3707       else {
3708         infof(data, "No connections available in cache");
3709         connections_available = FALSE;
3710       }
3711     }
3712 
3713     if(!connections_available) {
3714       infof(data, "No connections available.");
3715 
3716       conn_free(data, conn);
3717       *in_connect = NULL;
3718 
3719       result = CURLE_NO_CONNECTION_AVAILABLE;
3720       goto out;
3721     }
3722     else {
3723       /*
3724        * This is a brand new connection, so let's store it in the connection
3725        * cache of ours!
3726        */
3727       result = Curl_ssl_conn_config_init(data, conn);
3728       if(result) {
3729         DEBUGF(fprintf(stderr, "Error: init connection ssl config\n"));
3730         goto out;
3731       }
3732 
3733       Curl_attach_connection(data, conn);
3734       result = Curl_conncache_add_conn(data);
3735       if(result)
3736         goto out;
3737     }
3738 
3739 #if defined(USE_NTLM)
3740     /* If NTLM is requested in a part of this connection, make sure we don't
3741        assume the state is fine as this is a fresh connection and NTLM is
3742        connection based. */
3743     if((data->state.authhost.picked & CURLAUTH_NTLM) &&
3744        data->state.authhost.done) {
3745       infof(data, "NTLM picked AND auth done set, clear picked");
3746       data->state.authhost.picked = CURLAUTH_NONE;
3747       data->state.authhost.done = FALSE;
3748     }
3749 
3750     if((data->state.authproxy.picked & CURLAUTH_NTLM) &&
3751        data->state.authproxy.done) {
3752       infof(data, "NTLM-proxy picked AND auth done set, clear picked");
3753       data->state.authproxy.picked = CURLAUTH_NONE;
3754       data->state.authproxy.done = FALSE;
3755     }
3756 #endif
3757   }
3758 
3759   /* Setup and init stuff before DO starts, in preparing for the transfer. */
3760   Curl_init_do(data, conn);
3761 
3762   /*
3763    * Setup whatever necessary for a resumed transfer
3764    */
3765   result = setup_range(data);
3766   if(result)
3767     goto out;
3768 
3769   /* Continue connectdata initialization here. */
3770 
3771   /*************************************************************
3772    * Resolve the address of the server or proxy
3773    *************************************************************/
3774   result = resolve_server(data, conn, async);
3775   if(result)
3776     goto out;
3777 
3778   /* Everything general done, inform filters that they need
3779    * to prepare for a data transfer.
3780    */
3781   result = Curl_conn_ev_data_setup(data);
3782 
3783 out:
3784   return result;
3785 }
3786 
3787 /* Curl_setup_conn() is called after the name resolve initiated in
3788  * create_conn() is all done.
3789  *
3790  * Curl_setup_conn() also handles reused connections
3791  */
3792 CURLcode Curl_setup_conn(struct Curl_easy *data,
3793                          bool *protocol_done)
3794 {
3795   CURLcode result = CURLE_OK;
3796   struct connectdata *conn = data->conn;
3797 
3798   Curl_pgrsTime(data, TIMER_NAMELOOKUP);
3799 
3800   if(conn->handler->flags & PROTOPT_NONETWORK) {
3801     /* nothing to setup when not using a network */
3802     *protocol_done = TRUE;
3803     return result;
3804   }
3805 
3806 #ifndef CURL_DISABLE_PROXY
3807   /* set proxy_connect_closed to false unconditionally already here since it
3808      is used strictly to provide extra information to a parent function in the
3809      case of proxy CONNECT failures and we must make sure we don't have it
3810      lingering set from a previous invoke */
3811   conn->bits.proxy_connect_closed = FALSE;
3812 #endif
3813 
3814 #ifdef CURL_DO_LINEEND_CONV
3815   data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
3816 #endif /* CURL_DO_LINEEND_CONV */
3817 
3818   /* set start time here for timeout purposes in the connect procedure, it
3819      is later set again for the progress meter purpose */
3820   conn->now = Curl_now();
3821   if(!conn->bits.reuse)
3822     result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry,
3823                              CURL_CF_SSL_DEFAULT);
3824   if(!result)
3825     result = Curl_headers_init(data);
3826 
3827   /* not sure we need this flag to be passed around any more */
3828   *protocol_done = FALSE;
3829   return result;
3830 }
3831 
3832 CURLcode Curl_connect(struct Curl_easy *data,
3833                       bool *asyncp,
3834                       bool *protocol_done)
3835 {
3836   CURLcode result;
3837   struct connectdata *conn;
3838 
3839   *asyncp = FALSE; /* assume synchronous resolves by default */
3840 
3841   /* Set the request to virgin state based on transfer settings */
3842   Curl_req_hard_reset(&data->req, data);
3843 
3844   /* call the stuff that needs to be called */
3845   result = create_conn(data, &conn, asyncp);
3846 
3847   if(!result) {
3848     if(CONN_INUSE(conn) > 1)
3849       /* multiplexed */
3850       *protocol_done = TRUE;
3851     else if(!*asyncp) {
3852       /* DNS resolution is done: that's either because this is a reused
3853          connection, in which case DNS was unnecessary, or because DNS
3854          really did finish already (synch resolver/fast async resolve) */
3855       result = Curl_setup_conn(data, protocol_done);
3856     }
3857   }
3858 
3859   if(result == CURLE_NO_CONNECTION_AVAILABLE) {
3860     return result;
3861   }
3862   else if(result && conn) {
3863     /* We're not allowed to return failure with memory left allocated in the
3864        connectdata struct, free those here */
3865     Curl_detach_connection(data);
3866     Curl_conncache_remove_conn(data, conn, TRUE);
3867     Curl_disconnect(data, conn, TRUE);
3868   }
3869 
3870   return result;
3871 }
3872 
3873 /*
3874  * Curl_init_do() inits the readwrite session. This is inited each time (in
3875  * the DO function before the protocol-specific DO functions are invoked) for
3876  * a transfer, sometimes multiple times on the same Curl_easy. Make sure
3877  * nothing in here depends on stuff that are setup dynamically for the
3878  * transfer.
3879  *
3880  * Allow this function to get called with 'conn' set to NULL.
3881  */
3882 
3883 CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
3884 {
3885   /* if this is a pushed stream, we need this: */
3886   CURLcode result;
3887 
3888   if(conn) {
3889     conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
3890                                    use */
3891     /* if the protocol used doesn't support wildcards, switch it off */
3892     if(data->state.wildcardmatch &&
3893        !(conn->handler->flags & PROTOPT_WILDCARD))
3894       data->state.wildcardmatch = FALSE;
3895   }
3896 
3897   data->state.done = FALSE; /* *_done() is not called yet */
3898 
3899   if(data->req.no_body)
3900     /* in HTTP lingo, no body means using the HEAD request... */
3901     data->state.httpreq = HTTPREQ_HEAD;
3902 
3903   result = Curl_req_start(&data->req, data);
3904   if(!result) {
3905     Curl_speedinit(data);
3906     Curl_pgrsSetUploadCounter(data, 0);
3907     Curl_pgrsSetDownloadCounter(data, 0);
3908   }
3909   return result;
3910 }
3911 
3912 #if defined(USE_HTTP2) || defined(USE_HTTP3)
3913 
3914 #ifdef USE_NGHTTP2
3915 
3916 static void priority_remove_child(struct Curl_easy *parent,
3917                                   struct Curl_easy *child)
3918 {
3919   struct Curl_data_prio_node **pnext = &parent->set.priority.children;
3920   struct Curl_data_prio_node *pnode = parent->set.priority.children;
3921 
3922   DEBUGASSERT(child->set.priority.parent == parent);
3923   while(pnode && pnode->data != child) {
3924     pnext = &pnode->next;
3925     pnode = pnode->next;
3926   }
3927 
3928   DEBUGASSERT(pnode);
3929   if(pnode) {
3930     *pnext = pnode->next;
3931     free(pnode);
3932   }
3933 
3934   child->set.priority.parent = 0;
3935   child->set.priority.exclusive = FALSE;
3936 }
3937 
3938 CURLcode Curl_data_priority_add_child(struct Curl_easy *parent,
3939                                       struct Curl_easy *child,
3940                                       bool exclusive)
3941 {
3942   if(child->set.priority.parent) {
3943     priority_remove_child(child->set.priority.parent, child);
3944   }
3945 
3946   if(parent) {
3947     struct Curl_data_prio_node **tail;
3948     struct Curl_data_prio_node *pnode;
3949 
3950     pnode = calloc(1, sizeof(*pnode));
3951     if(!pnode)
3952       return CURLE_OUT_OF_MEMORY;
3953     pnode->data = child;
3954 
3955     if(parent->set.priority.children && exclusive) {
3956       /* exclusive: move all existing children underneath the new child */
3957       struct Curl_data_prio_node *node = parent->set.priority.children;
3958       while(node) {
3959         node->data->set.priority.parent = child;
3960         node = node->next;
3961       }
3962 
3963       tail = &child->set.priority.children;
3964       while(*tail)
3965         tail = &(*tail)->next;
3966 
3967       DEBUGASSERT(!*tail);
3968       *tail = parent->set.priority.children;
3969       parent->set.priority.children = 0;
3970     }
3971 
3972     tail = &parent->set.priority.children;
3973     while(*tail) {
3974       (*tail)->data->set.priority.exclusive = FALSE;
3975       tail = &(*tail)->next;
3976     }
3977 
3978     DEBUGASSERT(!*tail);
3979     *tail = pnode;
3980   }
3981 
3982   child->set.priority.parent = parent;
3983   child->set.priority.exclusive = exclusive;
3984   return CURLE_OK;
3985 }
3986 
3987 #endif /* USE_NGHTTP2 */
3988 
3989 #ifdef USE_NGHTTP2
3990 static void data_priority_cleanup(struct Curl_easy *data)
3991 {
3992   while(data->set.priority.children) {
3993     struct Curl_easy *tmp = data->set.priority.children->data;
3994     priority_remove_child(data, tmp);
3995     if(data->set.priority.parent)
3996       Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE);
3997   }
3998 
3999   if(data->set.priority.parent)
4000     priority_remove_child(data->set.priority.parent, data);
4001 }
4002 #endif
4003 
4004 void Curl_data_priority_clear_state(struct Curl_easy *data)
4005 {
4006   memset(&data->state.priority, 0, sizeof(data->state.priority));
4007 }
4008 
4009 #endif /* defined(USE_HTTP2) || defined(USE_HTTP3) */
4010