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