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