VirtualBox

source: vbox/trunk/src/libs/curl-8.3.0/lib/url.c@ 101127

Last change on this file since 101127 was 101127, checked in by vboxsync, 19 months ago

curl-8.3.0: Applied and adjusted our curl changes to 8.0.1. bugref:10526

  • Property svn:eol-style set to native
File size: 123.3 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <[email protected]>, 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(&data->set.mimepost);
321
322#ifndef CURL_DISABLE_COOKIES
323 curl_slist_free_all(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(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(data->multi, 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(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(&data->state.headerb);
407 Curl_safefree(data->state.ulbuf);
408 Curl_flush_cookies(data, TRUE);
409 Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
410 Curl_altsvc_cleanup(&data->asi);
411 Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
412#ifndef CURL_DISABLE_HSTS
413 if(!data->share || !data->share->hsts)
414 Curl_hsts_cleanup(&data->hsts);
415 curl_slist_free_all(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(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(&data->req.doh->probe[0].serverdoh);
454 Curl_dyn_free(&data->req.doh->probe[1].serverdoh);
455 curl_slist_free_all(data->req.doh->headers);
456 Curl_safefree(data->req.doh);
457 }
458#endif
459
460 Curl_mime_cleanpart(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(&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(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
576 if(result)
577 return result;
578
579 result = Curl_setstropt(&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(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
586 if(result)
587 return result;
588
589 result = Curl_setstropt(&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(data, &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(&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(data->state.async.resolver);
677 Curl_dyn_free(&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, (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(&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(&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(&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, 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(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(data->user, needle->user) ||
867 Curl_timestrcmp(data->passwd, 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(now, conn->lastused);
888 idletime /= 1000; /* integer seconds is fine */
889
890 if(idletime > data->set.maxage_conn) {
891 infof(data, "Too old connection (%ld seconds idle), disconnect it",
892 idletime);
893 return TRUE;
894 }
895
896 lifetime = Curl_timediff(now, 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 (%ld seconds since creation), disconnect it",
902 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);
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(now, 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, data->state.conn_cache, &prune,
1018 call_extract_if_dead)) {
1019 /* unlocked */
1020
1021 /* remove connection from cache */
1022 Curl_conncache_remove_conn(data, prune.extracted, TRUE);
1023
1024 /* disconnect it */
1025 Curl_disconnect(data, 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(data, 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, needle, 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(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(check, data)) {
1140 /* disconnect it */
1141 Curl_disconnect(data, 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(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(needle->unix_domain_socket, 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(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(&needle->socks_proxy,
1205 &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(&needle->http_proxy, &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(&needle->proxy_ssl_config,
1234 &check->proxy_ssl_config))
1235 continue;
1236 }
1237 else if(!Curl_ssl_config_matches(&needle->ssl_config,
1238 &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(check->localdev, 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(needle->user, check->user) ||
1292 Curl_timestrcmp(needle->passwd, check->passwd) ||
1293 Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) ||
1294 Curl_timestrcmp(needle->oauth_bearer, 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(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(&needle->ssl_config,
1357 &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(needle->user, check->user) ||
1383 Curl_timestrcmp(needle->passwd, 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(needle->http_proxy.user,
1406 check->http_proxy.user) ||
1407 Curl_timestrcmp(needle->http_proxy.passwd,
1408 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, 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(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(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, "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(uh, CURLUPART_ZONEID, &zoneid, 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(zoneid, &endp, 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(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(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(data->state.url, NULL, 0, TRUE)) {
1766 char *url = aprintf("%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(uh, CURLUPART_URL, 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, "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(uh, CURLUPART_URL, &newurl, 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(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
1800 if(uc)
1801 return Curl_uc_to_curlcode(uc);
1802
1803 uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
1804 if(uc) {
1805 if(!strcasecompare("file", data->state.up.scheme))
1806 return CURLE_OUT_OF_MEMORY;
1807 }
1808 else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
1809 failf(data, "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(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(&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(data->hsts, conn->host.name, TRUE)) {
1845 char *url;
1846 Curl_safefree(data->state.up.scheme);
1847 uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 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(uh, CURLUPART_URL, &url, 0);
1854 if(uc)
1855 return Curl_uc_to_curlcode(uc);
1856 uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 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, 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(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
1879 if(!uc) {
1880 char *decoded;
1881 result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL,
1882 conn->handler->flags&PROTOPT_USERPWDCTRL ?
1883 REJECT_ZERO : REJECT_CTRL);
1884 if(result)
1885 return result;
1886 conn->passwd = decoded;
1887 result = Curl_setstropt(&data->state.aptr.passwd, 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(uh, CURLUPART_USER, &data->state.up.user, 0);
1900 if(!uc) {
1901 char *decoded;
1902 result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL,
1903 conn->handler->flags&PROTOPT_USERPWDCTRL ?
1904 REJECT_ZERO : REJECT_CTRL);
1905 if(result)
1906 return result;
1907 conn->user = decoded;
1908 result = Curl_setstropt(&data->state.aptr.user, 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(&data->state.aptr.user, "");
1915 }
1916 if(result)
1917 return result;
1918 }
1919
1920 uc = curl_url_get(uh, CURLUPART_OPTIONS, &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(uh, CURLUPART_PATH, &data->state.up.path,
1931 CURLU_URLENCODE);
1932 if(uc)
1933 return Curl_uc_to_curlcode(uc);
1934
1935 uc = curl_url_get(uh, CURLUPART_PORT, &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(data->state.up.port, NULL, 10);
1943 conn->port = conn->remote_port =
1944 (data->set.use_port && data->state.allow_port) ?
1945 data->set.use_port : curlx_ultous(port);
1946 }
1947
1948 (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 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("%" 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
2037#ifndef CURL_DISABLE_DOH
2038 if(data->req.doh) {
2039 Curl_close(&data->req.doh->probe[0].easy);
2040 Curl_close(&data->req.doh->probe[1].easy);
2041 }
2042#endif
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 char *prox;
2080#ifdef CURL_DISABLE_VERBOSE_STRINGS
2081 (void)data;
2082#endif
2083
2084 /* Now, build <protocol>_proxy and check for such a one to use */
2085 while(*protop)
2086 *envp++ = Curl_raw_tolower(*protop++);
2087
2088 /* append _proxy */
2089 strcpy(envp, "_proxy");
2090
2091 /* read the protocol proxy: */
2092 prox = curl_getenv(proxy_env);
2093
2094 /*
2095 * We don't try the uppercase version of HTTP_PROXY because of
2096 * security reasons:
2097 *
2098 * When curl is used in a webserver application
2099 * environment (cgi or php), this environment variable can
2100 * be controlled by the web server user by setting the
2101 * http header 'Proxy:' to some value.
2102 *
2103 * This can cause 'internal' http/ftp requests to be
2104 * arbitrarily redirected by any external attacker.
2105 */
2106 if(!prox && !strcasecompare("http_proxy", proxy_env)) {
2107 /* There was no lowercase variable, try the uppercase version: */
2108 Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
2109 prox = curl_getenv(proxy_env);
2110 }
2111
2112 envp = proxy_env;
2113 if(prox) {
2114 proxy = prox; /* use this */
2115 }
2116 else {
2117 envp = (char *)"all_proxy";
2118 proxy = curl_getenv(envp); /* default proxy to use */
2119 if(!proxy) {
2120 envp = (char *)"ALL_PROXY";
2121 proxy = curl_getenv(envp);
2122 }
2123 }
2124 if(proxy)
2125 infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
2126
2127 return proxy;
2128}
2129#endif /* CURL_DISABLE_HTTP */
2130
2131/*
2132 * If this is supposed to use a proxy, we need to figure out the proxy
2133 * host name, so that we can reuse an existing connection
2134 * that may exist registered to the same proxy host.
2135 */
2136static CURLcode parse_proxy(struct Curl_easy *data,
2137 struct connectdata *conn, char *proxy,
2138 curl_proxytype proxytype)
2139{
2140 char *portptr = NULL;
2141 int port = -1;
2142 char *proxyuser = NULL;
2143 char *proxypasswd = NULL;
2144 char *host = NULL;
2145 bool sockstype;
2146 CURLUcode uc;
2147 struct proxy_info *proxyinfo;
2148 CURLU *uhp = curl_url();
2149 CURLcode result = CURLE_OK;
2150 char *scheme = NULL;
2151#ifdef USE_UNIX_SOCKETS
2152 char *path = NULL;
2153 bool is_unix_proxy = FALSE;
2154#endif
2155
2156
2157 if(!uhp) {
2158 result = CURLE_OUT_OF_MEMORY;
2159 goto error;
2160 }
2161
2162 /* When parsing the proxy, allowing non-supported schemes since we have
2163 these made up ones for proxies. Guess scheme for URLs without it. */
2164 uc = curl_url_set(uhp, CURLUPART_URL, proxy,
2165 CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
2166 if(!uc) {
2167 /* parsed okay as a URL */
2168 uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, 0);
2169 if(uc) {
2170 result = CURLE_OUT_OF_MEMORY;
2171 goto error;
2172 }
2173
2174 if(strcasecompare("https", scheme)) {
2175 if(proxytype != CURLPROXY_HTTPS2)
2176 proxytype = CURLPROXY_HTTPS;
2177 else
2178 proxytype = CURLPROXY_HTTPS2;
2179 }
2180 else if(strcasecompare("socks5h", scheme))
2181 proxytype = CURLPROXY_SOCKS5_HOSTNAME;
2182 else if(strcasecompare("socks5", scheme))
2183 proxytype = CURLPROXY_SOCKS5;
2184 else if(strcasecompare("socks4a", scheme))
2185 proxytype = CURLPROXY_SOCKS4A;
2186 else if(strcasecompare("socks4", scheme) ||
2187 strcasecompare("socks", scheme))
2188 proxytype = CURLPROXY_SOCKS4;
2189 else if(strcasecompare("http", scheme))
2190 ; /* leave it as HTTP or HTTP/1.0 */
2191 else {
2192 /* Any other xxx:// reject! */
2193 failf(data, "Unsupported proxy scheme for \'%s\'", proxy);
2194 result = CURLE_COULDNT_CONNECT;
2195 goto error;
2196 }
2197 }
2198 else {
2199 failf(data, "Unsupported proxy syntax in \'%s\': %s", proxy,
2200 curl_url_strerror(uc));
2201 result = CURLE_COULDNT_RESOLVE_PROXY;
2202 goto error;
2203 }
2204
2205#ifdef USE_SSL
2206 if(!Curl_ssl_supports(data, SSLSUPP_HTTPS_PROXY))
2207#endif
2208 if(IS_HTTPS_PROXY(proxytype)) {
2209 failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
2210 "HTTPS-proxy support.", proxy);
2211 result = CURLE_NOT_BUILT_IN;
2212 goto error;
2213 }
2214
2215 sockstype =
2216 proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
2217 proxytype == CURLPROXY_SOCKS5 ||
2218 proxytype == CURLPROXY_SOCKS4A ||
2219 proxytype == CURLPROXY_SOCKS4;
2220
2221 proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy;
2222 proxyinfo->proxytype = (unsigned char)proxytype;
2223
2224 /* Is there a username and password given in this proxy url? */
2225 uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
2226 if(uc && (uc != CURLUE_NO_USER))
2227 goto error;
2228 uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
2229 if(uc && (uc != CURLUE_NO_PASSWORD))
2230 goto error;
2231
2232 if(proxyuser || proxypasswd) {
2233 Curl_safefree(proxyinfo->user);
2234 proxyinfo->user = proxyuser;
2235 result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser);
2236 proxyuser = NULL;
2237 if(result)
2238 goto error;
2239 Curl_safefree(proxyinfo->passwd);
2240 if(!proxypasswd) {
2241 proxypasswd = strdup("");
2242 if(!proxypasswd) {
2243 result = CURLE_OUT_OF_MEMORY;
2244 goto error;
2245 }
2246 }
2247 proxyinfo->passwd = proxypasswd;
2248 result = Curl_setstropt(&data->state.aptr.proxypasswd, proxypasswd);
2249 proxypasswd = NULL;
2250 if(result)
2251 goto error;
2252 conn->bits.proxy_user_passwd = TRUE; /* enable it */
2253 }
2254
2255 (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
2256
2257 if(portptr) {
2258 port = (int)strtol(portptr, NULL, 10);
2259 free(portptr);
2260 }
2261 else {
2262 if(data->set.proxyport)
2263 /* None given in the proxy string, then get the default one if it is
2264 given */
2265 port = (int)data->set.proxyport;
2266 else {
2267 if(IS_HTTPS_PROXY(proxytype))
2268 port = CURL_DEFAULT_HTTPS_PROXY_PORT;
2269 else
2270 port = CURL_DEFAULT_PROXY_PORT;
2271 }
2272 }
2273 if(port >= 0) {
2274 proxyinfo->port = port;
2275 if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc)
2276 conn->port = port;
2277 }
2278
2279 /* now, clone the proxy host name */
2280 uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
2281 if(uc) {
2282 result = CURLE_OUT_OF_MEMORY;
2283 goto error;
2284 }
2285#ifdef USE_UNIX_SOCKETS
2286 if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) {
2287 uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE);
2288 if(uc) {
2289 result = CURLE_OUT_OF_MEMORY;
2290 goto error;
2291 }
2292 /* path will be "/", if no path was found */
2293 if(strcmp("/", path)) {
2294 is_unix_proxy = TRUE;
2295 free(host);
2296 host = aprintf(UNIX_SOCKET_PREFIX"%s", path);
2297 if(!host) {
2298 result = CURLE_OUT_OF_MEMORY;
2299 goto error;
2300 }
2301 Curl_safefree(proxyinfo->host.rawalloc);
2302 proxyinfo->host.rawalloc = host;
2303 proxyinfo->host.name = host;
2304 host = NULL;
2305 }
2306 }
2307
2308 if(!is_unix_proxy) {
2309#endif
2310 Curl_safefree(proxyinfo->host.rawalloc);
2311 proxyinfo->host.rawalloc = host;
2312 if(host[0] == '[') {
2313 /* this is a numerical IPv6, strip off the brackets */
2314 size_t len = strlen(host);
2315 host[len-1] = 0; /* clear the trailing bracket */
2316 host++;
2317 zonefrom_url(uhp, data, conn);
2318 }
2319 proxyinfo->host.name = host;
2320 host = NULL;
2321#ifdef USE_UNIX_SOCKETS
2322 }
2323#endif
2324
2325error:
2326 free(proxyuser);
2327 free(proxypasswd);
2328 free(host);
2329 free(scheme);
2330#ifdef USE_UNIX_SOCKETS
2331 free(path);
2332#endif
2333 curl_url_cleanup(uhp);
2334 return result;
2335}
2336
2337/*
2338 * Extract the user and password from the authentication string
2339 */
2340static CURLcode parse_proxy_auth(struct Curl_easy *data,
2341 struct connectdata *conn)
2342{
2343 const char *proxyuser = data->state.aptr.proxyuser ?
2344 data->state.aptr.proxyuser : "";
2345 const char *proxypasswd = data->state.aptr.proxypasswd ?
2346 data->state.aptr.proxypasswd : "";
2347 CURLcode result = Curl_urldecode(proxyuser, 0, &conn->http_proxy.user, NULL,
2348 REJECT_ZERO);
2349 if(!result)
2350 result = Curl_setstropt(&data->state.aptr.proxyuser,
2351 conn->http_proxy.user);
2352 if(!result)
2353 result = Curl_urldecode(proxypasswd, 0, &conn->http_proxy.passwd,
2354 NULL, REJECT_ZERO);
2355 if(!result)
2356 result = Curl_setstropt(&data->state.aptr.proxypasswd,
2357 conn->http_proxy.passwd);
2358 return result;
2359}
2360
2361/* create_conn helper to parse and init proxy values. to be called after unix
2362 socket init but before any proxy vars are evaluated. */
2363static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
2364 struct connectdata *conn)
2365{
2366 char *proxy = NULL;
2367 char *socksproxy = NULL;
2368 char *no_proxy = NULL;
2369 CURLcode result = CURLE_OK;
2370 bool spacesep = FALSE;
2371
2372 /*************************************************************
2373 * Extract the user and password from the authentication string
2374 *************************************************************/
2375 if(conn->bits.proxy_user_passwd) {
2376 result = parse_proxy_auth(data, conn);
2377 if(result)
2378 goto out;
2379 }
2380
2381 /*************************************************************
2382 * Detect what (if any) proxy to use
2383 *************************************************************/
2384 if(data->set.str[STRING_PROXY]) {
2385 proxy = strdup(data->set.str[STRING_PROXY]);
2386 /* if global proxy is set, this is it */
2387 if(!proxy) {
2388 failf(data, "memory shortage");
2389 result = CURLE_OUT_OF_MEMORY;
2390 goto out;
2391 }
2392 }
2393
2394 if(data->set.str[STRING_PRE_PROXY]) {
2395 socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
2396 /* if global socks proxy is set, this is it */
2397 if(!socksproxy) {
2398 failf(data, "memory shortage");
2399 result = CURLE_OUT_OF_MEMORY;
2400 goto out;
2401 }
2402 }
2403
2404 if(!data->set.str[STRING_NOPROXY]) {
2405 const char *p = "no_proxy";
2406 no_proxy = curl_getenv(p);
2407 if(!no_proxy) {
2408 p = "NO_PROXY";
2409 no_proxy = curl_getenv(p);
2410 }
2411 if(no_proxy) {
2412 infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
2413 }
2414 }
2415
2416 if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
2417 data->set.str[STRING_NOPROXY] : no_proxy,
2418 &spacesep)) {
2419 Curl_safefree(proxy);
2420 Curl_safefree(socksproxy);
2421 }
2422#ifndef CURL_DISABLE_HTTP
2423 else if(!proxy && !socksproxy)
2424 /* if the host is not in the noproxy list, detect proxy. */
2425 proxy = detect_proxy(data, conn);
2426#endif /* CURL_DISABLE_HTTP */
2427 if(spacesep)
2428 infof(data, "space-separated NOPROXY patterns are deprecated");
2429
2430 Curl_safefree(no_proxy);
2431
2432#ifdef USE_UNIX_SOCKETS
2433 /* For the time being do not mix proxy and unix domain sockets. See #1274 */
2434 if(proxy && conn->unix_domain_socket) {
2435 free(proxy);
2436 proxy = NULL;
2437 }
2438#endif
2439
2440 if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
2441 free(proxy); /* Don't bother with an empty proxy string or if the
2442 protocol doesn't work with network */
2443 proxy = NULL;
2444 }
2445 if(socksproxy && (!*socksproxy ||
2446 (conn->handler->flags & PROTOPT_NONETWORK))) {
2447 free(socksproxy); /* Don't bother with an empty socks proxy string or if
2448 the protocol doesn't work with network */
2449 socksproxy = NULL;
2450 }
2451
2452 /***********************************************************************
2453 * If this is supposed to use a proxy, we need to figure out the proxy host
2454 * name, proxy type and port number, so that we can reuse an existing
2455 * connection that may exist registered to the same proxy host.
2456 ***********************************************************************/
2457 if(proxy || socksproxy) {
2458 curl_proxytype ptype = (curl_proxytype)conn->http_proxy.proxytype;
2459 if(proxy) {
2460 result = parse_proxy(data, conn, proxy, ptype);
2461 Curl_safefree(proxy); /* parse_proxy copies the proxy string */
2462 if(result)
2463 goto out;
2464 }
2465
2466 if(socksproxy) {
2467 result = parse_proxy(data, conn, socksproxy, ptype);
2468 /* parse_proxy copies the socks proxy string */
2469 Curl_safefree(socksproxy);
2470 if(result)
2471 goto out;
2472 }
2473
2474 if(conn->http_proxy.host.rawalloc) {
2475#ifdef CURL_DISABLE_HTTP
2476 /* asking for an HTTP proxy is a bit funny when HTTP is disabled... */
2477 result = CURLE_UNSUPPORTED_PROTOCOL;
2478 goto out;
2479#else
2480 /* force this connection's protocol to become HTTP if compatible */
2481 if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) {
2482 if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) &&
2483 !conn->bits.tunnel_proxy)
2484 conn->handler = &Curl_handler_http;
2485 else
2486 /* if not converting to HTTP over the proxy, enforce tunneling */
2487 conn->bits.tunnel_proxy = TRUE;
2488 }
2489 conn->bits.httpproxy = TRUE;
2490#endif
2491 }
2492 else {
2493 conn->bits.httpproxy = FALSE; /* not an HTTP proxy */
2494 conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
2495 }
2496
2497 if(conn->socks_proxy.host.rawalloc) {
2498 if(!conn->http_proxy.host.rawalloc) {
2499 /* once a socks proxy */
2500 if(!conn->socks_proxy.user) {
2501 conn->socks_proxy.user = conn->http_proxy.user;
2502 conn->http_proxy.user = NULL;
2503 Curl_safefree(conn->socks_proxy.passwd);
2504 conn->socks_proxy.passwd = conn->http_proxy.passwd;
2505 conn->http_proxy.passwd = NULL;
2506 }
2507 }
2508 conn->bits.socksproxy = TRUE;
2509 }
2510 else
2511 conn->bits.socksproxy = FALSE; /* not a socks proxy */
2512 }
2513 else {
2514 conn->bits.socksproxy = FALSE;
2515 conn->bits.httpproxy = FALSE;
2516 }
2517 conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
2518
2519 if(!conn->bits.proxy) {
2520 /* we aren't using the proxy after all... */
2521 conn->bits.proxy = FALSE;
2522 conn->bits.httpproxy = FALSE;
2523 conn->bits.socksproxy = FALSE;
2524 conn->bits.proxy_user_passwd = FALSE;
2525 conn->bits.tunnel_proxy = FALSE;
2526 /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
2527 to signal that CURLPROXY_HTTPS is not used for this connection */
2528 conn->http_proxy.proxytype = CURLPROXY_HTTP;
2529 }
2530
2531out:
2532
2533 free(socksproxy);
2534 free(proxy);
2535 return result;
2536}
2537#endif /* CURL_DISABLE_PROXY */
2538
2539/*
2540 * Curl_parse_login_details()
2541 *
2542 * This is used to parse a login string for user name, password and options in
2543 * the following formats:
2544 *
2545 * user
2546 * user:password
2547 * user:password;options
2548 * user;options
2549 * user;options:password
2550 * :password
2551 * :password;options
2552 * ;options
2553 * ;options:password
2554 *
2555 * Parameters:
2556 *
2557 * login [in] - The login string.
2558 * len [in] - The length of the login string.
2559 * userp [in/out] - The address where a pointer to newly allocated memory
2560 * holding the user will be stored upon completion.
2561 * passwdp [in/out] - The address where a pointer to newly allocated memory
2562 * holding the password will be stored upon completion.
2563 * optionsp [in/out] - The address where a pointer to newly allocated memory
2564 * holding the options will be stored upon completion.
2565 *
2566 * Returns CURLE_OK on success.
2567 */
2568CURLcode Curl_parse_login_details(const char *login, const size_t len,
2569 char **userp, char **passwdp,
2570 char **optionsp)
2571{
2572 CURLcode result = CURLE_OK;
2573 char *ubuf = NULL;
2574 char *pbuf = NULL;
2575 char *obuf = NULL;
2576 const char *psep = NULL;
2577 const char *osep = NULL;
2578 size_t ulen;
2579 size_t plen;
2580 size_t olen;
2581
2582 /* Attempt to find the password separator */
2583 if(passwdp)
2584 psep = memchr(login, ':', len);
2585
2586 /* Attempt to find the options separator */
2587 if(optionsp)
2588 osep = memchr(login, ';', len);
2589
2590 /* Calculate the portion lengths */
2591 ulen = (psep ?
2592 (size_t)(osep && psep > osep ? osep - login : psep - login) :
2593 (osep ? (size_t)(osep - login) : len));
2594 plen = (psep ?
2595 (osep && osep > psep ? (size_t)(osep - psep) :
2596 (size_t)(login + len - psep)) - 1 : 0);
2597 olen = (osep ?
2598 (psep && psep > osep ? (size_t)(psep - osep) :
2599 (size_t)(login + len - osep)) - 1 : 0);
2600
2601 /* Allocate the user portion buffer, which can be zero length */
2602 if(userp) {
2603 ubuf = malloc(ulen + 1);
2604 if(!ubuf)
2605 result = CURLE_OUT_OF_MEMORY;
2606 }
2607
2608 /* Allocate the password portion buffer */
2609 if(!result && passwdp && psep) {
2610 pbuf = malloc(plen + 1);
2611 if(!pbuf) {
2612 free(ubuf);
2613 result = CURLE_OUT_OF_MEMORY;
2614 }
2615 }
2616
2617 /* Allocate the options portion buffer */
2618 if(!result && optionsp && olen) {
2619 obuf = malloc(olen + 1);
2620 if(!obuf) {
2621 free(pbuf);
2622 free(ubuf);
2623 result = CURLE_OUT_OF_MEMORY;
2624 }
2625 }
2626
2627 if(!result) {
2628 /* Store the user portion if necessary */
2629 if(ubuf) {
2630 memcpy(ubuf, login, ulen);
2631 ubuf[ulen] = '\0';
2632 Curl_safefree(*userp);
2633 *userp = ubuf;
2634 }
2635
2636 /* Store the password portion if necessary */
2637 if(pbuf) {
2638 memcpy(pbuf, psep + 1, plen);
2639 pbuf[plen] = '\0';
2640 Curl_safefree(*passwdp);
2641 *passwdp = pbuf;
2642 }
2643
2644 /* Store the options portion if necessary */
2645 if(obuf) {
2646 memcpy(obuf, osep + 1, olen);
2647 obuf[olen] = '\0';
2648 Curl_safefree(*optionsp);
2649 *optionsp = obuf;
2650 }
2651 }
2652
2653 return result;
2654}
2655
2656/*************************************************************
2657 * Figure out the remote port number and fix it in the URL
2658 *
2659 * No matter if we use a proxy or not, we have to figure out the remote
2660 * port number of various reasons.
2661 *
2662 * The port number embedded in the URL is replaced, if necessary.
2663 *************************************************************/
2664static CURLcode parse_remote_port(struct Curl_easy *data,
2665 struct connectdata *conn)
2666{
2667
2668 if(data->set.use_port && data->state.allow_port) {
2669 /* if set, we use this instead of the port possibly given in the URL */
2670 char portbuf[16];
2671 CURLUcode uc;
2672 conn->remote_port = data->set.use_port;
2673 msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port);
2674 uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
2675 if(uc)
2676 return CURLE_OUT_OF_MEMORY;
2677 }
2678
2679 return CURLE_OK;
2680}
2681
2682/*
2683 * Override the login details from the URL with that in the CURLOPT_USERPWD
2684 * option or a .netrc file, if applicable.
2685 */
2686static CURLcode override_login(struct Curl_easy *data,
2687 struct connectdata *conn)
2688{
2689 CURLUcode uc;
2690 char **userp = &conn->user;
2691 char **passwdp = &conn->passwd;
2692 char **optionsp = &conn->options;
2693
2694 if(data->set.str[STRING_OPTIONS]) {
2695 free(*optionsp);
2696 *optionsp = strdup(data->set.str[STRING_OPTIONS]);
2697 if(!*optionsp)
2698 return CURLE_OUT_OF_MEMORY;
2699 }
2700
2701#ifndef CURL_DISABLE_NETRC
2702 if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
2703 Curl_safefree(*userp);
2704 Curl_safefree(*passwdp);
2705 }
2706 conn->bits.netrc = FALSE;
2707 if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
2708 int ret;
2709 bool url_provided = FALSE;
2710
2711 if(data->state.aptr.user) {
2712 /* there was a user name in the URL. Use the URL decoded version */
2713 userp = &data->state.aptr.user;
2714 url_provided = TRUE;
2715 }
2716
2717 ret = Curl_parsenetrc(conn->host.name,
2718 userp, passwdp,
2719 data->set.str[STRING_NETRC_FILE]);
2720 if(ret > 0) {
2721 infof(data, "Couldn't find host %s in the %s file; using defaults",
2722 conn->host.name, data->set.str[STRING_NETRC_FILE]);
2723 }
2724 else if(ret < 0) {
2725 failf(data, ".netrc parser error");
2726 return CURLE_READ_ERROR;
2727 }
2728 else {
2729 /* set bits.netrc TRUE to remember that we got the name from a .netrc
2730 file, so that it is safe to use even if we followed a Location: to a
2731 different host or similar. */
2732 conn->bits.netrc = TRUE;
2733 }
2734 if(url_provided) {
2735 Curl_safefree(conn->user);
2736 conn->user = strdup(*userp);
2737 if(!conn->user)
2738 return CURLE_OUT_OF_MEMORY;
2739 }
2740 /* no user was set but a password, set a blank user */
2741 if(!*userp && *passwdp) {
2742 *userp = strdup("");
2743 if(!*userp)
2744 return CURLE_OUT_OF_MEMORY;
2745 }
2746 }
2747#endif
2748
2749 /* for updated strings, we update them in the URL */
2750 if(*userp) {
2751 CURLcode result;
2752 if(data->state.aptr.user != *userp) {
2753 /* nothing to do then */
2754 result = Curl_setstropt(&data->state.aptr.user, *userp);
2755 if(result)
2756 return result;
2757 }
2758 }
2759 if(data->state.aptr.user) {
2760 uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
2761 CURLU_URLENCODE);
2762 if(uc)
2763 return Curl_uc_to_curlcode(uc);
2764 if(!*userp) {
2765 *userp = strdup(data->state.aptr.user);
2766 if(!*userp)
2767 return CURLE_OUT_OF_MEMORY;
2768 }
2769 }
2770 if(*passwdp) {
2771 CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
2772 if(result)
2773 return result;
2774 }
2775 if(data->state.aptr.passwd) {
2776 uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
2777 data->state.aptr.passwd, CURLU_URLENCODE);
2778 if(uc)
2779 return Curl_uc_to_curlcode(uc);
2780 if(!*passwdp) {
2781 *passwdp = strdup(data->state.aptr.passwd);
2782 if(!*passwdp)
2783 return CURLE_OUT_OF_MEMORY;
2784 }
2785 }
2786
2787 return CURLE_OK;
2788}
2789
2790/*
2791 * Set the login details so they're available in the connection
2792 */
2793static CURLcode set_login(struct Curl_easy *data,
2794 struct connectdata *conn)
2795{
2796 CURLcode result = CURLE_OK;
2797 const char *setuser = CURL_DEFAULT_USER;
2798 const char *setpasswd = CURL_DEFAULT_PASSWORD;
2799
2800 /* If our protocol needs a password and we have none, use the defaults */
2801 if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user)
2802 ;
2803 else {
2804 setuser = "";
2805 setpasswd = "";
2806 }
2807 /* Store the default user */
2808 if(!conn->user) {
2809 conn->user = strdup(setuser);
2810 if(!conn->user)
2811 return CURLE_OUT_OF_MEMORY;
2812 }
2813
2814 /* Store the default password */
2815 if(!conn->passwd) {
2816 conn->passwd = strdup(setpasswd);
2817 if(!conn->passwd)
2818 result = CURLE_OUT_OF_MEMORY;
2819 }
2820
2821 return result;
2822}
2823
2824/*
2825 * Parses a "host:port" string to connect to.
2826 * The hostname and the port may be empty; in this case, NULL is returned for
2827 * the hostname and -1 for the port.
2828 */
2829static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
2830 const char *host,
2831 char **hostname_result,
2832 int *port_result)
2833{
2834 char *host_dup;
2835 char *hostptr;
2836 char *host_portno;
2837 char *portptr;
2838 int port = -1;
2839 CURLcode result = CURLE_OK;
2840
2841#if defined(CURL_DISABLE_VERBOSE_STRINGS)
2842 (void) data;
2843#endif
2844
2845 *hostname_result = NULL;
2846 *port_result = -1;
2847
2848 if(!host || !*host)
2849 return CURLE_OK;
2850
2851 host_dup = strdup(host);
2852 if(!host_dup)
2853 return CURLE_OUT_OF_MEMORY;
2854
2855 hostptr = host_dup;
2856
2857 /* start scanning for port number at this point */
2858 portptr = hostptr;
2859
2860 /* detect and extract RFC6874-style IPv6-addresses */
2861 if(*hostptr == '[') {
2862#ifdef ENABLE_IPV6
2863 char *ptr = ++hostptr; /* advance beyond the initial bracket */
2864 while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
2865 ptr++;
2866 if(*ptr == '%') {
2867 /* There might be a zone identifier */
2868 if(strncmp("%25", ptr, 3))
2869 infof(data, "Please URL encode %% as %%25, see RFC 6874.");
2870 ptr++;
2871 /* Allow unreserved characters as defined in RFC 3986 */
2872 while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
2873 (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
2874 ptr++;
2875 }
2876 if(*ptr == ']')
2877 /* yeps, it ended nicely with a bracket as well */
2878 *ptr++ = '\0';
2879 else
2880 infof(data, "Invalid IPv6 address format");
2881 portptr = ptr;
2882 /* Note that if this didn't end with a bracket, we still advanced the
2883 * hostptr first, but I can't see anything wrong with that as no host
2884 * name nor a numeric can legally start with a bracket.
2885 */
2886#else
2887 failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
2888 result = CURLE_NOT_BUILT_IN;
2889 goto error;
2890#endif
2891 }
2892
2893 /* Get port number off server.com:1080 */
2894 host_portno = strchr(portptr, ':');
2895 if(host_portno) {
2896 char *endp = NULL;
2897 *host_portno = '\0'; /* cut off number from host name */
2898 host_portno++;
2899 if(*host_portno) {
2900 long portparse = strtol(host_portno, &endp, 10);
2901 if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
2902 failf(data, "No valid port number in connect to host string (%s)",
2903 host_portno);
2904 result = CURLE_SETOPT_OPTION_SYNTAX;
2905 goto error;
2906 }
2907 else
2908 port = (int)portparse; /* we know it will fit */
2909 }
2910 }
2911
2912 /* now, clone the cleaned host name */
2913 DEBUGASSERT(hostptr);
2914 *hostname_result = strdup(hostptr);
2915 if(!*hostname_result) {
2916 result = CURLE_OUT_OF_MEMORY;
2917 goto error;
2918 }
2919
2920 *port_result = port;
2921
2922error:
2923 free(host_dup);
2924 return result;
2925}
2926
2927/*
2928 * Parses one "connect to" string in the form:
2929 * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
2930 */
2931static CURLcode parse_connect_to_string(struct Curl_easy *data,
2932 struct connectdata *conn,
2933 const char *conn_to_host,
2934 char **host_result,
2935 int *port_result)
2936{
2937 CURLcode result = CURLE_OK;
2938 const char *ptr = conn_to_host;
2939 int host_match = FALSE;
2940 int port_match = FALSE;
2941
2942 *host_result = NULL;
2943 *port_result = -1;
2944
2945 if(*ptr == ':') {
2946 /* an empty hostname always matches */
2947 host_match = TRUE;
2948 ptr++;
2949 }
2950 else {
2951 /* check whether the URL's hostname matches */
2952 size_t hostname_to_match_len;
2953 char *hostname_to_match = aprintf("%s%s%s",
2954 conn->bits.ipv6_ip ? "[" : "",
2955 conn->host.name,
2956 conn->bits.ipv6_ip ? "]" : "");
2957 if(!hostname_to_match)
2958 return CURLE_OUT_OF_MEMORY;
2959 hostname_to_match_len = strlen(hostname_to_match);
2960 host_match = strncasecompare(ptr, hostname_to_match,
2961 hostname_to_match_len);
2962 free(hostname_to_match);
2963 ptr += hostname_to_match_len;
2964
2965 host_match = host_match && *ptr == ':';
2966 ptr++;
2967 }
2968
2969 if(host_match) {
2970 if(*ptr == ':') {
2971 /* an empty port always matches */
2972 port_match = TRUE;
2973 ptr++;
2974 }
2975 else {
2976 /* check whether the URL's port matches */
2977 char *ptr_next = strchr(ptr, ':');
2978 if(ptr_next) {
2979 char *endp = NULL;
2980 long port_to_match = strtol(ptr, &endp, 10);
2981 if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
2982 port_match = TRUE;
2983 ptr = ptr_next + 1;
2984 }
2985 }
2986 }
2987 }
2988
2989 if(host_match && port_match) {
2990 /* parse the hostname and port to connect to */
2991 result = parse_connect_to_host_port(data, ptr, host_result, port_result);
2992 }
2993
2994 return result;
2995}
2996
2997/*
2998 * Processes all strings in the "connect to" slist, and uses the "connect
2999 * to host" and "connect to port" of the first string that matches.
3000 */
3001static CURLcode parse_connect_to_slist(struct Curl_easy *data,
3002 struct connectdata *conn,
3003 struct curl_slist *conn_to_host)
3004{
3005 CURLcode result = CURLE_OK;
3006 char *host = NULL;
3007 int port = -1;
3008
3009 while(conn_to_host && !host && port == -1) {
3010 result = parse_connect_to_string(data, conn, conn_to_host->data,
3011 &host, &port);
3012 if(result)
3013 return result;
3014
3015 if(host && *host) {
3016 conn->conn_to_host.rawalloc = host;
3017 conn->conn_to_host.name = host;
3018 conn->bits.conn_to_host = TRUE;
3019
3020 infof(data, "Connecting to hostname: %s", host);
3021 }
3022 else {
3023 /* no "connect to host" */
3024 conn->bits.conn_to_host = FALSE;
3025 Curl_safefree(host);
3026 }
3027
3028 if(port >= 0) {
3029 conn->conn_to_port = port;
3030 conn->bits.conn_to_port = TRUE;
3031 infof(data, "Connecting to port: %d", port);
3032 }
3033 else {
3034 /* no "connect to port" */
3035 conn->bits.conn_to_port = FALSE;
3036 port = -1;
3037 }
3038
3039 conn_to_host = conn_to_host->next;
3040 }
3041
3042#ifndef CURL_DISABLE_ALTSVC
3043 if(data->asi && !host && (port == -1) &&
3044 ((conn->handler->protocol == CURLPROTO_HTTPS) ||
3045#ifdef CURLDEBUG
3046 /* allow debug builds to circumvent the HTTPS restriction */
3047 getenv("CURL_ALTSVC_HTTP")
3048#else
3049 0
3050#endif
3051 )) {
3052 /* no connect_to match, try alt-svc! */
3053 enum alpnid srcalpnid;
3054 bool hit;
3055 struct altsvc *as;
3056 const int allowed_versions = ( ALPN_h1
3057#ifdef USE_HTTP2
3058 | ALPN_h2
3059#endif
3060#ifdef ENABLE_QUIC
3061 | ALPN_h3
3062#endif
3063 ) & data->asi->flags;
3064
3065 host = conn->host.rawalloc;
3066#ifdef USE_HTTP2
3067 /* with h2 support, check that first */
3068 srcalpnid = ALPN_h2;
3069 hit = Curl_altsvc_lookup(data->asi,
3070 srcalpnid, host, conn->remote_port, /* from */
3071 &as /* to */,
3072 allowed_versions);
3073 if(!hit)
3074#endif
3075 {
3076 srcalpnid = ALPN_h1;
3077 hit = Curl_altsvc_lookup(data->asi,
3078 srcalpnid, host, conn->remote_port, /* from */
3079 &as /* to */,
3080 allowed_versions);
3081 }
3082 if(hit) {
3083 char *hostd = strdup((char *)as->dst.host);
3084 if(!hostd)
3085 return CURLE_OUT_OF_MEMORY;
3086 conn->conn_to_host.rawalloc = hostd;
3087 conn->conn_to_host.name = hostd;
3088 conn->bits.conn_to_host = TRUE;
3089 conn->conn_to_port = as->dst.port;
3090 conn->bits.conn_to_port = TRUE;
3091 conn->bits.altused = TRUE;
3092 infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d",
3093 Curl_alpnid2str(srcalpnid), host, conn->remote_port,
3094 Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
3095 if(srcalpnid != as->dst.alpnid) {
3096 /* protocol version switch */
3097 switch(as->dst.alpnid) {
3098 case ALPN_h1:
3099 conn->httpversion = 11;
3100 break;
3101 case ALPN_h2:
3102 conn->httpversion = 20;
3103 break;
3104 case ALPN_h3:
3105 conn->transport = TRNSPRT_QUIC;
3106 conn->httpversion = 30;
3107 break;
3108 default: /* shouldn't be possible */
3109 break;
3110 }
3111 }
3112 }
3113 }
3114#endif
3115
3116 return result;
3117}
3118
3119#ifdef USE_UNIX_SOCKETS
3120static CURLcode resolve_unix(struct Curl_easy *data,
3121 struct connectdata *conn,
3122 char *unix_path)
3123{
3124 struct Curl_dns_entry *hostaddr = NULL;
3125 bool longpath = FALSE;
3126
3127 DEBUGASSERT(unix_path);
3128 DEBUGASSERT(conn->dns_entry == NULL);
3129
3130 /* Unix domain sockets are local. The host gets ignored, just use the
3131 * specified domain socket address. Do not cache "DNS entries". There is
3132 * no DNS involved and we already have the filesystem path available. */
3133 hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
3134 if(!hostaddr)
3135 return CURLE_OUT_OF_MEMORY;
3136
3137 hostaddr->addr = Curl_unix2addr(unix_path, &longpath,
3138 conn->bits.abstract_unix_socket);
3139 if(!hostaddr->addr) {
3140 if(longpath)
3141 /* Long paths are not supported for now */
3142 failf(data, "Unix socket path too long: '%s'", unix_path);
3143 free(hostaddr);
3144 return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY;
3145 }
3146
3147 hostaddr->inuse++;
3148 conn->dns_entry = hostaddr;
3149 return CURLE_OK;
3150}
3151#endif
3152
3153#ifndef CURL_DISABLE_PROXY
3154static CURLcode resolve_proxy(struct Curl_easy *data,
3155 struct connectdata *conn,
3156 bool *async)
3157{
3158 struct Curl_dns_entry *hostaddr = NULL;
3159 struct hostname *host;
3160 timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
3161 int rc;
3162
3163 DEBUGASSERT(conn->dns_entry == NULL);
3164
3165 host = conn->bits.socksproxy ? &conn->socks_proxy.host :
3166 &conn->http_proxy.host;
3167
3168 conn->hostname_resolve = strdup(host->name);
3169 if(!conn->hostname_resolve)
3170 return CURLE_OUT_OF_MEMORY;
3171
3172 rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
3173 &hostaddr, timeout_ms);
3174 conn->dns_entry = hostaddr;
3175 if(rc == CURLRESOLV_PENDING)
3176 *async = TRUE;
3177 else if(rc == CURLRESOLV_TIMEDOUT)
3178 return CURLE_OPERATION_TIMEDOUT;
3179 else if(!hostaddr) {
3180 failf(data, "Couldn't resolve proxy '%s'", host->dispname);
3181 return CURLE_COULDNT_RESOLVE_PROXY;
3182 }
3183
3184 return CURLE_OK;
3185}
3186#endif
3187
3188static CURLcode resolve_host(struct Curl_easy *data,
3189 struct connectdata *conn,
3190 bool *async)
3191{
3192 struct Curl_dns_entry *hostaddr = NULL;
3193 struct hostname *connhost;
3194 timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
3195 int rc;
3196
3197 DEBUGASSERT(conn->dns_entry == NULL);
3198
3199 connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
3200
3201 /* If not connecting via a proxy, extract the port from the URL, if it is
3202 * there, thus overriding any defaults that might have been set above. */
3203 conn->port = conn->bits.conn_to_port ? conn->conn_to_port :
3204 conn->remote_port;
3205
3206 /* Resolve target host right on */
3207 conn->hostname_resolve = strdup(connhost->name);
3208 if(!conn->hostname_resolve)
3209 return CURLE_OUT_OF_MEMORY;
3210
3211 rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
3212 &hostaddr, timeout_ms);
3213 conn->dns_entry = hostaddr;
3214 if(rc == CURLRESOLV_PENDING)
3215 *async = TRUE;
3216 else if(rc == CURLRESOLV_TIMEDOUT) {
3217 failf(data, "Failed to resolve host '%s' with timeout after %ld ms",
3218 connhost->dispname,
3219 Curl_timediff(Curl_now(), data->progress.t_startsingle));
3220 return CURLE_OPERATION_TIMEDOUT;
3221 }
3222 else if(!hostaddr) {
3223 failf(data, "Could not resolve host: %s", connhost->dispname);
3224 return CURLE_COULDNT_RESOLVE_HOST;
3225 }
3226
3227 return CURLE_OK;
3228}
3229
3230/* Perform a fresh resolve */
3231static CURLcode resolve_fresh(struct Curl_easy *data,
3232 struct connectdata *conn,
3233 bool *async)
3234{
3235#ifdef USE_UNIX_SOCKETS
3236 char *unix_path = conn->unix_domain_socket;
3237
3238#ifndef CURL_DISABLE_PROXY
3239 if(!unix_path && conn->socks_proxy.host.name &&
3240 !strncmp(UNIX_SOCKET_PREFIX"/",
3241 conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
3242 unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
3243#endif
3244
3245 if(unix_path) {
3246 conn->transport = TRNSPRT_UNIX;
3247 return resolve_unix(data, conn, unix_path);
3248 }
3249#endif
3250
3251#ifndef CURL_DISABLE_PROXY
3252 if(CONN_IS_PROXIED(conn))
3253 return resolve_proxy(data, conn, async);
3254#endif
3255
3256 return resolve_host(data, conn, async);
3257}
3258
3259/*************************************************************
3260 * Resolve the address of the server or proxy
3261 *************************************************************/
3262static CURLcode resolve_server(struct Curl_easy *data,
3263 struct connectdata *conn,
3264 bool *async)
3265{
3266 DEBUGASSERT(conn);
3267 DEBUGASSERT(data);
3268
3269 /* Resolve the name of the server or proxy */
3270 if(conn->bits.reuse) {
3271 /* We're reusing the connection - no need to resolve anything, and
3272 idnconvert_hostname() was called already in create_conn() for the reuse
3273 case. */
3274 *async = FALSE;
3275 return CURLE_OK;
3276 }
3277
3278 return resolve_fresh(data, conn, async);
3279}
3280
3281/*
3282 * Cleanup the connection `temp`, just allocated for `data`, before using the
3283 * previously `existing` one for `data`. All relevant info is copied over
3284 * and `temp` is freed.
3285 */
3286static void reuse_conn(struct Curl_easy *data,
3287 struct connectdata *temp,
3288 struct connectdata *existing)
3289{
3290 /* get the user+password information from the temp struct since it may
3291 * be new for this request even when we reuse an existing connection */
3292 if(temp->user) {
3293 /* use the new user name and password though */
3294 Curl_safefree(existing->user);
3295 Curl_safefree(existing->passwd);
3296 existing->user = temp->user;
3297 existing->passwd = temp->passwd;
3298 temp->user = NULL;
3299 temp->passwd = NULL;
3300 }
3301
3302#ifndef CURL_DISABLE_PROXY
3303 existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
3304 if(existing->bits.proxy_user_passwd) {
3305 /* use the new proxy user name and proxy password though */
3306 Curl_safefree(existing->http_proxy.user);
3307 Curl_safefree(existing->socks_proxy.user);
3308 Curl_safefree(existing->http_proxy.passwd);
3309 Curl_safefree(existing->socks_proxy.passwd);
3310 existing->http_proxy.user = temp->http_proxy.user;
3311 existing->socks_proxy.user = temp->socks_proxy.user;
3312 existing->http_proxy.passwd = temp->http_proxy.passwd;
3313 existing->socks_proxy.passwd = temp->socks_proxy.passwd;
3314 temp->http_proxy.user = NULL;
3315 temp->socks_proxy.user = NULL;
3316 temp->http_proxy.passwd = NULL;
3317 temp->socks_proxy.passwd = NULL;
3318 }
3319#endif
3320
3321 /* Finding a connection for reuse in the cache matches, among other
3322 * things on the "remote-relevant" hostname. This is not necessarily
3323 * the authority of the URL, e.g. conn->host. For example:
3324 * - we use a proxy (not tunneling). we want to send all requests
3325 * that use the same proxy on this connection.
3326 * - we have a "connect-to" setting that may redirect the hostname of
3327 * a new request to the same remote endpoint of an existing conn.
3328 * We want to reuse an existing conn to the remote endpoint.
3329 * Since connection reuse does not match on conn->host necessarily, we
3330 * switch `existing` conn to `temp` conn's host settings.
3331 * TODO: is this correct in the case of TLS connections that have
3332 * used the original hostname in SNI to negotiate? Do we send
3333 * requests for another host through the different SNI?
3334 */
3335 Curl_free_idnconverted_hostname(&existing->host);
3336 Curl_free_idnconverted_hostname(&existing->conn_to_host);
3337 Curl_safefree(existing->host.rawalloc);
3338 Curl_safefree(existing->conn_to_host.rawalloc);
3339 existing->host = temp->host;
3340 temp->host.rawalloc = NULL;
3341 temp->host.encalloc = NULL;
3342 existing->conn_to_host = temp->conn_to_host;
3343 temp->conn_to_host.rawalloc = NULL;
3344 existing->conn_to_port = temp->conn_to_port;
3345 existing->remote_port = temp->remote_port;
3346 Curl_safefree(existing->hostname_resolve);
3347
3348 existing->hostname_resolve = temp->hostname_resolve;
3349 temp->hostname_resolve = NULL;
3350
3351 /* reuse init */
3352 existing->bits.reuse = TRUE; /* yes, we're reusing here */
3353
3354 conn_free(data, temp);
3355}
3356
3357/**
3358 * create_conn() sets up a new connectdata struct, or reuses an already
3359 * existing one, and resolves host name.
3360 *
3361 * if this function returns CURLE_OK and *async is set to TRUE, the resolve
3362 * response will be coming asynchronously. If *async is FALSE, the name is
3363 * already resolved.
3364 *
3365 * @param data The sessionhandle pointer
3366 * @param in_connect is set to the next connection data pointer
3367 * @param async is set TRUE when an async DNS resolution is pending
3368 * @see Curl_setup_conn()
3369 *
3370 */
3371
3372static CURLcode create_conn(struct Curl_easy *data,
3373 struct connectdata **in_connect,
3374 bool *async)
3375{
3376 CURLcode result = CURLE_OK;
3377 struct connectdata *conn;
3378 struct connectdata *existing = NULL;
3379 bool reuse;
3380 bool connections_available = TRUE;
3381 bool force_reuse = FALSE;
3382 bool waitpipe = FALSE;
3383 size_t max_host_connections = Curl_multi_max_host_connections(data->multi);
3384 size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
3385
3386 *async = FALSE;
3387 *in_connect = NULL;
3388
3389 /*************************************************************
3390 * Check input data
3391 *************************************************************/
3392 if(!data->state.url) {
3393 result = CURLE_URL_MALFORMAT;
3394 goto out;
3395 }
3396
3397 /* First, split up the current URL in parts so that we can use the
3398 parts for checking against the already present connections. In order
3399 to not have to modify everything at once, we allocate a temporary
3400 connection data struct and fill in for comparison purposes. */
3401 conn = allocate_conn(data);
3402
3403 if(!conn) {
3404 result = CURLE_OUT_OF_MEMORY;
3405 goto out;
3406 }
3407
3408 /* We must set the return variable as soon as possible, so that our
3409 parent can cleanup any possible allocs we may have done before
3410 any failure */
3411 *in_connect = conn;
3412
3413 result = parseurlandfillconn(data, conn);
3414 if(result)
3415 goto out;
3416
3417 if(data->set.str[STRING_SASL_AUTHZID]) {
3418 conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
3419 if(!conn->sasl_authzid) {
3420 result = CURLE_OUT_OF_MEMORY;
3421 goto out;
3422 }
3423 }
3424
3425 if(data->set.str[STRING_BEARER]) {
3426 conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
3427 if(!conn->oauth_bearer) {
3428 result = CURLE_OUT_OF_MEMORY;
3429 goto out;
3430 }
3431 }
3432
3433#ifdef USE_UNIX_SOCKETS
3434 if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
3435 conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
3436 if(!conn->unix_domain_socket) {
3437 result = CURLE_OUT_OF_MEMORY;
3438 goto out;
3439 }
3440 conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
3441 }
3442#endif
3443
3444 /* After the unix socket init but before the proxy vars are used, parse and
3445 initialize the proxy vars */
3446#ifndef CURL_DISABLE_PROXY
3447 result = create_conn_helper_init_proxy(data, conn);
3448 if(result)
3449 goto out;
3450
3451 /*************************************************************
3452 * If the protocol is using SSL and HTTP proxy is used, we set
3453 * the tunnel_proxy bit.
3454 *************************************************************/
3455 if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
3456 conn->bits.tunnel_proxy = TRUE;
3457#endif
3458
3459 /*************************************************************
3460 * Figure out the remote port number and fix it in the URL
3461 *************************************************************/
3462 result = parse_remote_port(data, conn);
3463 if(result)
3464 goto out;
3465
3466 /* Check for overridden login details and set them accordingly so that
3467 they are known when protocol->setup_connection is called! */
3468 result = override_login(data, conn);
3469 if(result)
3470 goto out;
3471
3472 result = set_login(data, conn); /* default credentials */
3473 if(result)
3474 goto out;
3475
3476 /*************************************************************
3477 * Process the "connect to" linked list of hostname/port mappings.
3478 * Do this after the remote port number has been fixed in the URL.
3479 *************************************************************/
3480 result = parse_connect_to_slist(data, conn, data->set.connect_to);
3481 if(result)
3482 goto out;
3483
3484 /*************************************************************
3485 * IDN-convert the proxy hostnames
3486 *************************************************************/
3487#ifndef CURL_DISABLE_PROXY
3488 if(conn->bits.httpproxy) {
3489 result = Curl_idnconvert_hostname(&conn->http_proxy.host);
3490 if(result)
3491 return result;
3492 }
3493 if(conn->bits.socksproxy) {
3494 result = Curl_idnconvert_hostname(&conn->socks_proxy.host);
3495 if(result)
3496 return result;
3497 }
3498#endif
3499 if(conn->bits.conn_to_host) {
3500 result = Curl_idnconvert_hostname(&conn->conn_to_host);
3501 if(result)
3502 return result;
3503 }
3504
3505 /*************************************************************
3506 * Check whether the host and the "connect to host" are equal.
3507 * Do this after the hostnames have been IDN-converted.
3508 *************************************************************/
3509 if(conn->bits.conn_to_host &&
3510 strcasecompare(conn->conn_to_host.name, conn->host.name)) {
3511 conn->bits.conn_to_host = FALSE;
3512 }
3513
3514 /*************************************************************
3515 * Check whether the port and the "connect to port" are equal.
3516 * Do this after the remote port number has been fixed in the URL.
3517 *************************************************************/
3518 if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
3519 conn->bits.conn_to_port = FALSE;
3520 }
3521
3522#ifndef CURL_DISABLE_PROXY
3523 /*************************************************************
3524 * If the "connect to" feature is used with an HTTP proxy,
3525 * we set the tunnel_proxy bit.
3526 *************************************************************/
3527 if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
3528 conn->bits.httpproxy)
3529 conn->bits.tunnel_proxy = TRUE;
3530#endif
3531
3532 /*************************************************************
3533 * Setup internals depending on protocol. Needs to be done after
3534 * we figured out what/if proxy to use.
3535 *************************************************************/
3536 result = setup_connection_internals(data, conn);
3537 if(result)
3538 goto out;
3539
3540 /***********************************************************************
3541 * file: is a special case in that it doesn't need a network connection
3542 ***********************************************************************/
3543#ifndef CURL_DISABLE_FILE
3544 if(conn->handler->flags & PROTOPT_NONETWORK) {
3545 bool done;
3546 /* this is supposed to be the connect function so we better at least check
3547 that the file is present here! */
3548 DEBUGASSERT(conn->handler->connect_it);
3549 Curl_persistconninfo(data, conn, NULL, -1);
3550 result = conn->handler->connect_it(data, &done);
3551
3552 /* Setup a "faked" transfer that'll do nothing */
3553 if(!result) {
3554 Curl_attach_connection(data, conn);
3555 result = Curl_conncache_add_conn(data);
3556 if(result)
3557 goto out;
3558
3559 /*
3560 * Setup whatever necessary for a resumed transfer
3561 */
3562 result = setup_range(data);
3563 if(result) {
3564 DEBUGASSERT(conn->handler->done);
3565 /* we ignore the return code for the protocol-specific DONE */
3566 (void)conn->handler->done(data, result, FALSE);
3567 goto out;
3568 }
3569 Curl_setup_transfer(data, -1, -1, FALSE, -1);
3570 }
3571
3572 /* since we skip do_init() */
3573 Curl_init_do(data, conn);
3574
3575 goto out;
3576 }
3577#endif
3578
3579 /* Setup filter for network connections */
3580 conn->recv[FIRSTSOCKET] = Curl_conn_recv;
3581 conn->send[FIRSTSOCKET] = Curl_conn_send;
3582 conn->recv[SECONDARYSOCKET] = Curl_conn_recv;
3583 conn->send[SECONDARYSOCKET] = Curl_conn_send;
3584 conn->bits.tcp_fastopen = data->set.tcp_fastopen;
3585
3586 /* Get a cloned copy of the SSL config situation stored in the
3587 connection struct. But to get this going nicely, we must first make
3588 sure that the strings in the master copy are pointing to the correct
3589 strings in the session handle strings array!
3590
3591 Keep in mind that the pointers in the master copy are pointing to strings
3592 that will be freed as part of the Curl_easy struct, but all cloned
3593 copies will be separately allocated.
3594 */
3595 data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH];
3596 data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE];
3597 data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
3598 data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
3599 data->set.ssl.primary.cipher_list =
3600 data->set.str[STRING_SSL_CIPHER_LIST];
3601 data->set.ssl.primary.cipher_list13 =
3602 data->set.str[STRING_SSL_CIPHER13_LIST];
3603 data->set.ssl.primary.pinned_key =
3604 data->set.str[STRING_SSL_PINNEDPUBLICKEY];
3605 data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT];
3606 data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
3607 data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES];
3608
3609#ifndef CURL_DISABLE_PROXY
3610 data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
3611 data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
3612 data->set.proxy_ssl.primary.cipher_list =
3613 data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
3614 data->set.proxy_ssl.primary.cipher_list13 =
3615 data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
3616 data->set.proxy_ssl.primary.pinned_key =
3617 data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
3618 data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
3619 data->set.proxy_ssl.primary.ca_info_blob =
3620 data->set.blobs[BLOB_CAINFO_PROXY];
3621 data->set.proxy_ssl.primary.issuercert =
3622 data->set.str[STRING_SSL_ISSUERCERT_PROXY];
3623 data->set.proxy_ssl.primary.issuercert_blob =
3624 data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
3625 data->set.proxy_ssl.primary.CRLfile =
3626 data->set.str[STRING_SSL_CRLFILE_PROXY];
3627 data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
3628 data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
3629 data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
3630 data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
3631 data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
3632 data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
3633#endif
3634 data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE];
3635 data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE];
3636 data->set.ssl.key = data->set.str[STRING_KEY];
3637 data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE];
3638 data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD];
3639 data->set.ssl.primary.clientcert = data->set.str[STRING_CERT];
3640#ifdef USE_TLS_SRP
3641 data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME];
3642 data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD];
3643#ifndef CURL_DISABLE_PROXY
3644 data->set.proxy_ssl.primary.username =
3645 data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
3646 data->set.proxy_ssl.primary.password =
3647 data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
3648#endif
3649#endif
3650 data->set.ssl.key_blob = data->set.blobs[BLOB_KEY];
3651
3652 if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary,
3653 &conn->ssl_config)) {
3654 result = CURLE_OUT_OF_MEMORY;
3655 goto out;
3656 }
3657
3658#ifndef CURL_DISABLE_PROXY
3659 if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary,
3660 &conn->proxy_ssl_config)) {
3661 result = CURLE_OUT_OF_MEMORY;
3662 goto out;
3663 }
3664#endif
3665
3666 prune_dead_connections(data);
3667
3668 /*************************************************************
3669 * Check the current list of connections to see if we can
3670 * reuse an already existing one or if we have to create a
3671 * new one.
3672 *************************************************************/
3673
3674 DEBUGASSERT(conn->user);
3675 DEBUGASSERT(conn->passwd);
3676
3677 /* reuse_fresh is TRUE if we are told to use a new connection by force, but
3678 we only acknowledge this option if this is not a reused connection
3679 already (which happens due to follow-location or during an HTTP
3680 authentication phase). CONNECT_ONLY transfers also refuse reuse. */
3681 if((data->set.reuse_fresh && !data->state.followlocation) ||
3682 data->set.connect_only)
3683 reuse = FALSE;
3684 else
3685 reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
3686
3687 if(reuse) {
3688 /*
3689 * We already have a connection for this, we got the former connection in
3690 * `existing` and thus we need to cleanup the one we just
3691 * allocated before we can move along and use `existing`.
3692 */
3693 reuse_conn(data, conn, existing);
3694 conn = existing;
3695 *in_connect = conn;
3696
3697#ifndef CURL_DISABLE_PROXY
3698 infof(data, "Re-using existing connection with %s %s",
3699 conn->bits.proxy?"proxy":"host",
3700 conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
3701 conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
3702 conn->host.dispname);
3703#else
3704 infof(data, "Re-using existing connection with host %s",
3705 conn->host.dispname);
3706#endif
3707 }
3708 else {
3709 /* We have decided that we want a new connection. However, we may not
3710 be able to do that if we have reached the limit of how many
3711 connections we are allowed to open. */
3712
3713 if(conn->handler->flags & PROTOPT_ALPN) {
3714 /* The protocol wants it, so set the bits if enabled in the easy handle
3715 (default) */
3716 if(data->set.ssl_enable_alpn)
3717 conn->bits.tls_enable_alpn = TRUE;
3718 }
3719
3720 if(waitpipe)
3721 /* There is a connection that *might* become usable for multiplexing
3722 "soon", and we wait for that */
3723 connections_available = FALSE;
3724 else {
3725 /* this gets a lock on the conncache */
3726 struct connectbundle *bundle =
3727 Curl_conncache_find_bundle(data, conn, data->state.conn_cache);
3728
3729 if(max_host_connections > 0 && bundle &&
3730 (bundle->num_connections >= max_host_connections)) {
3731 struct connectdata *conn_candidate;
3732
3733 /* The bundle is full. Extract the oldest connection. */
3734 conn_candidate = Curl_conncache_extract_bundle(data, bundle);
3735 CONNCACHE_UNLOCK(data);
3736
3737 if(conn_candidate)
3738 Curl_disconnect(data, conn_candidate, FALSE);
3739 else {
3740 infof(data, "No more connections allowed to host: %zu",
3741 max_host_connections);
3742 connections_available = FALSE;
3743 }
3744 }
3745 else
3746 CONNCACHE_UNLOCK(data);
3747
3748 }
3749
3750 if(connections_available &&
3751 (max_total_connections > 0) &&
3752 (Curl_conncache_size(data) >= max_total_connections)) {
3753 struct connectdata *conn_candidate;
3754
3755 /* The cache is full. Let's see if we can kill a connection. */
3756 conn_candidate = Curl_conncache_extract_oldest(data);
3757 if(conn_candidate)
3758 Curl_disconnect(data, conn_candidate, FALSE);
3759 else {
3760 infof(data, "No connections available in cache");
3761 connections_available = FALSE;
3762 }
3763 }
3764
3765 if(!connections_available) {
3766 infof(data, "No connections available.");
3767
3768 conn_free(data, conn);
3769 *in_connect = NULL;
3770
3771 result = CURLE_NO_CONNECTION_AVAILABLE;
3772 goto out;
3773 }
3774 else {
3775 /*
3776 * This is a brand new connection, so let's store it in the connection
3777 * cache of ours!
3778 */
3779 Curl_attach_connection(data, conn);
3780 result = Curl_conncache_add_conn(data);
3781 if(result)
3782 goto out;
3783 }
3784
3785#if defined(USE_NTLM)
3786 /* If NTLM is requested in a part of this connection, make sure we don't
3787 assume the state is fine as this is a fresh connection and NTLM is
3788 connection based. */
3789 if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
3790 data->state.authhost.done) {
3791 infof(data, "NTLM picked AND auth done set, clear picked");
3792 data->state.authhost.picked = CURLAUTH_NONE;
3793 data->state.authhost.done = FALSE;
3794 }
3795
3796 if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
3797 data->state.authproxy.done) {
3798 infof(data, "NTLM-proxy picked AND auth done set, clear picked");
3799 data->state.authproxy.picked = CURLAUTH_NONE;
3800 data->state.authproxy.done = FALSE;
3801 }
3802#endif
3803 }
3804
3805 /* Setup and init stuff before DO starts, in preparing for the transfer. */
3806 Curl_init_do(data, conn);
3807
3808 /*
3809 * Setup whatever necessary for a resumed transfer
3810 */
3811 result = setup_range(data);
3812 if(result)
3813 goto out;
3814
3815 /* Continue connectdata initialization here. */
3816
3817 /*
3818 * Inherit the proper values from the urldata struct AFTER we have arranged
3819 * the persistent connection stuff
3820 */
3821 conn->seek_func = data->set.seek_func;
3822 conn->seek_client = data->set.seek_client;
3823
3824 /*************************************************************
3825 * Resolve the address of the server or proxy
3826 *************************************************************/
3827 result = resolve_server(data, conn, async);
3828 if(result)
3829 goto out;
3830
3831 /* Everything general done, inform filters that they need
3832 * to prepare for a data transfer.
3833 */
3834 result = Curl_conn_ev_data_setup(data);
3835
3836out:
3837 return result;
3838}
3839
3840/* Curl_setup_conn() is called after the name resolve initiated in
3841 * create_conn() is all done.
3842 *
3843 * Curl_setup_conn() also handles reused connections
3844 */
3845CURLcode Curl_setup_conn(struct Curl_easy *data,
3846 bool *protocol_done)
3847{
3848 CURLcode result = CURLE_OK;
3849 struct connectdata *conn = data->conn;
3850
3851 Curl_pgrsTime(data, TIMER_NAMELOOKUP);
3852
3853 if(conn->handler->flags & PROTOPT_NONETWORK) {
3854 /* nothing to setup when not using a network */
3855 *protocol_done = TRUE;
3856 return result;
3857 }
3858
3859#ifndef CURL_DISABLE_PROXY
3860 /* set proxy_connect_closed to false unconditionally already here since it
3861 is used strictly to provide extra information to a parent function in the
3862 case of proxy CONNECT failures and we must make sure we don't have it
3863 lingering set from a previous invoke */
3864 conn->bits.proxy_connect_closed = FALSE;
3865#endif
3866
3867#ifdef CURL_DO_LINEEND_CONV
3868 data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
3869#endif /* CURL_DO_LINEEND_CONV */
3870
3871 /* set start time here for timeout purposes in the connect procedure, it
3872 is later set again for the progress meter purpose */
3873 conn->now = Curl_now();
3874 if(!conn->bits.reuse)
3875 result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry,
3876 CURL_CF_SSL_DEFAULT);
3877 /* not sure we need this flag to be passed around any more */
3878 *protocol_done = FALSE;
3879 return result;
3880}
3881
3882CURLcode Curl_connect(struct Curl_easy *data,
3883 bool *asyncp,
3884 bool *protocol_done)
3885{
3886 CURLcode result;
3887 struct connectdata *conn;
3888
3889 *asyncp = FALSE; /* assume synchronous resolves by default */
3890
3891 /* init the single-transfer specific data */
3892 Curl_free_request_state(data);
3893 memset(&data->req, 0, sizeof(struct SingleRequest));
3894 data->req.size = data->req.maxdownload = -1;
3895 data->req.no_body = data->set.opt_no_body;
3896
3897 /* call the stuff that needs to be called */
3898 result = create_conn(data, &conn, asyncp);
3899
3900 if(!result) {
3901 if(CONN_INUSE(conn) > 1)
3902 /* multiplexed */
3903 *protocol_done = TRUE;
3904 else if(!*asyncp) {
3905 /* DNS resolution is done: that's either because this is a reused
3906 connection, in which case DNS was unnecessary, or because DNS
3907 really did finish already (synch resolver/fast async resolve) */
3908 result = Curl_setup_conn(data, protocol_done);
3909 }
3910 }
3911
3912 if(result == CURLE_NO_CONNECTION_AVAILABLE) {
3913 return result;
3914 }
3915 else if(result && conn) {
3916 /* We're not allowed to return failure with memory left allocated in the
3917 connectdata struct, free those here */
3918 Curl_detach_connection(data);
3919 Curl_conncache_remove_conn(data, conn, TRUE);
3920 Curl_disconnect(data, conn, TRUE);
3921 }
3922
3923 return result;
3924}
3925
3926/*
3927 * Curl_init_do() inits the readwrite session. This is inited each time (in
3928 * the DO function before the protocol-specific DO functions are invoked) for
3929 * a transfer, sometimes multiple times on the same Curl_easy. Make sure
3930 * nothing in here depends on stuff that are setup dynamically for the
3931 * transfer.
3932 *
3933 * Allow this function to get called with 'conn' set to NULL.
3934 */
3935
3936CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
3937{
3938 struct SingleRequest *k = &data->req;
3939
3940 /* if this is a pushed stream, we need this: */
3941 CURLcode result = Curl_preconnect(data);
3942 if(result)
3943 return result;
3944
3945 if(conn) {
3946 conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
3947 use */
3948 /* if the protocol used doesn't support wildcards, switch it off */
3949 if(data->state.wildcardmatch &&
3950 !(conn->handler->flags & PROTOPT_WILDCARD))
3951 data->state.wildcardmatch = FALSE;
3952 }
3953
3954 data->state.done = FALSE; /* *_done() is not called yet */
3955 data->state.expect100header = FALSE;
3956
3957 if(data->req.no_body)
3958 /* in HTTP lingo, no body means using the HEAD request... */
3959 data->state.httpreq = HTTPREQ_HEAD;
3960
3961 k->start = Curl_now(); /* start time */
3962 k->header = TRUE; /* assume header */
3963 k->bytecount = 0;
3964 k->ignorebody = FALSE;
3965
3966 Curl_speedinit(data);
3967 Curl_pgrsSetUploadCounter(data, 0);
3968 Curl_pgrsSetDownloadCounter(data, 0);
3969
3970 return CURLE_OK;
3971}
3972
3973#if defined(USE_HTTP2) || defined(USE_HTTP3)
3974
3975#ifdef USE_NGHTTP2
3976
3977static void priority_remove_child(struct Curl_easy *parent,
3978 struct Curl_easy *child)
3979{
3980 struct Curl_data_prio_node **pnext = &parent->set.priority.children;
3981 struct Curl_data_prio_node *pnode = parent->set.priority.children;
3982
3983 DEBUGASSERT(child->set.priority.parent == parent);
3984 while(pnode && pnode->data != child) {
3985 pnext = &pnode->next;
3986 pnode = pnode->next;
3987 }
3988
3989 DEBUGASSERT(pnode);
3990 if(pnode) {
3991 *pnext = pnode->next;
3992 free(pnode);
3993 }
3994
3995 child->set.priority.parent = 0;
3996 child->set.priority.exclusive = FALSE;
3997}
3998
3999CURLcode Curl_data_priority_add_child(struct Curl_easy *parent,
4000 struct Curl_easy *child,
4001 bool exclusive)
4002{
4003 if(child->set.priority.parent) {
4004 priority_remove_child(child->set.priority.parent, child);
4005 }
4006
4007 if(parent) {
4008 struct Curl_data_prio_node **tail;
4009 struct Curl_data_prio_node *pnode;
4010
4011 pnode = calloc(1, sizeof(*pnode));
4012 if(!pnode)
4013 return CURLE_OUT_OF_MEMORY;
4014 pnode->data = child;
4015
4016 if(parent->set.priority.children && exclusive) {
4017 /* exclusive: move all existing children underneath the new child */
4018 struct Curl_data_prio_node *node = parent->set.priority.children;
4019 while(node) {
4020 node->data->set.priority.parent = child;
4021 node = node->next;
4022 }
4023
4024 tail = &child->set.priority.children;
4025 while(*tail)
4026 tail = &(*tail)->next;
4027
4028 DEBUGASSERT(!*tail);
4029 *tail = parent->set.priority.children;
4030 parent->set.priority.children = 0;
4031 }
4032
4033 tail = &parent->set.priority.children;
4034 while(*tail) {
4035 (*tail)->data->set.priority.exclusive = FALSE;
4036 tail = &(*tail)->next;
4037 }
4038
4039 DEBUGASSERT(!*tail);
4040 *tail = pnode;
4041 }
4042
4043 child->set.priority.parent = parent;
4044 child->set.priority.exclusive = exclusive;
4045 return CURLE_OK;
4046}
4047
4048#endif /* USE_NGHTTP2 */
4049
4050#ifdef USE_NGHTTP2
4051static void data_priority_cleanup(struct Curl_easy *data)
4052{
4053 while(data->set.priority.children) {
4054 struct Curl_easy *tmp = data->set.priority.children->data;
4055 priority_remove_child(data, tmp);
4056 if(data->set.priority.parent)
4057 Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE);
4058 }
4059
4060 if(data->set.priority.parent)
4061 priority_remove_child(data->set.priority.parent, data);
4062}
4063#endif
4064
4065void Curl_data_priority_clear_state(struct Curl_easy *data)
4066{
4067 memset(&data->state.priority, 0, sizeof(data->state.priority));
4068}
4069
4070#endif /* defined(USE_HTTP2) || defined(USE_HTTP3) */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette