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