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