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