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