VirtualBox

source: vbox/trunk/src/libs/curl-7.87.0/lib/url.c@ 99005

Last change on this file since 99005 was 98326, checked in by vboxsync, 2 years ago

curl-7.87.0: Applied and adjusted our curl changes to 7.83.1. bugref:10356

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