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