VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/url.c@ 104119

Last change on this file since 104119 was 104083, checked in by vboxsync, 11 months ago

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

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

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