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