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