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