VirtualBox

source: vbox/trunk/src/libs/curl-8.0.1/lib/url.c@ 99797

Last change on this file since 99797 was 99344, checked in by vboxsync, 2 years ago

curl-8.0.1: Applied and adjusted our curl changes to 7.87.0 bugref:10417

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

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