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