113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci
2513498266Sopenharmony_ci#include "curl_setup.h"
2613498266Sopenharmony_ci
2713498266Sopenharmony_ci#ifdef HAVE_NETINET_IN_H
2813498266Sopenharmony_ci#include <netinet/in.h>
2913498266Sopenharmony_ci#endif
3013498266Sopenharmony_ci#ifdef HAVE_NETDB_H
3113498266Sopenharmony_ci#include <netdb.h>
3213498266Sopenharmony_ci#endif
3313498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H
3413498266Sopenharmony_ci#include <arpa/inet.h>
3513498266Sopenharmony_ci#endif
3613498266Sopenharmony_ci#ifdef HAVE_NET_IF_H
3713498266Sopenharmony_ci#include <net/if.h>
3813498266Sopenharmony_ci#endif
3913498266Sopenharmony_ci#ifdef HAVE_IPHLPAPI_H
4013498266Sopenharmony_ci#include <Iphlpapi.h>
4113498266Sopenharmony_ci#endif
4213498266Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H
4313498266Sopenharmony_ci#include <sys/ioctl.h>
4413498266Sopenharmony_ci#endif
4513498266Sopenharmony_ci#ifdef HAVE_SYS_PARAM_H
4613498266Sopenharmony_ci#include <sys/param.h>
4713498266Sopenharmony_ci#endif
4813498266Sopenharmony_ci
4913498266Sopenharmony_ci#ifdef __VMS
5013498266Sopenharmony_ci#include <in.h>
5113498266Sopenharmony_ci#include <inet.h>
5213498266Sopenharmony_ci#endif
5313498266Sopenharmony_ci
5413498266Sopenharmony_ci#ifdef HAVE_SYS_UN_H
5513498266Sopenharmony_ci#include <sys/un.h>
5613498266Sopenharmony_ci#endif
5713498266Sopenharmony_ci
5813498266Sopenharmony_ci#ifndef HAVE_SOCKET
5913498266Sopenharmony_ci#error "We can't compile without socket() support!"
6013498266Sopenharmony_ci#endif
6113498266Sopenharmony_ci
6213498266Sopenharmony_ci#include <limits.h>
6313498266Sopenharmony_ci
6413498266Sopenharmony_ci#include "doh.h"
6513498266Sopenharmony_ci#include "urldata.h"
6613498266Sopenharmony_ci#include "netrc.h"
6713498266Sopenharmony_ci#include "formdata.h"
6813498266Sopenharmony_ci#include "mime.h"
6913498266Sopenharmony_ci#include "vtls/vtls.h"
7013498266Sopenharmony_ci#include "hostip.h"
7113498266Sopenharmony_ci#include "transfer.h"
7213498266Sopenharmony_ci#include "sendf.h"
7313498266Sopenharmony_ci#include "progress.h"
7413498266Sopenharmony_ci#include "cookie.h"
7513498266Sopenharmony_ci#include "strcase.h"
7613498266Sopenharmony_ci#include "strerror.h"
7713498266Sopenharmony_ci#include "escape.h"
7813498266Sopenharmony_ci#include "strtok.h"
7913498266Sopenharmony_ci#include "share.h"
8013498266Sopenharmony_ci#include "content_encoding.h"
8113498266Sopenharmony_ci#include "http_digest.h"
8213498266Sopenharmony_ci#include "http_negotiate.h"
8313498266Sopenharmony_ci#include "select.h"
8413498266Sopenharmony_ci#include "multiif.h"
8513498266Sopenharmony_ci#include "easyif.h"
8613498266Sopenharmony_ci#include "speedcheck.h"
8713498266Sopenharmony_ci#include "warnless.h"
8813498266Sopenharmony_ci#include "getinfo.h"
8913498266Sopenharmony_ci#include "urlapi-int.h"
9013498266Sopenharmony_ci#include "system_win32.h"
9113498266Sopenharmony_ci#include "hsts.h"
9213498266Sopenharmony_ci#include "noproxy.h"
9313498266Sopenharmony_ci#include "cfilters.h"
9413498266Sopenharmony_ci#include "idn.h"
9513498266Sopenharmony_ci
9613498266Sopenharmony_ci/* And now for the protocols */
9713498266Sopenharmony_ci#include "ftp.h"
9813498266Sopenharmony_ci#include "dict.h"
9913498266Sopenharmony_ci#include "telnet.h"
10013498266Sopenharmony_ci#include "tftp.h"
10113498266Sopenharmony_ci#include "http.h"
10213498266Sopenharmony_ci#include "http2.h"
10313498266Sopenharmony_ci#include "file.h"
10413498266Sopenharmony_ci#include "curl_ldap.h"
10513498266Sopenharmony_ci#include "vssh/ssh.h"
10613498266Sopenharmony_ci#include "imap.h"
10713498266Sopenharmony_ci#include "url.h"
10813498266Sopenharmony_ci#include "connect.h"
10913498266Sopenharmony_ci#include "inet_ntop.h"
11013498266Sopenharmony_ci#include "http_ntlm.h"
11113498266Sopenharmony_ci#include "curl_rtmp.h"
11213498266Sopenharmony_ci#include "gopher.h"
11313498266Sopenharmony_ci#include "mqtt.h"
11413498266Sopenharmony_ci#include "http_proxy.h"
11513498266Sopenharmony_ci#include "conncache.h"
11613498266Sopenharmony_ci#include "multihandle.h"
11713498266Sopenharmony_ci#include "strdup.h"
11813498266Sopenharmony_ci#include "setopt.h"
11913498266Sopenharmony_ci#include "altsvc.h"
12013498266Sopenharmony_ci#include "dynbuf.h"
12113498266Sopenharmony_ci#include "headers.h"
12213498266Sopenharmony_ci
12313498266Sopenharmony_ci/* The last 3 #include files should be in this order */
12413498266Sopenharmony_ci#include "curl_printf.h"
12513498266Sopenharmony_ci#include "curl_memory.h"
12613498266Sopenharmony_ci#include "memdebug.h"
12713498266Sopenharmony_ci
12813498266Sopenharmony_ci#ifndef ARRAYSIZE
12913498266Sopenharmony_ci#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
13013498266Sopenharmony_ci#endif
13113498266Sopenharmony_ci
13213498266Sopenharmony_ci#ifdef USE_NGHTTP2
13313498266Sopenharmony_cistatic void data_priority_cleanup(struct Curl_easy *data);
13413498266Sopenharmony_ci#else
13513498266Sopenharmony_ci#define data_priority_cleanup(x)
13613498266Sopenharmony_ci#endif
13713498266Sopenharmony_ci
13813498266Sopenharmony_ci/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
13913498266Sopenharmony_ci * more than just a few bytes to play with. Don't let it become too small or
14013498266Sopenharmony_ci * bad things will happen.
14113498266Sopenharmony_ci */
14213498266Sopenharmony_ci#if READBUFFER_SIZE < READBUFFER_MIN
14313498266Sopenharmony_ci# error READBUFFER_SIZE is too small
14413498266Sopenharmony_ci#endif
14513498266Sopenharmony_ci
14613498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
14713498266Sopenharmony_ci#define UNIX_SOCKET_PREFIX "localhost"
14813498266Sopenharmony_ci#endif
14913498266Sopenharmony_ci
15013498266Sopenharmony_ci/* Reject URLs exceeding this length */
15113498266Sopenharmony_ci#define MAX_URL_LEN 0xffff
15213498266Sopenharmony_ci
15313498266Sopenharmony_ci/*
15413498266Sopenharmony_ci* get_protocol_family()
15513498266Sopenharmony_ci*
15613498266Sopenharmony_ci* This is used to return the protocol family for a given protocol.
15713498266Sopenharmony_ci*
15813498266Sopenharmony_ci* Parameters:
15913498266Sopenharmony_ci*
16013498266Sopenharmony_ci* 'h'  [in]  - struct Curl_handler pointer.
16113498266Sopenharmony_ci*
16213498266Sopenharmony_ci* Returns the family as a single bit protocol identifier.
16313498266Sopenharmony_ci*/
16413498266Sopenharmony_cistatic curl_prot_t get_protocol_family(const struct Curl_handler *h)
16513498266Sopenharmony_ci{
16613498266Sopenharmony_ci  DEBUGASSERT(h);
16713498266Sopenharmony_ci  DEBUGASSERT(h->family);
16813498266Sopenharmony_ci  return h->family;
16913498266Sopenharmony_ci}
17013498266Sopenharmony_ci
17113498266Sopenharmony_civoid Curl_freeset(struct Curl_easy *data)
17213498266Sopenharmony_ci{
17313498266Sopenharmony_ci  /* Free all dynamic strings stored in the data->set substructure. */
17413498266Sopenharmony_ci  enum dupstring i;
17513498266Sopenharmony_ci  enum dupblob j;
17613498266Sopenharmony_ci
17713498266Sopenharmony_ci  for(i = (enum dupstring)0; i < STRING_LAST; i++) {
17813498266Sopenharmony_ci    Curl_safefree(data->set.str[i]);
17913498266Sopenharmony_ci  }
18013498266Sopenharmony_ci
18113498266Sopenharmony_ci  for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
18213498266Sopenharmony_ci    Curl_safefree(data->set.blobs[j]);
18313498266Sopenharmony_ci  }
18413498266Sopenharmony_ci
18513498266Sopenharmony_ci  if(data->state.referer_alloc) {
18613498266Sopenharmony_ci    Curl_safefree(data->state.referer);
18713498266Sopenharmony_ci    data->state.referer_alloc = FALSE;
18813498266Sopenharmony_ci  }
18913498266Sopenharmony_ci  data->state.referer = NULL;
19013498266Sopenharmony_ci  if(data->state.url_alloc) {
19113498266Sopenharmony_ci    Curl_safefree(data->state.url);
19213498266Sopenharmony_ci    data->state.url_alloc = FALSE;
19313498266Sopenharmony_ci  }
19413498266Sopenharmony_ci  data->state.url = NULL;
19513498266Sopenharmony_ci
19613498266Sopenharmony_ci  Curl_mime_cleanpart(&data->set.mimepost);
19713498266Sopenharmony_ci
19813498266Sopenharmony_ci#ifndef CURL_DISABLE_COOKIES
19913498266Sopenharmony_ci  curl_slist_free_all(data->state.cookielist);
20013498266Sopenharmony_ci  data->state.cookielist = NULL;
20113498266Sopenharmony_ci#endif
20213498266Sopenharmony_ci}
20313498266Sopenharmony_ci
20413498266Sopenharmony_ci/* free the URL pieces */
20513498266Sopenharmony_cistatic void up_free(struct Curl_easy *data)
20613498266Sopenharmony_ci{
20713498266Sopenharmony_ci  struct urlpieces *up = &data->state.up;
20813498266Sopenharmony_ci  Curl_safefree(up->scheme);
20913498266Sopenharmony_ci  Curl_safefree(up->hostname);
21013498266Sopenharmony_ci  Curl_safefree(up->port);
21113498266Sopenharmony_ci  Curl_safefree(up->user);
21213498266Sopenharmony_ci  Curl_safefree(up->password);
21313498266Sopenharmony_ci  Curl_safefree(up->options);
21413498266Sopenharmony_ci  Curl_safefree(up->path);
21513498266Sopenharmony_ci  Curl_safefree(up->query);
21613498266Sopenharmony_ci  curl_url_cleanup(data->state.uh);
21713498266Sopenharmony_ci  data->state.uh = NULL;
21813498266Sopenharmony_ci}
21913498266Sopenharmony_ci
22013498266Sopenharmony_ci/*
22113498266Sopenharmony_ci * This is the internal function curl_easy_cleanup() calls. This should
22213498266Sopenharmony_ci * cleanup and free all resources associated with this sessionhandle.
22313498266Sopenharmony_ci *
22413498266Sopenharmony_ci * We ignore SIGPIPE when this is called from curl_easy_cleanup.
22513498266Sopenharmony_ci */
22613498266Sopenharmony_ci
22713498266Sopenharmony_ciCURLcode Curl_close(struct Curl_easy **datap)
22813498266Sopenharmony_ci{
22913498266Sopenharmony_ci  struct Curl_easy *data;
23013498266Sopenharmony_ci
23113498266Sopenharmony_ci  if(!datap || !*datap)
23213498266Sopenharmony_ci    return CURLE_OK;
23313498266Sopenharmony_ci
23413498266Sopenharmony_ci  data = *datap;
23513498266Sopenharmony_ci  *datap = NULL;
23613498266Sopenharmony_ci
23713498266Sopenharmony_ci  Curl_expire_clear(data); /* shut off timers */
23813498266Sopenharmony_ci
23913498266Sopenharmony_ci  /* Detach connection if any is left. This should not be normal, but can be
24013498266Sopenharmony_ci     the case for example with CONNECT_ONLY + recv/send (test 556) */
24113498266Sopenharmony_ci  Curl_detach_connection(data);
24213498266Sopenharmony_ci  if(!data->state.internal) {
24313498266Sopenharmony_ci    if(data->multi)
24413498266Sopenharmony_ci      /* This handle is still part of a multi handle, take care of this first
24513498266Sopenharmony_ci         and detach this handle from there. */
24613498266Sopenharmony_ci      curl_multi_remove_handle(data->multi, data);
24713498266Sopenharmony_ci
24813498266Sopenharmony_ci    if(data->multi_easy) {
24913498266Sopenharmony_ci      /* when curl_easy_perform() is used, it creates its own multi handle to
25013498266Sopenharmony_ci         use and this is the one */
25113498266Sopenharmony_ci      curl_multi_cleanup(data->multi_easy);
25213498266Sopenharmony_ci      data->multi_easy = NULL;
25313498266Sopenharmony_ci    }
25413498266Sopenharmony_ci  }
25513498266Sopenharmony_ci
25613498266Sopenharmony_ci  data->magic = 0; /* force a clear AFTER the possibly enforced removal from
25713498266Sopenharmony_ci                      the multi handle, since that function uses the magic
25813498266Sopenharmony_ci                      field! */
25913498266Sopenharmony_ci
26013498266Sopenharmony_ci  if(data->state.rangestringalloc)
26113498266Sopenharmony_ci    free(data->state.range);
26213498266Sopenharmony_ci
26313498266Sopenharmony_ci  /* freed here just in case DONE wasn't called */
26413498266Sopenharmony_ci  Curl_free_request_state(data);
26513498266Sopenharmony_ci
26613498266Sopenharmony_ci  /* Close down all open SSL info and sessions */
26713498266Sopenharmony_ci  Curl_ssl_close_all(data);
26813498266Sopenharmony_ci  Curl_safefree(data->state.first_host);
26913498266Sopenharmony_ci  Curl_safefree(data->state.scratch);
27013498266Sopenharmony_ci  Curl_ssl_free_certinfo(data);
27113498266Sopenharmony_ci
27213498266Sopenharmony_ci  /* Cleanup possible redirect junk */
27313498266Sopenharmony_ci  free(data->req.newurl);
27413498266Sopenharmony_ci  data->req.newurl = NULL;
27513498266Sopenharmony_ci
27613498266Sopenharmony_ci  if(data->state.referer_alloc) {
27713498266Sopenharmony_ci    Curl_safefree(data->state.referer);
27813498266Sopenharmony_ci    data->state.referer_alloc = FALSE;
27913498266Sopenharmony_ci  }
28013498266Sopenharmony_ci  data->state.referer = NULL;
28113498266Sopenharmony_ci
28213498266Sopenharmony_ci  up_free(data);
28313498266Sopenharmony_ci  Curl_safefree(data->state.buffer);
28413498266Sopenharmony_ci  Curl_dyn_free(&data->state.headerb);
28513498266Sopenharmony_ci  Curl_safefree(data->state.ulbuf);
28613498266Sopenharmony_ci  Curl_flush_cookies(data, TRUE);
28713498266Sopenharmony_ci  Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
28813498266Sopenharmony_ci  Curl_altsvc_cleanup(&data->asi);
28913498266Sopenharmony_ci  Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
29013498266Sopenharmony_ci#ifndef CURL_DISABLE_HSTS
29113498266Sopenharmony_ci  if(!data->share || !data->share->hsts)
29213498266Sopenharmony_ci    Curl_hsts_cleanup(&data->hsts);
29313498266Sopenharmony_ci  curl_slist_free_all(data->state.hstslist); /* clean up list */
29413498266Sopenharmony_ci#endif
29513498266Sopenharmony_ci#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
29613498266Sopenharmony_ci  Curl_http_auth_cleanup_digest(data);
29713498266Sopenharmony_ci#endif
29813498266Sopenharmony_ci  Curl_safefree(data->info.contenttype);
29913498266Sopenharmony_ci  Curl_safefree(data->info.wouldredirect);
30013498266Sopenharmony_ci
30113498266Sopenharmony_ci  /* this destroys the channel and we cannot use it anymore after this */
30213498266Sopenharmony_ci  Curl_resolver_cancel(data);
30313498266Sopenharmony_ci  Curl_resolver_cleanup(data->state.async.resolver);
30413498266Sopenharmony_ci
30513498266Sopenharmony_ci  data_priority_cleanup(data);
30613498266Sopenharmony_ci
30713498266Sopenharmony_ci  /* No longer a dirty share, if it exists */
30813498266Sopenharmony_ci  if(data->share) {
30913498266Sopenharmony_ci    Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
31013498266Sopenharmony_ci    data->share->dirty--;
31113498266Sopenharmony_ci    Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
31213498266Sopenharmony_ci  }
31313498266Sopenharmony_ci
31413498266Sopenharmony_ci  Curl_safefree(data->state.aptr.proxyuserpwd);
31513498266Sopenharmony_ci  Curl_safefree(data->state.aptr.uagent);
31613498266Sopenharmony_ci  Curl_safefree(data->state.aptr.userpwd);
31713498266Sopenharmony_ci  Curl_safefree(data->state.aptr.accept_encoding);
31813498266Sopenharmony_ci  Curl_safefree(data->state.aptr.te);
31913498266Sopenharmony_ci  Curl_safefree(data->state.aptr.rangeline);
32013498266Sopenharmony_ci  Curl_safefree(data->state.aptr.ref);
32113498266Sopenharmony_ci  Curl_safefree(data->state.aptr.host);
32213498266Sopenharmony_ci  Curl_safefree(data->state.aptr.cookiehost);
32313498266Sopenharmony_ci  Curl_safefree(data->state.aptr.rtsp_transport);
32413498266Sopenharmony_ci  Curl_safefree(data->state.aptr.user);
32513498266Sopenharmony_ci  Curl_safefree(data->state.aptr.passwd);
32613498266Sopenharmony_ci  Curl_safefree(data->state.aptr.proxyuser);
32713498266Sopenharmony_ci  Curl_safefree(data->state.aptr.proxypasswd);
32813498266Sopenharmony_ci
32913498266Sopenharmony_ci#ifndef CURL_DISABLE_DOH
33013498266Sopenharmony_ci  if(data->req.doh) {
33113498266Sopenharmony_ci    Curl_dyn_free(&data->req.doh->probe[0].serverdoh);
33213498266Sopenharmony_ci    Curl_dyn_free(&data->req.doh->probe[1].serverdoh);
33313498266Sopenharmony_ci    curl_slist_free_all(data->req.doh->headers);
33413498266Sopenharmony_ci    Curl_safefree(data->req.doh);
33513498266Sopenharmony_ci  }
33613498266Sopenharmony_ci#endif
33713498266Sopenharmony_ci
33813498266Sopenharmony_ci#ifndef CURL_DISABLE_HTTP
33913498266Sopenharmony_ci  Curl_mime_cleanpart(data->state.formp);
34013498266Sopenharmony_ci  Curl_safefree(data->state.formp);
34113498266Sopenharmony_ci#endif
34213498266Sopenharmony_ci
34313498266Sopenharmony_ci  /* destruct wildcard structures if it is needed */
34413498266Sopenharmony_ci  Curl_wildcard_dtor(&data->wildcard);
34513498266Sopenharmony_ci  Curl_freeset(data);
34613498266Sopenharmony_ci  Curl_headers_cleanup(data);
34713498266Sopenharmony_ci  free(data);
34813498266Sopenharmony_ci  return CURLE_OK;
34913498266Sopenharmony_ci}
35013498266Sopenharmony_ci
35113498266Sopenharmony_ci/*
35213498266Sopenharmony_ci * Initialize the UserDefined fields within a Curl_easy.
35313498266Sopenharmony_ci * This may be safely called on a new or existing Curl_easy.
35413498266Sopenharmony_ci */
35513498266Sopenharmony_ciCURLcode Curl_init_userdefined(struct Curl_easy *data)
35613498266Sopenharmony_ci{
35713498266Sopenharmony_ci  struct UserDefined *set = &data->set;
35813498266Sopenharmony_ci  CURLcode result = CURLE_OK;
35913498266Sopenharmony_ci
36013498266Sopenharmony_ci  set->out = stdout; /* default output to stdout */
36113498266Sopenharmony_ci  set->in_set = stdin;  /* default input from stdin */
36213498266Sopenharmony_ci  set->err  = stderr;  /* default stderr to stderr */
36313498266Sopenharmony_ci
36413498266Sopenharmony_ci  /* use fwrite as default function to store output */
36513498266Sopenharmony_ci  set->fwrite_func = (curl_write_callback)fwrite;
36613498266Sopenharmony_ci
36713498266Sopenharmony_ci  /* use fread as default function to read input */
36813498266Sopenharmony_ci  set->fread_func_set = (curl_read_callback)fread;
36913498266Sopenharmony_ci  set->is_fread_set = 0;
37013498266Sopenharmony_ci
37113498266Sopenharmony_ci  set->seek_func = ZERO_NULL;
37213498266Sopenharmony_ci  set->seek_client = ZERO_NULL;
37313498266Sopenharmony_ci
37413498266Sopenharmony_ci  set->filesize = -1;        /* we don't know the size */
37513498266Sopenharmony_ci  set->postfieldsize = -1;   /* unknown size */
37613498266Sopenharmony_ci  set->maxredirs = 30;       /* sensible default */
37713498266Sopenharmony_ci
37813498266Sopenharmony_ci  set->method = HTTPREQ_GET; /* Default HTTP request */
37913498266Sopenharmony_ci#ifndef CURL_DISABLE_RTSP
38013498266Sopenharmony_ci  set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
38113498266Sopenharmony_ci#endif
38213498266Sopenharmony_ci#ifndef CURL_DISABLE_FTP
38313498266Sopenharmony_ci  set->ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
38413498266Sopenharmony_ci  set->ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
38513498266Sopenharmony_ci  set->ftp_use_pret = FALSE;  /* mainly useful for drftpd servers */
38613498266Sopenharmony_ci  set->ftp_filemethod = FTPFILE_MULTICWD;
38713498266Sopenharmony_ci  set->ftp_skip_ip = TRUE;    /* skip PASV IP by default */
38813498266Sopenharmony_ci#endif
38913498266Sopenharmony_ci  set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
39013498266Sopenharmony_ci
39113498266Sopenharmony_ci  /* Set the default size of the SSL session ID cache */
39213498266Sopenharmony_ci  set->general_ssl.max_ssl_sessions = 5;
39313498266Sopenharmony_ci  /* Timeout every 24 hours by default */
39413498266Sopenharmony_ci  set->general_ssl.ca_cache_timeout = 24 * 60 * 60;
39513498266Sopenharmony_ci
39613498266Sopenharmony_ci  set->httpauth = CURLAUTH_BASIC;  /* defaults to basic */
39713498266Sopenharmony_ci
39813498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
39913498266Sopenharmony_ci  set->proxyport = 0;
40013498266Sopenharmony_ci  set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
40113498266Sopenharmony_ci  set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
40213498266Sopenharmony_ci  /* SOCKS5 proxy auth defaults to username/password + GSS-API */
40313498266Sopenharmony_ci  set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI;
40413498266Sopenharmony_ci#endif
40513498266Sopenharmony_ci
40613498266Sopenharmony_ci  /* make libcurl quiet by default: */
40713498266Sopenharmony_ci  set->hide_progress = TRUE;  /* CURLOPT_NOPROGRESS changes these */
40813498266Sopenharmony_ci
40913498266Sopenharmony_ci  Curl_mime_initpart(&set->mimepost);
41013498266Sopenharmony_ci
41113498266Sopenharmony_ci  Curl_ssl_easy_config_init(data);
41213498266Sopenharmony_ci#ifndef CURL_DISABLE_DOH
41313498266Sopenharmony_ci  set->doh_verifyhost = TRUE;
41413498266Sopenharmony_ci  set->doh_verifypeer = TRUE;
41513498266Sopenharmony_ci#endif
41613498266Sopenharmony_ci#ifdef USE_SSH
41713498266Sopenharmony_ci  /* defaults to any auth type */
41813498266Sopenharmony_ci  set->ssh_auth_types = CURLSSH_AUTH_DEFAULT;
41913498266Sopenharmony_ci  set->new_directory_perms = 0755; /* Default permissions */
42013498266Sopenharmony_ci#endif
42113498266Sopenharmony_ci
42213498266Sopenharmony_ci  set->new_file_perms = 0644;    /* Default permissions */
42313498266Sopenharmony_ci  set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL;
42413498266Sopenharmony_ci  set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP |
42513498266Sopenharmony_ci                         CURLPROTO_FTPS;
42613498266Sopenharmony_ci
42713498266Sopenharmony_ci#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
42813498266Sopenharmony_ci  /*
42913498266Sopenharmony_ci   * disallow unprotected protection negotiation NEC reference implementation
43013498266Sopenharmony_ci   * seem not to follow rfc1961 section 4.3/4.4
43113498266Sopenharmony_ci   */
43213498266Sopenharmony_ci  set->socks5_gssapi_nec = FALSE;
43313498266Sopenharmony_ci#endif
43413498266Sopenharmony_ci
43513498266Sopenharmony_ci  /* Set the default CA cert bundle/path detected/specified at build time.
43613498266Sopenharmony_ci   *
43713498266Sopenharmony_ci   * If Schannel or SecureTransport is the selected SSL backend then these
43813498266Sopenharmony_ci   * locations are ignored. We allow setting CA location for schannel and
43913498266Sopenharmony_ci   * securetransport when explicitly specified by the user via
44013498266Sopenharmony_ci   *  CURLOPT_CAINFO / --cacert.
44113498266Sopenharmony_ci   */
44213498266Sopenharmony_ci  if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL &&
44313498266Sopenharmony_ci     Curl_ssl_backend() != CURLSSLBACKEND_SECURETRANSPORT) {
44413498266Sopenharmony_ci#if defined(CURL_CA_BUNDLE)
44513498266Sopenharmony_ci    result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
44613498266Sopenharmony_ci    if(result)
44713498266Sopenharmony_ci      return result;
44813498266Sopenharmony_ci
44913498266Sopenharmony_ci    result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
45013498266Sopenharmony_ci                            CURL_CA_BUNDLE);
45113498266Sopenharmony_ci    if(result)
45213498266Sopenharmony_ci      return result;
45313498266Sopenharmony_ci#endif
45413498266Sopenharmony_ci#if defined(CURL_CA_PATH)
45513498266Sopenharmony_ci    result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
45613498266Sopenharmony_ci    if(result)
45713498266Sopenharmony_ci      return result;
45813498266Sopenharmony_ci
45913498266Sopenharmony_ci    result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
46013498266Sopenharmony_ci    if(result)
46113498266Sopenharmony_ci      return result;
46213498266Sopenharmony_ci#endif
46313498266Sopenharmony_ci  }
46413498266Sopenharmony_ci
46513498266Sopenharmony_ci#ifndef CURL_DISABLE_FTP
46613498266Sopenharmony_ci  set->wildcard_enabled = FALSE;
46713498266Sopenharmony_ci  set->chunk_bgn      = ZERO_NULL;
46813498266Sopenharmony_ci  set->chunk_end      = ZERO_NULL;
46913498266Sopenharmony_ci  set->fnmatch = ZERO_NULL;
47013498266Sopenharmony_ci#endif
47113498266Sopenharmony_ci  set->tcp_keepalive = FALSE;
47213498266Sopenharmony_ci  set->tcp_keepintvl = 60;
47313498266Sopenharmony_ci  set->tcp_keepidle = 60;
47413498266Sopenharmony_ci  set->tcp_fastopen = FALSE;
47513498266Sopenharmony_ci  set->tcp_nodelay = TRUE;
47613498266Sopenharmony_ci  set->ssl_enable_alpn = TRUE;
47713498266Sopenharmony_ci  set->expect_100_timeout = 1000L; /* Wait for a second by default. */
47813498266Sopenharmony_ci  set->sep_headers = TRUE; /* separated header lists by default */
47913498266Sopenharmony_ci  set->buffer_size = READBUFFER_SIZE;
48013498266Sopenharmony_ci  set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
48113498266Sopenharmony_ci  set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
48213498266Sopenharmony_ci  set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
48313498266Sopenharmony_ci  set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
48413498266Sopenharmony_ci  set->maxage_conn = 118;
48513498266Sopenharmony_ci  set->maxlifetime_conn = 0;
48613498266Sopenharmony_ci  set->http09_allowed = FALSE;
48713498266Sopenharmony_ci#ifdef USE_HTTP2
48813498266Sopenharmony_ci  set->httpwant = CURL_HTTP_VERSION_2TLS
48913498266Sopenharmony_ci#else
49013498266Sopenharmony_ci  set->httpwant = CURL_HTTP_VERSION_1_1
49113498266Sopenharmony_ci#endif
49213498266Sopenharmony_ci    ;
49313498266Sopenharmony_ci#if defined(USE_HTTP2) || defined(USE_HTTP3)
49413498266Sopenharmony_ci  memset(&set->priority, 0, sizeof(set->priority));
49513498266Sopenharmony_ci#endif
49613498266Sopenharmony_ci  set->quick_exit = 0L;
49713498266Sopenharmony_ci  return result;
49813498266Sopenharmony_ci}
49913498266Sopenharmony_ci
50013498266Sopenharmony_ci/**
50113498266Sopenharmony_ci * Curl_open()
50213498266Sopenharmony_ci *
50313498266Sopenharmony_ci * @param curl is a pointer to a sessionhandle pointer that gets set by this
50413498266Sopenharmony_ci * function.
50513498266Sopenharmony_ci * @return CURLcode
50613498266Sopenharmony_ci */
50713498266Sopenharmony_ci
50813498266Sopenharmony_ciCURLcode Curl_open(struct Curl_easy **curl)
50913498266Sopenharmony_ci{
51013498266Sopenharmony_ci  CURLcode result;
51113498266Sopenharmony_ci  struct Curl_easy *data;
51213498266Sopenharmony_ci
51313498266Sopenharmony_ci  /* Very simple start-up: alloc the struct, init it with zeroes and return */
51413498266Sopenharmony_ci  data = calloc(1, sizeof(struct Curl_easy));
51513498266Sopenharmony_ci  if(!data) {
51613498266Sopenharmony_ci    /* this is a very serious error */
51713498266Sopenharmony_ci    DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n"));
51813498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
51913498266Sopenharmony_ci  }
52013498266Sopenharmony_ci
52113498266Sopenharmony_ci  data->magic = CURLEASY_MAGIC_NUMBER;
52213498266Sopenharmony_ci
52313498266Sopenharmony_ci  result = Curl_resolver_init(data, &data->state.async.resolver);
52413498266Sopenharmony_ci  if(result) {
52513498266Sopenharmony_ci    DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
52613498266Sopenharmony_ci    free(data);
52713498266Sopenharmony_ci    return result;
52813498266Sopenharmony_ci  }
52913498266Sopenharmony_ci
53013498266Sopenharmony_ci  result = Curl_init_userdefined(data);
53113498266Sopenharmony_ci  if(!result) {
53213498266Sopenharmony_ci    Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
53313498266Sopenharmony_ci    Curl_initinfo(data);
53413498266Sopenharmony_ci
53513498266Sopenharmony_ci    /* most recent connection is not yet defined */
53613498266Sopenharmony_ci    data->state.lastconnect_id = -1;
53713498266Sopenharmony_ci    data->state.recent_conn_id = -1;
53813498266Sopenharmony_ci    /* and not assigned an id yet */
53913498266Sopenharmony_ci    data->id = -1;
54013498266Sopenharmony_ci
54113498266Sopenharmony_ci    data->progress.flags |= PGRS_HIDE;
54213498266Sopenharmony_ci    data->state.current_speed = -1; /* init to negative == impossible */
54313498266Sopenharmony_ci  }
54413498266Sopenharmony_ci
54513498266Sopenharmony_ci  if(result) {
54613498266Sopenharmony_ci    Curl_resolver_cleanup(data->state.async.resolver);
54713498266Sopenharmony_ci    Curl_dyn_free(&data->state.headerb);
54813498266Sopenharmony_ci    Curl_freeset(data);
54913498266Sopenharmony_ci    free(data);
55013498266Sopenharmony_ci    data = NULL;
55113498266Sopenharmony_ci  }
55213498266Sopenharmony_ci  else
55313498266Sopenharmony_ci    *curl = data;
55413498266Sopenharmony_ci
55513498266Sopenharmony_ci  return result;
55613498266Sopenharmony_ci}
55713498266Sopenharmony_ci
55813498266Sopenharmony_cistatic void conn_shutdown(struct Curl_easy *data)
55913498266Sopenharmony_ci{
56013498266Sopenharmony_ci  DEBUGASSERT(data);
56113498266Sopenharmony_ci  infof(data, "Closing connection");
56213498266Sopenharmony_ci
56313498266Sopenharmony_ci  /* possible left-overs from the async name resolvers */
56413498266Sopenharmony_ci  Curl_resolver_cancel(data);
56513498266Sopenharmony_ci
56613498266Sopenharmony_ci  Curl_conn_close(data, SECONDARYSOCKET);
56713498266Sopenharmony_ci  Curl_conn_close(data, FIRSTSOCKET);
56813498266Sopenharmony_ci}
56913498266Sopenharmony_ci
57013498266Sopenharmony_cistatic void conn_free(struct Curl_easy *data, struct connectdata *conn)
57113498266Sopenharmony_ci{
57213498266Sopenharmony_ci  size_t i;
57313498266Sopenharmony_ci
57413498266Sopenharmony_ci  DEBUGASSERT(conn);
57513498266Sopenharmony_ci
57613498266Sopenharmony_ci  for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
57713498266Sopenharmony_ci    Curl_conn_cf_discard_all(data, conn, (int)i);
57813498266Sopenharmony_ci  }
57913498266Sopenharmony_ci
58013498266Sopenharmony_ci  Curl_free_idnconverted_hostname(&conn->host);
58113498266Sopenharmony_ci  Curl_free_idnconverted_hostname(&conn->conn_to_host);
58213498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
58313498266Sopenharmony_ci  Curl_free_idnconverted_hostname(&conn->http_proxy.host);
58413498266Sopenharmony_ci  Curl_free_idnconverted_hostname(&conn->socks_proxy.host);
58513498266Sopenharmony_ci  Curl_safefree(conn->http_proxy.user);
58613498266Sopenharmony_ci  Curl_safefree(conn->socks_proxy.user);
58713498266Sopenharmony_ci  Curl_safefree(conn->http_proxy.passwd);
58813498266Sopenharmony_ci  Curl_safefree(conn->socks_proxy.passwd);
58913498266Sopenharmony_ci  Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
59013498266Sopenharmony_ci  Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
59113498266Sopenharmony_ci#endif
59213498266Sopenharmony_ci  Curl_safefree(conn->user);
59313498266Sopenharmony_ci  Curl_safefree(conn->passwd);
59413498266Sopenharmony_ci  Curl_safefree(conn->sasl_authzid);
59513498266Sopenharmony_ci  Curl_safefree(conn->options);
59613498266Sopenharmony_ci  Curl_safefree(conn->oauth_bearer);
59713498266Sopenharmony_ci  Curl_safefree(conn->host.rawalloc); /* host name buffer */
59813498266Sopenharmony_ci  Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
59913498266Sopenharmony_ci  Curl_safefree(conn->hostname_resolve);
60013498266Sopenharmony_ci  Curl_safefree(conn->secondaryhostname);
60113498266Sopenharmony_ci  Curl_safefree(conn->localdev);
60213498266Sopenharmony_ci  Curl_ssl_conn_config_cleanup(conn);
60313498266Sopenharmony_ci
60413498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
60513498266Sopenharmony_ci  Curl_safefree(conn->unix_domain_socket);
60613498266Sopenharmony_ci#endif
60713498266Sopenharmony_ci
60813498266Sopenharmony_ci  free(conn); /* free all the connection oriented data */
60913498266Sopenharmony_ci}
61013498266Sopenharmony_ci
61113498266Sopenharmony_ci/*
61213498266Sopenharmony_ci * Disconnects the given connection. Note the connection may not be the
61313498266Sopenharmony_ci * primary connection, like when freeing room in the connection cache or
61413498266Sopenharmony_ci * killing of a dead old connection.
61513498266Sopenharmony_ci *
61613498266Sopenharmony_ci * A connection needs an easy handle when closing down. We support this passed
61713498266Sopenharmony_ci * in separately since the connection to get closed here is often already
61813498266Sopenharmony_ci * disassociated from an easy handle.
61913498266Sopenharmony_ci *
62013498266Sopenharmony_ci * This function MUST NOT reset state in the Curl_easy struct if that
62113498266Sopenharmony_ci * isn't strictly bound to the life-time of *this* particular connection.
62213498266Sopenharmony_ci *
62313498266Sopenharmony_ci */
62413498266Sopenharmony_ci
62513498266Sopenharmony_civoid Curl_disconnect(struct Curl_easy *data,
62613498266Sopenharmony_ci                     struct connectdata *conn, bool dead_connection)
62713498266Sopenharmony_ci{
62813498266Sopenharmony_ci  /* there must be a connection to close */
62913498266Sopenharmony_ci  DEBUGASSERT(conn);
63013498266Sopenharmony_ci
63113498266Sopenharmony_ci  /* it must be removed from the connection cache */
63213498266Sopenharmony_ci  DEBUGASSERT(!conn->bundle);
63313498266Sopenharmony_ci
63413498266Sopenharmony_ci  /* there must be an associated transfer */
63513498266Sopenharmony_ci  DEBUGASSERT(data);
63613498266Sopenharmony_ci
63713498266Sopenharmony_ci  /* the transfer must be detached from the connection */
63813498266Sopenharmony_ci  DEBUGASSERT(!data->conn);
63913498266Sopenharmony_ci
64013498266Sopenharmony_ci  DEBUGF(infof(data, "Curl_disconnect(conn #%"
64113498266Sopenharmony_ci         CURL_FORMAT_CURL_OFF_T ", dead=%d)",
64213498266Sopenharmony_ci         conn->connection_id, dead_connection));
64313498266Sopenharmony_ci  /*
64413498266Sopenharmony_ci   * If this connection isn't marked to force-close, leave it open if there
64513498266Sopenharmony_ci   * are other users of it
64613498266Sopenharmony_ci   */
64713498266Sopenharmony_ci  if(CONN_INUSE(conn) && !dead_connection) {
64813498266Sopenharmony_ci    DEBUGF(infof(data, "Curl_disconnect when inuse: %zu", CONN_INUSE(conn)));
64913498266Sopenharmony_ci    return;
65013498266Sopenharmony_ci  }
65113498266Sopenharmony_ci
65213498266Sopenharmony_ci  if(conn->dns_entry) {
65313498266Sopenharmony_ci    Curl_resolv_unlock(data, conn->dns_entry);
65413498266Sopenharmony_ci    conn->dns_entry = NULL;
65513498266Sopenharmony_ci  }
65613498266Sopenharmony_ci
65713498266Sopenharmony_ci  /* Cleanup NTLM connection-related data */
65813498266Sopenharmony_ci  Curl_http_auth_cleanup_ntlm(conn);
65913498266Sopenharmony_ci
66013498266Sopenharmony_ci  /* Cleanup NEGOTIATE connection-related data */
66113498266Sopenharmony_ci  Curl_http_auth_cleanup_negotiate(conn);
66213498266Sopenharmony_ci
66313498266Sopenharmony_ci  if(conn->connect_only)
66413498266Sopenharmony_ci    /* treat the connection as dead in CONNECT_ONLY situations */
66513498266Sopenharmony_ci    dead_connection = TRUE;
66613498266Sopenharmony_ci
66713498266Sopenharmony_ci  /* temporarily attach the connection to this transfer handle for the
66813498266Sopenharmony_ci     disconnect and shutdown */
66913498266Sopenharmony_ci  Curl_attach_connection(data, conn);
67013498266Sopenharmony_ci
67113498266Sopenharmony_ci  if(conn->handler && conn->handler->disconnect)
67213498266Sopenharmony_ci    /* This is set if protocol-specific cleanups should be made */
67313498266Sopenharmony_ci    conn->handler->disconnect(data, conn, dead_connection);
67413498266Sopenharmony_ci
67513498266Sopenharmony_ci  conn_shutdown(data);
67613498266Sopenharmony_ci
67713498266Sopenharmony_ci  /* detach it again */
67813498266Sopenharmony_ci  Curl_detach_connection(data);
67913498266Sopenharmony_ci
68013498266Sopenharmony_ci  conn_free(data, conn);
68113498266Sopenharmony_ci}
68213498266Sopenharmony_ci
68313498266Sopenharmony_ci/*
68413498266Sopenharmony_ci * IsMultiplexingPossible()
68513498266Sopenharmony_ci *
68613498266Sopenharmony_ci * Return a bitmask with the available multiplexing options for the given
68713498266Sopenharmony_ci * requested connection.
68813498266Sopenharmony_ci */
68913498266Sopenharmony_cistatic int IsMultiplexingPossible(const struct Curl_easy *handle,
69013498266Sopenharmony_ci                                  const struct connectdata *conn)
69113498266Sopenharmony_ci{
69213498266Sopenharmony_ci  int avail = 0;
69313498266Sopenharmony_ci
69413498266Sopenharmony_ci  /* If an HTTP protocol and multiplexing is enabled */
69513498266Sopenharmony_ci  if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
69613498266Sopenharmony_ci     (!conn->bits.protoconnstart || !conn->bits.close)) {
69713498266Sopenharmony_ci
69813498266Sopenharmony_ci    if(Curl_multiplex_wanted(handle->multi) &&
69913498266Sopenharmony_ci       (handle->state.httpwant >= CURL_HTTP_VERSION_2))
70013498266Sopenharmony_ci      /* allows HTTP/2 */
70113498266Sopenharmony_ci      avail |= CURLPIPE_MULTIPLEX;
70213498266Sopenharmony_ci  }
70313498266Sopenharmony_ci  return avail;
70413498266Sopenharmony_ci}
70513498266Sopenharmony_ci
70613498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
70713498266Sopenharmony_cistatic bool
70813498266Sopenharmony_ciproxy_info_matches(const struct proxy_info *data,
70913498266Sopenharmony_ci                   const struct proxy_info *needle)
71013498266Sopenharmony_ci{
71113498266Sopenharmony_ci  if((data->proxytype == needle->proxytype) &&
71213498266Sopenharmony_ci     (data->port == needle->port) &&
71313498266Sopenharmony_ci     strcasecompare(data->host.name, needle->host.name))
71413498266Sopenharmony_ci    return TRUE;
71513498266Sopenharmony_ci
71613498266Sopenharmony_ci  return FALSE;
71713498266Sopenharmony_ci}
71813498266Sopenharmony_ci
71913498266Sopenharmony_cistatic bool
72013498266Sopenharmony_cisocks_proxy_info_matches(const struct proxy_info *data,
72113498266Sopenharmony_ci                         const struct proxy_info *needle)
72213498266Sopenharmony_ci{
72313498266Sopenharmony_ci  if(!proxy_info_matches(data, needle))
72413498266Sopenharmony_ci    return FALSE;
72513498266Sopenharmony_ci
72613498266Sopenharmony_ci  /* the user information is case-sensitive
72713498266Sopenharmony_ci     or at least it is not defined as case-insensitive
72813498266Sopenharmony_ci     see https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1 */
72913498266Sopenharmony_ci
73013498266Sopenharmony_ci  /* curl_strequal does a case insensitive comparison,
73113498266Sopenharmony_ci     so do not use it here! */
73213498266Sopenharmony_ci  if(Curl_timestrcmp(data->user, needle->user) ||
73313498266Sopenharmony_ci     Curl_timestrcmp(data->passwd, needle->passwd))
73413498266Sopenharmony_ci    return FALSE;
73513498266Sopenharmony_ci  return TRUE;
73613498266Sopenharmony_ci}
73713498266Sopenharmony_ci#else
73813498266Sopenharmony_ci/* disabled, won't get called */
73913498266Sopenharmony_ci#define proxy_info_matches(x,y) FALSE
74013498266Sopenharmony_ci#define socks_proxy_info_matches(x,y) FALSE
74113498266Sopenharmony_ci#endif
74213498266Sopenharmony_ci
74313498266Sopenharmony_ci/* A connection has to have been idle for a shorter time than 'maxage_conn'
74413498266Sopenharmony_ci   (the success rate is just too low after this), or created less than
74513498266Sopenharmony_ci   'maxlifetime_conn' ago, to be subject for reuse. */
74613498266Sopenharmony_ci
74713498266Sopenharmony_cistatic bool conn_maxage(struct Curl_easy *data,
74813498266Sopenharmony_ci                        struct connectdata *conn,
74913498266Sopenharmony_ci                        struct curltime now)
75013498266Sopenharmony_ci{
75113498266Sopenharmony_ci  timediff_t idletime, lifetime;
75213498266Sopenharmony_ci
75313498266Sopenharmony_ci  idletime = Curl_timediff(now, conn->lastused);
75413498266Sopenharmony_ci  idletime /= 1000; /* integer seconds is fine */
75513498266Sopenharmony_ci
75613498266Sopenharmony_ci  if(idletime > data->set.maxage_conn) {
75713498266Sopenharmony_ci    infof(data, "Too old connection (%" CURL_FORMAT_TIMEDIFF_T
75813498266Sopenharmony_ci          " seconds idle), disconnect it", idletime);
75913498266Sopenharmony_ci    return TRUE;
76013498266Sopenharmony_ci  }
76113498266Sopenharmony_ci
76213498266Sopenharmony_ci  lifetime = Curl_timediff(now, conn->created);
76313498266Sopenharmony_ci  lifetime /= 1000; /* integer seconds is fine */
76413498266Sopenharmony_ci
76513498266Sopenharmony_ci  if(data->set.maxlifetime_conn && lifetime > data->set.maxlifetime_conn) {
76613498266Sopenharmony_ci    infof(data,
76713498266Sopenharmony_ci          "Too old connection (%" CURL_FORMAT_TIMEDIFF_T
76813498266Sopenharmony_ci          " seconds since creation), disconnect it", lifetime);
76913498266Sopenharmony_ci    return TRUE;
77013498266Sopenharmony_ci  }
77113498266Sopenharmony_ci
77213498266Sopenharmony_ci
77313498266Sopenharmony_ci  return FALSE;
77413498266Sopenharmony_ci}
77513498266Sopenharmony_ci
77613498266Sopenharmony_ci/*
77713498266Sopenharmony_ci * This function checks if the given connection is dead and extracts it from
77813498266Sopenharmony_ci * the connection cache if so.
77913498266Sopenharmony_ci *
78013498266Sopenharmony_ci * When this is called as a Curl_conncache_foreach() callback, the connection
78113498266Sopenharmony_ci * cache lock is held!
78213498266Sopenharmony_ci *
78313498266Sopenharmony_ci * Returns TRUE if the connection was dead and extracted.
78413498266Sopenharmony_ci */
78513498266Sopenharmony_cistatic bool extract_if_dead(struct connectdata *conn,
78613498266Sopenharmony_ci                            struct Curl_easy *data)
78713498266Sopenharmony_ci{
78813498266Sopenharmony_ci  if(!CONN_INUSE(conn)) {
78913498266Sopenharmony_ci    /* The check for a dead socket makes sense only if the connection isn't in
79013498266Sopenharmony_ci       use */
79113498266Sopenharmony_ci    bool dead;
79213498266Sopenharmony_ci    struct curltime now = Curl_now();
79313498266Sopenharmony_ci    if(conn_maxage(data, conn, now)) {
79413498266Sopenharmony_ci      /* avoid check if already too old */
79513498266Sopenharmony_ci      dead = TRUE;
79613498266Sopenharmony_ci    }
79713498266Sopenharmony_ci    else if(conn->handler->connection_check) {
79813498266Sopenharmony_ci      /* The protocol has a special method for checking the state of the
79913498266Sopenharmony_ci         connection. Use it to check if the connection is dead. */
80013498266Sopenharmony_ci      unsigned int state;
80113498266Sopenharmony_ci
80213498266Sopenharmony_ci      /* briefly attach the connection to this transfer for the purpose of
80313498266Sopenharmony_ci         checking it */
80413498266Sopenharmony_ci      Curl_attach_connection(data, conn);
80513498266Sopenharmony_ci
80613498266Sopenharmony_ci      state = conn->handler->connection_check(data, conn, CONNCHECK_ISDEAD);
80713498266Sopenharmony_ci      dead = (state & CONNRESULT_DEAD);
80813498266Sopenharmony_ci      /* detach the connection again */
80913498266Sopenharmony_ci      Curl_detach_connection(data);
81013498266Sopenharmony_ci
81113498266Sopenharmony_ci    }
81213498266Sopenharmony_ci    else {
81313498266Sopenharmony_ci      bool input_pending;
81413498266Sopenharmony_ci
81513498266Sopenharmony_ci      Curl_attach_connection(data, conn);
81613498266Sopenharmony_ci      dead = !Curl_conn_is_alive(data, conn, &input_pending);
81713498266Sopenharmony_ci      if(input_pending) {
81813498266Sopenharmony_ci        /* For reuse, we want a "clean" connection state. The includes
81913498266Sopenharmony_ci         * that we expect - in general - no waiting input data. Input
82013498266Sopenharmony_ci         * waiting might be a TLS Notify Close, for example. We reject
82113498266Sopenharmony_ci         * that.
82213498266Sopenharmony_ci         * For protocols where data from other end may arrive at
82313498266Sopenharmony_ci         * any time (HTTP/2 PING for example), the protocol handler needs
82413498266Sopenharmony_ci         * to install its own `connection_check` callback.
82513498266Sopenharmony_ci         */
82613498266Sopenharmony_ci        dead = TRUE;
82713498266Sopenharmony_ci      }
82813498266Sopenharmony_ci      Curl_detach_connection(data);
82913498266Sopenharmony_ci    }
83013498266Sopenharmony_ci
83113498266Sopenharmony_ci    if(dead) {
83213498266Sopenharmony_ci      infof(data, "Connection %" CURL_FORMAT_CURL_OFF_T " seems to be dead",
83313498266Sopenharmony_ci            conn->connection_id);
83413498266Sopenharmony_ci      Curl_conncache_remove_conn(data, conn, FALSE);
83513498266Sopenharmony_ci      return TRUE;
83613498266Sopenharmony_ci    }
83713498266Sopenharmony_ci  }
83813498266Sopenharmony_ci  return FALSE;
83913498266Sopenharmony_ci}
84013498266Sopenharmony_ci
84113498266Sopenharmony_cistruct prunedead {
84213498266Sopenharmony_ci  struct Curl_easy *data;
84313498266Sopenharmony_ci  struct connectdata *extracted;
84413498266Sopenharmony_ci};
84513498266Sopenharmony_ci
84613498266Sopenharmony_ci/*
84713498266Sopenharmony_ci * Wrapper to use extract_if_dead() function in Curl_conncache_foreach()
84813498266Sopenharmony_ci *
84913498266Sopenharmony_ci */
85013498266Sopenharmony_cistatic int call_extract_if_dead(struct Curl_easy *data,
85113498266Sopenharmony_ci                                struct connectdata *conn, void *param)
85213498266Sopenharmony_ci{
85313498266Sopenharmony_ci  struct prunedead *p = (struct prunedead *)param;
85413498266Sopenharmony_ci  if(extract_if_dead(conn, data)) {
85513498266Sopenharmony_ci    /* stop the iteration here, pass back the connection that was extracted */
85613498266Sopenharmony_ci    p->extracted = conn;
85713498266Sopenharmony_ci    return 1;
85813498266Sopenharmony_ci  }
85913498266Sopenharmony_ci  return 0; /* continue iteration */
86013498266Sopenharmony_ci}
86113498266Sopenharmony_ci
86213498266Sopenharmony_ci/*
86313498266Sopenharmony_ci * This function scans the connection cache for half-open/dead connections,
86413498266Sopenharmony_ci * closes and removes them. The cleanup is done at most once per second.
86513498266Sopenharmony_ci *
86613498266Sopenharmony_ci * When called, this transfer has no connection attached.
86713498266Sopenharmony_ci */
86813498266Sopenharmony_cistatic void prune_dead_connections(struct Curl_easy *data)
86913498266Sopenharmony_ci{
87013498266Sopenharmony_ci  struct curltime now = Curl_now();
87113498266Sopenharmony_ci  timediff_t elapsed;
87213498266Sopenharmony_ci
87313498266Sopenharmony_ci  DEBUGASSERT(!data->conn); /* no connection */
87413498266Sopenharmony_ci  CONNCACHE_LOCK(data);
87513498266Sopenharmony_ci  elapsed =
87613498266Sopenharmony_ci    Curl_timediff(now, data->state.conn_cache->last_cleanup);
87713498266Sopenharmony_ci  CONNCACHE_UNLOCK(data);
87813498266Sopenharmony_ci
87913498266Sopenharmony_ci  if(elapsed >= 1000L) {
88013498266Sopenharmony_ci    struct prunedead prune;
88113498266Sopenharmony_ci    prune.data = data;
88213498266Sopenharmony_ci    prune.extracted = NULL;
88313498266Sopenharmony_ci    while(Curl_conncache_foreach(data, data->state.conn_cache, &prune,
88413498266Sopenharmony_ci                                 call_extract_if_dead)) {
88513498266Sopenharmony_ci      /* unlocked */
88613498266Sopenharmony_ci
88713498266Sopenharmony_ci      /* remove connection from cache */
88813498266Sopenharmony_ci      Curl_conncache_remove_conn(data, prune.extracted, TRUE);
88913498266Sopenharmony_ci
89013498266Sopenharmony_ci      /* disconnect it */
89113498266Sopenharmony_ci      Curl_disconnect(data, prune.extracted, TRUE);
89213498266Sopenharmony_ci    }
89313498266Sopenharmony_ci    CONNCACHE_LOCK(data);
89413498266Sopenharmony_ci    data->state.conn_cache->last_cleanup = now;
89513498266Sopenharmony_ci    CONNCACHE_UNLOCK(data);
89613498266Sopenharmony_ci  }
89713498266Sopenharmony_ci}
89813498266Sopenharmony_ci
89913498266Sopenharmony_ci#ifdef USE_SSH
90013498266Sopenharmony_cistatic bool ssh_config_matches(struct connectdata *one,
90113498266Sopenharmony_ci                               struct connectdata *two)
90213498266Sopenharmony_ci{
90313498266Sopenharmony_ci  return (Curl_safecmp(one->proto.sshc.rsa, two->proto.sshc.rsa) &&
90413498266Sopenharmony_ci          Curl_safecmp(one->proto.sshc.rsa_pub, two->proto.sshc.rsa_pub));
90513498266Sopenharmony_ci}
90613498266Sopenharmony_ci#else
90713498266Sopenharmony_ci#define ssh_config_matches(x,y) FALSE
90813498266Sopenharmony_ci#endif
90913498266Sopenharmony_ci
91013498266Sopenharmony_ci/*
91113498266Sopenharmony_ci * Given one filled in connection struct (named needle), this function should
91213498266Sopenharmony_ci * detect if there already is one that has all the significant details
91313498266Sopenharmony_ci * exactly the same and thus should be used instead.
91413498266Sopenharmony_ci *
91513498266Sopenharmony_ci * If there is a match, this function returns TRUE - and has marked the
91613498266Sopenharmony_ci * connection as 'in-use'. It must later be called with ConnectionDone() to
91713498266Sopenharmony_ci * return back to 'idle' (unused) state.
91813498266Sopenharmony_ci *
91913498266Sopenharmony_ci * The force_reuse flag is set if the connection must be used.
92013498266Sopenharmony_ci */
92113498266Sopenharmony_cistatic bool
92213498266Sopenharmony_ciConnectionExists(struct Curl_easy *data,
92313498266Sopenharmony_ci                 struct connectdata *needle,
92413498266Sopenharmony_ci                 struct connectdata **usethis,
92513498266Sopenharmony_ci                 bool *force_reuse,
92613498266Sopenharmony_ci                 bool *waitpipe)
92713498266Sopenharmony_ci{
92813498266Sopenharmony_ci  struct connectdata *chosen = NULL;
92913498266Sopenharmony_ci  bool foundPendingCandidate = FALSE;
93013498266Sopenharmony_ci  bool canmultiplex = FALSE;
93113498266Sopenharmony_ci  struct connectbundle *bundle;
93213498266Sopenharmony_ci  struct Curl_llist_element *curr;
93313498266Sopenharmony_ci
93413498266Sopenharmony_ci#ifdef USE_NTLM
93513498266Sopenharmony_ci  bool wantNTLMhttp = ((data->state.authhost.want &
93613498266Sopenharmony_ci                        (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
93713498266Sopenharmony_ci                       (needle->handler->protocol & PROTO_FAMILY_HTTP));
93813498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
93913498266Sopenharmony_ci  bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd &&
94013498266Sopenharmony_ci                            ((data->state.authproxy.want &
94113498266Sopenharmony_ci                              (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
94213498266Sopenharmony_ci                             (needle->handler->protocol & PROTO_FAMILY_HTTP)));
94313498266Sopenharmony_ci#else
94413498266Sopenharmony_ci  bool wantProxyNTLMhttp = FALSE;
94513498266Sopenharmony_ci#endif
94613498266Sopenharmony_ci#endif
94713498266Sopenharmony_ci  /* plain HTTP with upgrade */
94813498266Sopenharmony_ci  bool h2upgrade = (data->state.httpwant == CURL_HTTP_VERSION_2_0) &&
94913498266Sopenharmony_ci    (needle->handler->protocol & CURLPROTO_HTTP);
95013498266Sopenharmony_ci
95113498266Sopenharmony_ci  *usethis = NULL;
95213498266Sopenharmony_ci  *force_reuse = FALSE;
95313498266Sopenharmony_ci  *waitpipe = FALSE;
95413498266Sopenharmony_ci
95513498266Sopenharmony_ci  /* Look up the bundle with all the connections to this particular host.
95613498266Sopenharmony_ci     Locks the connection cache, beware of early returns! */
95713498266Sopenharmony_ci  bundle = Curl_conncache_find_bundle(data, needle, data->state.conn_cache);
95813498266Sopenharmony_ci  if(!bundle) {
95913498266Sopenharmony_ci    CONNCACHE_UNLOCK(data);
96013498266Sopenharmony_ci    return FALSE;
96113498266Sopenharmony_ci  }
96213498266Sopenharmony_ci  infof(data, "Found bundle for host: %p [%s]",
96313498266Sopenharmony_ci        (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ?
96413498266Sopenharmony_ci                         "can multiplex" : "serially"));
96513498266Sopenharmony_ci
96613498266Sopenharmony_ci  /* We can only multiplex iff the transfer allows it AND we know
96713498266Sopenharmony_ci   * that the server we want to talk to supports it as well. */
96813498266Sopenharmony_ci  canmultiplex = FALSE;
96913498266Sopenharmony_ci  if(IsMultiplexingPossible(data, needle)) {
97013498266Sopenharmony_ci    if(bundle->multiuse == BUNDLE_UNKNOWN) {
97113498266Sopenharmony_ci      if(data->set.pipewait) {
97213498266Sopenharmony_ci        infof(data, "Server doesn't support multiplex yet, wait");
97313498266Sopenharmony_ci        *waitpipe = TRUE;
97413498266Sopenharmony_ci        CONNCACHE_UNLOCK(data);
97513498266Sopenharmony_ci        return FALSE; /* no reuse */
97613498266Sopenharmony_ci      }
97713498266Sopenharmony_ci      infof(data, "Server doesn't support multiplex (yet)");
97813498266Sopenharmony_ci    }
97913498266Sopenharmony_ci    else if(bundle->multiuse == BUNDLE_MULTIPLEX) {
98013498266Sopenharmony_ci      if(Curl_multiplex_wanted(data->multi))
98113498266Sopenharmony_ci        canmultiplex = TRUE;
98213498266Sopenharmony_ci      else
98313498266Sopenharmony_ci        infof(data, "Could multiplex, but not asked to");
98413498266Sopenharmony_ci    }
98513498266Sopenharmony_ci    else if(bundle->multiuse == BUNDLE_NO_MULTIUSE) {
98613498266Sopenharmony_ci      infof(data, "Can not multiplex, even if we wanted to");
98713498266Sopenharmony_ci    }
98813498266Sopenharmony_ci  }
98913498266Sopenharmony_ci
99013498266Sopenharmony_ci  curr = bundle->conn_list.head;
99113498266Sopenharmony_ci  while(curr) {
99213498266Sopenharmony_ci    struct connectdata *check = curr->ptr;
99313498266Sopenharmony_ci    /* Get next node now. We might remove a dead `check` connection which
99413498266Sopenharmony_ci     * would invalidate `curr` as well. */
99513498266Sopenharmony_ci    curr = curr->next;
99613498266Sopenharmony_ci
99713498266Sopenharmony_ci    /* Note that if we use an HTTP proxy in normal mode (no tunneling), we
99813498266Sopenharmony_ci     * check connections to that proxy and not to the actual remote server.
99913498266Sopenharmony_ci     */
100013498266Sopenharmony_ci    if(check->connect_only || check->bits.close)
100113498266Sopenharmony_ci      /* connect-only or to-be-closed connections will not be reused */
100213498266Sopenharmony_ci      continue;
100313498266Sopenharmony_ci
100413498266Sopenharmony_ci    if(data->set.ipver != CURL_IPRESOLVE_WHATEVER
100513498266Sopenharmony_ci       && data->set.ipver != check->ip_version) {
100613498266Sopenharmony_ci      /* skip because the connection is not via the requested IP version */
100713498266Sopenharmony_ci      continue;
100813498266Sopenharmony_ci    }
100913498266Sopenharmony_ci
101013498266Sopenharmony_ci    if(!canmultiplex) {
101113498266Sopenharmony_ci      if(Curl_resolver_asynch() &&
101213498266Sopenharmony_ci         /* primary_ip[0] is NUL only if the resolving of the name hasn't
101313498266Sopenharmony_ci            completed yet and until then we don't reuse this connection */
101413498266Sopenharmony_ci         !check->primary_ip[0])
101513498266Sopenharmony_ci        continue;
101613498266Sopenharmony_ci    }
101713498266Sopenharmony_ci
101813498266Sopenharmony_ci    if(CONN_INUSE(check)) {
101913498266Sopenharmony_ci      if(!canmultiplex) {
102013498266Sopenharmony_ci        /* transfer can't be multiplexed and check is in use */
102113498266Sopenharmony_ci        continue;
102213498266Sopenharmony_ci      }
102313498266Sopenharmony_ci      else {
102413498266Sopenharmony_ci        /* Could multiplex, but not when check belongs to another multi */
102513498266Sopenharmony_ci        struct Curl_llist_element *e = check->easyq.head;
102613498266Sopenharmony_ci        struct Curl_easy *entry = e->ptr;
102713498266Sopenharmony_ci        if(entry->multi != data->multi)
102813498266Sopenharmony_ci          continue;
102913498266Sopenharmony_ci      }
103013498266Sopenharmony_ci    }
103113498266Sopenharmony_ci
103213498266Sopenharmony_ci    if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
103313498266Sopenharmony_ci      foundPendingCandidate = TRUE;
103413498266Sopenharmony_ci      /* Don't pick a connection that hasn't connected yet */
103513498266Sopenharmony_ci      infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T
103613498266Sopenharmony_ci            " isn't open enough, can't reuse", check->connection_id);
103713498266Sopenharmony_ci      continue;
103813498266Sopenharmony_ci    }
103913498266Sopenharmony_ci
104013498266Sopenharmony_ci    /* `check` is connected. if it is in use and does not support multiplex,
104113498266Sopenharmony_ci     * we cannot use it. */
104213498266Sopenharmony_ci    if(!check->bits.multiplex && CONN_INUSE(check))
104313498266Sopenharmony_ci      continue;
104413498266Sopenharmony_ci
104513498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
104613498266Sopenharmony_ci    if(needle->unix_domain_socket) {
104713498266Sopenharmony_ci      if(!check->unix_domain_socket)
104813498266Sopenharmony_ci        continue;
104913498266Sopenharmony_ci      if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
105013498266Sopenharmony_ci        continue;
105113498266Sopenharmony_ci      if(needle->bits.abstract_unix_socket !=
105213498266Sopenharmony_ci         check->bits.abstract_unix_socket)
105313498266Sopenharmony_ci        continue;
105413498266Sopenharmony_ci    }
105513498266Sopenharmony_ci    else if(check->unix_domain_socket)
105613498266Sopenharmony_ci      continue;
105713498266Sopenharmony_ci#endif
105813498266Sopenharmony_ci
105913498266Sopenharmony_ci    if((needle->handler->flags&PROTOPT_SSL) !=
106013498266Sopenharmony_ci       (check->handler->flags&PROTOPT_SSL))
106113498266Sopenharmony_ci      /* don't do mixed SSL and non-SSL connections */
106213498266Sopenharmony_ci      if(get_protocol_family(check->handler) !=
106313498266Sopenharmony_ci         needle->handler->protocol || !check->bits.tls_upgraded)
106413498266Sopenharmony_ci        /* except protocols that have been upgraded via TLS */
106513498266Sopenharmony_ci        continue;
106613498266Sopenharmony_ci
106713498266Sopenharmony_ci    if(needle->bits.conn_to_host != check->bits.conn_to_host)
106813498266Sopenharmony_ci      /* don't mix connections that use the "connect to host" feature and
106913498266Sopenharmony_ci       * connections that don't use this feature */
107013498266Sopenharmony_ci      continue;
107113498266Sopenharmony_ci
107213498266Sopenharmony_ci    if(needle->bits.conn_to_port != check->bits.conn_to_port)
107313498266Sopenharmony_ci      /* don't mix connections that use the "connect to port" feature and
107413498266Sopenharmony_ci       * connections that don't use this feature */
107513498266Sopenharmony_ci      continue;
107613498266Sopenharmony_ci
107713498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
107813498266Sopenharmony_ci    if(needle->bits.httpproxy != check->bits.httpproxy ||
107913498266Sopenharmony_ci       needle->bits.socksproxy != check->bits.socksproxy)
108013498266Sopenharmony_ci      continue;
108113498266Sopenharmony_ci
108213498266Sopenharmony_ci    if(needle->bits.socksproxy &&
108313498266Sopenharmony_ci      !socks_proxy_info_matches(&needle->socks_proxy,
108413498266Sopenharmony_ci                                &check->socks_proxy))
108513498266Sopenharmony_ci      continue;
108613498266Sopenharmony_ci
108713498266Sopenharmony_ci    if(needle->bits.httpproxy) {
108813498266Sopenharmony_ci      if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy)
108913498266Sopenharmony_ci        continue;
109013498266Sopenharmony_ci
109113498266Sopenharmony_ci      if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy))
109213498266Sopenharmony_ci        continue;
109313498266Sopenharmony_ci
109413498266Sopenharmony_ci      if(IS_HTTPS_PROXY(needle->http_proxy.proxytype)) {
109513498266Sopenharmony_ci        /* https proxies come in different types, http/1.1, h2, ... */
109613498266Sopenharmony_ci        if(needle->http_proxy.proxytype != check->http_proxy.proxytype)
109713498266Sopenharmony_ci          continue;
109813498266Sopenharmony_ci        /* match SSL config to proxy */
109913498266Sopenharmony_ci        if(!Curl_ssl_conn_config_match(data, check, TRUE)) {
110013498266Sopenharmony_ci          DEBUGF(infof(data,
110113498266Sopenharmony_ci            "Connection #%" CURL_FORMAT_CURL_OFF_T
110213498266Sopenharmony_ci            " has different SSL proxy parameters, can't reuse",
110313498266Sopenharmony_ci            check->connection_id));
110413498266Sopenharmony_ci          continue;
110513498266Sopenharmony_ci        }
110613498266Sopenharmony_ci        /* the SSL config to the server, which may apply here is checked
110713498266Sopenharmony_ci         * further below */
110813498266Sopenharmony_ci      }
110913498266Sopenharmony_ci    }
111013498266Sopenharmony_ci#endif
111113498266Sopenharmony_ci
111213498266Sopenharmony_ci    if(h2upgrade && !check->httpversion && canmultiplex) {
111313498266Sopenharmony_ci      if(data->set.pipewait) {
111413498266Sopenharmony_ci        infof(data, "Server upgrade doesn't support multiplex yet, wait");
111513498266Sopenharmony_ci        *waitpipe = TRUE;
111613498266Sopenharmony_ci        CONNCACHE_UNLOCK(data);
111713498266Sopenharmony_ci        return FALSE; /* no reuse */
111813498266Sopenharmony_ci      }
111913498266Sopenharmony_ci      infof(data, "Server upgrade cannot be used");
112013498266Sopenharmony_ci      continue; /* can't be used atm */
112113498266Sopenharmony_ci    }
112213498266Sopenharmony_ci
112313498266Sopenharmony_ci    if(needle->localdev || needle->localport) {
112413498266Sopenharmony_ci      /* If we are bound to a specific local end (IP+port), we must not
112513498266Sopenharmony_ci         reuse a random other one, although if we didn't ask for a
112613498266Sopenharmony_ci         particular one we can reuse one that was bound.
112713498266Sopenharmony_ci
112813498266Sopenharmony_ci         This comparison is a bit rough and too strict. Since the input
112913498266Sopenharmony_ci         parameters can be specified in numerous ways and still end up the
113013498266Sopenharmony_ci         same it would take a lot of processing to make it really accurate.
113113498266Sopenharmony_ci         Instead, this matching will assume that reuses of bound connections
113213498266Sopenharmony_ci         will most likely also reuse the exact same binding parameters and
113313498266Sopenharmony_ci         missing out a few edge cases shouldn't hurt anyone very much.
113413498266Sopenharmony_ci      */
113513498266Sopenharmony_ci      if((check->localport != needle->localport) ||
113613498266Sopenharmony_ci         (check->localportrange != needle->localportrange) ||
113713498266Sopenharmony_ci         (needle->localdev &&
113813498266Sopenharmony_ci          (!check->localdev || strcmp(check->localdev, needle->localdev))))
113913498266Sopenharmony_ci        continue;
114013498266Sopenharmony_ci    }
114113498266Sopenharmony_ci
114213498266Sopenharmony_ci    if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
114313498266Sopenharmony_ci      /* This protocol requires credentials per connection,
114413498266Sopenharmony_ci         so verify that we're using the same name and password as well */
114513498266Sopenharmony_ci      if(Curl_timestrcmp(needle->user, check->user) ||
114613498266Sopenharmony_ci         Curl_timestrcmp(needle->passwd, check->passwd) ||
114713498266Sopenharmony_ci         Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) ||
114813498266Sopenharmony_ci         Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) {
114913498266Sopenharmony_ci        /* one of them was different */
115013498266Sopenharmony_ci        continue;
115113498266Sopenharmony_ci      }
115213498266Sopenharmony_ci    }
115313498266Sopenharmony_ci
115413498266Sopenharmony_ci    /* GSS delegation differences do not actually affect every connection
115513498266Sopenharmony_ci       and auth method, but this check takes precaution before efficiency */
115613498266Sopenharmony_ci    if(needle->gssapi_delegation != check->gssapi_delegation)
115713498266Sopenharmony_ci      continue;
115813498266Sopenharmony_ci
115913498266Sopenharmony_ci    /* If looking for HTTP and the HTTP version  we want is less
116013498266Sopenharmony_ci     * than the HTTP version of the check connection, continue looking */
116113498266Sopenharmony_ci    if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
116213498266Sopenharmony_ci       (((check->httpversion >= 20) &&
116313498266Sopenharmony_ci         (data->state.httpwant < CURL_HTTP_VERSION_2_0))
116413498266Sopenharmony_ci        || ((check->httpversion >= 30) &&
116513498266Sopenharmony_ci            (data->state.httpwant < CURL_HTTP_VERSION_3))))
116613498266Sopenharmony_ci      continue;
116713498266Sopenharmony_ci#ifdef USE_SSH
116813498266Sopenharmony_ci    else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
116913498266Sopenharmony_ci      if(!ssh_config_matches(needle, check))
117013498266Sopenharmony_ci        continue;
117113498266Sopenharmony_ci    }
117213498266Sopenharmony_ci#endif
117313498266Sopenharmony_ci#ifndef CURL_DISABLE_FTP
117413498266Sopenharmony_ci    else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) {
117513498266Sopenharmony_ci      /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */
117613498266Sopenharmony_ci      if(Curl_timestrcmp(needle->proto.ftpc.account,
117713498266Sopenharmony_ci                         check->proto.ftpc.account) ||
117813498266Sopenharmony_ci         Curl_timestrcmp(needle->proto.ftpc.alternative_to_user,
117913498266Sopenharmony_ci                         check->proto.ftpc.alternative_to_user) ||
118013498266Sopenharmony_ci         (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) ||
118113498266Sopenharmony_ci         (needle->proto.ftpc.ccc != check->proto.ftpc.ccc))
118213498266Sopenharmony_ci        continue;
118313498266Sopenharmony_ci    }
118413498266Sopenharmony_ci#endif
118513498266Sopenharmony_ci
118613498266Sopenharmony_ci    /* Additional match requirements if talking TLS OR
118713498266Sopenharmony_ci     * not talking to a HTTP proxy OR using a tunnel through a proxy */
118813498266Sopenharmony_ci    if((needle->handler->flags&PROTOPT_SSL)
118913498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
119013498266Sopenharmony_ci       || !needle->bits.httpproxy || needle->bits.tunnel_proxy
119113498266Sopenharmony_ci#endif
119213498266Sopenharmony_ci      ) {
119313498266Sopenharmony_ci      /* Talking the same protocol scheme or a TLS upgraded protocol in the
119413498266Sopenharmony_ci       * same protocol family? */
119513498266Sopenharmony_ci      if(!strcasecompare(needle->handler->scheme, check->handler->scheme) &&
119613498266Sopenharmony_ci         (get_protocol_family(check->handler) !=
119713498266Sopenharmony_ci          needle->handler->protocol || !check->bits.tls_upgraded))
119813498266Sopenharmony_ci        continue;
119913498266Sopenharmony_ci
120013498266Sopenharmony_ci      /* If needle has "conn_to_*" set, check must match this */
120113498266Sopenharmony_ci      if((needle->bits.conn_to_host && !strcasecompare(
120213498266Sopenharmony_ci          needle->conn_to_host.name, check->conn_to_host.name)) ||
120313498266Sopenharmony_ci         (needle->bits.conn_to_port &&
120413498266Sopenharmony_ci           needle->conn_to_port != check->conn_to_port))
120513498266Sopenharmony_ci        continue;
120613498266Sopenharmony_ci
120713498266Sopenharmony_ci      /* hostname and port must match */
120813498266Sopenharmony_ci      if(!strcasecompare(needle->host.name, check->host.name) ||
120913498266Sopenharmony_ci         needle->remote_port != check->remote_port)
121013498266Sopenharmony_ci        continue;
121113498266Sopenharmony_ci
121213498266Sopenharmony_ci      /* If talking TLS, check needs to use the same SSL options. */
121313498266Sopenharmony_ci      if((needle->handler->flags & PROTOPT_SSL) &&
121413498266Sopenharmony_ci         !Curl_ssl_conn_config_match(data, check, FALSE)) {
121513498266Sopenharmony_ci        DEBUGF(infof(data,
121613498266Sopenharmony_ci                     "Connection #%" CURL_FORMAT_CURL_OFF_T
121713498266Sopenharmony_ci                     " has different SSL parameters, can't reuse",
121813498266Sopenharmony_ci                     check->connection_id));
121913498266Sopenharmony_ci        continue;
122013498266Sopenharmony_ci      }
122113498266Sopenharmony_ci    }
122213498266Sopenharmony_ci
122313498266Sopenharmony_ci#if defined(USE_NTLM)
122413498266Sopenharmony_ci    /* If we are looking for an HTTP+NTLM connection, check if this is
122513498266Sopenharmony_ci       already authenticating with the right credentials. If not, keep
122613498266Sopenharmony_ci       looking so that we can reuse NTLM connections if
122713498266Sopenharmony_ci       possible. (Especially we must not reuse the same connection if
122813498266Sopenharmony_ci       partway through a handshake!) */
122913498266Sopenharmony_ci    if(wantNTLMhttp) {
123013498266Sopenharmony_ci      if(Curl_timestrcmp(needle->user, check->user) ||
123113498266Sopenharmony_ci         Curl_timestrcmp(needle->passwd, check->passwd)) {
123213498266Sopenharmony_ci
123313498266Sopenharmony_ci        /* we prefer a credential match, but this is at least a connection
123413498266Sopenharmony_ci           that can be reused and "upgraded" to NTLM */
123513498266Sopenharmony_ci        if(check->http_ntlm_state == NTLMSTATE_NONE)
123613498266Sopenharmony_ci          chosen = check;
123713498266Sopenharmony_ci        continue;
123813498266Sopenharmony_ci      }
123913498266Sopenharmony_ci    }
124013498266Sopenharmony_ci    else if(check->http_ntlm_state != NTLMSTATE_NONE) {
124113498266Sopenharmony_ci      /* Connection is using NTLM auth but we don't want NTLM */
124213498266Sopenharmony_ci      continue;
124313498266Sopenharmony_ci    }
124413498266Sopenharmony_ci
124513498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
124613498266Sopenharmony_ci    /* Same for Proxy NTLM authentication */
124713498266Sopenharmony_ci    if(wantProxyNTLMhttp) {
124813498266Sopenharmony_ci      /* Both check->http_proxy.user and check->http_proxy.passwd can be
124913498266Sopenharmony_ci       * NULL */
125013498266Sopenharmony_ci      if(!check->http_proxy.user || !check->http_proxy.passwd)
125113498266Sopenharmony_ci        continue;
125213498266Sopenharmony_ci
125313498266Sopenharmony_ci      if(Curl_timestrcmp(needle->http_proxy.user,
125413498266Sopenharmony_ci                         check->http_proxy.user) ||
125513498266Sopenharmony_ci         Curl_timestrcmp(needle->http_proxy.passwd,
125613498266Sopenharmony_ci                         check->http_proxy.passwd))
125713498266Sopenharmony_ci        continue;
125813498266Sopenharmony_ci    }
125913498266Sopenharmony_ci    else if(check->proxy_ntlm_state != NTLMSTATE_NONE) {
126013498266Sopenharmony_ci      /* Proxy connection is using NTLM auth but we don't want NTLM */
126113498266Sopenharmony_ci      continue;
126213498266Sopenharmony_ci    }
126313498266Sopenharmony_ci#endif
126413498266Sopenharmony_ci    if(wantNTLMhttp || wantProxyNTLMhttp) {
126513498266Sopenharmony_ci      /* Credentials are already checked, we may use this connection.
126613498266Sopenharmony_ci       * With NTLM being weird as it is, we MUST use a
126713498266Sopenharmony_ci       * connection where it has already been fully negotiated.
126813498266Sopenharmony_ci       * If it has not, we keep on looking for a better one. */
126913498266Sopenharmony_ci      chosen = check;
127013498266Sopenharmony_ci
127113498266Sopenharmony_ci      if((wantNTLMhttp &&
127213498266Sopenharmony_ci         (check->http_ntlm_state != NTLMSTATE_NONE)) ||
127313498266Sopenharmony_ci          (wantProxyNTLMhttp &&
127413498266Sopenharmony_ci           (check->proxy_ntlm_state != NTLMSTATE_NONE))) {
127513498266Sopenharmony_ci        /* We must use this connection, no other */
127613498266Sopenharmony_ci        *force_reuse = TRUE;
127713498266Sopenharmony_ci        break;
127813498266Sopenharmony_ci      }
127913498266Sopenharmony_ci      /* Continue look up for a better connection */
128013498266Sopenharmony_ci      continue;
128113498266Sopenharmony_ci    }
128213498266Sopenharmony_ci#endif
128313498266Sopenharmony_ci
128413498266Sopenharmony_ci    if(CONN_INUSE(check)) {
128513498266Sopenharmony_ci      DEBUGASSERT(canmultiplex);
128613498266Sopenharmony_ci      DEBUGASSERT(check->bits.multiplex);
128713498266Sopenharmony_ci      /* If multiplexed, make sure we don't go over concurrency limit */
128813498266Sopenharmony_ci      if(CONN_INUSE(check) >=
128913498266Sopenharmony_ci              Curl_multi_max_concurrent_streams(data->multi)) {
129013498266Sopenharmony_ci        infof(data, "client side MAX_CONCURRENT_STREAMS reached"
129113498266Sopenharmony_ci              ", skip (%zu)", CONN_INUSE(check));
129213498266Sopenharmony_ci        continue;
129313498266Sopenharmony_ci      }
129413498266Sopenharmony_ci      if(CONN_INUSE(check) >=
129513498266Sopenharmony_ci              Curl_conn_get_max_concurrent(data, check, FIRSTSOCKET)) {
129613498266Sopenharmony_ci        infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
129713498266Sopenharmony_ci              CONN_INUSE(check));
129813498266Sopenharmony_ci        continue;
129913498266Sopenharmony_ci      }
130013498266Sopenharmony_ci      /* When not multiplexed, we have a match here! */
130113498266Sopenharmony_ci      infof(data, "Multiplexed connection found");
130213498266Sopenharmony_ci    }
130313498266Sopenharmony_ci    else if(extract_if_dead(check, data)) {
130413498266Sopenharmony_ci      /* disconnect it */
130513498266Sopenharmony_ci      Curl_disconnect(data, check, TRUE);
130613498266Sopenharmony_ci      continue;
130713498266Sopenharmony_ci    }
130813498266Sopenharmony_ci
130913498266Sopenharmony_ci    /* We have found a connection. Let's stop searching. */
131013498266Sopenharmony_ci    chosen = check;
131113498266Sopenharmony_ci    break;
131213498266Sopenharmony_ci  } /* loop over connection bundle */
131313498266Sopenharmony_ci
131413498266Sopenharmony_ci  if(chosen) {
131513498266Sopenharmony_ci    /* mark it as used before releasing the lock */
131613498266Sopenharmony_ci    Curl_attach_connection(data, chosen);
131713498266Sopenharmony_ci    CONNCACHE_UNLOCK(data);
131813498266Sopenharmony_ci    *usethis = chosen;
131913498266Sopenharmony_ci    return TRUE; /* yes, we found one to use! */
132013498266Sopenharmony_ci  }
132113498266Sopenharmony_ci  CONNCACHE_UNLOCK(data);
132213498266Sopenharmony_ci
132313498266Sopenharmony_ci  if(foundPendingCandidate && data->set.pipewait) {
132413498266Sopenharmony_ci    infof(data,
132513498266Sopenharmony_ci          "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
132613498266Sopenharmony_ci    *waitpipe = TRUE;
132713498266Sopenharmony_ci  }
132813498266Sopenharmony_ci
132913498266Sopenharmony_ci  return FALSE; /* no matching connecting exists */
133013498266Sopenharmony_ci}
133113498266Sopenharmony_ci
133213498266Sopenharmony_ci/*
133313498266Sopenharmony_ci * verboseconnect() displays verbose information after a connect
133413498266Sopenharmony_ci */
133513498266Sopenharmony_ci#ifndef CURL_DISABLE_VERBOSE_STRINGS
133613498266Sopenharmony_civoid Curl_verboseconnect(struct Curl_easy *data,
133713498266Sopenharmony_ci                         struct connectdata *conn)
133813498266Sopenharmony_ci{
133913498266Sopenharmony_ci  if(data->set.verbose)
134013498266Sopenharmony_ci    infof(data, "Connected to %s (%s) port %u",
134113498266Sopenharmony_ci          CURL_CONN_HOST_DISPNAME(conn), conn->primary_ip, conn->port);
134213498266Sopenharmony_ci}
134313498266Sopenharmony_ci#endif
134413498266Sopenharmony_ci
134513498266Sopenharmony_ci/*
134613498266Sopenharmony_ci * Allocate and initialize a new connectdata object.
134713498266Sopenharmony_ci */
134813498266Sopenharmony_cistatic struct connectdata *allocate_conn(struct Curl_easy *data)
134913498266Sopenharmony_ci{
135013498266Sopenharmony_ci  struct connectdata *conn = calloc(1, sizeof(struct connectdata));
135113498266Sopenharmony_ci  if(!conn)
135213498266Sopenharmony_ci    return NULL;
135313498266Sopenharmony_ci
135413498266Sopenharmony_ci  /* and we setup a few fields in case we end up actually using this struct */
135513498266Sopenharmony_ci
135613498266Sopenharmony_ci  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
135713498266Sopenharmony_ci  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
135813498266Sopenharmony_ci  conn->sockfd = CURL_SOCKET_BAD;
135913498266Sopenharmony_ci  conn->writesockfd = CURL_SOCKET_BAD;
136013498266Sopenharmony_ci  conn->connection_id = -1;    /* no ID */
136113498266Sopenharmony_ci  conn->port = -1; /* unknown at this point */
136213498266Sopenharmony_ci  conn->remote_port = -1; /* unknown at this point */
136313498266Sopenharmony_ci
136413498266Sopenharmony_ci  /* Default protocol-independent behavior doesn't support persistent
136513498266Sopenharmony_ci     connections, so we set this to force-close. Protocols that support
136613498266Sopenharmony_ci     this need to set this to FALSE in their "curl_do" functions. */
136713498266Sopenharmony_ci  connclose(conn, "Default to force-close");
136813498266Sopenharmony_ci
136913498266Sopenharmony_ci  /* Store creation time to help future close decision making */
137013498266Sopenharmony_ci  conn->created = Curl_now();
137113498266Sopenharmony_ci
137213498266Sopenharmony_ci  /* Store current time to give a baseline to keepalive connection times. */
137313498266Sopenharmony_ci  conn->keepalive = conn->created;
137413498266Sopenharmony_ci
137513498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
137613498266Sopenharmony_ci  conn->http_proxy.proxytype = data->set.proxytype;
137713498266Sopenharmony_ci  conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
137813498266Sopenharmony_ci
137913498266Sopenharmony_ci  /* note that these two proxy bits are now just on what looks to be
138013498266Sopenharmony_ci     requested, they may be altered down the road */
138113498266Sopenharmony_ci  conn->bits.proxy = (data->set.str[STRING_PROXY] &&
138213498266Sopenharmony_ci                      *data->set.str[STRING_PROXY]) ? TRUE : FALSE;
138313498266Sopenharmony_ci  conn->bits.httpproxy = (conn->bits.proxy &&
138413498266Sopenharmony_ci                          (conn->http_proxy.proxytype == CURLPROXY_HTTP ||
138513498266Sopenharmony_ci                           conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
138613498266Sopenharmony_ci                           IS_HTTPS_PROXY(conn->http_proxy.proxytype))) ?
138713498266Sopenharmony_ci    TRUE : FALSE;
138813498266Sopenharmony_ci  conn->bits.socksproxy = (conn->bits.proxy &&
138913498266Sopenharmony_ci                           !conn->bits.httpproxy) ? TRUE : FALSE;
139013498266Sopenharmony_ci
139113498266Sopenharmony_ci  if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
139213498266Sopenharmony_ci    conn->bits.proxy = TRUE;
139313498266Sopenharmony_ci    conn->bits.socksproxy = TRUE;
139413498266Sopenharmony_ci  }
139513498266Sopenharmony_ci
139613498266Sopenharmony_ci  conn->bits.proxy_user_passwd =
139713498266Sopenharmony_ci    (data->state.aptr.proxyuser) ? TRUE : FALSE;
139813498266Sopenharmony_ci  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
139913498266Sopenharmony_ci#endif /* CURL_DISABLE_PROXY */
140013498266Sopenharmony_ci
140113498266Sopenharmony_ci#ifndef CURL_DISABLE_FTP
140213498266Sopenharmony_ci  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
140313498266Sopenharmony_ci  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
140413498266Sopenharmony_ci#endif
140513498266Sopenharmony_ci  conn->ip_version = data->set.ipver;
140613498266Sopenharmony_ci  conn->connect_only = data->set.connect_only;
140713498266Sopenharmony_ci  conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
140813498266Sopenharmony_ci
140913498266Sopenharmony_ci#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
141013498266Sopenharmony_ci    defined(NTLM_WB_ENABLED)
141113498266Sopenharmony_ci  conn->ntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
141213498266Sopenharmony_ci  conn->proxyntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
141313498266Sopenharmony_ci#endif
141413498266Sopenharmony_ci
141513498266Sopenharmony_ci  /* Initialize the easy handle list */
141613498266Sopenharmony_ci  Curl_llist_init(&conn->easyq, NULL);
141713498266Sopenharmony_ci
141813498266Sopenharmony_ci#ifdef HAVE_GSSAPI
141913498266Sopenharmony_ci  conn->data_prot = PROT_CLEAR;
142013498266Sopenharmony_ci#endif
142113498266Sopenharmony_ci
142213498266Sopenharmony_ci  /* Store the local bind parameters that will be used for this connection */
142313498266Sopenharmony_ci  if(data->set.str[STRING_DEVICE]) {
142413498266Sopenharmony_ci    conn->localdev = strdup(data->set.str[STRING_DEVICE]);
142513498266Sopenharmony_ci    if(!conn->localdev)
142613498266Sopenharmony_ci      goto error;
142713498266Sopenharmony_ci  }
142813498266Sopenharmony_ci#ifndef CURL_DISABLE_BINDLOCAL
142913498266Sopenharmony_ci  conn->localportrange = data->set.localportrange;
143013498266Sopenharmony_ci  conn->localport = data->set.localport;
143113498266Sopenharmony_ci#endif
143213498266Sopenharmony_ci
143313498266Sopenharmony_ci  /* the close socket stuff needs to be copied to the connection struct as
143413498266Sopenharmony_ci     it may live on without (this specific) Curl_easy */
143513498266Sopenharmony_ci  conn->fclosesocket = data->set.fclosesocket;
143613498266Sopenharmony_ci  conn->closesocket_client = data->set.closesocket_client;
143713498266Sopenharmony_ci  conn->lastused = conn->created;
143813498266Sopenharmony_ci  conn->gssapi_delegation = data->set.gssapi_delegation;
143913498266Sopenharmony_ci
144013498266Sopenharmony_ci  return conn;
144113498266Sopenharmony_cierror:
144213498266Sopenharmony_ci
144313498266Sopenharmony_ci  free(conn->localdev);
144413498266Sopenharmony_ci  free(conn);
144513498266Sopenharmony_ci  return NULL;
144613498266Sopenharmony_ci}
144713498266Sopenharmony_ci
144813498266Sopenharmony_ciconst struct Curl_handler *Curl_get_scheme_handler(const char *scheme)
144913498266Sopenharmony_ci{
145013498266Sopenharmony_ci  return Curl_getn_scheme_handler(scheme, strlen(scheme));
145113498266Sopenharmony_ci}
145213498266Sopenharmony_ci
145313498266Sopenharmony_ci/* returns the handler if the given scheme is built-in */
145413498266Sopenharmony_ciconst struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
145513498266Sopenharmony_ci                                                    size_t len)
145613498266Sopenharmony_ci{
145713498266Sopenharmony_ci  /* table generated by schemetable.c:
145813498266Sopenharmony_ci     1. gcc schemetable.c && ./a.out
145913498266Sopenharmony_ci     2. check how small the table gets
146013498266Sopenharmony_ci     3. tweak the hash algorithm, then rerun from 1
146113498266Sopenharmony_ci     4. when the table is good enough
146213498266Sopenharmony_ci     5. copy the table into this source code
146313498266Sopenharmony_ci     6. make sure this function uses the same hash function that worked for
146413498266Sopenharmony_ci     schemetable.c
146513498266Sopenharmony_ci     7. if needed, adjust the #ifdefs in schemetable.c and rerun
146613498266Sopenharmony_ci     */
146713498266Sopenharmony_ci  static const struct Curl_handler * const protocols[67] = {
146813498266Sopenharmony_ci#ifndef CURL_DISABLE_FILE
146913498266Sopenharmony_ci    &Curl_handler_file,
147013498266Sopenharmony_ci#else
147113498266Sopenharmony_ci    NULL,
147213498266Sopenharmony_ci#endif
147313498266Sopenharmony_ci    NULL, NULL,
147413498266Sopenharmony_ci#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)
147513498266Sopenharmony_ci    &Curl_handler_gophers,
147613498266Sopenharmony_ci#else
147713498266Sopenharmony_ci    NULL,
147813498266Sopenharmony_ci#endif
147913498266Sopenharmony_ci    NULL,
148013498266Sopenharmony_ci#ifdef USE_LIBRTMP
148113498266Sopenharmony_ci    &Curl_handler_rtmpe,
148213498266Sopenharmony_ci#else
148313498266Sopenharmony_ci    NULL,
148413498266Sopenharmony_ci#endif
148513498266Sopenharmony_ci#ifndef CURL_DISABLE_SMTP
148613498266Sopenharmony_ci    &Curl_handler_smtp,
148713498266Sopenharmony_ci#else
148813498266Sopenharmony_ci    NULL,
148913498266Sopenharmony_ci#endif
149013498266Sopenharmony_ci#if defined(USE_SSH)
149113498266Sopenharmony_ci    &Curl_handler_sftp,
149213498266Sopenharmony_ci#else
149313498266Sopenharmony_ci    NULL,
149413498266Sopenharmony_ci#endif
149513498266Sopenharmony_ci#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
149613498266Sopenharmony_ci  (SIZEOF_CURL_OFF_T > 4)
149713498266Sopenharmony_ci    &Curl_handler_smb,
149813498266Sopenharmony_ci#else
149913498266Sopenharmony_ci    NULL,
150013498266Sopenharmony_ci#endif
150113498266Sopenharmony_ci#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
150213498266Sopenharmony_ci    &Curl_handler_smtps,
150313498266Sopenharmony_ci#else
150413498266Sopenharmony_ci    NULL,
150513498266Sopenharmony_ci#endif
150613498266Sopenharmony_ci#ifndef CURL_DISABLE_TELNET
150713498266Sopenharmony_ci    &Curl_handler_telnet,
150813498266Sopenharmony_ci#else
150913498266Sopenharmony_ci    NULL,
151013498266Sopenharmony_ci#endif
151113498266Sopenharmony_ci#ifndef CURL_DISABLE_GOPHER
151213498266Sopenharmony_ci    &Curl_handler_gopher,
151313498266Sopenharmony_ci#else
151413498266Sopenharmony_ci    NULL,
151513498266Sopenharmony_ci#endif
151613498266Sopenharmony_ci#ifndef CURL_DISABLE_TFTP
151713498266Sopenharmony_ci    &Curl_handler_tftp,
151813498266Sopenharmony_ci#else
151913498266Sopenharmony_ci    NULL,
152013498266Sopenharmony_ci#endif
152113498266Sopenharmony_ci    NULL, NULL, NULL,
152213498266Sopenharmony_ci#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
152313498266Sopenharmony_ci    &Curl_handler_ftps,
152413498266Sopenharmony_ci#else
152513498266Sopenharmony_ci    NULL,
152613498266Sopenharmony_ci#endif
152713498266Sopenharmony_ci#ifndef CURL_DISABLE_HTTP
152813498266Sopenharmony_ci    &Curl_handler_http,
152913498266Sopenharmony_ci#else
153013498266Sopenharmony_ci    NULL,
153113498266Sopenharmony_ci#endif
153213498266Sopenharmony_ci#ifndef CURL_DISABLE_IMAP
153313498266Sopenharmony_ci    &Curl_handler_imap,
153413498266Sopenharmony_ci#else
153513498266Sopenharmony_ci    NULL,
153613498266Sopenharmony_ci#endif
153713498266Sopenharmony_ci#ifdef USE_LIBRTMP
153813498266Sopenharmony_ci    &Curl_handler_rtmps,
153913498266Sopenharmony_ci#else
154013498266Sopenharmony_ci    NULL,
154113498266Sopenharmony_ci#endif
154213498266Sopenharmony_ci#ifdef USE_LIBRTMP
154313498266Sopenharmony_ci    &Curl_handler_rtmpt,
154413498266Sopenharmony_ci#else
154513498266Sopenharmony_ci    NULL,
154613498266Sopenharmony_ci#endif
154713498266Sopenharmony_ci    NULL, NULL, NULL,
154813498266Sopenharmony_ci#if !defined(CURL_DISABLE_LDAP) && \
154913498266Sopenharmony_ci  !defined(CURL_DISABLE_LDAPS) && \
155013498266Sopenharmony_ci  ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
155113498266Sopenharmony_ci   (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
155213498266Sopenharmony_ci    &Curl_handler_ldaps,
155313498266Sopenharmony_ci#else
155413498266Sopenharmony_ci    NULL,
155513498266Sopenharmony_ci#endif
155613498266Sopenharmony_ci#if defined(USE_WEBSOCKETS) && \
155713498266Sopenharmony_ci  defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
155813498266Sopenharmony_ci    &Curl_handler_wss,
155913498266Sopenharmony_ci#else
156013498266Sopenharmony_ci    NULL,
156113498266Sopenharmony_ci#endif
156213498266Sopenharmony_ci#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
156313498266Sopenharmony_ci    &Curl_handler_https,
156413498266Sopenharmony_ci#else
156513498266Sopenharmony_ci    NULL,
156613498266Sopenharmony_ci#endif
156713498266Sopenharmony_ci    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
156813498266Sopenharmony_ci#ifndef CURL_DISABLE_RTSP
156913498266Sopenharmony_ci    &Curl_handler_rtsp,
157013498266Sopenharmony_ci#else
157113498266Sopenharmony_ci    NULL,
157213498266Sopenharmony_ci#endif
157313498266Sopenharmony_ci#if defined(USE_SSL) && !defined(CURL_DISABLE_SMB) && \
157413498266Sopenharmony_ci  defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)
157513498266Sopenharmony_ci    &Curl_handler_smbs,
157613498266Sopenharmony_ci#else
157713498266Sopenharmony_ci    NULL,
157813498266Sopenharmony_ci#endif
157913498266Sopenharmony_ci#if defined(USE_SSH) && !defined(USE_WOLFSSH)
158013498266Sopenharmony_ci    &Curl_handler_scp,
158113498266Sopenharmony_ci#else
158213498266Sopenharmony_ci    NULL,
158313498266Sopenharmony_ci#endif
158413498266Sopenharmony_ci    NULL, NULL, NULL,
158513498266Sopenharmony_ci#ifndef CURL_DISABLE_POP3
158613498266Sopenharmony_ci    &Curl_handler_pop3,
158713498266Sopenharmony_ci#else
158813498266Sopenharmony_ci    NULL,
158913498266Sopenharmony_ci#endif
159013498266Sopenharmony_ci    NULL, NULL,
159113498266Sopenharmony_ci#ifdef USE_LIBRTMP
159213498266Sopenharmony_ci    &Curl_handler_rtmp,
159313498266Sopenharmony_ci#else
159413498266Sopenharmony_ci    NULL,
159513498266Sopenharmony_ci#endif
159613498266Sopenharmony_ci    NULL, NULL, NULL,
159713498266Sopenharmony_ci#ifdef USE_LIBRTMP
159813498266Sopenharmony_ci    &Curl_handler_rtmpte,
159913498266Sopenharmony_ci#else
160013498266Sopenharmony_ci    NULL,
160113498266Sopenharmony_ci#endif
160213498266Sopenharmony_ci    NULL, NULL, NULL,
160313498266Sopenharmony_ci#ifndef CURL_DISABLE_DICT
160413498266Sopenharmony_ci    &Curl_handler_dict,
160513498266Sopenharmony_ci#else
160613498266Sopenharmony_ci    NULL,
160713498266Sopenharmony_ci#endif
160813498266Sopenharmony_ci    NULL, NULL, NULL,
160913498266Sopenharmony_ci#ifndef CURL_DISABLE_MQTT
161013498266Sopenharmony_ci    &Curl_handler_mqtt,
161113498266Sopenharmony_ci#else
161213498266Sopenharmony_ci    NULL,
161313498266Sopenharmony_ci#endif
161413498266Sopenharmony_ci#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
161513498266Sopenharmony_ci    &Curl_handler_pop3s,
161613498266Sopenharmony_ci#else
161713498266Sopenharmony_ci    NULL,
161813498266Sopenharmony_ci#endif
161913498266Sopenharmony_ci#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
162013498266Sopenharmony_ci    &Curl_handler_imaps,
162113498266Sopenharmony_ci#else
162213498266Sopenharmony_ci    NULL,
162313498266Sopenharmony_ci#endif
162413498266Sopenharmony_ci    NULL,
162513498266Sopenharmony_ci#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
162613498266Sopenharmony_ci    &Curl_handler_ws,
162713498266Sopenharmony_ci#else
162813498266Sopenharmony_ci    NULL,
162913498266Sopenharmony_ci#endif
163013498266Sopenharmony_ci    NULL,
163113498266Sopenharmony_ci#ifdef USE_LIBRTMP
163213498266Sopenharmony_ci    &Curl_handler_rtmpts,
163313498266Sopenharmony_ci#else
163413498266Sopenharmony_ci    NULL,
163513498266Sopenharmony_ci#endif
163613498266Sopenharmony_ci#ifndef CURL_DISABLE_LDAP
163713498266Sopenharmony_ci    &Curl_handler_ldap,
163813498266Sopenharmony_ci#else
163913498266Sopenharmony_ci    NULL,
164013498266Sopenharmony_ci#endif
164113498266Sopenharmony_ci    NULL, NULL,
164213498266Sopenharmony_ci#ifndef CURL_DISABLE_FTP
164313498266Sopenharmony_ci    &Curl_handler_ftp,
164413498266Sopenharmony_ci#else
164513498266Sopenharmony_ci    NULL,
164613498266Sopenharmony_ci#endif
164713498266Sopenharmony_ci  };
164813498266Sopenharmony_ci
164913498266Sopenharmony_ci  if(len && (len <= 7)) {
165013498266Sopenharmony_ci    const char *s = scheme;
165113498266Sopenharmony_ci    size_t l = len;
165213498266Sopenharmony_ci    const struct Curl_handler *h;
165313498266Sopenharmony_ci    unsigned int c = 978;
165413498266Sopenharmony_ci    while(l) {
165513498266Sopenharmony_ci      c <<= 5;
165613498266Sopenharmony_ci      c += Curl_raw_tolower(*s);
165713498266Sopenharmony_ci      s++;
165813498266Sopenharmony_ci      l--;
165913498266Sopenharmony_ci    }
166013498266Sopenharmony_ci
166113498266Sopenharmony_ci    h = protocols[c % 67];
166213498266Sopenharmony_ci    if(h && strncasecompare(scheme, h->scheme, len) && !h->scheme[len])
166313498266Sopenharmony_ci      return h;
166413498266Sopenharmony_ci  }
166513498266Sopenharmony_ci  return NULL;
166613498266Sopenharmony_ci}
166713498266Sopenharmony_ci
166813498266Sopenharmony_cistatic CURLcode findprotocol(struct Curl_easy *data,
166913498266Sopenharmony_ci                             struct connectdata *conn,
167013498266Sopenharmony_ci                             const char *protostr)
167113498266Sopenharmony_ci{
167213498266Sopenharmony_ci  const struct Curl_handler *p = Curl_get_scheme_handler(protostr);
167313498266Sopenharmony_ci
167413498266Sopenharmony_ci  if(p && /* Protocol found in table. Check if allowed */
167513498266Sopenharmony_ci     (data->set.allowed_protocols & p->protocol)) {
167613498266Sopenharmony_ci
167713498266Sopenharmony_ci    /* it is allowed for "normal" request, now do an extra check if this is
167813498266Sopenharmony_ci       the result of a redirect */
167913498266Sopenharmony_ci    if(data->state.this_is_a_follow &&
168013498266Sopenharmony_ci       !(data->set.redir_protocols & p->protocol))
168113498266Sopenharmony_ci      /* nope, get out */
168213498266Sopenharmony_ci      ;
168313498266Sopenharmony_ci    else {
168413498266Sopenharmony_ci      /* Perform setup complement if some. */
168513498266Sopenharmony_ci      conn->handler = conn->given = p;
168613498266Sopenharmony_ci      /* 'port' and 'remote_port' are set in setup_connection_internals() */
168713498266Sopenharmony_ci      return CURLE_OK;
168813498266Sopenharmony_ci    }
168913498266Sopenharmony_ci  }
169013498266Sopenharmony_ci
169113498266Sopenharmony_ci  /* The protocol was not found in the table, but we don't have to assign it
169213498266Sopenharmony_ci     to anything since it is already assigned to a dummy-struct in the
169313498266Sopenharmony_ci     create_conn() function when the connectdata struct is allocated. */
169413498266Sopenharmony_ci  failf(data, "Protocol \"%s\" %s%s", protostr,
169513498266Sopenharmony_ci        p ? "disabled" : "not supported",
169613498266Sopenharmony_ci        data->state.this_is_a_follow ? " (in redirect)":"");
169713498266Sopenharmony_ci
169813498266Sopenharmony_ci  return CURLE_UNSUPPORTED_PROTOCOL;
169913498266Sopenharmony_ci}
170013498266Sopenharmony_ci
170113498266Sopenharmony_ci
170213498266Sopenharmony_ciCURLcode Curl_uc_to_curlcode(CURLUcode uc)
170313498266Sopenharmony_ci{
170413498266Sopenharmony_ci  switch(uc) {
170513498266Sopenharmony_ci  default:
170613498266Sopenharmony_ci    return CURLE_URL_MALFORMAT;
170713498266Sopenharmony_ci  case CURLUE_UNSUPPORTED_SCHEME:
170813498266Sopenharmony_ci    return CURLE_UNSUPPORTED_PROTOCOL;
170913498266Sopenharmony_ci  case CURLUE_OUT_OF_MEMORY:
171013498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
171113498266Sopenharmony_ci  case CURLUE_USER_NOT_ALLOWED:
171213498266Sopenharmony_ci    return CURLE_LOGIN_DENIED;
171313498266Sopenharmony_ci  }
171413498266Sopenharmony_ci}
171513498266Sopenharmony_ci
171613498266Sopenharmony_ci#ifdef ENABLE_IPV6
171713498266Sopenharmony_ci/*
171813498266Sopenharmony_ci * If the URL was set with an IPv6 numerical address with a zone id part, set
171913498266Sopenharmony_ci * the scope_id based on that!
172013498266Sopenharmony_ci */
172113498266Sopenharmony_ci
172213498266Sopenharmony_cistatic void zonefrom_url(CURLU *uh, struct Curl_easy *data,
172313498266Sopenharmony_ci                         struct connectdata *conn)
172413498266Sopenharmony_ci{
172513498266Sopenharmony_ci  char *zoneid;
172613498266Sopenharmony_ci  CURLUcode uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
172713498266Sopenharmony_ci#ifdef CURL_DISABLE_VERBOSE_STRINGS
172813498266Sopenharmony_ci  (void)data;
172913498266Sopenharmony_ci#endif
173013498266Sopenharmony_ci
173113498266Sopenharmony_ci  if(!uc && zoneid) {
173213498266Sopenharmony_ci    char *endp;
173313498266Sopenharmony_ci    unsigned long scope = strtoul(zoneid, &endp, 10);
173413498266Sopenharmony_ci    if(!*endp && (scope < UINT_MAX))
173513498266Sopenharmony_ci      /* A plain number, use it directly as a scope id. */
173613498266Sopenharmony_ci      conn->scope_id = (unsigned int)scope;
173713498266Sopenharmony_ci#if defined(HAVE_IF_NAMETOINDEX)
173813498266Sopenharmony_ci    else {
173913498266Sopenharmony_ci#elif defined(_WIN32)
174013498266Sopenharmony_ci    else if(Curl_if_nametoindex) {
174113498266Sopenharmony_ci#endif
174213498266Sopenharmony_ci
174313498266Sopenharmony_ci#if defined(HAVE_IF_NAMETOINDEX) || defined(_WIN32)
174413498266Sopenharmony_ci      /* Zone identifier is not numeric */
174513498266Sopenharmony_ci      unsigned int scopeidx = 0;
174613498266Sopenharmony_ci#if defined(_WIN32)
174713498266Sopenharmony_ci      scopeidx = Curl_if_nametoindex(zoneid);
174813498266Sopenharmony_ci#else
174913498266Sopenharmony_ci      scopeidx = if_nametoindex(zoneid);
175013498266Sopenharmony_ci#endif
175113498266Sopenharmony_ci      if(!scopeidx) {
175213498266Sopenharmony_ci#ifndef CURL_DISABLE_VERBOSE_STRINGS
175313498266Sopenharmony_ci        char buffer[STRERROR_LEN];
175413498266Sopenharmony_ci        infof(data, "Invalid zoneid: %s; %s", zoneid,
175513498266Sopenharmony_ci              Curl_strerror(errno, buffer, sizeof(buffer)));
175613498266Sopenharmony_ci#endif
175713498266Sopenharmony_ci      }
175813498266Sopenharmony_ci      else
175913498266Sopenharmony_ci        conn->scope_id = scopeidx;
176013498266Sopenharmony_ci    }
176113498266Sopenharmony_ci#endif /* HAVE_IF_NAMETOINDEX || _WIN32 */
176213498266Sopenharmony_ci
176313498266Sopenharmony_ci    free(zoneid);
176413498266Sopenharmony_ci  }
176513498266Sopenharmony_ci}
176613498266Sopenharmony_ci#else
176713498266Sopenharmony_ci#define zonefrom_url(a,b,c) Curl_nop_stmt
176813498266Sopenharmony_ci#endif
176913498266Sopenharmony_ci
177013498266Sopenharmony_ci/*
177113498266Sopenharmony_ci * Parse URL and fill in the relevant members of the connection struct.
177213498266Sopenharmony_ci */
177313498266Sopenharmony_cistatic CURLcode parseurlandfillconn(struct Curl_easy *data,
177413498266Sopenharmony_ci                                    struct connectdata *conn)
177513498266Sopenharmony_ci{
177613498266Sopenharmony_ci  CURLcode result;
177713498266Sopenharmony_ci  CURLU *uh;
177813498266Sopenharmony_ci  CURLUcode uc;
177913498266Sopenharmony_ci  char *hostname;
178013498266Sopenharmony_ci  bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
178113498266Sopenharmony_ci
178213498266Sopenharmony_ci  up_free(data); /* cleanup previous leftovers first */
178313498266Sopenharmony_ci
178413498266Sopenharmony_ci  /* parse the URL */
178513498266Sopenharmony_ci  if(use_set_uh) {
178613498266Sopenharmony_ci    uh = data->state.uh = curl_url_dup(data->set.uh);
178713498266Sopenharmony_ci  }
178813498266Sopenharmony_ci  else {
178913498266Sopenharmony_ci    uh = data->state.uh = curl_url();
179013498266Sopenharmony_ci  }
179113498266Sopenharmony_ci
179213498266Sopenharmony_ci  if(!uh)
179313498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
179413498266Sopenharmony_ci
179513498266Sopenharmony_ci  if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
179613498266Sopenharmony_ci     !Curl_is_absolute_url(data->state.url, NULL, 0, TRUE)) {
179713498266Sopenharmony_ci    char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL],
179813498266Sopenharmony_ci                        data->state.url);
179913498266Sopenharmony_ci    if(!url)
180013498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
180113498266Sopenharmony_ci    if(data->state.url_alloc)
180213498266Sopenharmony_ci      free(data->state.url);
180313498266Sopenharmony_ci    data->state.url = url;
180413498266Sopenharmony_ci    data->state.url_alloc = TRUE;
180513498266Sopenharmony_ci  }
180613498266Sopenharmony_ci
180713498266Sopenharmony_ci  if(!use_set_uh) {
180813498266Sopenharmony_ci    char *newurl;
180913498266Sopenharmony_ci    uc = curl_url_set(uh, CURLUPART_URL, data->state.url,
181013498266Sopenharmony_ci                      CURLU_GUESS_SCHEME |
181113498266Sopenharmony_ci                      CURLU_NON_SUPPORT_SCHEME |
181213498266Sopenharmony_ci                      (data->set.disallow_username_in_url ?
181313498266Sopenharmony_ci                       CURLU_DISALLOW_USER : 0) |
181413498266Sopenharmony_ci                      (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
181513498266Sopenharmony_ci    if(uc) {
181613498266Sopenharmony_ci      failf(data, "URL rejected: %s", curl_url_strerror(uc));
181713498266Sopenharmony_ci      return Curl_uc_to_curlcode(uc);
181813498266Sopenharmony_ci    }
181913498266Sopenharmony_ci
182013498266Sopenharmony_ci    /* after it was parsed, get the generated normalized version */
182113498266Sopenharmony_ci    uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
182213498266Sopenharmony_ci    if(uc)
182313498266Sopenharmony_ci      return Curl_uc_to_curlcode(uc);
182413498266Sopenharmony_ci    if(data->state.url_alloc)
182513498266Sopenharmony_ci      free(data->state.url);
182613498266Sopenharmony_ci    data->state.url = newurl;
182713498266Sopenharmony_ci    data->state.url_alloc = TRUE;
182813498266Sopenharmony_ci  }
182913498266Sopenharmony_ci
183013498266Sopenharmony_ci  uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
183113498266Sopenharmony_ci  if(uc)
183213498266Sopenharmony_ci    return Curl_uc_to_curlcode(uc);
183313498266Sopenharmony_ci
183413498266Sopenharmony_ci  uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
183513498266Sopenharmony_ci  if(uc) {
183613498266Sopenharmony_ci    if(!strcasecompare("file", data->state.up.scheme))
183713498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
183813498266Sopenharmony_ci  }
183913498266Sopenharmony_ci  else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
184013498266Sopenharmony_ci    failf(data, "Too long host name (maximum is %d)", MAX_URL_LEN);
184113498266Sopenharmony_ci    return CURLE_URL_MALFORMAT;
184213498266Sopenharmony_ci  }
184313498266Sopenharmony_ci  hostname = data->state.up.hostname;
184413498266Sopenharmony_ci
184513498266Sopenharmony_ci  if(hostname && hostname[0] == '[') {
184613498266Sopenharmony_ci    /* This looks like an IPv6 address literal. See if there is an address
184713498266Sopenharmony_ci       scope. */
184813498266Sopenharmony_ci    size_t hlen;
184913498266Sopenharmony_ci    conn->bits.ipv6_ip = TRUE;
185013498266Sopenharmony_ci    /* cut off the brackets! */
185113498266Sopenharmony_ci    hostname++;
185213498266Sopenharmony_ci    hlen = strlen(hostname);
185313498266Sopenharmony_ci    hostname[hlen - 1] = 0;
185413498266Sopenharmony_ci
185513498266Sopenharmony_ci    zonefrom_url(uh, data, conn);
185613498266Sopenharmony_ci  }
185713498266Sopenharmony_ci
185813498266Sopenharmony_ci  /* make sure the connect struct gets its own copy of the host name */
185913498266Sopenharmony_ci  conn->host.rawalloc = strdup(hostname ? hostname : "");
186013498266Sopenharmony_ci  if(!conn->host.rawalloc)
186113498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
186213498266Sopenharmony_ci  conn->host.name = conn->host.rawalloc;
186313498266Sopenharmony_ci
186413498266Sopenharmony_ci  /*************************************************************
186513498266Sopenharmony_ci   * IDN-convert the hostnames
186613498266Sopenharmony_ci   *************************************************************/
186713498266Sopenharmony_ci  result = Curl_idnconvert_hostname(&conn->host);
186813498266Sopenharmony_ci  if(result)
186913498266Sopenharmony_ci    return result;
187013498266Sopenharmony_ci
187113498266Sopenharmony_ci#ifndef CURL_DISABLE_HSTS
187213498266Sopenharmony_ci  /* HSTS upgrade */
187313498266Sopenharmony_ci  if(data->hsts && strcasecompare("http", data->state.up.scheme)) {
187413498266Sopenharmony_ci    /* This MUST use the IDN decoded name */
187513498266Sopenharmony_ci    if(Curl_hsts(data->hsts, conn->host.name, TRUE)) {
187613498266Sopenharmony_ci      char *url;
187713498266Sopenharmony_ci      Curl_safefree(data->state.up.scheme);
187813498266Sopenharmony_ci      uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0);
187913498266Sopenharmony_ci      if(uc)
188013498266Sopenharmony_ci        return Curl_uc_to_curlcode(uc);
188113498266Sopenharmony_ci      if(data->state.url_alloc)
188213498266Sopenharmony_ci        Curl_safefree(data->state.url);
188313498266Sopenharmony_ci      /* after update, get the updated version */
188413498266Sopenharmony_ci      uc = curl_url_get(uh, CURLUPART_URL, &url, 0);
188513498266Sopenharmony_ci      if(uc)
188613498266Sopenharmony_ci        return Curl_uc_to_curlcode(uc);
188713498266Sopenharmony_ci      uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
188813498266Sopenharmony_ci      if(uc) {
188913498266Sopenharmony_ci        free(url);
189013498266Sopenharmony_ci        return Curl_uc_to_curlcode(uc);
189113498266Sopenharmony_ci      }
189213498266Sopenharmony_ci      data->state.url = url;
189313498266Sopenharmony_ci      data->state.url_alloc = TRUE;
189413498266Sopenharmony_ci      infof(data, "Switched from HTTP to HTTPS due to HSTS => %s",
189513498266Sopenharmony_ci            data->state.url);
189613498266Sopenharmony_ci    }
189713498266Sopenharmony_ci  }
189813498266Sopenharmony_ci#endif
189913498266Sopenharmony_ci
190013498266Sopenharmony_ci  result = findprotocol(data, conn, data->state.up.scheme);
190113498266Sopenharmony_ci  if(result)
190213498266Sopenharmony_ci    return result;
190313498266Sopenharmony_ci
190413498266Sopenharmony_ci  /*
190513498266Sopenharmony_ci   * User name and password set with their own options override the
190613498266Sopenharmony_ci   * credentials possibly set in the URL.
190713498266Sopenharmony_ci   */
190813498266Sopenharmony_ci  if(!data->set.str[STRING_PASSWORD]) {
190913498266Sopenharmony_ci    uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
191013498266Sopenharmony_ci    if(!uc) {
191113498266Sopenharmony_ci      char *decoded;
191213498266Sopenharmony_ci      result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL,
191313498266Sopenharmony_ci                              conn->handler->flags&PROTOPT_USERPWDCTRL ?
191413498266Sopenharmony_ci                              REJECT_ZERO : REJECT_CTRL);
191513498266Sopenharmony_ci      if(result)
191613498266Sopenharmony_ci        return result;
191713498266Sopenharmony_ci      conn->passwd = decoded;
191813498266Sopenharmony_ci      result = Curl_setstropt(&data->state.aptr.passwd, decoded);
191913498266Sopenharmony_ci      if(result)
192013498266Sopenharmony_ci        return result;
192113498266Sopenharmony_ci    }
192213498266Sopenharmony_ci    else if(uc != CURLUE_NO_PASSWORD)
192313498266Sopenharmony_ci      return Curl_uc_to_curlcode(uc);
192413498266Sopenharmony_ci  }
192513498266Sopenharmony_ci
192613498266Sopenharmony_ci  if(!data->set.str[STRING_USERNAME]) {
192713498266Sopenharmony_ci    /* we don't use the URL API's URL decoder option here since it rejects
192813498266Sopenharmony_ci       control codes and we want to allow them for some schemes in the user
192913498266Sopenharmony_ci       and password fields */
193013498266Sopenharmony_ci    uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
193113498266Sopenharmony_ci    if(!uc) {
193213498266Sopenharmony_ci      char *decoded;
193313498266Sopenharmony_ci      result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL,
193413498266Sopenharmony_ci                              conn->handler->flags&PROTOPT_USERPWDCTRL ?
193513498266Sopenharmony_ci                              REJECT_ZERO : REJECT_CTRL);
193613498266Sopenharmony_ci      if(result)
193713498266Sopenharmony_ci        return result;
193813498266Sopenharmony_ci      conn->user = decoded;
193913498266Sopenharmony_ci      result = Curl_setstropt(&data->state.aptr.user, decoded);
194013498266Sopenharmony_ci    }
194113498266Sopenharmony_ci    else if(uc != CURLUE_NO_USER)
194213498266Sopenharmony_ci      return Curl_uc_to_curlcode(uc);
194313498266Sopenharmony_ci    else if(data->state.aptr.passwd) {
194413498266Sopenharmony_ci      /* no user was set but a password, set a blank user */
194513498266Sopenharmony_ci      result = Curl_setstropt(&data->state.aptr.user, "");
194613498266Sopenharmony_ci    }
194713498266Sopenharmony_ci    if(result)
194813498266Sopenharmony_ci      return result;
194913498266Sopenharmony_ci  }
195013498266Sopenharmony_ci
195113498266Sopenharmony_ci  uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
195213498266Sopenharmony_ci                    CURLU_URLDECODE);
195313498266Sopenharmony_ci  if(!uc) {
195413498266Sopenharmony_ci    conn->options = strdup(data->state.up.options);
195513498266Sopenharmony_ci    if(!conn->options)
195613498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
195713498266Sopenharmony_ci  }
195813498266Sopenharmony_ci  else if(uc != CURLUE_NO_OPTIONS)
195913498266Sopenharmony_ci    return Curl_uc_to_curlcode(uc);
196013498266Sopenharmony_ci
196113498266Sopenharmony_ci  uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path,
196213498266Sopenharmony_ci                    CURLU_URLENCODE);
196313498266Sopenharmony_ci  if(uc)
196413498266Sopenharmony_ci    return Curl_uc_to_curlcode(uc);
196513498266Sopenharmony_ci
196613498266Sopenharmony_ci  uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port,
196713498266Sopenharmony_ci                    CURLU_DEFAULT_PORT);
196813498266Sopenharmony_ci  if(uc) {
196913498266Sopenharmony_ci    if(!strcasecompare("file", data->state.up.scheme))
197013498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
197113498266Sopenharmony_ci  }
197213498266Sopenharmony_ci  else {
197313498266Sopenharmony_ci    unsigned long port = strtoul(data->state.up.port, NULL, 10);
197413498266Sopenharmony_ci    conn->port = conn->remote_port =
197513498266Sopenharmony_ci      (data->set.use_port && data->state.allow_port) ?
197613498266Sopenharmony_ci      data->set.use_port : curlx_ultous(port);
197713498266Sopenharmony_ci  }
197813498266Sopenharmony_ci
197913498266Sopenharmony_ci  (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
198013498266Sopenharmony_ci
198113498266Sopenharmony_ci#ifdef ENABLE_IPV6
198213498266Sopenharmony_ci  if(data->set.scope_id)
198313498266Sopenharmony_ci    /* Override any scope that was set above.  */
198413498266Sopenharmony_ci    conn->scope_id = data->set.scope_id;
198513498266Sopenharmony_ci#endif
198613498266Sopenharmony_ci
198713498266Sopenharmony_ci  return CURLE_OK;
198813498266Sopenharmony_ci}
198913498266Sopenharmony_ci
199013498266Sopenharmony_ci
199113498266Sopenharmony_ci/*
199213498266Sopenharmony_ci * If we're doing a resumed transfer, we need to setup our stuff
199313498266Sopenharmony_ci * properly.
199413498266Sopenharmony_ci */
199513498266Sopenharmony_cistatic CURLcode setup_range(struct Curl_easy *data)
199613498266Sopenharmony_ci{
199713498266Sopenharmony_ci  struct UrlState *s = &data->state;
199813498266Sopenharmony_ci  s->resume_from = data->set.set_resume_from;
199913498266Sopenharmony_ci  if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
200013498266Sopenharmony_ci    if(s->rangestringalloc)
200113498266Sopenharmony_ci      free(s->range);
200213498266Sopenharmony_ci
200313498266Sopenharmony_ci    if(s->resume_from)
200413498266Sopenharmony_ci      s->range = aprintf("%" CURL_FORMAT_CURL_OFF_T "-", s->resume_from);
200513498266Sopenharmony_ci    else
200613498266Sopenharmony_ci      s->range = strdup(data->set.str[STRING_SET_RANGE]);
200713498266Sopenharmony_ci
200813498266Sopenharmony_ci    s->rangestringalloc = (s->range) ? TRUE : FALSE;
200913498266Sopenharmony_ci
201013498266Sopenharmony_ci    if(!s->range)
201113498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
201213498266Sopenharmony_ci
201313498266Sopenharmony_ci    /* tell ourselves to fetch this range */
201413498266Sopenharmony_ci    s->use_range = TRUE;        /* enable range download */
201513498266Sopenharmony_ci  }
201613498266Sopenharmony_ci  else
201713498266Sopenharmony_ci    s->use_range = FALSE; /* disable range download */
201813498266Sopenharmony_ci
201913498266Sopenharmony_ci  return CURLE_OK;
202013498266Sopenharmony_ci}
202113498266Sopenharmony_ci
202213498266Sopenharmony_ci
202313498266Sopenharmony_ci/*
202413498266Sopenharmony_ci * setup_connection_internals() -
202513498266Sopenharmony_ci *
202613498266Sopenharmony_ci * Setup connection internals specific to the requested protocol in the
202713498266Sopenharmony_ci * Curl_easy. This is inited and setup before the connection is made but
202813498266Sopenharmony_ci * is about the particular protocol that is to be used.
202913498266Sopenharmony_ci *
203013498266Sopenharmony_ci * This MUST get called after proxy magic has been figured out.
203113498266Sopenharmony_ci */
203213498266Sopenharmony_cistatic CURLcode setup_connection_internals(struct Curl_easy *data,
203313498266Sopenharmony_ci                                           struct connectdata *conn)
203413498266Sopenharmony_ci{
203513498266Sopenharmony_ci  const struct Curl_handler *p;
203613498266Sopenharmony_ci  CURLcode result;
203713498266Sopenharmony_ci
203813498266Sopenharmony_ci  /* Perform setup complement if some. */
203913498266Sopenharmony_ci  p = conn->handler;
204013498266Sopenharmony_ci
204113498266Sopenharmony_ci  if(p->setup_connection) {
204213498266Sopenharmony_ci    result = (*p->setup_connection)(data, conn);
204313498266Sopenharmony_ci
204413498266Sopenharmony_ci    if(result)
204513498266Sopenharmony_ci      return result;
204613498266Sopenharmony_ci
204713498266Sopenharmony_ci    p = conn->handler;              /* May have changed. */
204813498266Sopenharmony_ci  }
204913498266Sopenharmony_ci
205013498266Sopenharmony_ci  if(conn->port < 0)
205113498266Sopenharmony_ci    /* we check for -1 here since if proxy was detected already, this
205213498266Sopenharmony_ci       was very likely already set to the proxy port */
205313498266Sopenharmony_ci    conn->port = p->defport;
205413498266Sopenharmony_ci
205513498266Sopenharmony_ci  return CURLE_OK;
205613498266Sopenharmony_ci}
205713498266Sopenharmony_ci
205813498266Sopenharmony_ci/*
205913498266Sopenharmony_ci * Curl_free_request_state() should free temp data that was allocated in the
206013498266Sopenharmony_ci * Curl_easy for this single request.
206113498266Sopenharmony_ci */
206213498266Sopenharmony_ci
206313498266Sopenharmony_civoid Curl_free_request_state(struct Curl_easy *data)
206413498266Sopenharmony_ci{
206513498266Sopenharmony_ci  Curl_safefree(data->req.p.http);
206613498266Sopenharmony_ci  Curl_safefree(data->req.newurl);
206713498266Sopenharmony_ci#ifndef CURL_DISABLE_DOH
206813498266Sopenharmony_ci  if(data->req.doh) {
206913498266Sopenharmony_ci    Curl_close(&data->req.doh->probe[0].easy);
207013498266Sopenharmony_ci    Curl_close(&data->req.doh->probe[1].easy);
207113498266Sopenharmony_ci  }
207213498266Sopenharmony_ci#endif
207313498266Sopenharmony_ci  Curl_client_cleanup(data);
207413498266Sopenharmony_ci}
207513498266Sopenharmony_ci
207613498266Sopenharmony_ci
207713498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
207813498266Sopenharmony_ci
207913498266Sopenharmony_ci#ifndef CURL_DISABLE_HTTP
208013498266Sopenharmony_ci/****************************************************************
208113498266Sopenharmony_ci* Detect what (if any) proxy to use. Remember that this selects a host
208213498266Sopenharmony_ci* name and is not limited to HTTP proxies only.
208313498266Sopenharmony_ci* The returned pointer must be freed by the caller (unless NULL)
208413498266Sopenharmony_ci****************************************************************/
208513498266Sopenharmony_cistatic char *detect_proxy(struct Curl_easy *data,
208613498266Sopenharmony_ci                          struct connectdata *conn)
208713498266Sopenharmony_ci{
208813498266Sopenharmony_ci  char *proxy = NULL;
208913498266Sopenharmony_ci
209013498266Sopenharmony_ci  /* If proxy was not specified, we check for default proxy environment
209113498266Sopenharmony_ci   * variables, to enable i.e Lynx compliance:
209213498266Sopenharmony_ci   *
209313498266Sopenharmony_ci   * http_proxy=http://some.server.dom:port/
209413498266Sopenharmony_ci   * https_proxy=http://some.server.dom:port/
209513498266Sopenharmony_ci   * ftp_proxy=http://some.server.dom:port/
209613498266Sopenharmony_ci   * no_proxy=domain1.dom,host.domain2.dom
209713498266Sopenharmony_ci   *   (a comma-separated list of hosts which should
209813498266Sopenharmony_ci   *   not be proxied, or an asterisk to override
209913498266Sopenharmony_ci   *   all proxy variables)
210013498266Sopenharmony_ci   * all_proxy=http://some.server.dom:port/
210113498266Sopenharmony_ci   *   (seems to exist for the CERN www lib. Probably
210213498266Sopenharmony_ci   *   the first to check for.)
210313498266Sopenharmony_ci   *
210413498266Sopenharmony_ci   * For compatibility, the all-uppercase versions of these variables are
210513498266Sopenharmony_ci   * checked if the lowercase versions don't exist.
210613498266Sopenharmony_ci   */
210713498266Sopenharmony_ci  char proxy_env[128];
210813498266Sopenharmony_ci  const char *protop = conn->handler->scheme;
210913498266Sopenharmony_ci  char *envp = proxy_env;
211013498266Sopenharmony_ci#ifdef CURL_DISABLE_VERBOSE_STRINGS
211113498266Sopenharmony_ci  (void)data;
211213498266Sopenharmony_ci#endif
211313498266Sopenharmony_ci
211413498266Sopenharmony_ci  /* Now, build <protocol>_proxy and check for such a one to use */
211513498266Sopenharmony_ci  while(*protop)
211613498266Sopenharmony_ci    *envp++ = Curl_raw_tolower(*protop++);
211713498266Sopenharmony_ci
211813498266Sopenharmony_ci  /* append _proxy */
211913498266Sopenharmony_ci  strcpy(envp, "_proxy");
212013498266Sopenharmony_ci
212113498266Sopenharmony_ci  /* read the protocol proxy: */
212213498266Sopenharmony_ci  proxy = curl_getenv(proxy_env);
212313498266Sopenharmony_ci
212413498266Sopenharmony_ci  /*
212513498266Sopenharmony_ci   * We don't try the uppercase version of HTTP_PROXY because of
212613498266Sopenharmony_ci   * security reasons:
212713498266Sopenharmony_ci   *
212813498266Sopenharmony_ci   * When curl is used in a webserver application
212913498266Sopenharmony_ci   * environment (cgi or php), this environment variable can
213013498266Sopenharmony_ci   * be controlled by the web server user by setting the
213113498266Sopenharmony_ci   * http header 'Proxy:' to some value.
213213498266Sopenharmony_ci   *
213313498266Sopenharmony_ci   * This can cause 'internal' http/ftp requests to be
213413498266Sopenharmony_ci   * arbitrarily redirected by any external attacker.
213513498266Sopenharmony_ci   */
213613498266Sopenharmony_ci  if(!proxy && !strcasecompare("http_proxy", proxy_env)) {
213713498266Sopenharmony_ci    /* There was no lowercase variable, try the uppercase version: */
213813498266Sopenharmony_ci    Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
213913498266Sopenharmony_ci    proxy = curl_getenv(proxy_env);
214013498266Sopenharmony_ci  }
214113498266Sopenharmony_ci
214213498266Sopenharmony_ci  envp = proxy_env;
214313498266Sopenharmony_ci  if(!proxy) {
214413498266Sopenharmony_ci#ifdef USE_WEBSOCKETS
214513498266Sopenharmony_ci    /* websocket proxy fallbacks */
214613498266Sopenharmony_ci    if(strcasecompare("ws_proxy", proxy_env)) {
214713498266Sopenharmony_ci      proxy = curl_getenv("http_proxy");
214813498266Sopenharmony_ci    }
214913498266Sopenharmony_ci    else if(strcasecompare("wss_proxy", proxy_env)) {
215013498266Sopenharmony_ci      proxy = curl_getenv("https_proxy");
215113498266Sopenharmony_ci      if(!proxy)
215213498266Sopenharmony_ci        proxy = curl_getenv("HTTPS_PROXY");
215313498266Sopenharmony_ci    }
215413498266Sopenharmony_ci    if(!proxy) {
215513498266Sopenharmony_ci#endif
215613498266Sopenharmony_ci      envp = (char *)"all_proxy";
215713498266Sopenharmony_ci      proxy = curl_getenv(envp); /* default proxy to use */
215813498266Sopenharmony_ci      if(!proxy) {
215913498266Sopenharmony_ci        envp = (char *)"ALL_PROXY";
216013498266Sopenharmony_ci        proxy = curl_getenv(envp);
216113498266Sopenharmony_ci      }
216213498266Sopenharmony_ci#ifdef USE_WEBSOCKETS
216313498266Sopenharmony_ci    }
216413498266Sopenharmony_ci#endif
216513498266Sopenharmony_ci  }
216613498266Sopenharmony_ci  if(proxy)
216713498266Sopenharmony_ci    infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
216813498266Sopenharmony_ci
216913498266Sopenharmony_ci  return proxy;
217013498266Sopenharmony_ci}
217113498266Sopenharmony_ci#endif /* CURL_DISABLE_HTTP */
217213498266Sopenharmony_ci
217313498266Sopenharmony_ci/*
217413498266Sopenharmony_ci * If this is supposed to use a proxy, we need to figure out the proxy
217513498266Sopenharmony_ci * host name, so that we can reuse an existing connection
217613498266Sopenharmony_ci * that may exist registered to the same proxy host.
217713498266Sopenharmony_ci */
217813498266Sopenharmony_cistatic CURLcode parse_proxy(struct Curl_easy *data,
217913498266Sopenharmony_ci                            struct connectdata *conn, char *proxy,
218013498266Sopenharmony_ci                            curl_proxytype proxytype)
218113498266Sopenharmony_ci{
218213498266Sopenharmony_ci  char *portptr = NULL;
218313498266Sopenharmony_ci  int port = -1;
218413498266Sopenharmony_ci  char *proxyuser = NULL;
218513498266Sopenharmony_ci  char *proxypasswd = NULL;
218613498266Sopenharmony_ci  char *host = NULL;
218713498266Sopenharmony_ci  bool sockstype;
218813498266Sopenharmony_ci  CURLUcode uc;
218913498266Sopenharmony_ci  struct proxy_info *proxyinfo;
219013498266Sopenharmony_ci  CURLU *uhp = curl_url();
219113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
219213498266Sopenharmony_ci  char *scheme = NULL;
219313498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
219413498266Sopenharmony_ci  char *path = NULL;
219513498266Sopenharmony_ci  bool is_unix_proxy = FALSE;
219613498266Sopenharmony_ci#endif
219713498266Sopenharmony_ci
219813498266Sopenharmony_ci
219913498266Sopenharmony_ci  if(!uhp) {
220013498266Sopenharmony_ci    result = CURLE_OUT_OF_MEMORY;
220113498266Sopenharmony_ci    goto error;
220213498266Sopenharmony_ci  }
220313498266Sopenharmony_ci
220413498266Sopenharmony_ci  /* When parsing the proxy, allowing non-supported schemes since we have
220513498266Sopenharmony_ci     these made up ones for proxies. Guess scheme for URLs without it. */
220613498266Sopenharmony_ci  uc = curl_url_set(uhp, CURLUPART_URL, proxy,
220713498266Sopenharmony_ci                    CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
220813498266Sopenharmony_ci  if(!uc) {
220913498266Sopenharmony_ci    /* parsed okay as a URL */
221013498266Sopenharmony_ci    uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, 0);
221113498266Sopenharmony_ci    if(uc) {
221213498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
221313498266Sopenharmony_ci      goto error;
221413498266Sopenharmony_ci    }
221513498266Sopenharmony_ci
221613498266Sopenharmony_ci    if(strcasecompare("https", scheme)) {
221713498266Sopenharmony_ci      if(proxytype != CURLPROXY_HTTPS2)
221813498266Sopenharmony_ci        proxytype = CURLPROXY_HTTPS;
221913498266Sopenharmony_ci      else
222013498266Sopenharmony_ci        proxytype = CURLPROXY_HTTPS2;
222113498266Sopenharmony_ci    }
222213498266Sopenharmony_ci    else if(strcasecompare("socks5h", scheme))
222313498266Sopenharmony_ci      proxytype = CURLPROXY_SOCKS5_HOSTNAME;
222413498266Sopenharmony_ci    else if(strcasecompare("socks5", scheme))
222513498266Sopenharmony_ci      proxytype = CURLPROXY_SOCKS5;
222613498266Sopenharmony_ci    else if(strcasecompare("socks4a", scheme))
222713498266Sopenharmony_ci      proxytype = CURLPROXY_SOCKS4A;
222813498266Sopenharmony_ci    else if(strcasecompare("socks4", scheme) ||
222913498266Sopenharmony_ci            strcasecompare("socks", scheme))
223013498266Sopenharmony_ci      proxytype = CURLPROXY_SOCKS4;
223113498266Sopenharmony_ci    else if(strcasecompare("http", scheme))
223213498266Sopenharmony_ci      ; /* leave it as HTTP or HTTP/1.0 */
223313498266Sopenharmony_ci    else {
223413498266Sopenharmony_ci      /* Any other xxx:// reject! */
223513498266Sopenharmony_ci      failf(data, "Unsupported proxy scheme for \'%s\'", proxy);
223613498266Sopenharmony_ci      result = CURLE_COULDNT_CONNECT;
223713498266Sopenharmony_ci      goto error;
223813498266Sopenharmony_ci    }
223913498266Sopenharmony_ci  }
224013498266Sopenharmony_ci  else {
224113498266Sopenharmony_ci    failf(data, "Unsupported proxy syntax in \'%s\': %s", proxy,
224213498266Sopenharmony_ci          curl_url_strerror(uc));
224313498266Sopenharmony_ci    result = CURLE_COULDNT_RESOLVE_PROXY;
224413498266Sopenharmony_ci    goto error;
224513498266Sopenharmony_ci  }
224613498266Sopenharmony_ci
224713498266Sopenharmony_ci#ifdef USE_SSL
224813498266Sopenharmony_ci  if(!Curl_ssl_supports(data, SSLSUPP_HTTPS_PROXY))
224913498266Sopenharmony_ci#endif
225013498266Sopenharmony_ci    if(IS_HTTPS_PROXY(proxytype)) {
225113498266Sopenharmony_ci      failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
225213498266Sopenharmony_ci            "HTTPS-proxy support.", proxy);
225313498266Sopenharmony_ci      result = CURLE_NOT_BUILT_IN;
225413498266Sopenharmony_ci      goto error;
225513498266Sopenharmony_ci    }
225613498266Sopenharmony_ci
225713498266Sopenharmony_ci  sockstype =
225813498266Sopenharmony_ci    proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
225913498266Sopenharmony_ci    proxytype == CURLPROXY_SOCKS5 ||
226013498266Sopenharmony_ci    proxytype == CURLPROXY_SOCKS4A ||
226113498266Sopenharmony_ci    proxytype == CURLPROXY_SOCKS4;
226213498266Sopenharmony_ci
226313498266Sopenharmony_ci  proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy;
226413498266Sopenharmony_ci  proxyinfo->proxytype = (unsigned char)proxytype;
226513498266Sopenharmony_ci
226613498266Sopenharmony_ci  /* Is there a username and password given in this proxy url? */
226713498266Sopenharmony_ci  uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
226813498266Sopenharmony_ci  if(uc && (uc != CURLUE_NO_USER))
226913498266Sopenharmony_ci    goto error;
227013498266Sopenharmony_ci  uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
227113498266Sopenharmony_ci  if(uc && (uc != CURLUE_NO_PASSWORD))
227213498266Sopenharmony_ci    goto error;
227313498266Sopenharmony_ci
227413498266Sopenharmony_ci  if(proxyuser || proxypasswd) {
227513498266Sopenharmony_ci    Curl_safefree(proxyinfo->user);
227613498266Sopenharmony_ci    proxyinfo->user = proxyuser;
227713498266Sopenharmony_ci    result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser);
227813498266Sopenharmony_ci    proxyuser = NULL;
227913498266Sopenharmony_ci    if(result)
228013498266Sopenharmony_ci      goto error;
228113498266Sopenharmony_ci    Curl_safefree(proxyinfo->passwd);
228213498266Sopenharmony_ci    if(!proxypasswd) {
228313498266Sopenharmony_ci      proxypasswd = strdup("");
228413498266Sopenharmony_ci      if(!proxypasswd) {
228513498266Sopenharmony_ci        result = CURLE_OUT_OF_MEMORY;
228613498266Sopenharmony_ci        goto error;
228713498266Sopenharmony_ci      }
228813498266Sopenharmony_ci    }
228913498266Sopenharmony_ci    proxyinfo->passwd = proxypasswd;
229013498266Sopenharmony_ci    result = Curl_setstropt(&data->state.aptr.proxypasswd, proxypasswd);
229113498266Sopenharmony_ci    proxypasswd = NULL;
229213498266Sopenharmony_ci    if(result)
229313498266Sopenharmony_ci      goto error;
229413498266Sopenharmony_ci    conn->bits.proxy_user_passwd = TRUE; /* enable it */
229513498266Sopenharmony_ci  }
229613498266Sopenharmony_ci
229713498266Sopenharmony_ci  (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
229813498266Sopenharmony_ci
229913498266Sopenharmony_ci  if(portptr) {
230013498266Sopenharmony_ci    port = (int)strtol(portptr, NULL, 10);
230113498266Sopenharmony_ci    free(portptr);
230213498266Sopenharmony_ci  }
230313498266Sopenharmony_ci  else {
230413498266Sopenharmony_ci    if(data->set.proxyport)
230513498266Sopenharmony_ci      /* None given in the proxy string, then get the default one if it is
230613498266Sopenharmony_ci         given */
230713498266Sopenharmony_ci      port = (int)data->set.proxyport;
230813498266Sopenharmony_ci    else {
230913498266Sopenharmony_ci      if(IS_HTTPS_PROXY(proxytype))
231013498266Sopenharmony_ci        port = CURL_DEFAULT_HTTPS_PROXY_PORT;
231113498266Sopenharmony_ci      else
231213498266Sopenharmony_ci        port = CURL_DEFAULT_PROXY_PORT;
231313498266Sopenharmony_ci    }
231413498266Sopenharmony_ci  }
231513498266Sopenharmony_ci  if(port >= 0) {
231613498266Sopenharmony_ci    proxyinfo->port = port;
231713498266Sopenharmony_ci    if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc)
231813498266Sopenharmony_ci      conn->port = port;
231913498266Sopenharmony_ci  }
232013498266Sopenharmony_ci
232113498266Sopenharmony_ci  /* now, clone the proxy host name */
232213498266Sopenharmony_ci  uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
232313498266Sopenharmony_ci  if(uc) {
232413498266Sopenharmony_ci    result = CURLE_OUT_OF_MEMORY;
232513498266Sopenharmony_ci    goto error;
232613498266Sopenharmony_ci  }
232713498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
232813498266Sopenharmony_ci  if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) {
232913498266Sopenharmony_ci    uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE);
233013498266Sopenharmony_ci    if(uc) {
233113498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
233213498266Sopenharmony_ci      goto error;
233313498266Sopenharmony_ci    }
233413498266Sopenharmony_ci    /* path will be "/", if no path was found */
233513498266Sopenharmony_ci    if(strcmp("/", path)) {
233613498266Sopenharmony_ci      is_unix_proxy = TRUE;
233713498266Sopenharmony_ci      free(host);
233813498266Sopenharmony_ci      host = aprintf(UNIX_SOCKET_PREFIX"%s", path);
233913498266Sopenharmony_ci      if(!host) {
234013498266Sopenharmony_ci        result = CURLE_OUT_OF_MEMORY;
234113498266Sopenharmony_ci        goto error;
234213498266Sopenharmony_ci      }
234313498266Sopenharmony_ci      Curl_safefree(proxyinfo->host.rawalloc);
234413498266Sopenharmony_ci      proxyinfo->host.rawalloc = host;
234513498266Sopenharmony_ci      proxyinfo->host.name = host;
234613498266Sopenharmony_ci      host = NULL;
234713498266Sopenharmony_ci    }
234813498266Sopenharmony_ci  }
234913498266Sopenharmony_ci
235013498266Sopenharmony_ci  if(!is_unix_proxy) {
235113498266Sopenharmony_ci#endif
235213498266Sopenharmony_ci    Curl_safefree(proxyinfo->host.rawalloc);
235313498266Sopenharmony_ci    proxyinfo->host.rawalloc = host;
235413498266Sopenharmony_ci    if(host[0] == '[') {
235513498266Sopenharmony_ci      /* this is a numerical IPv6, strip off the brackets */
235613498266Sopenharmony_ci      size_t len = strlen(host);
235713498266Sopenharmony_ci      host[len-1] = 0; /* clear the trailing bracket */
235813498266Sopenharmony_ci      host++;
235913498266Sopenharmony_ci      zonefrom_url(uhp, data, conn);
236013498266Sopenharmony_ci    }
236113498266Sopenharmony_ci    proxyinfo->host.name = host;
236213498266Sopenharmony_ci    host = NULL;
236313498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
236413498266Sopenharmony_ci  }
236513498266Sopenharmony_ci#endif
236613498266Sopenharmony_ci
236713498266Sopenharmony_cierror:
236813498266Sopenharmony_ci  free(proxyuser);
236913498266Sopenharmony_ci  free(proxypasswd);
237013498266Sopenharmony_ci  free(host);
237113498266Sopenharmony_ci  free(scheme);
237213498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
237313498266Sopenharmony_ci  free(path);
237413498266Sopenharmony_ci#endif
237513498266Sopenharmony_ci  curl_url_cleanup(uhp);
237613498266Sopenharmony_ci  return result;
237713498266Sopenharmony_ci}
237813498266Sopenharmony_ci
237913498266Sopenharmony_ci/*
238013498266Sopenharmony_ci * Extract the user and password from the authentication string
238113498266Sopenharmony_ci */
238213498266Sopenharmony_cistatic CURLcode parse_proxy_auth(struct Curl_easy *data,
238313498266Sopenharmony_ci                                 struct connectdata *conn)
238413498266Sopenharmony_ci{
238513498266Sopenharmony_ci  const char *proxyuser = data->state.aptr.proxyuser ?
238613498266Sopenharmony_ci    data->state.aptr.proxyuser : "";
238713498266Sopenharmony_ci  const char *proxypasswd = data->state.aptr.proxypasswd ?
238813498266Sopenharmony_ci    data->state.aptr.proxypasswd : "";
238913498266Sopenharmony_ci  CURLcode result = Curl_urldecode(proxyuser, 0, &conn->http_proxy.user, NULL,
239013498266Sopenharmony_ci                                   REJECT_ZERO);
239113498266Sopenharmony_ci  if(!result)
239213498266Sopenharmony_ci    result = Curl_setstropt(&data->state.aptr.proxyuser,
239313498266Sopenharmony_ci                            conn->http_proxy.user);
239413498266Sopenharmony_ci  if(!result)
239513498266Sopenharmony_ci    result = Curl_urldecode(proxypasswd, 0, &conn->http_proxy.passwd,
239613498266Sopenharmony_ci                            NULL, REJECT_ZERO);
239713498266Sopenharmony_ci  if(!result)
239813498266Sopenharmony_ci    result = Curl_setstropt(&data->state.aptr.proxypasswd,
239913498266Sopenharmony_ci                            conn->http_proxy.passwd);
240013498266Sopenharmony_ci  return result;
240113498266Sopenharmony_ci}
240213498266Sopenharmony_ci
240313498266Sopenharmony_ci/* create_conn helper to parse and init proxy values. to be called after unix
240413498266Sopenharmony_ci   socket init but before any proxy vars are evaluated. */
240513498266Sopenharmony_cistatic CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
240613498266Sopenharmony_ci                                              struct connectdata *conn)
240713498266Sopenharmony_ci{
240813498266Sopenharmony_ci  char *proxy = NULL;
240913498266Sopenharmony_ci  char *socksproxy = NULL;
241013498266Sopenharmony_ci  char *no_proxy = NULL;
241113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
241213498266Sopenharmony_ci  bool spacesep = FALSE;
241313498266Sopenharmony_ci
241413498266Sopenharmony_ci  /*************************************************************
241513498266Sopenharmony_ci   * Extract the user and password from the authentication string
241613498266Sopenharmony_ci   *************************************************************/
241713498266Sopenharmony_ci  if(conn->bits.proxy_user_passwd) {
241813498266Sopenharmony_ci    result = parse_proxy_auth(data, conn);
241913498266Sopenharmony_ci    if(result)
242013498266Sopenharmony_ci      goto out;
242113498266Sopenharmony_ci  }
242213498266Sopenharmony_ci
242313498266Sopenharmony_ci  /*************************************************************
242413498266Sopenharmony_ci   * Detect what (if any) proxy to use
242513498266Sopenharmony_ci   *************************************************************/
242613498266Sopenharmony_ci  if(data->set.str[STRING_PROXY]) {
242713498266Sopenharmony_ci    proxy = strdup(data->set.str[STRING_PROXY]);
242813498266Sopenharmony_ci    /* if global proxy is set, this is it */
242913498266Sopenharmony_ci    if(!proxy) {
243013498266Sopenharmony_ci      failf(data, "memory shortage");
243113498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
243213498266Sopenharmony_ci      goto out;
243313498266Sopenharmony_ci    }
243413498266Sopenharmony_ci  }
243513498266Sopenharmony_ci
243613498266Sopenharmony_ci  if(data->set.str[STRING_PRE_PROXY]) {
243713498266Sopenharmony_ci    socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
243813498266Sopenharmony_ci    /* if global socks proxy is set, this is it */
243913498266Sopenharmony_ci    if(!socksproxy) {
244013498266Sopenharmony_ci      failf(data, "memory shortage");
244113498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
244213498266Sopenharmony_ci      goto out;
244313498266Sopenharmony_ci    }
244413498266Sopenharmony_ci  }
244513498266Sopenharmony_ci
244613498266Sopenharmony_ci  if(!data->set.str[STRING_NOPROXY]) {
244713498266Sopenharmony_ci    const char *p = "no_proxy";
244813498266Sopenharmony_ci    no_proxy = curl_getenv(p);
244913498266Sopenharmony_ci    if(!no_proxy) {
245013498266Sopenharmony_ci      p = "NO_PROXY";
245113498266Sopenharmony_ci      no_proxy = curl_getenv(p);
245213498266Sopenharmony_ci    }
245313498266Sopenharmony_ci    if(no_proxy) {
245413498266Sopenharmony_ci      infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
245513498266Sopenharmony_ci    }
245613498266Sopenharmony_ci  }
245713498266Sopenharmony_ci
245813498266Sopenharmony_ci  if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
245913498266Sopenharmony_ci                        data->set.str[STRING_NOPROXY] : no_proxy,
246013498266Sopenharmony_ci                        &spacesep)) {
246113498266Sopenharmony_ci    Curl_safefree(proxy);
246213498266Sopenharmony_ci    Curl_safefree(socksproxy);
246313498266Sopenharmony_ci  }
246413498266Sopenharmony_ci#ifndef CURL_DISABLE_HTTP
246513498266Sopenharmony_ci  else if(!proxy && !socksproxy)
246613498266Sopenharmony_ci    /* if the host is not in the noproxy list, detect proxy. */
246713498266Sopenharmony_ci    proxy = detect_proxy(data, conn);
246813498266Sopenharmony_ci#endif /* CURL_DISABLE_HTTP */
246913498266Sopenharmony_ci  if(spacesep)
247013498266Sopenharmony_ci    infof(data, "space-separated NOPROXY patterns are deprecated");
247113498266Sopenharmony_ci
247213498266Sopenharmony_ci  Curl_safefree(no_proxy);
247313498266Sopenharmony_ci
247413498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
247513498266Sopenharmony_ci  /* For the time being do not mix proxy and unix domain sockets. See #1274 */
247613498266Sopenharmony_ci  if(proxy && conn->unix_domain_socket) {
247713498266Sopenharmony_ci    free(proxy);
247813498266Sopenharmony_ci    proxy = NULL;
247913498266Sopenharmony_ci  }
248013498266Sopenharmony_ci#endif
248113498266Sopenharmony_ci
248213498266Sopenharmony_ci  if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
248313498266Sopenharmony_ci    free(proxy);  /* Don't bother with an empty proxy string or if the
248413498266Sopenharmony_ci                     protocol doesn't work with network */
248513498266Sopenharmony_ci    proxy = NULL;
248613498266Sopenharmony_ci  }
248713498266Sopenharmony_ci  if(socksproxy && (!*socksproxy ||
248813498266Sopenharmony_ci                    (conn->handler->flags & PROTOPT_NONETWORK))) {
248913498266Sopenharmony_ci    free(socksproxy);  /* Don't bother with an empty socks proxy string or if
249013498266Sopenharmony_ci                          the protocol doesn't work with network */
249113498266Sopenharmony_ci    socksproxy = NULL;
249213498266Sopenharmony_ci  }
249313498266Sopenharmony_ci
249413498266Sopenharmony_ci  /***********************************************************************
249513498266Sopenharmony_ci   * If this is supposed to use a proxy, we need to figure out the proxy host
249613498266Sopenharmony_ci   * name, proxy type and port number, so that we can reuse an existing
249713498266Sopenharmony_ci   * connection that may exist registered to the same proxy host.
249813498266Sopenharmony_ci   ***********************************************************************/
249913498266Sopenharmony_ci  if(proxy || socksproxy) {
250013498266Sopenharmony_ci    curl_proxytype ptype = (curl_proxytype)conn->http_proxy.proxytype;
250113498266Sopenharmony_ci    if(proxy) {
250213498266Sopenharmony_ci      result = parse_proxy(data, conn, proxy, ptype);
250313498266Sopenharmony_ci      Curl_safefree(proxy); /* parse_proxy copies the proxy string */
250413498266Sopenharmony_ci      if(result)
250513498266Sopenharmony_ci        goto out;
250613498266Sopenharmony_ci    }
250713498266Sopenharmony_ci
250813498266Sopenharmony_ci    if(socksproxy) {
250913498266Sopenharmony_ci      result = parse_proxy(data, conn, socksproxy, ptype);
251013498266Sopenharmony_ci      /* parse_proxy copies the socks proxy string */
251113498266Sopenharmony_ci      Curl_safefree(socksproxy);
251213498266Sopenharmony_ci      if(result)
251313498266Sopenharmony_ci        goto out;
251413498266Sopenharmony_ci    }
251513498266Sopenharmony_ci
251613498266Sopenharmony_ci    if(conn->http_proxy.host.rawalloc) {
251713498266Sopenharmony_ci#ifdef CURL_DISABLE_HTTP
251813498266Sopenharmony_ci      /* asking for an HTTP proxy is a bit funny when HTTP is disabled... */
251913498266Sopenharmony_ci      result = CURLE_UNSUPPORTED_PROTOCOL;
252013498266Sopenharmony_ci      goto out;
252113498266Sopenharmony_ci#else
252213498266Sopenharmony_ci      /* force this connection's protocol to become HTTP if compatible */
252313498266Sopenharmony_ci      if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) {
252413498266Sopenharmony_ci        if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) &&
252513498266Sopenharmony_ci           !conn->bits.tunnel_proxy)
252613498266Sopenharmony_ci          conn->handler = &Curl_handler_http;
252713498266Sopenharmony_ci        else
252813498266Sopenharmony_ci          /* if not converting to HTTP over the proxy, enforce tunneling */
252913498266Sopenharmony_ci          conn->bits.tunnel_proxy = TRUE;
253013498266Sopenharmony_ci      }
253113498266Sopenharmony_ci      conn->bits.httpproxy = TRUE;
253213498266Sopenharmony_ci#endif
253313498266Sopenharmony_ci    }
253413498266Sopenharmony_ci    else {
253513498266Sopenharmony_ci      conn->bits.httpproxy = FALSE; /* not an HTTP proxy */
253613498266Sopenharmony_ci      conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
253713498266Sopenharmony_ci    }
253813498266Sopenharmony_ci
253913498266Sopenharmony_ci    if(conn->socks_proxy.host.rawalloc) {
254013498266Sopenharmony_ci      if(!conn->http_proxy.host.rawalloc) {
254113498266Sopenharmony_ci        /* once a socks proxy */
254213498266Sopenharmony_ci        if(!conn->socks_proxy.user) {
254313498266Sopenharmony_ci          conn->socks_proxy.user = conn->http_proxy.user;
254413498266Sopenharmony_ci          conn->http_proxy.user = NULL;
254513498266Sopenharmony_ci          Curl_safefree(conn->socks_proxy.passwd);
254613498266Sopenharmony_ci          conn->socks_proxy.passwd = conn->http_proxy.passwd;
254713498266Sopenharmony_ci          conn->http_proxy.passwd = NULL;
254813498266Sopenharmony_ci        }
254913498266Sopenharmony_ci      }
255013498266Sopenharmony_ci      conn->bits.socksproxy = TRUE;
255113498266Sopenharmony_ci    }
255213498266Sopenharmony_ci    else
255313498266Sopenharmony_ci      conn->bits.socksproxy = FALSE; /* not a socks proxy */
255413498266Sopenharmony_ci  }
255513498266Sopenharmony_ci  else {
255613498266Sopenharmony_ci    conn->bits.socksproxy = FALSE;
255713498266Sopenharmony_ci    conn->bits.httpproxy = FALSE;
255813498266Sopenharmony_ci  }
255913498266Sopenharmony_ci  conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
256013498266Sopenharmony_ci
256113498266Sopenharmony_ci  if(!conn->bits.proxy) {
256213498266Sopenharmony_ci    /* we aren't using the proxy after all... */
256313498266Sopenharmony_ci    conn->bits.proxy = FALSE;
256413498266Sopenharmony_ci    conn->bits.httpproxy = FALSE;
256513498266Sopenharmony_ci    conn->bits.socksproxy = FALSE;
256613498266Sopenharmony_ci    conn->bits.proxy_user_passwd = FALSE;
256713498266Sopenharmony_ci    conn->bits.tunnel_proxy = FALSE;
256813498266Sopenharmony_ci    /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
256913498266Sopenharmony_ci       to signal that CURLPROXY_HTTPS is not used for this connection */
257013498266Sopenharmony_ci    conn->http_proxy.proxytype = CURLPROXY_HTTP;
257113498266Sopenharmony_ci  }
257213498266Sopenharmony_ci
257313498266Sopenharmony_ciout:
257413498266Sopenharmony_ci
257513498266Sopenharmony_ci  free(socksproxy);
257613498266Sopenharmony_ci  free(proxy);
257713498266Sopenharmony_ci  return result;
257813498266Sopenharmony_ci}
257913498266Sopenharmony_ci#endif /* CURL_DISABLE_PROXY */
258013498266Sopenharmony_ci
258113498266Sopenharmony_ci/*
258213498266Sopenharmony_ci * Curl_parse_login_details()
258313498266Sopenharmony_ci *
258413498266Sopenharmony_ci * This is used to parse a login string for user name, password and options in
258513498266Sopenharmony_ci * the following formats:
258613498266Sopenharmony_ci *
258713498266Sopenharmony_ci *   user
258813498266Sopenharmony_ci *   user:password
258913498266Sopenharmony_ci *   user:password;options
259013498266Sopenharmony_ci *   user;options
259113498266Sopenharmony_ci *   user;options:password
259213498266Sopenharmony_ci *   :password
259313498266Sopenharmony_ci *   :password;options
259413498266Sopenharmony_ci *   ;options
259513498266Sopenharmony_ci *   ;options:password
259613498266Sopenharmony_ci *
259713498266Sopenharmony_ci * Parameters:
259813498266Sopenharmony_ci *
259913498266Sopenharmony_ci * login    [in]     - The login string.
260013498266Sopenharmony_ci * len      [in]     - The length of the login string.
260113498266Sopenharmony_ci * userp    [in/out] - The address where a pointer to newly allocated memory
260213498266Sopenharmony_ci *                     holding the user will be stored upon completion.
260313498266Sopenharmony_ci * passwdp  [in/out] - The address where a pointer to newly allocated memory
260413498266Sopenharmony_ci *                     holding the password will be stored upon completion.
260513498266Sopenharmony_ci * optionsp [in/out] - The address where a pointer to newly allocated memory
260613498266Sopenharmony_ci *                     holding the options will be stored upon completion.
260713498266Sopenharmony_ci *
260813498266Sopenharmony_ci * Returns CURLE_OK on success.
260913498266Sopenharmony_ci */
261013498266Sopenharmony_ciCURLcode Curl_parse_login_details(const char *login, const size_t len,
261113498266Sopenharmony_ci                                  char **userp, char **passwdp,
261213498266Sopenharmony_ci                                  char **optionsp)
261313498266Sopenharmony_ci{
261413498266Sopenharmony_ci  CURLcode result = CURLE_OK;
261513498266Sopenharmony_ci  char *ubuf = NULL;
261613498266Sopenharmony_ci  char *pbuf = NULL;
261713498266Sopenharmony_ci  char *obuf = NULL;
261813498266Sopenharmony_ci  const char *psep = NULL;
261913498266Sopenharmony_ci  const char *osep = NULL;
262013498266Sopenharmony_ci  size_t ulen;
262113498266Sopenharmony_ci  size_t plen;
262213498266Sopenharmony_ci  size_t olen;
262313498266Sopenharmony_ci
262413498266Sopenharmony_ci  /* Attempt to find the password separator */
262513498266Sopenharmony_ci  if(passwdp)
262613498266Sopenharmony_ci    psep = memchr(login, ':', len);
262713498266Sopenharmony_ci
262813498266Sopenharmony_ci  /* Attempt to find the options separator */
262913498266Sopenharmony_ci  if(optionsp)
263013498266Sopenharmony_ci    osep = memchr(login, ';', len);
263113498266Sopenharmony_ci
263213498266Sopenharmony_ci  /* Calculate the portion lengths */
263313498266Sopenharmony_ci  ulen = (psep ?
263413498266Sopenharmony_ci          (size_t)(osep && psep > osep ? osep - login : psep - login) :
263513498266Sopenharmony_ci          (osep ? (size_t)(osep - login) : len));
263613498266Sopenharmony_ci  plen = (psep ?
263713498266Sopenharmony_ci          (osep && osep > psep ? (size_t)(osep - psep) :
263813498266Sopenharmony_ci                                 (size_t)(login + len - psep)) - 1 : 0);
263913498266Sopenharmony_ci  olen = (osep ?
264013498266Sopenharmony_ci          (psep && psep > osep ? (size_t)(psep - osep) :
264113498266Sopenharmony_ci                                 (size_t)(login + len - osep)) - 1 : 0);
264213498266Sopenharmony_ci
264313498266Sopenharmony_ci  /* Allocate the user portion buffer, which can be zero length */
264413498266Sopenharmony_ci  if(userp) {
264513498266Sopenharmony_ci    ubuf = malloc(ulen + 1);
264613498266Sopenharmony_ci    if(!ubuf)
264713498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
264813498266Sopenharmony_ci  }
264913498266Sopenharmony_ci
265013498266Sopenharmony_ci  /* Allocate the password portion buffer */
265113498266Sopenharmony_ci  if(!result && passwdp && psep) {
265213498266Sopenharmony_ci    pbuf = malloc(plen + 1);
265313498266Sopenharmony_ci    if(!pbuf) {
265413498266Sopenharmony_ci      free(ubuf);
265513498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
265613498266Sopenharmony_ci    }
265713498266Sopenharmony_ci  }
265813498266Sopenharmony_ci
265913498266Sopenharmony_ci  /* Allocate the options portion buffer */
266013498266Sopenharmony_ci  if(!result && optionsp && olen) {
266113498266Sopenharmony_ci    obuf = malloc(olen + 1);
266213498266Sopenharmony_ci    if(!obuf) {
266313498266Sopenharmony_ci      free(pbuf);
266413498266Sopenharmony_ci      free(ubuf);
266513498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
266613498266Sopenharmony_ci    }
266713498266Sopenharmony_ci  }
266813498266Sopenharmony_ci
266913498266Sopenharmony_ci  if(!result) {
267013498266Sopenharmony_ci    /* Store the user portion if necessary */
267113498266Sopenharmony_ci    if(ubuf) {
267213498266Sopenharmony_ci      memcpy(ubuf, login, ulen);
267313498266Sopenharmony_ci      ubuf[ulen] = '\0';
267413498266Sopenharmony_ci      Curl_safefree(*userp);
267513498266Sopenharmony_ci      *userp = ubuf;
267613498266Sopenharmony_ci    }
267713498266Sopenharmony_ci
267813498266Sopenharmony_ci    /* Store the password portion if necessary */
267913498266Sopenharmony_ci    if(pbuf) {
268013498266Sopenharmony_ci      memcpy(pbuf, psep + 1, plen);
268113498266Sopenharmony_ci      pbuf[plen] = '\0';
268213498266Sopenharmony_ci      Curl_safefree(*passwdp);
268313498266Sopenharmony_ci      *passwdp = pbuf;
268413498266Sopenharmony_ci    }
268513498266Sopenharmony_ci
268613498266Sopenharmony_ci    /* Store the options portion if necessary */
268713498266Sopenharmony_ci    if(obuf) {
268813498266Sopenharmony_ci      memcpy(obuf, osep + 1, olen);
268913498266Sopenharmony_ci      obuf[olen] = '\0';
269013498266Sopenharmony_ci      Curl_safefree(*optionsp);
269113498266Sopenharmony_ci      *optionsp = obuf;
269213498266Sopenharmony_ci    }
269313498266Sopenharmony_ci  }
269413498266Sopenharmony_ci
269513498266Sopenharmony_ci  return result;
269613498266Sopenharmony_ci}
269713498266Sopenharmony_ci
269813498266Sopenharmony_ci/*************************************************************
269913498266Sopenharmony_ci * Figure out the remote port number and fix it in the URL
270013498266Sopenharmony_ci *
270113498266Sopenharmony_ci * No matter if we use a proxy or not, we have to figure out the remote
270213498266Sopenharmony_ci * port number of various reasons.
270313498266Sopenharmony_ci *
270413498266Sopenharmony_ci * The port number embedded in the URL is replaced, if necessary.
270513498266Sopenharmony_ci *************************************************************/
270613498266Sopenharmony_cistatic CURLcode parse_remote_port(struct Curl_easy *data,
270713498266Sopenharmony_ci                                  struct connectdata *conn)
270813498266Sopenharmony_ci{
270913498266Sopenharmony_ci
271013498266Sopenharmony_ci  if(data->set.use_port && data->state.allow_port) {
271113498266Sopenharmony_ci    /* if set, we use this instead of the port possibly given in the URL */
271213498266Sopenharmony_ci    char portbuf[16];
271313498266Sopenharmony_ci    CURLUcode uc;
271413498266Sopenharmony_ci    conn->remote_port = data->set.use_port;
271513498266Sopenharmony_ci    msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port);
271613498266Sopenharmony_ci    uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
271713498266Sopenharmony_ci    if(uc)
271813498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
271913498266Sopenharmony_ci  }
272013498266Sopenharmony_ci
272113498266Sopenharmony_ci  return CURLE_OK;
272213498266Sopenharmony_ci}
272313498266Sopenharmony_ci
272413498266Sopenharmony_ci/*
272513498266Sopenharmony_ci * Override the login details from the URL with that in the CURLOPT_USERPWD
272613498266Sopenharmony_ci * option or a .netrc file, if applicable.
272713498266Sopenharmony_ci */
272813498266Sopenharmony_cistatic CURLcode override_login(struct Curl_easy *data,
272913498266Sopenharmony_ci                               struct connectdata *conn)
273013498266Sopenharmony_ci{
273113498266Sopenharmony_ci  CURLUcode uc;
273213498266Sopenharmony_ci  char **userp = &conn->user;
273313498266Sopenharmony_ci  char **passwdp = &conn->passwd;
273413498266Sopenharmony_ci  char **optionsp = &conn->options;
273513498266Sopenharmony_ci
273613498266Sopenharmony_ci  if(data->set.str[STRING_OPTIONS]) {
273713498266Sopenharmony_ci    free(*optionsp);
273813498266Sopenharmony_ci    *optionsp = strdup(data->set.str[STRING_OPTIONS]);
273913498266Sopenharmony_ci    if(!*optionsp)
274013498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
274113498266Sopenharmony_ci  }
274213498266Sopenharmony_ci
274313498266Sopenharmony_ci#ifndef CURL_DISABLE_NETRC
274413498266Sopenharmony_ci  if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
274513498266Sopenharmony_ci    Curl_safefree(*userp);
274613498266Sopenharmony_ci    Curl_safefree(*passwdp);
274713498266Sopenharmony_ci  }
274813498266Sopenharmony_ci  conn->bits.netrc = FALSE;
274913498266Sopenharmony_ci  if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
275013498266Sopenharmony_ci    int ret;
275113498266Sopenharmony_ci    bool url_provided = FALSE;
275213498266Sopenharmony_ci
275313498266Sopenharmony_ci    if(data->state.aptr.user) {
275413498266Sopenharmony_ci      /* there was a user name in the URL. Use the URL decoded version */
275513498266Sopenharmony_ci      userp = &data->state.aptr.user;
275613498266Sopenharmony_ci      url_provided = TRUE;
275713498266Sopenharmony_ci    }
275813498266Sopenharmony_ci
275913498266Sopenharmony_ci    ret = Curl_parsenetrc(conn->host.name,
276013498266Sopenharmony_ci                          userp, passwdp,
276113498266Sopenharmony_ci                          data->set.str[STRING_NETRC_FILE]);
276213498266Sopenharmony_ci    if(ret > 0) {
276313498266Sopenharmony_ci      infof(data, "Couldn't find host %s in the %s file; using defaults",
276413498266Sopenharmony_ci            conn->host.name,
276513498266Sopenharmony_ci            (data->set.str[STRING_NETRC_FILE] ?
276613498266Sopenharmony_ci             data->set.str[STRING_NETRC_FILE] : ".netrc"));
276713498266Sopenharmony_ci    }
276813498266Sopenharmony_ci    else if(ret < 0) {
276913498266Sopenharmony_ci      failf(data, ".netrc parser error");
277013498266Sopenharmony_ci      return CURLE_READ_ERROR;
277113498266Sopenharmony_ci    }
277213498266Sopenharmony_ci    else {
277313498266Sopenharmony_ci      /* set bits.netrc TRUE to remember that we got the name from a .netrc
277413498266Sopenharmony_ci         file, so that it is safe to use even if we followed a Location: to a
277513498266Sopenharmony_ci         different host or similar. */
277613498266Sopenharmony_ci      conn->bits.netrc = TRUE;
277713498266Sopenharmony_ci    }
277813498266Sopenharmony_ci    if(url_provided) {
277913498266Sopenharmony_ci      Curl_safefree(conn->user);
278013498266Sopenharmony_ci      conn->user = strdup(*userp);
278113498266Sopenharmony_ci      if(!conn->user)
278213498266Sopenharmony_ci        return CURLE_OUT_OF_MEMORY;
278313498266Sopenharmony_ci    }
278413498266Sopenharmony_ci    /* no user was set but a password, set a blank user */
278513498266Sopenharmony_ci    if(!*userp && *passwdp) {
278613498266Sopenharmony_ci      *userp = strdup("");
278713498266Sopenharmony_ci      if(!*userp)
278813498266Sopenharmony_ci        return CURLE_OUT_OF_MEMORY;
278913498266Sopenharmony_ci    }
279013498266Sopenharmony_ci  }
279113498266Sopenharmony_ci#endif
279213498266Sopenharmony_ci
279313498266Sopenharmony_ci  /* for updated strings, we update them in the URL */
279413498266Sopenharmony_ci  if(*userp) {
279513498266Sopenharmony_ci    CURLcode result;
279613498266Sopenharmony_ci    if(data->state.aptr.user != *userp) {
279713498266Sopenharmony_ci      /* nothing to do then */
279813498266Sopenharmony_ci      result = Curl_setstropt(&data->state.aptr.user, *userp);
279913498266Sopenharmony_ci      if(result)
280013498266Sopenharmony_ci        return result;
280113498266Sopenharmony_ci    }
280213498266Sopenharmony_ci  }
280313498266Sopenharmony_ci  if(data->state.aptr.user) {
280413498266Sopenharmony_ci    uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
280513498266Sopenharmony_ci                      CURLU_URLENCODE);
280613498266Sopenharmony_ci    if(uc)
280713498266Sopenharmony_ci      return Curl_uc_to_curlcode(uc);
280813498266Sopenharmony_ci    if(!*userp) {
280913498266Sopenharmony_ci      *userp = strdup(data->state.aptr.user);
281013498266Sopenharmony_ci      if(!*userp)
281113498266Sopenharmony_ci        return CURLE_OUT_OF_MEMORY;
281213498266Sopenharmony_ci    }
281313498266Sopenharmony_ci  }
281413498266Sopenharmony_ci  if(*passwdp) {
281513498266Sopenharmony_ci    CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
281613498266Sopenharmony_ci    if(result)
281713498266Sopenharmony_ci      return result;
281813498266Sopenharmony_ci  }
281913498266Sopenharmony_ci  if(data->state.aptr.passwd) {
282013498266Sopenharmony_ci    uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
282113498266Sopenharmony_ci                      data->state.aptr.passwd, CURLU_URLENCODE);
282213498266Sopenharmony_ci    if(uc)
282313498266Sopenharmony_ci      return Curl_uc_to_curlcode(uc);
282413498266Sopenharmony_ci    if(!*passwdp) {
282513498266Sopenharmony_ci      *passwdp = strdup(data->state.aptr.passwd);
282613498266Sopenharmony_ci      if(!*passwdp)
282713498266Sopenharmony_ci        return CURLE_OUT_OF_MEMORY;
282813498266Sopenharmony_ci    }
282913498266Sopenharmony_ci  }
283013498266Sopenharmony_ci
283113498266Sopenharmony_ci  return CURLE_OK;
283213498266Sopenharmony_ci}
283313498266Sopenharmony_ci
283413498266Sopenharmony_ci/*
283513498266Sopenharmony_ci * Set the login details so they're available in the connection
283613498266Sopenharmony_ci */
283713498266Sopenharmony_cistatic CURLcode set_login(struct Curl_easy *data,
283813498266Sopenharmony_ci                          struct connectdata *conn)
283913498266Sopenharmony_ci{
284013498266Sopenharmony_ci  CURLcode result = CURLE_OK;
284113498266Sopenharmony_ci  const char *setuser = CURL_DEFAULT_USER;
284213498266Sopenharmony_ci  const char *setpasswd = CURL_DEFAULT_PASSWORD;
284313498266Sopenharmony_ci
284413498266Sopenharmony_ci  /* If our protocol needs a password and we have none, use the defaults */
284513498266Sopenharmony_ci  if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user)
284613498266Sopenharmony_ci    ;
284713498266Sopenharmony_ci  else {
284813498266Sopenharmony_ci    setuser = "";
284913498266Sopenharmony_ci    setpasswd = "";
285013498266Sopenharmony_ci  }
285113498266Sopenharmony_ci  /* Store the default user */
285213498266Sopenharmony_ci  if(!conn->user) {
285313498266Sopenharmony_ci    conn->user = strdup(setuser);
285413498266Sopenharmony_ci    if(!conn->user)
285513498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
285613498266Sopenharmony_ci  }
285713498266Sopenharmony_ci
285813498266Sopenharmony_ci  /* Store the default password */
285913498266Sopenharmony_ci  if(!conn->passwd) {
286013498266Sopenharmony_ci    conn->passwd = strdup(setpasswd);
286113498266Sopenharmony_ci    if(!conn->passwd)
286213498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
286313498266Sopenharmony_ci  }
286413498266Sopenharmony_ci
286513498266Sopenharmony_ci  return result;
286613498266Sopenharmony_ci}
286713498266Sopenharmony_ci
286813498266Sopenharmony_ci/*
286913498266Sopenharmony_ci * Parses a "host:port" string to connect to.
287013498266Sopenharmony_ci * The hostname and the port may be empty; in this case, NULL is returned for
287113498266Sopenharmony_ci * the hostname and -1 for the port.
287213498266Sopenharmony_ci */
287313498266Sopenharmony_cistatic CURLcode parse_connect_to_host_port(struct Curl_easy *data,
287413498266Sopenharmony_ci                                           const char *host,
287513498266Sopenharmony_ci                                           char **hostname_result,
287613498266Sopenharmony_ci                                           int *port_result)
287713498266Sopenharmony_ci{
287813498266Sopenharmony_ci  char *host_dup;
287913498266Sopenharmony_ci  char *hostptr;
288013498266Sopenharmony_ci  char *host_portno;
288113498266Sopenharmony_ci  char *portptr;
288213498266Sopenharmony_ci  int port = -1;
288313498266Sopenharmony_ci  CURLcode result = CURLE_OK;
288413498266Sopenharmony_ci
288513498266Sopenharmony_ci#if defined(CURL_DISABLE_VERBOSE_STRINGS)
288613498266Sopenharmony_ci  (void) data;
288713498266Sopenharmony_ci#endif
288813498266Sopenharmony_ci
288913498266Sopenharmony_ci  *hostname_result = NULL;
289013498266Sopenharmony_ci  *port_result = -1;
289113498266Sopenharmony_ci
289213498266Sopenharmony_ci  if(!host || !*host)
289313498266Sopenharmony_ci    return CURLE_OK;
289413498266Sopenharmony_ci
289513498266Sopenharmony_ci  host_dup = strdup(host);
289613498266Sopenharmony_ci  if(!host_dup)
289713498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
289813498266Sopenharmony_ci
289913498266Sopenharmony_ci  hostptr = host_dup;
290013498266Sopenharmony_ci
290113498266Sopenharmony_ci  /* start scanning for port number at this point */
290213498266Sopenharmony_ci  portptr = hostptr;
290313498266Sopenharmony_ci
290413498266Sopenharmony_ci  /* detect and extract RFC6874-style IPv6-addresses */
290513498266Sopenharmony_ci  if(*hostptr == '[') {
290613498266Sopenharmony_ci#ifdef ENABLE_IPV6
290713498266Sopenharmony_ci    char *ptr = ++hostptr; /* advance beyond the initial bracket */
290813498266Sopenharmony_ci    while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
290913498266Sopenharmony_ci      ptr++;
291013498266Sopenharmony_ci    if(*ptr == '%') {
291113498266Sopenharmony_ci      /* There might be a zone identifier */
291213498266Sopenharmony_ci      if(strncmp("%25", ptr, 3))
291313498266Sopenharmony_ci        infof(data, "Please URL encode %% as %%25, see RFC 6874.");
291413498266Sopenharmony_ci      ptr++;
291513498266Sopenharmony_ci      /* Allow unreserved characters as defined in RFC 3986 */
291613498266Sopenharmony_ci      while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
291713498266Sopenharmony_ci                     (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
291813498266Sopenharmony_ci        ptr++;
291913498266Sopenharmony_ci    }
292013498266Sopenharmony_ci    if(*ptr == ']')
292113498266Sopenharmony_ci      /* yeps, it ended nicely with a bracket as well */
292213498266Sopenharmony_ci      *ptr++ = '\0';
292313498266Sopenharmony_ci    else
292413498266Sopenharmony_ci      infof(data, "Invalid IPv6 address format");
292513498266Sopenharmony_ci    portptr = ptr;
292613498266Sopenharmony_ci    /* Note that if this didn't end with a bracket, we still advanced the
292713498266Sopenharmony_ci     * hostptr first, but I can't see anything wrong with that as no host
292813498266Sopenharmony_ci     * name nor a numeric can legally start with a bracket.
292913498266Sopenharmony_ci     */
293013498266Sopenharmony_ci#else
293113498266Sopenharmony_ci    failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
293213498266Sopenharmony_ci    result = CURLE_NOT_BUILT_IN;
293313498266Sopenharmony_ci    goto error;
293413498266Sopenharmony_ci#endif
293513498266Sopenharmony_ci  }
293613498266Sopenharmony_ci
293713498266Sopenharmony_ci  /* Get port number off server.com:1080 */
293813498266Sopenharmony_ci  host_portno = strchr(portptr, ':');
293913498266Sopenharmony_ci  if(host_portno) {
294013498266Sopenharmony_ci    char *endp = NULL;
294113498266Sopenharmony_ci    *host_portno = '\0'; /* cut off number from host name */
294213498266Sopenharmony_ci    host_portno++;
294313498266Sopenharmony_ci    if(*host_portno) {
294413498266Sopenharmony_ci      long portparse = strtol(host_portno, &endp, 10);
294513498266Sopenharmony_ci      if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
294613498266Sopenharmony_ci        failf(data, "No valid port number in connect to host string (%s)",
294713498266Sopenharmony_ci              host_portno);
294813498266Sopenharmony_ci        result = CURLE_SETOPT_OPTION_SYNTAX;
294913498266Sopenharmony_ci        goto error;
295013498266Sopenharmony_ci      }
295113498266Sopenharmony_ci      else
295213498266Sopenharmony_ci        port = (int)portparse; /* we know it will fit */
295313498266Sopenharmony_ci    }
295413498266Sopenharmony_ci  }
295513498266Sopenharmony_ci
295613498266Sopenharmony_ci  /* now, clone the cleaned host name */
295713498266Sopenharmony_ci  DEBUGASSERT(hostptr);
295813498266Sopenharmony_ci  *hostname_result = strdup(hostptr);
295913498266Sopenharmony_ci  if(!*hostname_result) {
296013498266Sopenharmony_ci    result = CURLE_OUT_OF_MEMORY;
296113498266Sopenharmony_ci    goto error;
296213498266Sopenharmony_ci  }
296313498266Sopenharmony_ci
296413498266Sopenharmony_ci  *port_result = port;
296513498266Sopenharmony_ci
296613498266Sopenharmony_cierror:
296713498266Sopenharmony_ci  free(host_dup);
296813498266Sopenharmony_ci  return result;
296913498266Sopenharmony_ci}
297013498266Sopenharmony_ci
297113498266Sopenharmony_ci/*
297213498266Sopenharmony_ci * Parses one "connect to" string in the form:
297313498266Sopenharmony_ci * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
297413498266Sopenharmony_ci */
297513498266Sopenharmony_cistatic CURLcode parse_connect_to_string(struct Curl_easy *data,
297613498266Sopenharmony_ci                                        struct connectdata *conn,
297713498266Sopenharmony_ci                                        const char *conn_to_host,
297813498266Sopenharmony_ci                                        char **host_result,
297913498266Sopenharmony_ci                                        int *port_result)
298013498266Sopenharmony_ci{
298113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
298213498266Sopenharmony_ci  const char *ptr = conn_to_host;
298313498266Sopenharmony_ci  int host_match = FALSE;
298413498266Sopenharmony_ci  int port_match = FALSE;
298513498266Sopenharmony_ci
298613498266Sopenharmony_ci  *host_result = NULL;
298713498266Sopenharmony_ci  *port_result = -1;
298813498266Sopenharmony_ci
298913498266Sopenharmony_ci  if(*ptr == ':') {
299013498266Sopenharmony_ci    /* an empty hostname always matches */
299113498266Sopenharmony_ci    host_match = TRUE;
299213498266Sopenharmony_ci    ptr++;
299313498266Sopenharmony_ci  }
299413498266Sopenharmony_ci  else {
299513498266Sopenharmony_ci    /* check whether the URL's hostname matches */
299613498266Sopenharmony_ci    size_t hostname_to_match_len;
299713498266Sopenharmony_ci    char *hostname_to_match = aprintf("%s%s%s",
299813498266Sopenharmony_ci                                      conn->bits.ipv6_ip ? "[" : "",
299913498266Sopenharmony_ci                                      conn->host.name,
300013498266Sopenharmony_ci                                      conn->bits.ipv6_ip ? "]" : "");
300113498266Sopenharmony_ci    if(!hostname_to_match)
300213498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
300313498266Sopenharmony_ci    hostname_to_match_len = strlen(hostname_to_match);
300413498266Sopenharmony_ci    host_match = strncasecompare(ptr, hostname_to_match,
300513498266Sopenharmony_ci                                 hostname_to_match_len);
300613498266Sopenharmony_ci    free(hostname_to_match);
300713498266Sopenharmony_ci    ptr += hostname_to_match_len;
300813498266Sopenharmony_ci
300913498266Sopenharmony_ci    host_match = host_match && *ptr == ':';
301013498266Sopenharmony_ci    ptr++;
301113498266Sopenharmony_ci  }
301213498266Sopenharmony_ci
301313498266Sopenharmony_ci  if(host_match) {
301413498266Sopenharmony_ci    if(*ptr == ':') {
301513498266Sopenharmony_ci      /* an empty port always matches */
301613498266Sopenharmony_ci      port_match = TRUE;
301713498266Sopenharmony_ci      ptr++;
301813498266Sopenharmony_ci    }
301913498266Sopenharmony_ci    else {
302013498266Sopenharmony_ci      /* check whether the URL's port matches */
302113498266Sopenharmony_ci      char *ptr_next = strchr(ptr, ':');
302213498266Sopenharmony_ci      if(ptr_next) {
302313498266Sopenharmony_ci        char *endp = NULL;
302413498266Sopenharmony_ci        long port_to_match = strtol(ptr, &endp, 10);
302513498266Sopenharmony_ci        if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
302613498266Sopenharmony_ci          port_match = TRUE;
302713498266Sopenharmony_ci          ptr = ptr_next + 1;
302813498266Sopenharmony_ci        }
302913498266Sopenharmony_ci      }
303013498266Sopenharmony_ci    }
303113498266Sopenharmony_ci  }
303213498266Sopenharmony_ci
303313498266Sopenharmony_ci  if(host_match && port_match) {
303413498266Sopenharmony_ci    /* parse the hostname and port to connect to */
303513498266Sopenharmony_ci    result = parse_connect_to_host_port(data, ptr, host_result, port_result);
303613498266Sopenharmony_ci  }
303713498266Sopenharmony_ci
303813498266Sopenharmony_ci  return result;
303913498266Sopenharmony_ci}
304013498266Sopenharmony_ci
304113498266Sopenharmony_ci/*
304213498266Sopenharmony_ci * Processes all strings in the "connect to" slist, and uses the "connect
304313498266Sopenharmony_ci * to host" and "connect to port" of the first string that matches.
304413498266Sopenharmony_ci */
304513498266Sopenharmony_cistatic CURLcode parse_connect_to_slist(struct Curl_easy *data,
304613498266Sopenharmony_ci                                       struct connectdata *conn,
304713498266Sopenharmony_ci                                       struct curl_slist *conn_to_host)
304813498266Sopenharmony_ci{
304913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
305013498266Sopenharmony_ci  char *host = NULL;
305113498266Sopenharmony_ci  int port = -1;
305213498266Sopenharmony_ci
305313498266Sopenharmony_ci  while(conn_to_host && !host && port == -1) {
305413498266Sopenharmony_ci    result = parse_connect_to_string(data, conn, conn_to_host->data,
305513498266Sopenharmony_ci                                     &host, &port);
305613498266Sopenharmony_ci    if(result)
305713498266Sopenharmony_ci      return result;
305813498266Sopenharmony_ci
305913498266Sopenharmony_ci    if(host && *host) {
306013498266Sopenharmony_ci      conn->conn_to_host.rawalloc = host;
306113498266Sopenharmony_ci      conn->conn_to_host.name = host;
306213498266Sopenharmony_ci      conn->bits.conn_to_host = TRUE;
306313498266Sopenharmony_ci
306413498266Sopenharmony_ci      infof(data, "Connecting to hostname: %s", host);
306513498266Sopenharmony_ci    }
306613498266Sopenharmony_ci    else {
306713498266Sopenharmony_ci      /* no "connect to host" */
306813498266Sopenharmony_ci      conn->bits.conn_to_host = FALSE;
306913498266Sopenharmony_ci      Curl_safefree(host);
307013498266Sopenharmony_ci    }
307113498266Sopenharmony_ci
307213498266Sopenharmony_ci    if(port >= 0) {
307313498266Sopenharmony_ci      conn->conn_to_port = port;
307413498266Sopenharmony_ci      conn->bits.conn_to_port = TRUE;
307513498266Sopenharmony_ci      infof(data, "Connecting to port: %d", port);
307613498266Sopenharmony_ci    }
307713498266Sopenharmony_ci    else {
307813498266Sopenharmony_ci      /* no "connect to port" */
307913498266Sopenharmony_ci      conn->bits.conn_to_port = FALSE;
308013498266Sopenharmony_ci      port = -1;
308113498266Sopenharmony_ci    }
308213498266Sopenharmony_ci
308313498266Sopenharmony_ci    conn_to_host = conn_to_host->next;
308413498266Sopenharmony_ci  }
308513498266Sopenharmony_ci
308613498266Sopenharmony_ci#ifndef CURL_DISABLE_ALTSVC
308713498266Sopenharmony_ci  if(data->asi && !host && (port == -1) &&
308813498266Sopenharmony_ci     ((conn->handler->protocol == CURLPROTO_HTTPS) ||
308913498266Sopenharmony_ci#ifdef CURLDEBUG
309013498266Sopenharmony_ci      /* allow debug builds to circumvent the HTTPS restriction */
309113498266Sopenharmony_ci      getenv("CURL_ALTSVC_HTTP")
309213498266Sopenharmony_ci#else
309313498266Sopenharmony_ci      0
309413498266Sopenharmony_ci#endif
309513498266Sopenharmony_ci       )) {
309613498266Sopenharmony_ci    /* no connect_to match, try alt-svc! */
309713498266Sopenharmony_ci    enum alpnid srcalpnid;
309813498266Sopenharmony_ci    bool hit;
309913498266Sopenharmony_ci    struct altsvc *as;
310013498266Sopenharmony_ci    const int allowed_versions = ( ALPN_h1
310113498266Sopenharmony_ci#ifdef USE_HTTP2
310213498266Sopenharmony_ci                                   | ALPN_h2
310313498266Sopenharmony_ci#endif
310413498266Sopenharmony_ci#ifdef ENABLE_QUIC
310513498266Sopenharmony_ci                                   | ALPN_h3
310613498266Sopenharmony_ci#endif
310713498266Sopenharmony_ci      ) & data->asi->flags;
310813498266Sopenharmony_ci
310913498266Sopenharmony_ci    host = conn->host.rawalloc;
311013498266Sopenharmony_ci#ifdef USE_HTTP2
311113498266Sopenharmony_ci    /* with h2 support, check that first */
311213498266Sopenharmony_ci    srcalpnid = ALPN_h2;
311313498266Sopenharmony_ci    hit = Curl_altsvc_lookup(data->asi,
311413498266Sopenharmony_ci                             srcalpnid, host, conn->remote_port, /* from */
311513498266Sopenharmony_ci                             &as /* to */,
311613498266Sopenharmony_ci                             allowed_versions);
311713498266Sopenharmony_ci    if(!hit)
311813498266Sopenharmony_ci#endif
311913498266Sopenharmony_ci    {
312013498266Sopenharmony_ci      srcalpnid = ALPN_h1;
312113498266Sopenharmony_ci      hit = Curl_altsvc_lookup(data->asi,
312213498266Sopenharmony_ci                               srcalpnid, host, conn->remote_port, /* from */
312313498266Sopenharmony_ci                               &as /* to */,
312413498266Sopenharmony_ci                               allowed_versions);
312513498266Sopenharmony_ci    }
312613498266Sopenharmony_ci    if(hit) {
312713498266Sopenharmony_ci      char *hostd = strdup((char *)as->dst.host);
312813498266Sopenharmony_ci      if(!hostd)
312913498266Sopenharmony_ci        return CURLE_OUT_OF_MEMORY;
313013498266Sopenharmony_ci      conn->conn_to_host.rawalloc = hostd;
313113498266Sopenharmony_ci      conn->conn_to_host.name = hostd;
313213498266Sopenharmony_ci      conn->bits.conn_to_host = TRUE;
313313498266Sopenharmony_ci      conn->conn_to_port = as->dst.port;
313413498266Sopenharmony_ci      conn->bits.conn_to_port = TRUE;
313513498266Sopenharmony_ci      conn->bits.altused = TRUE;
313613498266Sopenharmony_ci      infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d",
313713498266Sopenharmony_ci            Curl_alpnid2str(srcalpnid), host, conn->remote_port,
313813498266Sopenharmony_ci            Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
313913498266Sopenharmony_ci      if(srcalpnid != as->dst.alpnid) {
314013498266Sopenharmony_ci        /* protocol version switch */
314113498266Sopenharmony_ci        switch(as->dst.alpnid) {
314213498266Sopenharmony_ci        case ALPN_h1:
314313498266Sopenharmony_ci          conn->httpversion = 11;
314413498266Sopenharmony_ci          break;
314513498266Sopenharmony_ci        case ALPN_h2:
314613498266Sopenharmony_ci          conn->httpversion = 20;
314713498266Sopenharmony_ci          break;
314813498266Sopenharmony_ci        case ALPN_h3:
314913498266Sopenharmony_ci          conn->transport = TRNSPRT_QUIC;
315013498266Sopenharmony_ci          conn->httpversion = 30;
315113498266Sopenharmony_ci          break;
315213498266Sopenharmony_ci        default: /* shouldn't be possible */
315313498266Sopenharmony_ci          break;
315413498266Sopenharmony_ci        }
315513498266Sopenharmony_ci      }
315613498266Sopenharmony_ci    }
315713498266Sopenharmony_ci  }
315813498266Sopenharmony_ci#endif
315913498266Sopenharmony_ci
316013498266Sopenharmony_ci  return result;
316113498266Sopenharmony_ci}
316213498266Sopenharmony_ci
316313498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
316413498266Sopenharmony_cistatic CURLcode resolve_unix(struct Curl_easy *data,
316513498266Sopenharmony_ci                             struct connectdata *conn,
316613498266Sopenharmony_ci                             char *unix_path)
316713498266Sopenharmony_ci{
316813498266Sopenharmony_ci  struct Curl_dns_entry *hostaddr = NULL;
316913498266Sopenharmony_ci  bool longpath = FALSE;
317013498266Sopenharmony_ci
317113498266Sopenharmony_ci  DEBUGASSERT(unix_path);
317213498266Sopenharmony_ci  DEBUGASSERT(conn->dns_entry == NULL);
317313498266Sopenharmony_ci
317413498266Sopenharmony_ci  /* Unix domain sockets are local. The host gets ignored, just use the
317513498266Sopenharmony_ci   * specified domain socket address. Do not cache "DNS entries". There is
317613498266Sopenharmony_ci   * no DNS involved and we already have the filesystem path available. */
317713498266Sopenharmony_ci  hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
317813498266Sopenharmony_ci  if(!hostaddr)
317913498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
318013498266Sopenharmony_ci
318113498266Sopenharmony_ci  hostaddr->addr = Curl_unix2addr(unix_path, &longpath,
318213498266Sopenharmony_ci                                  conn->bits.abstract_unix_socket);
318313498266Sopenharmony_ci  if(!hostaddr->addr) {
318413498266Sopenharmony_ci    if(longpath)
318513498266Sopenharmony_ci      /* Long paths are not supported for now */
318613498266Sopenharmony_ci      failf(data, "Unix socket path too long: '%s'", unix_path);
318713498266Sopenharmony_ci    free(hostaddr);
318813498266Sopenharmony_ci    return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY;
318913498266Sopenharmony_ci  }
319013498266Sopenharmony_ci
319113498266Sopenharmony_ci  hostaddr->inuse++;
319213498266Sopenharmony_ci  conn->dns_entry = hostaddr;
319313498266Sopenharmony_ci  return CURLE_OK;
319413498266Sopenharmony_ci}
319513498266Sopenharmony_ci#endif
319613498266Sopenharmony_ci
319713498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
319813498266Sopenharmony_cistatic CURLcode resolve_proxy(struct Curl_easy *data,
319913498266Sopenharmony_ci                              struct connectdata *conn,
320013498266Sopenharmony_ci                              bool *async)
320113498266Sopenharmony_ci{
320213498266Sopenharmony_ci  struct Curl_dns_entry *hostaddr = NULL;
320313498266Sopenharmony_ci  struct hostname *host;
320413498266Sopenharmony_ci  timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
320513498266Sopenharmony_ci  int rc;
320613498266Sopenharmony_ci
320713498266Sopenharmony_ci  DEBUGASSERT(conn->dns_entry == NULL);
320813498266Sopenharmony_ci
320913498266Sopenharmony_ci  host = conn->bits.socksproxy ? &conn->socks_proxy.host :
321013498266Sopenharmony_ci    &conn->http_proxy.host;
321113498266Sopenharmony_ci
321213498266Sopenharmony_ci  conn->hostname_resolve = strdup(host->name);
321313498266Sopenharmony_ci  if(!conn->hostname_resolve)
321413498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
321513498266Sopenharmony_ci
321613498266Sopenharmony_ci  rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
321713498266Sopenharmony_ci                           &hostaddr, timeout_ms);
321813498266Sopenharmony_ci  conn->dns_entry = hostaddr;
321913498266Sopenharmony_ci  if(rc == CURLRESOLV_PENDING)
322013498266Sopenharmony_ci    *async = TRUE;
322113498266Sopenharmony_ci  else if(rc == CURLRESOLV_TIMEDOUT)
322213498266Sopenharmony_ci    return CURLE_OPERATION_TIMEDOUT;
322313498266Sopenharmony_ci  else if(!hostaddr) {
322413498266Sopenharmony_ci    failf(data, "Couldn't resolve proxy '%s'", host->dispname);
322513498266Sopenharmony_ci    return CURLE_COULDNT_RESOLVE_PROXY;
322613498266Sopenharmony_ci  }
322713498266Sopenharmony_ci
322813498266Sopenharmony_ci  return CURLE_OK;
322913498266Sopenharmony_ci}
323013498266Sopenharmony_ci#endif
323113498266Sopenharmony_ci
323213498266Sopenharmony_cistatic CURLcode resolve_host(struct Curl_easy *data,
323313498266Sopenharmony_ci                             struct connectdata *conn,
323413498266Sopenharmony_ci                             bool *async)
323513498266Sopenharmony_ci{
323613498266Sopenharmony_ci  struct Curl_dns_entry *hostaddr = NULL;
323713498266Sopenharmony_ci  struct hostname *connhost;
323813498266Sopenharmony_ci  timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
323913498266Sopenharmony_ci  int rc;
324013498266Sopenharmony_ci
324113498266Sopenharmony_ci  DEBUGASSERT(conn->dns_entry == NULL);
324213498266Sopenharmony_ci
324313498266Sopenharmony_ci  connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
324413498266Sopenharmony_ci
324513498266Sopenharmony_ci  /* If not connecting via a proxy, extract the port from the URL, if it is
324613498266Sopenharmony_ci   * there, thus overriding any defaults that might have been set above. */
324713498266Sopenharmony_ci  conn->port = conn->bits.conn_to_port ? conn->conn_to_port :
324813498266Sopenharmony_ci    conn->remote_port;
324913498266Sopenharmony_ci
325013498266Sopenharmony_ci  /* Resolve target host right on */
325113498266Sopenharmony_ci  conn->hostname_resolve = strdup(connhost->name);
325213498266Sopenharmony_ci  if(!conn->hostname_resolve)
325313498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
325413498266Sopenharmony_ci
325513498266Sopenharmony_ci  rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
325613498266Sopenharmony_ci                           &hostaddr, timeout_ms);
325713498266Sopenharmony_ci  conn->dns_entry = hostaddr;
325813498266Sopenharmony_ci  if(rc == CURLRESOLV_PENDING)
325913498266Sopenharmony_ci    *async = TRUE;
326013498266Sopenharmony_ci  else if(rc == CURLRESOLV_TIMEDOUT) {
326113498266Sopenharmony_ci    failf(data, "Failed to resolve host '%s' with timeout after %"
326213498266Sopenharmony_ci          CURL_FORMAT_TIMEDIFF_T " ms", connhost->dispname,
326313498266Sopenharmony_ci          Curl_timediff(Curl_now(), data->progress.t_startsingle));
326413498266Sopenharmony_ci    return CURLE_OPERATION_TIMEDOUT;
326513498266Sopenharmony_ci  }
326613498266Sopenharmony_ci  else if(!hostaddr) {
326713498266Sopenharmony_ci    failf(data, "Could not resolve host: %s", connhost->dispname);
326813498266Sopenharmony_ci    return CURLE_COULDNT_RESOLVE_HOST;
326913498266Sopenharmony_ci  }
327013498266Sopenharmony_ci
327113498266Sopenharmony_ci  return CURLE_OK;
327213498266Sopenharmony_ci}
327313498266Sopenharmony_ci
327413498266Sopenharmony_ci/* Perform a fresh resolve */
327513498266Sopenharmony_cistatic CURLcode resolve_fresh(struct Curl_easy *data,
327613498266Sopenharmony_ci                              struct connectdata *conn,
327713498266Sopenharmony_ci                              bool *async)
327813498266Sopenharmony_ci{
327913498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
328013498266Sopenharmony_ci  char *unix_path = conn->unix_domain_socket;
328113498266Sopenharmony_ci
328213498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
328313498266Sopenharmony_ci  if(!unix_path && conn->socks_proxy.host.name &&
328413498266Sopenharmony_ci     !strncmp(UNIX_SOCKET_PREFIX"/",
328513498266Sopenharmony_ci              conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
328613498266Sopenharmony_ci    unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
328713498266Sopenharmony_ci#endif
328813498266Sopenharmony_ci
328913498266Sopenharmony_ci  if(unix_path) {
329013498266Sopenharmony_ci    conn->transport = TRNSPRT_UNIX;
329113498266Sopenharmony_ci    return resolve_unix(data, conn, unix_path);
329213498266Sopenharmony_ci  }
329313498266Sopenharmony_ci#endif
329413498266Sopenharmony_ci
329513498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
329613498266Sopenharmony_ci  if(CONN_IS_PROXIED(conn))
329713498266Sopenharmony_ci    return resolve_proxy(data, conn, async);
329813498266Sopenharmony_ci#endif
329913498266Sopenharmony_ci
330013498266Sopenharmony_ci  return resolve_host(data, conn, async);
330113498266Sopenharmony_ci}
330213498266Sopenharmony_ci
330313498266Sopenharmony_ci/*************************************************************
330413498266Sopenharmony_ci * Resolve the address of the server or proxy
330513498266Sopenharmony_ci *************************************************************/
330613498266Sopenharmony_cistatic CURLcode resolve_server(struct Curl_easy *data,
330713498266Sopenharmony_ci                               struct connectdata *conn,
330813498266Sopenharmony_ci                               bool *async)
330913498266Sopenharmony_ci{
331013498266Sopenharmony_ci  DEBUGASSERT(conn);
331113498266Sopenharmony_ci  DEBUGASSERT(data);
331213498266Sopenharmony_ci
331313498266Sopenharmony_ci  /* Resolve the name of the server or proxy */
331413498266Sopenharmony_ci  if(conn->bits.reuse) {
331513498266Sopenharmony_ci    /* We're reusing the connection - no need to resolve anything, and
331613498266Sopenharmony_ci       idnconvert_hostname() was called already in create_conn() for the reuse
331713498266Sopenharmony_ci       case. */
331813498266Sopenharmony_ci    *async = FALSE;
331913498266Sopenharmony_ci    return CURLE_OK;
332013498266Sopenharmony_ci  }
332113498266Sopenharmony_ci
332213498266Sopenharmony_ci  return resolve_fresh(data, conn, async);
332313498266Sopenharmony_ci}
332413498266Sopenharmony_ci
332513498266Sopenharmony_ci/*
332613498266Sopenharmony_ci * Cleanup the connection `temp`, just allocated for `data`, before using the
332713498266Sopenharmony_ci * previously `existing` one for `data`.  All relevant info is copied over
332813498266Sopenharmony_ci * and `temp` is freed.
332913498266Sopenharmony_ci */
333013498266Sopenharmony_cistatic void reuse_conn(struct Curl_easy *data,
333113498266Sopenharmony_ci                       struct connectdata *temp,
333213498266Sopenharmony_ci                       struct connectdata *existing)
333313498266Sopenharmony_ci{
333413498266Sopenharmony_ci  /* get the user+password information from the temp struct since it may
333513498266Sopenharmony_ci   * be new for this request even when we reuse an existing connection */
333613498266Sopenharmony_ci  if(temp->user) {
333713498266Sopenharmony_ci    /* use the new user name and password though */
333813498266Sopenharmony_ci    Curl_safefree(existing->user);
333913498266Sopenharmony_ci    Curl_safefree(existing->passwd);
334013498266Sopenharmony_ci    existing->user = temp->user;
334113498266Sopenharmony_ci    existing->passwd = temp->passwd;
334213498266Sopenharmony_ci    temp->user = NULL;
334313498266Sopenharmony_ci    temp->passwd = NULL;
334413498266Sopenharmony_ci  }
334513498266Sopenharmony_ci
334613498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
334713498266Sopenharmony_ci  existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
334813498266Sopenharmony_ci  if(existing->bits.proxy_user_passwd) {
334913498266Sopenharmony_ci    /* use the new proxy user name and proxy password though */
335013498266Sopenharmony_ci    Curl_safefree(existing->http_proxy.user);
335113498266Sopenharmony_ci    Curl_safefree(existing->socks_proxy.user);
335213498266Sopenharmony_ci    Curl_safefree(existing->http_proxy.passwd);
335313498266Sopenharmony_ci    Curl_safefree(existing->socks_proxy.passwd);
335413498266Sopenharmony_ci    existing->http_proxy.user = temp->http_proxy.user;
335513498266Sopenharmony_ci    existing->socks_proxy.user = temp->socks_proxy.user;
335613498266Sopenharmony_ci    existing->http_proxy.passwd = temp->http_proxy.passwd;
335713498266Sopenharmony_ci    existing->socks_proxy.passwd = temp->socks_proxy.passwd;
335813498266Sopenharmony_ci    temp->http_proxy.user = NULL;
335913498266Sopenharmony_ci    temp->socks_proxy.user = NULL;
336013498266Sopenharmony_ci    temp->http_proxy.passwd = NULL;
336113498266Sopenharmony_ci    temp->socks_proxy.passwd = NULL;
336213498266Sopenharmony_ci  }
336313498266Sopenharmony_ci#endif
336413498266Sopenharmony_ci
336513498266Sopenharmony_ci  /* Finding a connection for reuse in the cache matches, among other
336613498266Sopenharmony_ci   * things on the "remote-relevant" hostname. This is not necessarily
336713498266Sopenharmony_ci   * the authority of the URL, e.g. conn->host. For example:
336813498266Sopenharmony_ci   * - we use a proxy (not tunneling). we want to send all requests
336913498266Sopenharmony_ci   *   that use the same proxy on this connection.
337013498266Sopenharmony_ci   * - we have a "connect-to" setting that may redirect the hostname of
337113498266Sopenharmony_ci   *   a new request to the same remote endpoint of an existing conn.
337213498266Sopenharmony_ci   *   We want to reuse an existing conn to the remote endpoint.
337313498266Sopenharmony_ci   * Since connection reuse does not match on conn->host necessarily, we
337413498266Sopenharmony_ci   * switch `existing` conn to `temp` conn's host settings.
337513498266Sopenharmony_ci   * TODO: is this correct in the case of TLS connections that have
337613498266Sopenharmony_ci   *       used the original hostname in SNI to negotiate? Do we send
337713498266Sopenharmony_ci   *       requests for another host through the different SNI?
337813498266Sopenharmony_ci   */
337913498266Sopenharmony_ci  Curl_free_idnconverted_hostname(&existing->host);
338013498266Sopenharmony_ci  Curl_free_idnconverted_hostname(&existing->conn_to_host);
338113498266Sopenharmony_ci  Curl_safefree(existing->host.rawalloc);
338213498266Sopenharmony_ci  Curl_safefree(existing->conn_to_host.rawalloc);
338313498266Sopenharmony_ci  existing->host = temp->host;
338413498266Sopenharmony_ci  temp->host.rawalloc = NULL;
338513498266Sopenharmony_ci  temp->host.encalloc = NULL;
338613498266Sopenharmony_ci  existing->conn_to_host = temp->conn_to_host;
338713498266Sopenharmony_ci  temp->conn_to_host.rawalloc = NULL;
338813498266Sopenharmony_ci  existing->conn_to_port = temp->conn_to_port;
338913498266Sopenharmony_ci  existing->remote_port = temp->remote_port;
339013498266Sopenharmony_ci  Curl_safefree(existing->hostname_resolve);
339113498266Sopenharmony_ci
339213498266Sopenharmony_ci  existing->hostname_resolve = temp->hostname_resolve;
339313498266Sopenharmony_ci  temp->hostname_resolve = NULL;
339413498266Sopenharmony_ci
339513498266Sopenharmony_ci  /* reuse init */
339613498266Sopenharmony_ci  existing->bits.reuse = TRUE; /* yes, we're reusing here */
339713498266Sopenharmony_ci
339813498266Sopenharmony_ci  conn_free(data, temp);
339913498266Sopenharmony_ci}
340013498266Sopenharmony_ci
340113498266Sopenharmony_ci/**
340213498266Sopenharmony_ci * create_conn() sets up a new connectdata struct, or reuses an already
340313498266Sopenharmony_ci * existing one, and resolves host name.
340413498266Sopenharmony_ci *
340513498266Sopenharmony_ci * if this function returns CURLE_OK and *async is set to TRUE, the resolve
340613498266Sopenharmony_ci * response will be coming asynchronously. If *async is FALSE, the name is
340713498266Sopenharmony_ci * already resolved.
340813498266Sopenharmony_ci *
340913498266Sopenharmony_ci * @param data The sessionhandle pointer
341013498266Sopenharmony_ci * @param in_connect is set to the next connection data pointer
341113498266Sopenharmony_ci * @param async is set TRUE when an async DNS resolution is pending
341213498266Sopenharmony_ci * @see Curl_setup_conn()
341313498266Sopenharmony_ci *
341413498266Sopenharmony_ci */
341513498266Sopenharmony_ci
341613498266Sopenharmony_cistatic CURLcode create_conn(struct Curl_easy *data,
341713498266Sopenharmony_ci                            struct connectdata **in_connect,
341813498266Sopenharmony_ci                            bool *async)
341913498266Sopenharmony_ci{
342013498266Sopenharmony_ci  CURLcode result = CURLE_OK;
342113498266Sopenharmony_ci  struct connectdata *conn;
342213498266Sopenharmony_ci  struct connectdata *existing = NULL;
342313498266Sopenharmony_ci  bool reuse;
342413498266Sopenharmony_ci  bool connections_available = TRUE;
342513498266Sopenharmony_ci  bool force_reuse = FALSE;
342613498266Sopenharmony_ci  bool waitpipe = FALSE;
342713498266Sopenharmony_ci  size_t max_host_connections = Curl_multi_max_host_connections(data->multi);
342813498266Sopenharmony_ci  size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
342913498266Sopenharmony_ci
343013498266Sopenharmony_ci  *async = FALSE;
343113498266Sopenharmony_ci  *in_connect = NULL;
343213498266Sopenharmony_ci
343313498266Sopenharmony_ci  /*************************************************************
343413498266Sopenharmony_ci   * Check input data
343513498266Sopenharmony_ci   *************************************************************/
343613498266Sopenharmony_ci  if(!data->state.url) {
343713498266Sopenharmony_ci    result = CURLE_URL_MALFORMAT;
343813498266Sopenharmony_ci    goto out;
343913498266Sopenharmony_ci  }
344013498266Sopenharmony_ci
344113498266Sopenharmony_ci  /* First, split up the current URL in parts so that we can use the
344213498266Sopenharmony_ci     parts for checking against the already present connections. In order
344313498266Sopenharmony_ci     to not have to modify everything at once, we allocate a temporary
344413498266Sopenharmony_ci     connection data struct and fill in for comparison purposes. */
344513498266Sopenharmony_ci  conn = allocate_conn(data);
344613498266Sopenharmony_ci
344713498266Sopenharmony_ci  if(!conn) {
344813498266Sopenharmony_ci    result = CURLE_OUT_OF_MEMORY;
344913498266Sopenharmony_ci    goto out;
345013498266Sopenharmony_ci  }
345113498266Sopenharmony_ci
345213498266Sopenharmony_ci  /* We must set the return variable as soon as possible, so that our
345313498266Sopenharmony_ci     parent can cleanup any possible allocs we may have done before
345413498266Sopenharmony_ci     any failure */
345513498266Sopenharmony_ci  *in_connect = conn;
345613498266Sopenharmony_ci
345713498266Sopenharmony_ci  result = parseurlandfillconn(data, conn);
345813498266Sopenharmony_ci  if(result)
345913498266Sopenharmony_ci    goto out;
346013498266Sopenharmony_ci
346113498266Sopenharmony_ci  if(data->set.str[STRING_SASL_AUTHZID]) {
346213498266Sopenharmony_ci    conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
346313498266Sopenharmony_ci    if(!conn->sasl_authzid) {
346413498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
346513498266Sopenharmony_ci      goto out;
346613498266Sopenharmony_ci    }
346713498266Sopenharmony_ci  }
346813498266Sopenharmony_ci
346913498266Sopenharmony_ci  if(data->set.str[STRING_BEARER]) {
347013498266Sopenharmony_ci    conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
347113498266Sopenharmony_ci    if(!conn->oauth_bearer) {
347213498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
347313498266Sopenharmony_ci      goto out;
347413498266Sopenharmony_ci    }
347513498266Sopenharmony_ci  }
347613498266Sopenharmony_ci
347713498266Sopenharmony_ci#ifdef USE_UNIX_SOCKETS
347813498266Sopenharmony_ci  if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
347913498266Sopenharmony_ci    conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
348013498266Sopenharmony_ci    if(!conn->unix_domain_socket) {
348113498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
348213498266Sopenharmony_ci      goto out;
348313498266Sopenharmony_ci    }
348413498266Sopenharmony_ci    conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
348513498266Sopenharmony_ci  }
348613498266Sopenharmony_ci#endif
348713498266Sopenharmony_ci
348813498266Sopenharmony_ci  /* After the unix socket init but before the proxy vars are used, parse and
348913498266Sopenharmony_ci     initialize the proxy vars */
349013498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
349113498266Sopenharmony_ci  result = create_conn_helper_init_proxy(data, conn);
349213498266Sopenharmony_ci  if(result)
349313498266Sopenharmony_ci    goto out;
349413498266Sopenharmony_ci
349513498266Sopenharmony_ci  /*************************************************************
349613498266Sopenharmony_ci   * If the protocol is using SSL and HTTP proxy is used, we set
349713498266Sopenharmony_ci   * the tunnel_proxy bit.
349813498266Sopenharmony_ci   *************************************************************/
349913498266Sopenharmony_ci  if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
350013498266Sopenharmony_ci    conn->bits.tunnel_proxy = TRUE;
350113498266Sopenharmony_ci#endif
350213498266Sopenharmony_ci
350313498266Sopenharmony_ci  /*************************************************************
350413498266Sopenharmony_ci   * Figure out the remote port number and fix it in the URL
350513498266Sopenharmony_ci   *************************************************************/
350613498266Sopenharmony_ci  result = parse_remote_port(data, conn);
350713498266Sopenharmony_ci  if(result)
350813498266Sopenharmony_ci    goto out;
350913498266Sopenharmony_ci
351013498266Sopenharmony_ci  /* Check for overridden login details and set them accordingly so that
351113498266Sopenharmony_ci     they are known when protocol->setup_connection is called! */
351213498266Sopenharmony_ci  result = override_login(data, conn);
351313498266Sopenharmony_ci  if(result)
351413498266Sopenharmony_ci    goto out;
351513498266Sopenharmony_ci
351613498266Sopenharmony_ci  result = set_login(data, conn); /* default credentials */
351713498266Sopenharmony_ci  if(result)
351813498266Sopenharmony_ci    goto out;
351913498266Sopenharmony_ci
352013498266Sopenharmony_ci  /*************************************************************
352113498266Sopenharmony_ci   * Process the "connect to" linked list of hostname/port mappings.
352213498266Sopenharmony_ci   * Do this after the remote port number has been fixed in the URL.
352313498266Sopenharmony_ci   *************************************************************/
352413498266Sopenharmony_ci  result = parse_connect_to_slist(data, conn, data->set.connect_to);
352513498266Sopenharmony_ci  if(result)
352613498266Sopenharmony_ci    goto out;
352713498266Sopenharmony_ci
352813498266Sopenharmony_ci  /*************************************************************
352913498266Sopenharmony_ci   * IDN-convert the proxy hostnames
353013498266Sopenharmony_ci   *************************************************************/
353113498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
353213498266Sopenharmony_ci  if(conn->bits.httpproxy) {
353313498266Sopenharmony_ci    result = Curl_idnconvert_hostname(&conn->http_proxy.host);
353413498266Sopenharmony_ci    if(result)
353513498266Sopenharmony_ci      return result;
353613498266Sopenharmony_ci  }
353713498266Sopenharmony_ci  if(conn->bits.socksproxy) {
353813498266Sopenharmony_ci    result = Curl_idnconvert_hostname(&conn->socks_proxy.host);
353913498266Sopenharmony_ci    if(result)
354013498266Sopenharmony_ci      return result;
354113498266Sopenharmony_ci  }
354213498266Sopenharmony_ci#endif
354313498266Sopenharmony_ci  if(conn->bits.conn_to_host) {
354413498266Sopenharmony_ci    result = Curl_idnconvert_hostname(&conn->conn_to_host);
354513498266Sopenharmony_ci    if(result)
354613498266Sopenharmony_ci      return result;
354713498266Sopenharmony_ci  }
354813498266Sopenharmony_ci
354913498266Sopenharmony_ci  /*************************************************************
355013498266Sopenharmony_ci   * Check whether the host and the "connect to host" are equal.
355113498266Sopenharmony_ci   * Do this after the hostnames have been IDN-converted.
355213498266Sopenharmony_ci   *************************************************************/
355313498266Sopenharmony_ci  if(conn->bits.conn_to_host &&
355413498266Sopenharmony_ci     strcasecompare(conn->conn_to_host.name, conn->host.name)) {
355513498266Sopenharmony_ci    conn->bits.conn_to_host = FALSE;
355613498266Sopenharmony_ci  }
355713498266Sopenharmony_ci
355813498266Sopenharmony_ci  /*************************************************************
355913498266Sopenharmony_ci   * Check whether the port and the "connect to port" are equal.
356013498266Sopenharmony_ci   * Do this after the remote port number has been fixed in the URL.
356113498266Sopenharmony_ci   *************************************************************/
356213498266Sopenharmony_ci  if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
356313498266Sopenharmony_ci    conn->bits.conn_to_port = FALSE;
356413498266Sopenharmony_ci  }
356513498266Sopenharmony_ci
356613498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
356713498266Sopenharmony_ci  /*************************************************************
356813498266Sopenharmony_ci   * If the "connect to" feature is used with an HTTP proxy,
356913498266Sopenharmony_ci   * we set the tunnel_proxy bit.
357013498266Sopenharmony_ci   *************************************************************/
357113498266Sopenharmony_ci  if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
357213498266Sopenharmony_ci      conn->bits.httpproxy)
357313498266Sopenharmony_ci    conn->bits.tunnel_proxy = TRUE;
357413498266Sopenharmony_ci#endif
357513498266Sopenharmony_ci
357613498266Sopenharmony_ci  /*************************************************************
357713498266Sopenharmony_ci   * Setup internals depending on protocol. Needs to be done after
357813498266Sopenharmony_ci   * we figured out what/if proxy to use.
357913498266Sopenharmony_ci   *************************************************************/
358013498266Sopenharmony_ci  result = setup_connection_internals(data, conn);
358113498266Sopenharmony_ci  if(result)
358213498266Sopenharmony_ci    goto out;
358313498266Sopenharmony_ci
358413498266Sopenharmony_ci  /***********************************************************************
358513498266Sopenharmony_ci   * file: is a special case in that it doesn't need a network connection
358613498266Sopenharmony_ci   ***********************************************************************/
358713498266Sopenharmony_ci#ifndef CURL_DISABLE_FILE
358813498266Sopenharmony_ci  if(conn->handler->flags & PROTOPT_NONETWORK) {
358913498266Sopenharmony_ci    bool done;
359013498266Sopenharmony_ci    /* this is supposed to be the connect function so we better at least check
359113498266Sopenharmony_ci       that the file is present here! */
359213498266Sopenharmony_ci    DEBUGASSERT(conn->handler->connect_it);
359313498266Sopenharmony_ci    Curl_persistconninfo(data, conn, NULL, -1);
359413498266Sopenharmony_ci    result = conn->handler->connect_it(data, &done);
359513498266Sopenharmony_ci
359613498266Sopenharmony_ci    /* Setup a "faked" transfer that'll do nothing */
359713498266Sopenharmony_ci    if(!result) {
359813498266Sopenharmony_ci      Curl_attach_connection(data, conn);
359913498266Sopenharmony_ci      result = Curl_conncache_add_conn(data);
360013498266Sopenharmony_ci      if(result)
360113498266Sopenharmony_ci        goto out;
360213498266Sopenharmony_ci
360313498266Sopenharmony_ci      /*
360413498266Sopenharmony_ci       * Setup whatever necessary for a resumed transfer
360513498266Sopenharmony_ci       */
360613498266Sopenharmony_ci      result = setup_range(data);
360713498266Sopenharmony_ci      if(result) {
360813498266Sopenharmony_ci        DEBUGASSERT(conn->handler->done);
360913498266Sopenharmony_ci        /* we ignore the return code for the protocol-specific DONE */
361013498266Sopenharmony_ci        (void)conn->handler->done(data, result, FALSE);
361113498266Sopenharmony_ci        goto out;
361213498266Sopenharmony_ci      }
361313498266Sopenharmony_ci      Curl_setup_transfer(data, -1, -1, FALSE, -1);
361413498266Sopenharmony_ci    }
361513498266Sopenharmony_ci
361613498266Sopenharmony_ci    /* since we skip do_init() */
361713498266Sopenharmony_ci    Curl_init_do(data, conn);
361813498266Sopenharmony_ci
361913498266Sopenharmony_ci    goto out;
362013498266Sopenharmony_ci  }
362113498266Sopenharmony_ci#endif
362213498266Sopenharmony_ci
362313498266Sopenharmony_ci  /* Setup filter for network connections */
362413498266Sopenharmony_ci  conn->recv[FIRSTSOCKET] = Curl_conn_recv;
362513498266Sopenharmony_ci  conn->send[FIRSTSOCKET] = Curl_conn_send;
362613498266Sopenharmony_ci  conn->recv[SECONDARYSOCKET] = Curl_conn_recv;
362713498266Sopenharmony_ci  conn->send[SECONDARYSOCKET] = Curl_conn_send;
362813498266Sopenharmony_ci  conn->bits.tcp_fastopen = data->set.tcp_fastopen;
362913498266Sopenharmony_ci
363013498266Sopenharmony_ci  /* Complete the easy's SSL configuration for connection cache matching */
363113498266Sopenharmony_ci  result = Curl_ssl_easy_config_complete(data);
363213498266Sopenharmony_ci  if(result)
363313498266Sopenharmony_ci    goto out;
363413498266Sopenharmony_ci
363513498266Sopenharmony_ci  prune_dead_connections(data);
363613498266Sopenharmony_ci
363713498266Sopenharmony_ci  /*************************************************************
363813498266Sopenharmony_ci   * Check the current list of connections to see if we can
363913498266Sopenharmony_ci   * reuse an already existing one or if we have to create a
364013498266Sopenharmony_ci   * new one.
364113498266Sopenharmony_ci   *************************************************************/
364213498266Sopenharmony_ci
364313498266Sopenharmony_ci  DEBUGASSERT(conn->user);
364413498266Sopenharmony_ci  DEBUGASSERT(conn->passwd);
364513498266Sopenharmony_ci
364613498266Sopenharmony_ci  /* reuse_fresh is TRUE if we are told to use a new connection by force, but
364713498266Sopenharmony_ci     we only acknowledge this option if this is not a reused connection
364813498266Sopenharmony_ci     already (which happens due to follow-location or during an HTTP
364913498266Sopenharmony_ci     authentication phase). CONNECT_ONLY transfers also refuse reuse. */
365013498266Sopenharmony_ci  if((data->set.reuse_fresh && !data->state.followlocation) ||
365113498266Sopenharmony_ci     data->set.connect_only)
365213498266Sopenharmony_ci    reuse = FALSE;
365313498266Sopenharmony_ci  else
365413498266Sopenharmony_ci    reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
365513498266Sopenharmony_ci
365613498266Sopenharmony_ci  if(reuse) {
365713498266Sopenharmony_ci    /*
365813498266Sopenharmony_ci     * We already have a connection for this, we got the former connection in
365913498266Sopenharmony_ci     * `existing` and thus we need to cleanup the one we just
366013498266Sopenharmony_ci     * allocated before we can move along and use `existing`.
366113498266Sopenharmony_ci     */
366213498266Sopenharmony_ci    reuse_conn(data, conn, existing);
366313498266Sopenharmony_ci    conn = existing;
366413498266Sopenharmony_ci    *in_connect = conn;
366513498266Sopenharmony_ci
366613498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
366713498266Sopenharmony_ci    infof(data, "Re-using existing connection with %s %s",
366813498266Sopenharmony_ci          conn->bits.proxy?"proxy":"host",
366913498266Sopenharmony_ci          conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
367013498266Sopenharmony_ci          conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
367113498266Sopenharmony_ci          conn->host.dispname);
367213498266Sopenharmony_ci#else
367313498266Sopenharmony_ci    infof(data, "Re-using existing connection with host %s",
367413498266Sopenharmony_ci          conn->host.dispname);
367513498266Sopenharmony_ci#endif
367613498266Sopenharmony_ci  }
367713498266Sopenharmony_ci  else {
367813498266Sopenharmony_ci    /* We have decided that we want a new connection. However, we may not
367913498266Sopenharmony_ci       be able to do that if we have reached the limit of how many
368013498266Sopenharmony_ci       connections we are allowed to open. */
368113498266Sopenharmony_ci
368213498266Sopenharmony_ci    if(conn->handler->flags & PROTOPT_ALPN) {
368313498266Sopenharmony_ci      /* The protocol wants it, so set the bits if enabled in the easy handle
368413498266Sopenharmony_ci         (default) */
368513498266Sopenharmony_ci      if(data->set.ssl_enable_alpn)
368613498266Sopenharmony_ci        conn->bits.tls_enable_alpn = TRUE;
368713498266Sopenharmony_ci    }
368813498266Sopenharmony_ci
368913498266Sopenharmony_ci    if(waitpipe)
369013498266Sopenharmony_ci      /* There is a connection that *might* become usable for multiplexing
369113498266Sopenharmony_ci         "soon", and we wait for that */
369213498266Sopenharmony_ci      connections_available = FALSE;
369313498266Sopenharmony_ci    else {
369413498266Sopenharmony_ci      /* this gets a lock on the conncache */
369513498266Sopenharmony_ci      struct connectbundle *bundle =
369613498266Sopenharmony_ci        Curl_conncache_find_bundle(data, conn, data->state.conn_cache);
369713498266Sopenharmony_ci
369813498266Sopenharmony_ci      if(max_host_connections > 0 && bundle &&
369913498266Sopenharmony_ci         (bundle->num_connections >= max_host_connections)) {
370013498266Sopenharmony_ci        struct connectdata *conn_candidate;
370113498266Sopenharmony_ci
370213498266Sopenharmony_ci        /* The bundle is full. Extract the oldest connection. */
370313498266Sopenharmony_ci        conn_candidate = Curl_conncache_extract_bundle(data, bundle);
370413498266Sopenharmony_ci        CONNCACHE_UNLOCK(data);
370513498266Sopenharmony_ci
370613498266Sopenharmony_ci        if(conn_candidate)
370713498266Sopenharmony_ci          Curl_disconnect(data, conn_candidate, FALSE);
370813498266Sopenharmony_ci        else {
370913498266Sopenharmony_ci          infof(data, "No more connections allowed to host: %zu",
371013498266Sopenharmony_ci                max_host_connections);
371113498266Sopenharmony_ci          connections_available = FALSE;
371213498266Sopenharmony_ci        }
371313498266Sopenharmony_ci      }
371413498266Sopenharmony_ci      else
371513498266Sopenharmony_ci        CONNCACHE_UNLOCK(data);
371613498266Sopenharmony_ci
371713498266Sopenharmony_ci    }
371813498266Sopenharmony_ci
371913498266Sopenharmony_ci    if(connections_available &&
372013498266Sopenharmony_ci       (max_total_connections > 0) &&
372113498266Sopenharmony_ci       (Curl_conncache_size(data) >= max_total_connections)) {
372213498266Sopenharmony_ci      struct connectdata *conn_candidate;
372313498266Sopenharmony_ci
372413498266Sopenharmony_ci      /* The cache is full. Let's see if we can kill a connection. */
372513498266Sopenharmony_ci      conn_candidate = Curl_conncache_extract_oldest(data);
372613498266Sopenharmony_ci      if(conn_candidate)
372713498266Sopenharmony_ci        Curl_disconnect(data, conn_candidate, FALSE);
372813498266Sopenharmony_ci      else {
372913498266Sopenharmony_ci        infof(data, "No connections available in cache");
373013498266Sopenharmony_ci        connections_available = FALSE;
373113498266Sopenharmony_ci      }
373213498266Sopenharmony_ci    }
373313498266Sopenharmony_ci
373413498266Sopenharmony_ci    if(!connections_available) {
373513498266Sopenharmony_ci      infof(data, "No connections available.");
373613498266Sopenharmony_ci
373713498266Sopenharmony_ci      conn_free(data, conn);
373813498266Sopenharmony_ci      *in_connect = NULL;
373913498266Sopenharmony_ci
374013498266Sopenharmony_ci      result = CURLE_NO_CONNECTION_AVAILABLE;
374113498266Sopenharmony_ci      goto out;
374213498266Sopenharmony_ci    }
374313498266Sopenharmony_ci    else {
374413498266Sopenharmony_ci      /*
374513498266Sopenharmony_ci       * This is a brand new connection, so let's store it in the connection
374613498266Sopenharmony_ci       * cache of ours!
374713498266Sopenharmony_ci       */
374813498266Sopenharmony_ci      result = Curl_ssl_conn_config_init(data, conn);
374913498266Sopenharmony_ci      if(result) {
375013498266Sopenharmony_ci        DEBUGF(fprintf(stderr, "Error: init connection ssl config\n"));
375113498266Sopenharmony_ci        goto out;
375213498266Sopenharmony_ci      }
375313498266Sopenharmony_ci
375413498266Sopenharmony_ci      Curl_attach_connection(data, conn);
375513498266Sopenharmony_ci      result = Curl_conncache_add_conn(data);
375613498266Sopenharmony_ci      if(result)
375713498266Sopenharmony_ci        goto out;
375813498266Sopenharmony_ci    }
375913498266Sopenharmony_ci
376013498266Sopenharmony_ci#if defined(USE_NTLM)
376113498266Sopenharmony_ci    /* If NTLM is requested in a part of this connection, make sure we don't
376213498266Sopenharmony_ci       assume the state is fine as this is a fresh connection and NTLM is
376313498266Sopenharmony_ci       connection based. */
376413498266Sopenharmony_ci    if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
376513498266Sopenharmony_ci       data->state.authhost.done) {
376613498266Sopenharmony_ci      infof(data, "NTLM picked AND auth done set, clear picked");
376713498266Sopenharmony_ci      data->state.authhost.picked = CURLAUTH_NONE;
376813498266Sopenharmony_ci      data->state.authhost.done = FALSE;
376913498266Sopenharmony_ci    }
377013498266Sopenharmony_ci
377113498266Sopenharmony_ci    if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
377213498266Sopenharmony_ci       data->state.authproxy.done) {
377313498266Sopenharmony_ci      infof(data, "NTLM-proxy picked AND auth done set, clear picked");
377413498266Sopenharmony_ci      data->state.authproxy.picked = CURLAUTH_NONE;
377513498266Sopenharmony_ci      data->state.authproxy.done = FALSE;
377613498266Sopenharmony_ci    }
377713498266Sopenharmony_ci#endif
377813498266Sopenharmony_ci  }
377913498266Sopenharmony_ci
378013498266Sopenharmony_ci  /* Setup and init stuff before DO starts, in preparing for the transfer. */
378113498266Sopenharmony_ci  Curl_init_do(data, conn);
378213498266Sopenharmony_ci
378313498266Sopenharmony_ci  /*
378413498266Sopenharmony_ci   * Setup whatever necessary for a resumed transfer
378513498266Sopenharmony_ci   */
378613498266Sopenharmony_ci  result = setup_range(data);
378713498266Sopenharmony_ci  if(result)
378813498266Sopenharmony_ci    goto out;
378913498266Sopenharmony_ci
379013498266Sopenharmony_ci  /* Continue connectdata initialization here. */
379113498266Sopenharmony_ci
379213498266Sopenharmony_ci  /*
379313498266Sopenharmony_ci   * Inherit the proper values from the urldata struct AFTER we have arranged
379413498266Sopenharmony_ci   * the persistent connection stuff
379513498266Sopenharmony_ci   */
379613498266Sopenharmony_ci  conn->seek_func = data->set.seek_func;
379713498266Sopenharmony_ci  conn->seek_client = data->set.seek_client;
379813498266Sopenharmony_ci
379913498266Sopenharmony_ci  /*************************************************************
380013498266Sopenharmony_ci   * Resolve the address of the server or proxy
380113498266Sopenharmony_ci   *************************************************************/
380213498266Sopenharmony_ci  result = resolve_server(data, conn, async);
380313498266Sopenharmony_ci  if(result)
380413498266Sopenharmony_ci    goto out;
380513498266Sopenharmony_ci
380613498266Sopenharmony_ci  /* Everything general done, inform filters that they need
380713498266Sopenharmony_ci   * to prepare for a data transfer.
380813498266Sopenharmony_ci   */
380913498266Sopenharmony_ci  result = Curl_conn_ev_data_setup(data);
381013498266Sopenharmony_ci
381113498266Sopenharmony_ciout:
381213498266Sopenharmony_ci  return result;
381313498266Sopenharmony_ci}
381413498266Sopenharmony_ci
381513498266Sopenharmony_ci/* Curl_setup_conn() is called after the name resolve initiated in
381613498266Sopenharmony_ci * create_conn() is all done.
381713498266Sopenharmony_ci *
381813498266Sopenharmony_ci * Curl_setup_conn() also handles reused connections
381913498266Sopenharmony_ci */
382013498266Sopenharmony_ciCURLcode Curl_setup_conn(struct Curl_easy *data,
382113498266Sopenharmony_ci                         bool *protocol_done)
382213498266Sopenharmony_ci{
382313498266Sopenharmony_ci  CURLcode result = CURLE_OK;
382413498266Sopenharmony_ci  struct connectdata *conn = data->conn;
382513498266Sopenharmony_ci
382613498266Sopenharmony_ci  Curl_pgrsTime(data, TIMER_NAMELOOKUP);
382713498266Sopenharmony_ci
382813498266Sopenharmony_ci  if(conn->handler->flags & PROTOPT_NONETWORK) {
382913498266Sopenharmony_ci    /* nothing to setup when not using a network */
383013498266Sopenharmony_ci    *protocol_done = TRUE;
383113498266Sopenharmony_ci    return result;
383213498266Sopenharmony_ci  }
383313498266Sopenharmony_ci
383413498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY
383513498266Sopenharmony_ci  /* set proxy_connect_closed to false unconditionally already here since it
383613498266Sopenharmony_ci     is used strictly to provide extra information to a parent function in the
383713498266Sopenharmony_ci     case of proxy CONNECT failures and we must make sure we don't have it
383813498266Sopenharmony_ci     lingering set from a previous invoke */
383913498266Sopenharmony_ci  conn->bits.proxy_connect_closed = FALSE;
384013498266Sopenharmony_ci#endif
384113498266Sopenharmony_ci
384213498266Sopenharmony_ci#ifdef CURL_DO_LINEEND_CONV
384313498266Sopenharmony_ci  data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
384413498266Sopenharmony_ci#endif /* CURL_DO_LINEEND_CONV */
384513498266Sopenharmony_ci
384613498266Sopenharmony_ci  /* set start time here for timeout purposes in the connect procedure, it
384713498266Sopenharmony_ci     is later set again for the progress meter purpose */
384813498266Sopenharmony_ci  conn->now = Curl_now();
384913498266Sopenharmony_ci  if(!conn->bits.reuse)
385013498266Sopenharmony_ci    result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry,
385113498266Sopenharmony_ci                             CURL_CF_SSL_DEFAULT);
385213498266Sopenharmony_ci  /* not sure we need this flag to be passed around any more */
385313498266Sopenharmony_ci  *protocol_done = FALSE;
385413498266Sopenharmony_ci  return result;
385513498266Sopenharmony_ci}
385613498266Sopenharmony_ci
385713498266Sopenharmony_ciCURLcode Curl_connect(struct Curl_easy *data,
385813498266Sopenharmony_ci                      bool *asyncp,
385913498266Sopenharmony_ci                      bool *protocol_done)
386013498266Sopenharmony_ci{
386113498266Sopenharmony_ci  CURLcode result;
386213498266Sopenharmony_ci  struct connectdata *conn;
386313498266Sopenharmony_ci
386413498266Sopenharmony_ci  *asyncp = FALSE; /* assume synchronous resolves by default */
386513498266Sopenharmony_ci
386613498266Sopenharmony_ci  /* init the single-transfer specific data */
386713498266Sopenharmony_ci  Curl_free_request_state(data);
386813498266Sopenharmony_ci  memset(&data->req, 0, sizeof(struct SingleRequest));
386913498266Sopenharmony_ci  data->req.size = data->req.maxdownload = -1;
387013498266Sopenharmony_ci  data->req.no_body = data->set.opt_no_body;
387113498266Sopenharmony_ci
387213498266Sopenharmony_ci  /* call the stuff that needs to be called */
387313498266Sopenharmony_ci  result = create_conn(data, &conn, asyncp);
387413498266Sopenharmony_ci
387513498266Sopenharmony_ci  if(!result) {
387613498266Sopenharmony_ci    if(CONN_INUSE(conn) > 1)
387713498266Sopenharmony_ci      /* multiplexed */
387813498266Sopenharmony_ci      *protocol_done = TRUE;
387913498266Sopenharmony_ci    else if(!*asyncp) {
388013498266Sopenharmony_ci      /* DNS resolution is done: that's either because this is a reused
388113498266Sopenharmony_ci         connection, in which case DNS was unnecessary, or because DNS
388213498266Sopenharmony_ci         really did finish already (synch resolver/fast async resolve) */
388313498266Sopenharmony_ci      result = Curl_setup_conn(data, protocol_done);
388413498266Sopenharmony_ci    }
388513498266Sopenharmony_ci  }
388613498266Sopenharmony_ci
388713498266Sopenharmony_ci  if(result == CURLE_NO_CONNECTION_AVAILABLE) {
388813498266Sopenharmony_ci    return result;
388913498266Sopenharmony_ci  }
389013498266Sopenharmony_ci  else if(result && conn) {
389113498266Sopenharmony_ci    /* We're not allowed to return failure with memory left allocated in the
389213498266Sopenharmony_ci       connectdata struct, free those here */
389313498266Sopenharmony_ci    Curl_detach_connection(data);
389413498266Sopenharmony_ci    Curl_conncache_remove_conn(data, conn, TRUE);
389513498266Sopenharmony_ci    Curl_disconnect(data, conn, TRUE);
389613498266Sopenharmony_ci  }
389713498266Sopenharmony_ci
389813498266Sopenharmony_ci  return result;
389913498266Sopenharmony_ci}
390013498266Sopenharmony_ci
390113498266Sopenharmony_ci/*
390213498266Sopenharmony_ci * Curl_init_do() inits the readwrite session. This is inited each time (in
390313498266Sopenharmony_ci * the DO function before the protocol-specific DO functions are invoked) for
390413498266Sopenharmony_ci * a transfer, sometimes multiple times on the same Curl_easy. Make sure
390513498266Sopenharmony_ci * nothing in here depends on stuff that are setup dynamically for the
390613498266Sopenharmony_ci * transfer.
390713498266Sopenharmony_ci *
390813498266Sopenharmony_ci * Allow this function to get called with 'conn' set to NULL.
390913498266Sopenharmony_ci */
391013498266Sopenharmony_ci
391113498266Sopenharmony_ciCURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
391213498266Sopenharmony_ci{
391313498266Sopenharmony_ci  struct SingleRequest *k = &data->req;
391413498266Sopenharmony_ci
391513498266Sopenharmony_ci  /* if this is a pushed stream, we need this: */
391613498266Sopenharmony_ci  CURLcode result = Curl_preconnect(data);
391713498266Sopenharmony_ci  if(result)
391813498266Sopenharmony_ci    return result;
391913498266Sopenharmony_ci
392013498266Sopenharmony_ci  if(conn) {
392113498266Sopenharmony_ci    conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
392213498266Sopenharmony_ci                                   use */
392313498266Sopenharmony_ci    /* if the protocol used doesn't support wildcards, switch it off */
392413498266Sopenharmony_ci    if(data->state.wildcardmatch &&
392513498266Sopenharmony_ci       !(conn->handler->flags & PROTOPT_WILDCARD))
392613498266Sopenharmony_ci      data->state.wildcardmatch = FALSE;
392713498266Sopenharmony_ci  }
392813498266Sopenharmony_ci
392913498266Sopenharmony_ci  data->state.done = FALSE; /* *_done() is not called yet */
393013498266Sopenharmony_ci  data->state.expect100header = FALSE;
393113498266Sopenharmony_ci
393213498266Sopenharmony_ci  if(data->req.no_body)
393313498266Sopenharmony_ci    /* in HTTP lingo, no body means using the HEAD request... */
393413498266Sopenharmony_ci    data->state.httpreq = HTTPREQ_HEAD;
393513498266Sopenharmony_ci
393613498266Sopenharmony_ci  k->start = Curl_now(); /* start time */
393713498266Sopenharmony_ci  k->header = TRUE; /* assume header */
393813498266Sopenharmony_ci  k->bytecount = 0;
393913498266Sopenharmony_ci  k->ignorebody = FALSE;
394013498266Sopenharmony_ci
394113498266Sopenharmony_ci  Curl_client_cleanup(data);
394213498266Sopenharmony_ci  Curl_speedinit(data);
394313498266Sopenharmony_ci  Curl_pgrsSetUploadCounter(data, 0);
394413498266Sopenharmony_ci  Curl_pgrsSetDownloadCounter(data, 0);
394513498266Sopenharmony_ci
394613498266Sopenharmony_ci  return CURLE_OK;
394713498266Sopenharmony_ci}
394813498266Sopenharmony_ci
394913498266Sopenharmony_ci#if defined(USE_HTTP2) || defined(USE_HTTP3)
395013498266Sopenharmony_ci
395113498266Sopenharmony_ci#ifdef USE_NGHTTP2
395213498266Sopenharmony_ci
395313498266Sopenharmony_cistatic void priority_remove_child(struct Curl_easy *parent,
395413498266Sopenharmony_ci                                  struct Curl_easy *child)
395513498266Sopenharmony_ci{
395613498266Sopenharmony_ci  struct Curl_data_prio_node **pnext = &parent->set.priority.children;
395713498266Sopenharmony_ci  struct Curl_data_prio_node *pnode = parent->set.priority.children;
395813498266Sopenharmony_ci
395913498266Sopenharmony_ci  DEBUGASSERT(child->set.priority.parent == parent);
396013498266Sopenharmony_ci  while(pnode && pnode->data != child) {
396113498266Sopenharmony_ci    pnext = &pnode->next;
396213498266Sopenharmony_ci    pnode = pnode->next;
396313498266Sopenharmony_ci  }
396413498266Sopenharmony_ci
396513498266Sopenharmony_ci  DEBUGASSERT(pnode);
396613498266Sopenharmony_ci  if(pnode) {
396713498266Sopenharmony_ci    *pnext = pnode->next;
396813498266Sopenharmony_ci    free(pnode);
396913498266Sopenharmony_ci  }
397013498266Sopenharmony_ci
397113498266Sopenharmony_ci  child->set.priority.parent = 0;
397213498266Sopenharmony_ci  child->set.priority.exclusive = FALSE;
397313498266Sopenharmony_ci}
397413498266Sopenharmony_ci
397513498266Sopenharmony_ciCURLcode Curl_data_priority_add_child(struct Curl_easy *parent,
397613498266Sopenharmony_ci                                      struct Curl_easy *child,
397713498266Sopenharmony_ci                                      bool exclusive)
397813498266Sopenharmony_ci{
397913498266Sopenharmony_ci  if(child->set.priority.parent) {
398013498266Sopenharmony_ci    priority_remove_child(child->set.priority.parent, child);
398113498266Sopenharmony_ci  }
398213498266Sopenharmony_ci
398313498266Sopenharmony_ci  if(parent) {
398413498266Sopenharmony_ci    struct Curl_data_prio_node **tail;
398513498266Sopenharmony_ci    struct Curl_data_prio_node *pnode;
398613498266Sopenharmony_ci
398713498266Sopenharmony_ci    pnode = calloc(1, sizeof(*pnode));
398813498266Sopenharmony_ci    if(!pnode)
398913498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
399013498266Sopenharmony_ci    pnode->data = child;
399113498266Sopenharmony_ci
399213498266Sopenharmony_ci    if(parent->set.priority.children && exclusive) {
399313498266Sopenharmony_ci      /* exclusive: move all existing children underneath the new child */
399413498266Sopenharmony_ci      struct Curl_data_prio_node *node = parent->set.priority.children;
399513498266Sopenharmony_ci      while(node) {
399613498266Sopenharmony_ci        node->data->set.priority.parent = child;
399713498266Sopenharmony_ci        node = node->next;
399813498266Sopenharmony_ci      }
399913498266Sopenharmony_ci
400013498266Sopenharmony_ci      tail = &child->set.priority.children;
400113498266Sopenharmony_ci      while(*tail)
400213498266Sopenharmony_ci        tail = &(*tail)->next;
400313498266Sopenharmony_ci
400413498266Sopenharmony_ci      DEBUGASSERT(!*tail);
400513498266Sopenharmony_ci      *tail = parent->set.priority.children;
400613498266Sopenharmony_ci      parent->set.priority.children = 0;
400713498266Sopenharmony_ci    }
400813498266Sopenharmony_ci
400913498266Sopenharmony_ci    tail = &parent->set.priority.children;
401013498266Sopenharmony_ci    while(*tail) {
401113498266Sopenharmony_ci      (*tail)->data->set.priority.exclusive = FALSE;
401213498266Sopenharmony_ci      tail = &(*tail)->next;
401313498266Sopenharmony_ci    }
401413498266Sopenharmony_ci
401513498266Sopenharmony_ci    DEBUGASSERT(!*tail);
401613498266Sopenharmony_ci    *tail = pnode;
401713498266Sopenharmony_ci  }
401813498266Sopenharmony_ci
401913498266Sopenharmony_ci  child->set.priority.parent = parent;
402013498266Sopenharmony_ci  child->set.priority.exclusive = exclusive;
402113498266Sopenharmony_ci  return CURLE_OK;
402213498266Sopenharmony_ci}
402313498266Sopenharmony_ci
402413498266Sopenharmony_ci#endif /* USE_NGHTTP2 */
402513498266Sopenharmony_ci
402613498266Sopenharmony_ci#ifdef USE_NGHTTP2
402713498266Sopenharmony_cistatic void data_priority_cleanup(struct Curl_easy *data)
402813498266Sopenharmony_ci{
402913498266Sopenharmony_ci  while(data->set.priority.children) {
403013498266Sopenharmony_ci    struct Curl_easy *tmp = data->set.priority.children->data;
403113498266Sopenharmony_ci    priority_remove_child(data, tmp);
403213498266Sopenharmony_ci    if(data->set.priority.parent)
403313498266Sopenharmony_ci      Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE);
403413498266Sopenharmony_ci  }
403513498266Sopenharmony_ci
403613498266Sopenharmony_ci  if(data->set.priority.parent)
403713498266Sopenharmony_ci    priority_remove_child(data->set.priority.parent, data);
403813498266Sopenharmony_ci}
403913498266Sopenharmony_ci#endif
404013498266Sopenharmony_ci
404113498266Sopenharmony_civoid Curl_data_priority_clear_state(struct Curl_easy *data)
404213498266Sopenharmony_ci{
404313498266Sopenharmony_ci  memset(&data->state.priority, 0, sizeof(data->state.priority));
404413498266Sopenharmony_ci}
404513498266Sopenharmony_ci
404613498266Sopenharmony_ci#endif /* defined(USE_HTTP2) || defined(USE_HTTP3) */
4047