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 Curl_netrc_cleanup(&data->state.netrc);
342 free(data);
343 return CURLE_OK;
344 }
345
346 /*
347 * Initialize the UserDefined fields within a Curl_easy.
348 * This may be safely called on a new or existing Curl_easy.
349 */
Curl_init_userdefined(struct Curl_easy * data)350 CURLcode Curl_init_userdefined(struct Curl_easy *data)
351 {
352 struct UserDefined *set = &data->set;
353 CURLcode result = CURLE_OK;
354
355 set->out = stdout; /* default output to stdout */
356 set->in_set = stdin; /* default input from stdin */
357 set->err = stderr; /* default stderr to stderr */
358
359 /* use fwrite as default function to store output */
360 set->fwrite_func = (curl_write_callback)fwrite;
361
362 /* use fread as default function to read input */
363 set->fread_func_set = (curl_read_callback)fread;
364 set->is_fread_set = 0;
365
366 set->seek_client = ZERO_NULL;
367
368 set->filesize = -1; /* we do not know the size */
369 set->postfieldsize = -1; /* unknown size */
370 set->maxredirs = 30; /* sensible default */
371
372 set->method = HTTPREQ_GET; /* Default HTTP request */
373 #ifndef CURL_DISABLE_RTSP
374 set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
375 #endif
376 #ifndef CURL_DISABLE_FTP
377 set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
378 set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
379 set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */
380 set->ftp_filemethod = FTPFILE_MULTICWD;
381 set->ftp_skip_ip = TRUE; /* skip PASV IP by default */
382 #endif
383 set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
384
385 /* Timeout every 24 hours by default */
386 set->general_ssl.ca_cache_timeout = 24 * 60 * 60;
387
388 set->httpauth = CURLAUTH_BASIC; /* defaults to basic */
389
390 #ifndef CURL_DISABLE_PROXY
391 set->proxyport = 0;
392 set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
393 set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
394 /* SOCKS5 proxy auth defaults to username/password + GSS-API */
395 set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI;
396 #endif
397
398 /* make libcurl quiet by default: */
399 set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
400
401 Curl_mime_initpart(&set->mimepost);
402
403 Curl_ssl_easy_config_init(data);
404 #ifndef CURL_DISABLE_DOH
405 set->doh_verifyhost = TRUE;
406 set->doh_verifypeer = TRUE;
407 #endif
408 #ifdef USE_SSH
409 /* defaults to any auth type */
410 set->ssh_auth_types = CURLSSH_AUTH_DEFAULT;
411 set->new_directory_perms = 0755; /* Default permissions */
412 #endif
413
414 set->new_file_perms = 0644; /* Default permissions */
415 set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL;
416 set->redir_protocols = CURLPROTO_REDIR;
417
418 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
419 /*
420 * disallow unprotected protection negotiation NEC reference implementation
421 * seem not to follow rfc1961 section 4.3/4.4
422 */
423 set->socks5_gssapi_nec = FALSE;
424 #endif
425
426 /* Set the default CA cert bundle/path detected/specified at build time.
427 *
428 * If Schannel or Secure Transport is the selected SSL backend then these
429 * locations are ignored. We allow setting CA location for Schannel and
430 * Secure Transport when explicitly specified by the user via
431 * CURLOPT_CAINFO / --cacert.
432 */
433 if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL &&
434 Curl_ssl_backend() != CURLSSLBACKEND_SECURETRANSPORT) {
435 #if defined(CURL_CA_BUNDLE)
436 result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
437 if(result)
438 return result;
439 #ifndef CURL_DISABLE_PROXY
440 result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
441 CURL_CA_BUNDLE);
442 if(result)
443 return result;
444 #endif
445 #endif
446 #if defined(CURL_CA_PATH)
447 result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
448 if(result)
449 return result;
450 #ifndef CURL_DISABLE_PROXY
451 result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
452 if(result)
453 return result;
454 #endif
455 #endif
456 }
457
458 #ifndef CURL_DISABLE_FTP
459 set->wildcard_enabled = FALSE;
460 set->chunk_bgn = ZERO_NULL;
461 set->chunk_end = ZERO_NULL;
462 set->fnmatch = ZERO_NULL;
463 #endif
464 set->tcp_keepalive = FALSE;
465 set->tcp_keepintvl = 60;
466 set->tcp_keepidle = 60;
467 set->tcp_keepcnt = 9;
468 set->tcp_fastopen = FALSE;
469 set->tcp_nodelay = TRUE;
470 set->ssl_enable_alpn = TRUE;
471 set->expect_100_timeout = 1000L; /* Wait for a second by default. */
472 set->sep_headers = TRUE; /* separated header lists by default */
473 set->buffer_size = READBUFFER_SIZE;
474 set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
475 set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
476 set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
477 set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
478 set->maxage_conn = 118;
479 set->maxlifetime_conn = 0;
480 set->http09_allowed = FALSE;
481 #ifdef USE_HTTP2
482 set->httpwant = CURL_HTTP_VERSION_2TLS
483 #else
484 set->httpwant = CURL_HTTP_VERSION_1_1
485 #endif
486 ;
487 #if defined(USE_HTTP2) || defined(USE_HTTP3)
488 memset(&set->priority, 0, sizeof(set->priority));
489 #endif
490 set->quick_exit = 0L;
491 return result;
492 }
493
494 /**
495 * Curl_open()
496 *
497 * @param curl is a pointer to a sessionhandle pointer that gets set by this
498 * function.
499 * @return CURLcode
500 */
501
Curl_open(struct Curl_easy ** curl)502 CURLcode Curl_open(struct Curl_easy **curl)
503 {
504 CURLcode result;
505 struct Curl_easy *data;
506
507 /* simple start-up: alloc the struct, init it with zeroes and return */
508 data = calloc(1, sizeof(struct Curl_easy));
509 if(!data) {
510 /* this is a serious error */
511 DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n"));
512 return CURLE_OUT_OF_MEMORY;
513 }
514
515 data->magic = CURLEASY_MAGIC_NUMBER;
516
517 Curl_req_init(&data->req);
518
519 result = Curl_resolver_init(data, &data->state.async.resolver);
520 if(result) {
521 DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
522 Curl_req_free(&data->req, data);
523 free(data);
524 return result;
525 }
526
527 result = Curl_init_userdefined(data);
528 if(!result) {
529 Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
530 Curl_initinfo(data);
531
532 /* most recent connection is not yet defined */
533 data->state.lastconnect_id = -1;
534 data->state.recent_conn_id = -1;
535 /* and not assigned an id yet */
536 data->id = -1;
537 data->mid = -1;
538 #ifndef CURL_DISABLE_DOH
539 data->set.dohfor_mid = -1;
540 #endif
541
542 data->progress.flags |= PGRS_HIDE;
543 data->state.current_speed = -1; /* init to negative == impossible */
544 #ifndef CURL_DISABLE_HTTP
545 Curl_llist_init(&data->state.httphdrs, NULL);
546 #endif
547 Curl_netrc_init(&data->state.netrc);
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 * xfer_may_multiplex()
653 *
654 * Return a TRUE, iff the transfer can be done over an (appropriate)
655 * multiplexed connection.
656 */
xfer_may_multiplex(const struct Curl_easy * data,const struct connectdata * conn)657 static bool 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 reuse a
882 random other one, although if we did not ask for a particular one we
883 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 same
887 it would take a lot of processing to make it really accurate. Instead,
888 this matching will assume that reuses of bound connections will most
889 likely also reuse the exact same binding parameters and missing out a
890 few edge cases should not hurt anyone 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 !Curl_conn_is_ssl(conn, FIRSTSOCKET)) &&
961 !(get_protocol_family(conn->handler) == needle->handler->protocol &&
962 conn->bits.tls_upgraded))
963 /* Deny `conn` if it is not fit for `needle`'s SSL needs,
964 * UNLESS `conn` is the same protocol family and was upgraded to SSL. */
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_seen) {
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 #ifdef HAVE_GSSAPI
1029 /* GSS delegation differences do not actually affect every connection
1030 and auth method, but this check takes precaution before efficiency */
1031 if(needle->gssapi_delegation != conn->gssapi_delegation)
1032 return FALSE;
1033 #endif
1034
1035 /* If looking for HTTP and the HTTP version we want is less
1036 * than the HTTP version of conn, continue looking.
1037 * CURL_HTTP_VERSION_2TLS is default which indicates no preference,
1038 * so we take any existing connection. */
1039 if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
1040 (data->state.httpwant != CURL_HTTP_VERSION_2TLS)) {
1041 unsigned char httpversion = Curl_conn_http_version(data);
1042 if((httpversion >= 20) &&
1043 (data->state.httpwant < CURL_HTTP_VERSION_2_0)) {
1044 DEBUGF(infof(data, "nor reusing conn #%" CURL_FORMAT_CURL_OFF_T
1045 " with httpversion=%d, we want a version less than h2",
1046 conn->connection_id, httpversion));
1047 }
1048 if((httpversion >= 30) &&
1049 (data->state.httpwant < CURL_HTTP_VERSION_3)) {
1050 DEBUGF(infof(data, "nor reusing conn #%" CURL_FORMAT_CURL_OFF_T
1051 " with httpversion=%d, we want a version less than h3",
1052 conn->connection_id, httpversion));
1053 return FALSE;
1054 }
1055 }
1056 #ifdef USE_SSH
1057 else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
1058 if(!ssh_config_matches(needle, conn))
1059 return FALSE;
1060 }
1061 #endif
1062 #ifndef CURL_DISABLE_FTP
1063 else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) {
1064 /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */
1065 if(Curl_timestrcmp(needle->proto.ftpc.account,
1066 conn->proto.ftpc.account) ||
1067 Curl_timestrcmp(needle->proto.ftpc.alternative_to_user,
1068 conn->proto.ftpc.alternative_to_user) ||
1069 (needle->proto.ftpc.use_ssl != conn->proto.ftpc.use_ssl) ||
1070 (needle->proto.ftpc.ccc != conn->proto.ftpc.ccc))
1071 return FALSE;
1072 }
1073 #endif
1074
1075 /* Additional match requirements if talking TLS OR
1076 * not talking to an HTTP proxy OR using a tunnel through a proxy */
1077 if((needle->handler->flags&PROTOPT_SSL)
1078 #ifndef CURL_DISABLE_PROXY
1079 || !needle->bits.httpproxy || needle->bits.tunnel_proxy
1080 #endif
1081 ) {
1082 /* Talking the same protocol scheme or a TLS upgraded protocol in the
1083 * same protocol family? */
1084 if(!strcasecompare(needle->handler->scheme, conn->handler->scheme) &&
1085 (get_protocol_family(conn->handler) !=
1086 needle->handler->protocol || !conn->bits.tls_upgraded))
1087 return FALSE;
1088
1089 /* If needle has "conn_to_*" set, conn must match this */
1090 if((needle->bits.conn_to_host && !strcasecompare(
1091 needle->conn_to_host.name, conn->conn_to_host.name)) ||
1092 (needle->bits.conn_to_port &&
1093 needle->conn_to_port != conn->conn_to_port))
1094 return FALSE;
1095
1096 /* hostname and port must match */
1097 if(!strcasecompare(needle->host.name, conn->host.name) ||
1098 needle->remote_port != conn->remote_port)
1099 return FALSE;
1100
1101 /* If talking TLS, conn needs to use the same SSL options. */
1102 if((needle->handler->flags & PROTOPT_SSL) &&
1103 !Curl_ssl_conn_config_match(data, conn, FALSE)) {
1104 DEBUGF(infof(data,
1105 "Connection #%" FMT_OFF_T
1106 " has different SSL parameters, cannot reuse",
1107 conn->connection_id));
1108 return FALSE;
1109 }
1110 }
1111
1112 #if defined(USE_NTLM)
1113 /* If we are looking for an HTTP+NTLM connection, check if this is
1114 already authenticating with the right credentials. If not, keep
1115 looking so that we can reuse NTLM connections if
1116 possible. (Especially we must not reuse the same connection if
1117 partway through a handshake!) */
1118 if(match->want_ntlm_http) {
1119 if(Curl_timestrcmp(needle->user, conn->user) ||
1120 Curl_timestrcmp(needle->passwd, conn->passwd)) {
1121
1122 /* we prefer a credential match, but this is at least a connection
1123 that can be reused and "upgraded" to NTLM */
1124 if(conn->http_ntlm_state == NTLMSTATE_NONE)
1125 match->found = conn;
1126 return FALSE;
1127 }
1128 }
1129 else if(conn->http_ntlm_state != NTLMSTATE_NONE) {
1130 /* Connection is using NTLM auth but we do not want NTLM */
1131 return FALSE;
1132 }
1133
1134 #ifndef CURL_DISABLE_PROXY
1135 /* Same for Proxy NTLM authentication */
1136 if(match->want_proxy_ntlm_http) {
1137 /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
1138 * NULL */
1139 if(!conn->http_proxy.user || !conn->http_proxy.passwd)
1140 return FALSE;
1141
1142 if(Curl_timestrcmp(needle->http_proxy.user,
1143 conn->http_proxy.user) ||
1144 Curl_timestrcmp(needle->http_proxy.passwd,
1145 conn->http_proxy.passwd))
1146 return FALSE;
1147 }
1148 else if(conn->proxy_ntlm_state != NTLMSTATE_NONE) {
1149 /* Proxy connection is using NTLM auth but we do not want NTLM */
1150 return FALSE;
1151 }
1152 #endif
1153 if(match->want_ntlm_http || match->want_proxy_ntlm_http) {
1154 /* Credentials are already checked, we may use this connection.
1155 * With NTLM being weird as it is, we MUST use a
1156 * connection where it has already been fully negotiated.
1157 * If it has not, we keep on looking for a better one. */
1158 match->found = conn;
1159
1160 if((match->want_ntlm_http &&
1161 (conn->http_ntlm_state != NTLMSTATE_NONE)) ||
1162 (match->want_proxy_ntlm_http &&
1163 (conn->proxy_ntlm_state != NTLMSTATE_NONE))) {
1164 /* We must use this connection, no other */
1165 match->force_reuse = TRUE;
1166 return TRUE;
1167 }
1168 /* Continue look up for a better connection */
1169 return FALSE;
1170 }
1171 #endif
1172
1173 if(CONN_INUSE(conn)) {
1174 DEBUGASSERT(match->may_multiplex);
1175 DEBUGASSERT(conn->bits.multiplex);
1176 /* If multiplexed, make sure we do not go over concurrency limit */
1177 if(CONN_INUSE(conn) >=
1178 Curl_multi_max_concurrent_streams(data->multi)) {
1179 infof(data, "client side MAX_CONCURRENT_STREAMS reached"
1180 ", skip (%zu)", CONN_INUSE(conn));
1181 return FALSE;
1182 }
1183 if(CONN_INUSE(conn) >=
1184 Curl_conn_get_max_concurrent(data, conn, FIRSTSOCKET)) {
1185 infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
1186 CONN_INUSE(conn));
1187 return FALSE;
1188 }
1189 /* When not multiplexed, we have a match here! */
1190 infof(data, "Multiplexed connection found");
1191 }
1192 else if(Curl_conn_seems_dead(conn, data, NULL)) {
1193 /* removed and disconnect. Do not treat as aborted. */
1194 Curl_cpool_disconnect(data, conn, FALSE);
1195 return FALSE;
1196 }
1197
1198 /* We have found a connection. Let's stop searching. */
1199 match->found = conn;
1200 return TRUE;
1201 }
1202
url_match_result(bool result,void * userdata)1203 static bool url_match_result(bool result, void *userdata)
1204 {
1205 struct url_conn_match *match = userdata;
1206 (void)result;
1207 if(match->found) {
1208 /* Attach it now while still under lock, so the connection does
1209 * no longer appear idle and can be reaped. */
1210 Curl_attach_connection(match->data, match->found);
1211 return TRUE;
1212 }
1213 else if(match->seen_single_use_conn && !match->seen_multiplex_conn) {
1214 /* We've seen a single-use, existing connection to the destination and
1215 * no multiplexed one. It seems safe to assume that the server does
1216 * not support multiplexing. */
1217 match->wait_pipe = FALSE;
1218 }
1219 else if(match->seen_pending_conn && match->data->set.pipewait) {
1220 infof(match->data,
1221 "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
1222 match->wait_pipe = TRUE;
1223 }
1224 match->force_reuse = FALSE;
1225 return FALSE;
1226 }
1227
1228 /*
1229 * Given one filled in connection struct (named needle), this function should
1230 * detect if there already is one that has all the significant details
1231 * exactly the same and thus should be used instead.
1232 *
1233 * If there is a match, this function returns TRUE - and has marked the
1234 * connection as 'in-use'. It must later be called with ConnectionDone() to
1235 * return back to 'idle' (unused) state.
1236 *
1237 * The force_reuse flag is set if the connection must be used.
1238 */
1239 static bool
ConnectionExists(struct Curl_easy * data,struct connectdata * needle,struct connectdata ** usethis,bool * force_reuse,bool * waitpipe)1240 ConnectionExists(struct Curl_easy *data,
1241 struct connectdata *needle,
1242 struct connectdata **usethis,
1243 bool *force_reuse,
1244 bool *waitpipe)
1245 {
1246 struct url_conn_match match;
1247 bool result;
1248
1249 memset(&match, 0, sizeof(match));
1250 match.data = data;
1251 match.needle = needle;
1252 match.may_multiplex = xfer_may_multiplex(data, needle);
1253
1254 #ifdef USE_NTLM
1255 match.want_ntlm_http = ((data->state.authhost.want & CURLAUTH_NTLM) &&
1256 (needle->handler->protocol & PROTO_FAMILY_HTTP));
1257 #ifndef CURL_DISABLE_PROXY
1258 match.want_proxy_ntlm_http =
1259 (needle->bits.proxy_user_passwd &&
1260 (data->state.authproxy.want & CURLAUTH_NTLM) &&
1261 (needle->handler->protocol & PROTO_FAMILY_HTTP));
1262 #endif
1263 #endif
1264
1265 /* Find a connection in the pool that matches what "data + needle"
1266 * requires. If a suitable candidate is found, it is attached to "data". */
1267 result = Curl_cpool_find(data, needle->destination, needle->destination_len,
1268 url_match_conn, url_match_result, &match);
1269
1270 /* wait_pipe is TRUE if we encounter a bundle that is undecided. There
1271 * is no matching connection then, yet. */
1272 *usethis = match.found;
1273 *force_reuse = match.force_reuse;
1274 *waitpipe = match.wait_pipe;
1275 return result;
1276 }
1277
1278 /*
1279 * verboseconnect() displays verbose information after a connect
1280 */
1281 #ifndef CURL_DISABLE_VERBOSE_STRINGS
Curl_verboseconnect(struct Curl_easy * data,struct connectdata * conn,int sockindex)1282 void Curl_verboseconnect(struct Curl_easy *data,
1283 struct connectdata *conn, int sockindex)
1284 {
1285 if(data->set.verbose && sockindex == SECONDARYSOCKET)
1286 infof(data, "Connected 2nd connection to %s port %u",
1287 conn->secondary.remote_ip, conn->secondary.remote_port);
1288 else
1289 infof(data, "Connected to %s (%s) port %u",
1290 CURL_CONN_HOST_DISPNAME(conn), conn->primary.remote_ip,
1291 conn->primary.remote_port);
1292 #if !defined(CURL_DISABLE_HTTP)
1293 if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
1294 switch(conn->alpn) {
1295 case CURL_HTTP_VERSION_3:
1296 infof(data, "using HTTP/3");
1297 break;
1298 case CURL_HTTP_VERSION_2:
1299 infof(data, "using HTTP/2");
1300 break;
1301 default:
1302 infof(data, "using HTTP/1.x");
1303 break;
1304 }
1305 }
1306 #endif
1307 }
1308 #endif
1309
1310 /*
1311 * Allocate and initialize a new connectdata object.
1312 */
allocate_conn(struct Curl_easy * data)1313 static struct connectdata *allocate_conn(struct Curl_easy *data)
1314 {
1315 struct connectdata *conn = calloc(1, sizeof(struct connectdata));
1316 if(!conn)
1317 return NULL;
1318
1319 /* and we setup a few fields in case we end up actually using this struct */
1320
1321 conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
1322 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
1323 conn->sockfd = CURL_SOCKET_BAD;
1324 conn->writesockfd = CURL_SOCKET_BAD;
1325 conn->connection_id = -1; /* no ID */
1326 conn->primary.remote_port = -1; /* unknown at this point */
1327 conn->remote_port = -1; /* unknown at this point */
1328
1329 /* Default protocol-independent behavior does not support persistent
1330 connections, so we set this to force-close. Protocols that support
1331 this need to set this to FALSE in their "curl_do" functions. */
1332 connclose(conn, "Default to force-close");
1333
1334 /* Store creation time to help future close decision making */
1335 conn->created = Curl_now();
1336
1337 /* Store current time to give a baseline to keepalive connection times. */
1338 conn->keepalive = conn->created;
1339
1340 #ifndef CURL_DISABLE_PROXY
1341 conn->http_proxy.proxytype = data->set.proxytype;
1342 conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
1343
1344 /* note that these two proxy bits are now just on what looks to be
1345 requested, they may be altered down the road */
1346 conn->bits.proxy = (data->set.str[STRING_PROXY] &&
1347 *data->set.str[STRING_PROXY]);
1348 conn->bits.httpproxy = (conn->bits.proxy &&
1349 (conn->http_proxy.proxytype == CURLPROXY_HTTP ||
1350 conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
1351 IS_HTTPS_PROXY(conn->http_proxy.proxytype)));
1352 conn->bits.socksproxy = (conn->bits.proxy && !conn->bits.httpproxy);
1353
1354 if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
1355 conn->bits.proxy = TRUE;
1356 conn->bits.socksproxy = TRUE;
1357 }
1358
1359 conn->bits.proxy_user_passwd = !!data->state.aptr.proxyuser;
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 #ifdef HAVE_GSSAPI
1395 conn->gssapi_delegation = data->set.gssapi_delegation;
1396 #endif
1397 return conn;
1398 error:
1399
1400 free(conn->localdev);
1401 free(conn);
1402 return NULL;
1403 }
1404
Curl_get_scheme_handler(const char * scheme)1405 const struct Curl_handler *Curl_get_scheme_handler(const char *scheme)
1406 {
1407 return Curl_getn_scheme_handler(scheme, strlen(scheme));
1408 }
1409
1410 /* returns the handler if the given scheme is built-in */
Curl_getn_scheme_handler(const char * scheme,size_t len)1411 const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
1412 size_t len)
1413 {
1414 /* table generated by schemetable.c:
1415 1. gcc schemetable.c && ./a.out
1416 2. check how small the table gets
1417 3. tweak the hash algorithm, then rerun from 1
1418 4. when the table is good enough
1419 5. copy the table into this source code
1420 6. make sure this function uses the same hash function that worked for
1421 schemetable.c
1422 7. if needed, adjust the #ifdefs in schemetable.c and rerun
1423 */
1424 static const struct Curl_handler * const protocols[67] = {
1425 #ifndef CURL_DISABLE_FILE
1426 &Curl_handler_file,
1427 #else
1428 NULL,
1429 #endif
1430 NULL, NULL,
1431 #if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)
1432 &Curl_handler_gophers,
1433 #else
1434 NULL,
1435 #endif
1436 NULL,
1437 #ifdef USE_LIBRTMP
1438 &Curl_handler_rtmpe,
1439 #else
1440 NULL,
1441 #endif
1442 #ifndef CURL_DISABLE_SMTP
1443 &Curl_handler_smtp,
1444 #else
1445 NULL,
1446 #endif
1447 #if defined(USE_SSH)
1448 &Curl_handler_sftp,
1449 #else
1450 NULL,
1451 #endif
1452 #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
1453 (SIZEOF_CURL_OFF_T > 4)
1454 &Curl_handler_smb,
1455 #else
1456 NULL,
1457 #endif
1458 #if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
1459 &Curl_handler_smtps,
1460 #else
1461 NULL,
1462 #endif
1463 #ifndef CURL_DISABLE_TELNET
1464 &Curl_handler_telnet,
1465 #else
1466 NULL,
1467 #endif
1468 #ifndef CURL_DISABLE_GOPHER
1469 &Curl_handler_gopher,
1470 #else
1471 NULL,
1472 #endif
1473 #ifndef CURL_DISABLE_TFTP
1474 &Curl_handler_tftp,
1475 #else
1476 NULL,
1477 #endif
1478 NULL, NULL, NULL,
1479 #if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
1480 &Curl_handler_ftps,
1481 #else
1482 NULL,
1483 #endif
1484 #ifndef CURL_DISABLE_HTTP
1485 &Curl_handler_http,
1486 #else
1487 NULL,
1488 #endif
1489 #ifndef CURL_DISABLE_IMAP
1490 &Curl_handler_imap,
1491 #else
1492 NULL,
1493 #endif
1494 #ifdef USE_LIBRTMP
1495 &Curl_handler_rtmps,
1496 #else
1497 NULL,
1498 #endif
1499 #ifdef USE_LIBRTMP
1500 &Curl_handler_rtmpt,
1501 #else
1502 NULL,
1503 #endif
1504 NULL, NULL, NULL,
1505 #if !defined(CURL_DISABLE_LDAP) && \
1506 !defined(CURL_DISABLE_LDAPS) && \
1507 ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
1508 (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
1509 &Curl_handler_ldaps,
1510 #else
1511 NULL,
1512 #endif
1513 #if !defined(CURL_DISABLE_WEBSOCKETS) && \
1514 defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
1515 &Curl_handler_wss,
1516 #else
1517 NULL,
1518 #endif
1519 #if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
1520 &Curl_handler_https,
1521 #else
1522 NULL,
1523 #endif
1524 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1525 #ifndef CURL_DISABLE_RTSP
1526 &Curl_handler_rtsp,
1527 #else
1528 NULL,
1529 #endif
1530 #if defined(USE_SSL) && !defined(CURL_DISABLE_SMB) && \
1531 defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)
1532 &Curl_handler_smbs,
1533 #else
1534 NULL,
1535 #endif
1536 #if defined(USE_SSH) && !defined(USE_WOLFSSH)
1537 &Curl_handler_scp,
1538 #else
1539 NULL,
1540 #endif
1541 NULL, NULL, NULL,
1542 #ifndef CURL_DISABLE_POP3
1543 &Curl_handler_pop3,
1544 #else
1545 NULL,
1546 #endif
1547 NULL, NULL,
1548 #ifdef USE_LIBRTMP
1549 &Curl_handler_rtmp,
1550 #else
1551 NULL,
1552 #endif
1553 NULL, NULL, NULL,
1554 #ifdef USE_LIBRTMP
1555 &Curl_handler_rtmpte,
1556 #else
1557 NULL,
1558 #endif
1559 NULL, NULL, NULL,
1560 #ifndef CURL_DISABLE_DICT
1561 &Curl_handler_dict,
1562 #else
1563 NULL,
1564 #endif
1565 NULL, NULL, NULL,
1566 #ifndef CURL_DISABLE_MQTT
1567 &Curl_handler_mqtt,
1568 #else
1569 NULL,
1570 #endif
1571 #if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
1572 &Curl_handler_pop3s,
1573 #else
1574 NULL,
1575 #endif
1576 #if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
1577 &Curl_handler_imaps,
1578 #else
1579 NULL,
1580 #endif
1581 NULL,
1582 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
1583 &Curl_handler_ws,
1584 #else
1585 NULL,
1586 #endif
1587 NULL,
1588 #ifdef USE_LIBRTMP
1589 &Curl_handler_rtmpts,
1590 #else
1591 NULL,
1592 #endif
1593 #ifndef CURL_DISABLE_LDAP
1594 &Curl_handler_ldap,
1595 #else
1596 NULL,
1597 #endif
1598 NULL, NULL,
1599 #ifndef CURL_DISABLE_FTP
1600 &Curl_handler_ftp,
1601 #else
1602 NULL,
1603 #endif
1604 };
1605
1606 if(len && (len <= 7)) {
1607 const char *s = scheme;
1608 size_t l = len;
1609 const struct Curl_handler *h;
1610 unsigned int c = 978;
1611 while(l) {
1612 c <<= 5;
1613 c += (unsigned int)Curl_raw_tolower(*s);
1614 s++;
1615 l--;
1616 }
1617
1618 h = protocols[c % 67];
1619 if(h && strncasecompare(scheme, h->scheme, len) && !h->scheme[len])
1620 return h;
1621 }
1622 return NULL;
1623 }
1624
findprotocol(struct Curl_easy * data,struct connectdata * conn,const char * protostr)1625 static CURLcode findprotocol(struct Curl_easy *data,
1626 struct connectdata *conn,
1627 const char *protostr)
1628 {
1629 const struct Curl_handler *p = Curl_get_scheme_handler(protostr);
1630
1631 if(p && /* Protocol found in table. Check if allowed */
1632 (data->set.allowed_protocols & p->protocol)) {
1633
1634 /* it is allowed for "normal" request, now do an extra check if this is
1635 the result of a redirect */
1636 if(data->state.this_is_a_follow &&
1637 !(data->set.redir_protocols & p->protocol))
1638 /* nope, get out */
1639 ;
1640 else {
1641 /* Perform setup complement if some. */
1642 conn->handler = conn->given = p;
1643 /* 'port' and 'remote_port' are set in setup_connection_internals() */
1644 return CURLE_OK;
1645 }
1646 }
1647
1648 /* The protocol was not found in the table, but we do not have to assign it
1649 to anything since it is already assigned to a dummy-struct in the
1650 create_conn() function when the connectdata struct is allocated. */
1651 failf(data, "Protocol \"%s\" %s%s", protostr,
1652 p ? "disabled" : "not supported",
1653 data->state.this_is_a_follow ? " (in redirect)":"");
1654
1655 return CURLE_UNSUPPORTED_PROTOCOL;
1656 }
1657
1658
Curl_uc_to_curlcode(CURLUcode uc)1659 CURLcode Curl_uc_to_curlcode(CURLUcode uc)
1660 {
1661 switch(uc) {
1662 default:
1663 return CURLE_URL_MALFORMAT;
1664 case CURLUE_UNSUPPORTED_SCHEME:
1665 return CURLE_UNSUPPORTED_PROTOCOL;
1666 case CURLUE_OUT_OF_MEMORY:
1667 return CURLE_OUT_OF_MEMORY;
1668 case CURLUE_USER_NOT_ALLOWED:
1669 return CURLE_LOGIN_DENIED;
1670 }
1671 }
1672
1673 #ifdef USE_IPV6
1674 /*
1675 * If the URL was set with an IPv6 numerical address with a zone id part, set
1676 * the scope_id based on that!
1677 */
1678
zonefrom_url(CURLU * uh,struct Curl_easy * data,struct connectdata * conn)1679 static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
1680 struct connectdata *conn)
1681 {
1682 char *zoneid;
1683 CURLUcode uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
1684 #ifdef CURL_DISABLE_VERBOSE_STRINGS
1685 (void)data;
1686 #endif
1687
1688 if(!uc && zoneid) {
1689 char *endp;
1690 unsigned long scope = strtoul(zoneid, &endp, 10);
1691 if(!*endp && (scope < UINT_MAX))
1692 /* A plain number, use it directly as a scope id. */
1693 conn->scope_id = (unsigned int)scope;
1694 #if defined(HAVE_IF_NAMETOINDEX)
1695 else {
1696 #elif defined(_WIN32)
1697 else if(Curl_if_nametoindex) {
1698 #endif
1699
1700 #if defined(HAVE_IF_NAMETOINDEX) || defined(_WIN32)
1701 /* Zone identifier is not numeric */
1702 unsigned int scopeidx = 0;
1703 #if defined(_WIN32)
1704 scopeidx = Curl_if_nametoindex(zoneid);
1705 #else
1706 scopeidx = if_nametoindex(zoneid);
1707 #endif
1708 if(!scopeidx) {
1709 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1710 char buffer[STRERROR_LEN];
1711 infof(data, "Invalid zoneid: %s; %s", zoneid,
1712 Curl_strerror(errno, buffer, sizeof(buffer)));
1713 #endif
1714 }
1715 else
1716 conn->scope_id = scopeidx;
1717 }
1718 #endif /* HAVE_IF_NAMETOINDEX || _WIN32 */
1719
1720 free(zoneid);
1721 }
1722 }
1723 #else
1724 #define zonefrom_url(a,b,c) Curl_nop_stmt
1725 #endif
1726
1727 /*
1728 * Parse URL and fill in the relevant members of the connection struct.
1729 */
1730 static CURLcode parseurlandfillconn(struct Curl_easy *data,
1731 struct connectdata *conn)
1732 {
1733 CURLcode result;
1734 CURLU *uh;
1735 CURLUcode uc;
1736 char *hostname;
1737 bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
1738
1739 up_free(data); /* cleanup previous leftovers first */
1740
1741 /* parse the URL */
1742 if(use_set_uh) {
1743 uh = data->state.uh = curl_url_dup(data->set.uh);
1744 }
1745 else {
1746 uh = data->state.uh = curl_url();
1747 }
1748
1749 if(!uh)
1750 return CURLE_OUT_OF_MEMORY;
1751
1752 if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
1753 !Curl_is_absolute_url(data->state.url, NULL, 0, TRUE)) {
1754 char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL],
1755 data->state.url);
1756 if(!url)
1757 return CURLE_OUT_OF_MEMORY;
1758 if(data->state.url_alloc)
1759 free(data->state.url);
1760 data->state.url = url;
1761 data->state.url_alloc = TRUE;
1762 }
1763
1764 if(!use_set_uh) {
1765 char *newurl;
1766 uc = curl_url_set(uh, CURLUPART_URL, data->state.url, (unsigned int)
1767 (CURLU_GUESS_SCHEME |
1768 CURLU_NON_SUPPORT_SCHEME |
1769 (data->set.disallow_username_in_url ?
1770 CURLU_DISALLOW_USER : 0) |
1771 (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
1772 if(uc) {
1773 failf(data, "URL rejected: %s", curl_url_strerror(uc));
1774 return Curl_uc_to_curlcode(uc);
1775 }
1776
1777 /* after it was parsed, get the generated normalized version */
1778 uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
1779 if(uc)
1780 return Curl_uc_to_curlcode(uc);
1781 if(data->state.url_alloc)
1782 free(data->state.url);
1783 data->state.url = newurl;
1784 data->state.url_alloc = TRUE;
1785 }
1786
1787 uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
1788 if(uc)
1789 return Curl_uc_to_curlcode(uc);
1790
1791 uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
1792 if(uc) {
1793 if(!strcasecompare("file", data->state.up.scheme))
1794 return CURLE_OUT_OF_MEMORY;
1795 }
1796 else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
1797 failf(data, "Too long hostname (maximum is %d)", MAX_URL_LEN);
1798 return CURLE_URL_MALFORMAT;
1799 }
1800 hostname = data->state.up.hostname;
1801
1802 if(hostname && hostname[0] == '[') {
1803 /* This looks like an IPv6 address literal. See if there is an address
1804 scope. */
1805 size_t hlen;
1806 conn->bits.ipv6_ip = TRUE;
1807 /* cut off the brackets! */
1808 hostname++;
1809 hlen = strlen(hostname);
1810 hostname[hlen - 1] = 0;
1811
1812 zonefrom_url(uh, data, conn);
1813 }
1814
1815 /* make sure the connect struct gets its own copy of the hostname */
1816 conn->host.rawalloc = strdup(hostname ? hostname : "");
1817 if(!conn->host.rawalloc)
1818 return CURLE_OUT_OF_MEMORY;
1819 conn->host.name = conn->host.rawalloc;
1820
1821 /*************************************************************
1822 * IDN-convert the hostnames
1823 *************************************************************/
1824 result = Curl_idnconvert_hostname(&conn->host);
1825 if(result)
1826 return result;
1827
1828 #ifndef CURL_DISABLE_HSTS
1829 /* HSTS upgrade */
1830 if(data->hsts && strcasecompare("http", data->state.up.scheme)) {
1831 /* This MUST use the IDN decoded name */
1832 if(Curl_hsts(data->hsts, conn->host.name, strlen(conn->host.name), TRUE)) {
1833 char *url;
1834 Curl_safefree(data->state.up.scheme);
1835 uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0);
1836 if(uc)
1837 return Curl_uc_to_curlcode(uc);
1838 if(data->state.url_alloc)
1839 Curl_safefree(data->state.url);
1840 /* after update, get the updated version */
1841 uc = curl_url_get(uh, CURLUPART_URL, &url, 0);
1842 if(uc)
1843 return Curl_uc_to_curlcode(uc);
1844 uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
1845 if(uc) {
1846 free(url);
1847 return Curl_uc_to_curlcode(uc);
1848 }
1849 data->state.url = url;
1850 data->state.url_alloc = TRUE;
1851 infof(data, "Switched from HTTP to HTTPS due to HSTS => %s",
1852 data->state.url);
1853 }
1854 }
1855 #endif
1856
1857 result = findprotocol(data, conn, data->state.up.scheme);
1858 if(result)
1859 return result;
1860
1861 /*
1862 * username and password set with their own options override the credentials
1863 * possibly set in the URL, but netrc does not.
1864 */
1865 if(!data->state.aptr.passwd || (data->state.creds_from != CREDS_OPTION)) {
1866 uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
1867 if(!uc) {
1868 char *decoded;
1869 result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL,
1870 conn->handler->flags&PROTOPT_USERPWDCTRL ?
1871 REJECT_ZERO : REJECT_CTRL);
1872 if(result)
1873 return result;
1874 conn->passwd = decoded;
1875 result = Curl_setstropt(&data->state.aptr.passwd, decoded);
1876 if(result)
1877 return result;
1878 data->state.creds_from = CREDS_URL;
1879 }
1880 else if(uc != CURLUE_NO_PASSWORD)
1881 return Curl_uc_to_curlcode(uc);
1882 }
1883
1884 if(!data->state.aptr.user || (data->state.creds_from != CREDS_OPTION)) {
1885 /* we do not use the URL API's URL decoder option here since it rejects
1886 control codes and we want to allow them for some schemes in the user
1887 and password fields */
1888 uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
1889 if(!uc) {
1890 char *decoded;
1891 result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL,
1892 conn->handler->flags&PROTOPT_USERPWDCTRL ?
1893 REJECT_ZERO : REJECT_CTRL);
1894 if(result)
1895 return result;
1896 conn->user = decoded;
1897 result = Curl_setstropt(&data->state.aptr.user, decoded);
1898 data->state.creds_from = CREDS_URL;
1899 }
1900 else if(uc != CURLUE_NO_USER)
1901 return Curl_uc_to_curlcode(uc);
1902 if(result)
1903 return result;
1904 }
1905
1906 uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
1907 CURLU_URLDECODE);
1908 if(!uc) {
1909 conn->options = strdup(data->state.up.options);
1910 if(!conn->options)
1911 return CURLE_OUT_OF_MEMORY;
1912 }
1913 else if(uc != CURLUE_NO_OPTIONS)
1914 return Curl_uc_to_curlcode(uc);
1915
1916 uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path,
1917 CURLU_URLENCODE);
1918 if(uc)
1919 return Curl_uc_to_curlcode(uc);
1920
1921 uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port,
1922 CURLU_DEFAULT_PORT);
1923 if(uc) {
1924 if(!strcasecompare("file", data->state.up.scheme))
1925 return CURLE_OUT_OF_MEMORY;
1926 }
1927 else {
1928 unsigned long port = strtoul(data->state.up.port, NULL, 10);
1929 conn->primary.remote_port = conn->remote_port =
1930 (data->set.use_port && data->state.allow_port) ?
1931 data->set.use_port : curlx_ultous(port);
1932 }
1933
1934 (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
1935
1936 #ifdef USE_IPV6
1937 if(data->set.scope_id)
1938 /* Override any scope that was set above. */
1939 conn->scope_id = data->set.scope_id;
1940 #endif
1941
1942 return CURLE_OK;
1943 }
1944
1945
1946 /*
1947 * If we are doing a resumed transfer, we need to setup our stuff
1948 * properly.
1949 */
1950 static CURLcode setup_range(struct Curl_easy *data)
1951 {
1952 struct UrlState *s = &data->state;
1953 s->resume_from = data->set.set_resume_from;
1954 if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
1955 if(s->rangestringalloc)
1956 free(s->range);
1957
1958 if(s->resume_from)
1959 s->range = aprintf("%" FMT_OFF_T "-", s->resume_from);
1960 else
1961 s->range = strdup(data->set.str[STRING_SET_RANGE]);
1962
1963 if(!s->range)
1964 return CURLE_OUT_OF_MEMORY;
1965
1966 s->rangestringalloc = TRUE;
1967
1968 /* tell ourselves to fetch this range */
1969 s->use_range = TRUE; /* enable range download */
1970 }
1971 else
1972 s->use_range = FALSE; /* disable range download */
1973
1974 return CURLE_OK;
1975 }
1976
1977
1978 /*
1979 * setup_connection_internals() -
1980 *
1981 * Setup connection internals specific to the requested protocol in the
1982 * Curl_easy. This is inited and setup before the connection is made but
1983 * is about the particular protocol that is to be used.
1984 *
1985 * This MUST get called after proxy magic has been figured out.
1986 */
1987 static CURLcode setup_connection_internals(struct Curl_easy *data,
1988 struct connectdata *conn)
1989 {
1990 const struct Curl_handler *p;
1991 const char *hostname;
1992 int port;
1993 CURLcode result;
1994
1995 /* Perform setup complement if some. */
1996 p = conn->handler;
1997
1998 if(p->setup_connection) {
1999 result = (*p->setup_connection)(data, conn);
2000
2001 if(result)
2002 return result;
2003
2004 p = conn->handler; /* May have changed. */
2005 }
2006
2007 if(conn->primary.remote_port < 0)
2008 /* we check for -1 here since if proxy was detected already, this was
2009 likely already set to the proxy port */
2010 conn->primary.remote_port = p->defport;
2011
2012 /* Now create the destination name */
2013 #ifndef CURL_DISABLE_PROXY
2014 if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
2015 hostname = conn->http_proxy.host.name;
2016 port = conn->primary.remote_port;
2017 }
2018 else
2019 #endif
2020 {
2021 port = conn->remote_port;
2022 if(conn->bits.conn_to_host)
2023 hostname = conn->conn_to_host.name;
2024 else
2025 hostname = conn->host.name;
2026 }
2027
2028 #ifdef USE_IPV6
2029 conn->destination = aprintf("%u/%d/%s", conn->scope_id, port, hostname);
2030 #else
2031 conn->destination = aprintf("%d/%s", port, hostname);
2032 #endif
2033 if(!conn->destination)
2034 return CURLE_OUT_OF_MEMORY;
2035
2036 conn->destination_len = strlen(conn->destination) + 1;
2037 Curl_strntolower(conn->destination, conn->destination,
2038 conn->destination_len - 1);
2039
2040 return CURLE_OK;
2041 }
2042
2043
2044 #ifndef CURL_DISABLE_PROXY
2045
2046 #ifndef CURL_DISABLE_HTTP
2047 /****************************************************************
2048 * Detect what (if any) proxy to use. Remember that this selects a host
2049 * name and is not limited to HTTP proxies only.
2050 * The returned pointer must be freed by the caller (unless NULL)
2051 ****************************************************************/
2052 static char *detect_proxy(struct Curl_easy *data,
2053 struct connectdata *conn)
2054 {
2055 char *proxy = NULL;
2056
2057 /* If proxy was not specified, we check for default proxy environment
2058 * variables, to enable i.e Lynx compliance:
2059 *
2060 * http_proxy=http://some.server.dom:port/
2061 * https_proxy=http://some.server.dom:port/
2062 * ftp_proxy=http://some.server.dom:port/
2063 * no_proxy=domain1.dom,host.domain2.dom
2064 * (a comma-separated list of hosts which should
2065 * not be proxied, or an asterisk to override
2066 * all proxy variables)
2067 * all_proxy=http://some.server.dom:port/
2068 * (seems to exist for the CERN www lib. Probably
2069 * the first to check for.)
2070 *
2071 * For compatibility, the all-uppercase versions of these variables are
2072 * checked if the lowercase versions do not exist.
2073 */
2074 char proxy_env[20];
2075 char *envp = proxy_env;
2076 #ifdef CURL_DISABLE_VERBOSE_STRINGS
2077 (void)data;
2078 #endif
2079
2080 msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy", conn->handler->scheme);
2081
2082 /* read the protocol proxy: */
2083 proxy = curl_getenv(proxy_env);
2084
2085 /*
2086 * We do not try the uppercase version of HTTP_PROXY because of
2087 * security reasons:
2088 *
2089 * When curl is used in a webserver application
2090 * environment (cgi or php), this environment variable can
2091 * be controlled by the web server user by setting the
2092 * http header 'Proxy:' to some value.
2093 *
2094 * This can cause 'internal' http/ftp requests to be
2095 * arbitrarily redirected by any external attacker.
2096 */
2097 if(!proxy && !strcasecompare("http_proxy", proxy_env)) {
2098 /* There was no lowercase variable, try the uppercase version: */
2099 Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
2100 proxy = curl_getenv(proxy_env);
2101 }
2102
2103 if(!proxy) {
2104 #ifndef CURL_DISABLE_WEBSOCKETS
2105 /* websocket proxy fallbacks */
2106 if(strcasecompare("ws_proxy", proxy_env)) {
2107 proxy = curl_getenv("http_proxy");
2108 }
2109 else if(strcasecompare("wss_proxy", proxy_env)) {
2110 proxy = curl_getenv("https_proxy");
2111 if(!proxy)
2112 proxy = curl_getenv("HTTPS_PROXY");
2113 }
2114 if(!proxy) {
2115 #endif
2116 envp = (char *)"all_proxy";
2117 proxy = curl_getenv(envp); /* default proxy to use */
2118 if(!proxy) {
2119 envp = (char *)"ALL_PROXY";
2120 proxy = curl_getenv(envp);
2121 }
2122 #ifndef CURL_DISABLE_WEBSOCKETS
2123 }
2124 #endif
2125 }
2126 if(proxy)
2127 infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
2128
2129 return proxy;
2130 }
2131 #endif /* CURL_DISABLE_HTTP */
2132
2133 /*
2134 * If this is supposed to use a proxy, we need to figure out the proxy
2135 * hostname, so that we can reuse an existing connection
2136 * that may exist registered to the same proxy host.
2137 */
2138 static CURLcode parse_proxy(struct Curl_easy *data,
2139 struct connectdata *conn, char *proxy,
2140 curl_proxytype proxytype)
2141 {
2142 char *portptr = NULL;
2143 int port = -1;
2144 char *proxyuser = NULL;
2145 char *proxypasswd = NULL;
2146 char *host = NULL;
2147 bool sockstype;
2148 CURLUcode uc;
2149 struct proxy_info *proxyinfo;
2150 CURLU *uhp = curl_url();
2151 CURLcode result = CURLE_OK;
2152 char *scheme = NULL;
2153 #ifdef USE_UNIX_SOCKETS
2154 char *path = NULL;
2155 bool is_unix_proxy = FALSE;
2156 #endif
2157
2158
2159 if(!uhp) {
2160 result = CURLE_OUT_OF_MEMORY;
2161 goto error;
2162 }
2163
2164 /* When parsing the proxy, allowing non-supported schemes since we have
2165 these made up ones for proxies. Guess scheme for URLs without it. */
2166 uc = curl_url_set(uhp, CURLUPART_URL, proxy,
2167 CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
2168 if(!uc) {
2169 /* parsed okay as a URL */
2170 uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, 0);
2171 if(uc) {
2172 result = CURLE_OUT_OF_MEMORY;
2173 goto error;
2174 }
2175
2176 if(strcasecompare("https", scheme)) {
2177 if(proxytype != CURLPROXY_HTTPS2)
2178 proxytype = CURLPROXY_HTTPS;
2179 else
2180 proxytype = CURLPROXY_HTTPS2;
2181 }
2182 else if(strcasecompare("socks5h", scheme))
2183 proxytype = CURLPROXY_SOCKS5_HOSTNAME;
2184 else if(strcasecompare("socks5", scheme))
2185 proxytype = CURLPROXY_SOCKS5;
2186 else if(strcasecompare("socks4a", scheme))
2187 proxytype = CURLPROXY_SOCKS4A;
2188 else if(strcasecompare("socks4", scheme) ||
2189 strcasecompare("socks", scheme))
2190 proxytype = CURLPROXY_SOCKS4;
2191 else if(strcasecompare("http", scheme))
2192 ; /* leave it as HTTP or HTTP/1.0 */
2193 else {
2194 /* Any other xxx:// reject! */
2195 failf(data, "Unsupported proxy scheme for \'%s\'", proxy);
2196 result = CURLE_COULDNT_CONNECT;
2197 goto error;
2198 }
2199 }
2200 else {
2201 failf(data, "Unsupported proxy syntax in \'%s\': %s", proxy,
2202 curl_url_strerror(uc));
2203 result = CURLE_COULDNT_RESOLVE_PROXY;
2204 goto error;
2205 }
2206
2207 #ifdef USE_SSL
2208 if(!Curl_ssl_supports(data, SSLSUPP_HTTPS_PROXY))
2209 #endif
2210 if(IS_HTTPS_PROXY(proxytype)) {
2211 failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
2212 "HTTPS-proxy support.", proxy);
2213 result = CURLE_NOT_BUILT_IN;
2214 goto error;
2215 }
2216
2217 sockstype =
2218 proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
2219 proxytype == CURLPROXY_SOCKS5 ||
2220 proxytype == CURLPROXY_SOCKS4A ||
2221 proxytype == CURLPROXY_SOCKS4;
2222
2223 proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy;
2224 proxyinfo->proxytype = (unsigned char)proxytype;
2225
2226 /* Is there a username and password given in this proxy url? */
2227 uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
2228 if(uc && (uc != CURLUE_NO_USER))
2229 goto error;
2230 uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
2231 if(uc && (uc != CURLUE_NO_PASSWORD))
2232 goto error;
2233
2234 if(proxyuser || proxypasswd) {
2235 Curl_safefree(proxyinfo->user);
2236 proxyinfo->user = proxyuser;
2237 result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser);
2238 proxyuser = NULL;
2239 if(result)
2240 goto error;
2241 Curl_safefree(proxyinfo->passwd);
2242 if(!proxypasswd) {
2243 proxypasswd = strdup("");
2244 if(!proxypasswd) {
2245 result = CURLE_OUT_OF_MEMORY;
2246 goto error;
2247 }
2248 }
2249 proxyinfo->passwd = proxypasswd;
2250 result = Curl_setstropt(&data->state.aptr.proxypasswd, proxypasswd);
2251 proxypasswd = NULL;
2252 if(result)
2253 goto error;
2254 conn->bits.proxy_user_passwd = TRUE; /* enable it */
2255 }
2256
2257 (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
2258
2259 if(portptr) {
2260 port = (int)strtol(portptr, NULL, 10);
2261 free(portptr);
2262 }
2263 else {
2264 if(data->set.proxyport)
2265 /* None given in the proxy string, then get the default one if it is
2266 given */
2267 port = (int)data->set.proxyport;
2268 else {
2269 if(IS_HTTPS_PROXY(proxytype))
2270 port = CURL_DEFAULT_HTTPS_PROXY_PORT;
2271 else
2272 port = CURL_DEFAULT_PROXY_PORT;
2273 }
2274 }
2275 if(port >= 0) {
2276 proxyinfo->port = port;
2277 if(conn->primary.remote_port < 0 || sockstype ||
2278 !conn->socks_proxy.host.rawalloc)
2279 conn->primary.remote_port = port;
2280 }
2281
2282 /* now, clone the proxy hostname */
2283 uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
2284 if(uc) {
2285 result = CURLE_OUT_OF_MEMORY;
2286 goto error;
2287 }
2288 #ifdef USE_UNIX_SOCKETS
2289 if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) {
2290 uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE);
2291 if(uc) {
2292 result = CURLE_OUT_OF_MEMORY;
2293 goto error;
2294 }
2295 /* path will be "/", if no path was found */
2296 if(strcmp("/", path)) {
2297 is_unix_proxy = TRUE;
2298 free(host);
2299 host = aprintf(UNIX_SOCKET_PREFIX"%s", path);
2300 if(!host) {
2301 result = CURLE_OUT_OF_MEMORY;
2302 goto error;
2303 }
2304 Curl_safefree(proxyinfo->host.rawalloc);
2305 proxyinfo->host.rawalloc = host;
2306 proxyinfo->host.name = host;
2307 host = NULL;
2308 }
2309 }
2310
2311 if(!is_unix_proxy) {
2312 #endif
2313 Curl_safefree(proxyinfo->host.rawalloc);
2314 proxyinfo->host.rawalloc = host;
2315 if(host[0] == '[') {
2316 /* this is a numerical IPv6, strip off the brackets */
2317 size_t len = strlen(host);
2318 host[len-1] = 0; /* clear the trailing bracket */
2319 host++;
2320 zonefrom_url(uhp, data, conn);
2321 }
2322 proxyinfo->host.name = host;
2323 host = NULL;
2324 #ifdef USE_UNIX_SOCKETS
2325 }
2326 #endif
2327
2328 error:
2329 free(proxyuser);
2330 free(proxypasswd);
2331 free(host);
2332 free(scheme);
2333 #ifdef USE_UNIX_SOCKETS
2334 free(path);
2335 #endif
2336 curl_url_cleanup(uhp);
2337 return result;
2338 }
2339
2340 /*
2341 * Extract the user and password from the authentication string
2342 */
2343 static CURLcode parse_proxy_auth(struct Curl_easy *data,
2344 struct connectdata *conn)
2345 {
2346 const char *proxyuser = data->state.aptr.proxyuser ?
2347 data->state.aptr.proxyuser : "";
2348 const char *proxypasswd = data->state.aptr.proxypasswd ?
2349 data->state.aptr.proxypasswd : "";
2350 CURLcode result = CURLE_OUT_OF_MEMORY;
2351
2352 conn->http_proxy.user = strdup(proxyuser);
2353 if(conn->http_proxy.user) {
2354 conn->http_proxy.passwd = strdup(proxypasswd);
2355 if(conn->http_proxy.passwd)
2356 result = CURLE_OK;
2357 else
2358 Curl_safefree(conn->http_proxy.user);
2359 }
2360 return result;
2361 }
2362
2363 /* create_conn helper to parse and init proxy values. to be called after Unix
2364 socket init but before any proxy vars are evaluated. */
2365 static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
2366 struct connectdata *conn)
2367 {
2368 char *proxy = NULL;
2369 char *socksproxy = NULL;
2370 char *no_proxy = NULL;
2371 CURLcode result = CURLE_OK;
2372
2373 /*************************************************************
2374 * Extract the user and password from the authentication string
2375 *************************************************************/
2376 if(conn->bits.proxy_user_passwd) {
2377 result = parse_proxy_auth(data, conn);
2378 if(result)
2379 goto out;
2380 }
2381
2382 /*************************************************************
2383 * Detect what (if any) proxy to use
2384 *************************************************************/
2385 if(data->set.str[STRING_PROXY]) {
2386 proxy = strdup(data->set.str[STRING_PROXY]);
2387 /* if global proxy is set, this is it */
2388 if(!proxy) {
2389 failf(data, "memory shortage");
2390 result = CURLE_OUT_OF_MEMORY;
2391 goto out;
2392 }
2393 }
2394
2395 if(data->set.str[STRING_PRE_PROXY]) {
2396 socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
2397 /* if global socks proxy is set, this is it */
2398 if(!socksproxy) {
2399 failf(data, "memory shortage");
2400 result = CURLE_OUT_OF_MEMORY;
2401 goto out;
2402 }
2403 }
2404
2405 if(!data->set.str[STRING_NOPROXY]) {
2406 const char *p = "no_proxy";
2407 no_proxy = curl_getenv(p);
2408 if(!no_proxy) {
2409 p = "NO_PROXY";
2410 no_proxy = curl_getenv(p);
2411 }
2412 if(no_proxy) {
2413 infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
2414 }
2415 }
2416
2417 if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
2418 data->set.str[STRING_NOPROXY] : no_proxy)) {
2419 Curl_safefree(proxy);
2420 Curl_safefree(socksproxy);
2421 }
2422 #ifndef CURL_DISABLE_HTTP
2423 else if(!proxy && !socksproxy)
2424 /* if the host is not in the noproxy list, detect proxy. */
2425 proxy = detect_proxy(data, conn);
2426 #endif /* CURL_DISABLE_HTTP */
2427 Curl_safefree(no_proxy);
2428
2429 #ifdef USE_UNIX_SOCKETS
2430 /* For the time being do not mix proxy and Unix domain sockets. See #1274 */
2431 if(proxy && conn->unix_domain_socket) {
2432 free(proxy);
2433 proxy = NULL;
2434 }
2435 #endif
2436
2437 if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
2438 free(proxy); /* Do not bother with an empty proxy string or if the
2439 protocol does not work with network */
2440 proxy = NULL;
2441 }
2442 if(socksproxy && (!*socksproxy ||
2443 (conn->handler->flags & PROTOPT_NONETWORK))) {
2444 free(socksproxy); /* Do not bother with an empty socks proxy string or if
2445 the protocol does not work with network */
2446 socksproxy = NULL;
2447 }
2448
2449 /***********************************************************************
2450 * If this is supposed to use a proxy, we need to figure out the proxy host
2451 * name, proxy type and port number, so that we can reuse an existing
2452 * connection that may exist registered to the same proxy host.
2453 ***********************************************************************/
2454 if(proxy || socksproxy) {
2455 curl_proxytype ptype = (curl_proxytype)conn->http_proxy.proxytype;
2456 if(proxy) {
2457 result = parse_proxy(data, conn, proxy, ptype);
2458 Curl_safefree(proxy); /* parse_proxy copies the proxy string */
2459 if(result)
2460 goto out;
2461 }
2462
2463 if(socksproxy) {
2464 result = parse_proxy(data, conn, socksproxy, ptype);
2465 /* parse_proxy copies the socks proxy string */
2466 Curl_safefree(socksproxy);
2467 if(result)
2468 goto out;
2469 }
2470
2471 if(conn->http_proxy.host.rawalloc) {
2472 #ifdef CURL_DISABLE_HTTP
2473 /* asking for an HTTP proxy is a bit funny when HTTP is disabled... */
2474 result = CURLE_UNSUPPORTED_PROTOCOL;
2475 goto out;
2476 #else
2477 /* force this connection's protocol to become HTTP if compatible */
2478 if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) {
2479 if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) &&
2480 !conn->bits.tunnel_proxy)
2481 conn->handler = &Curl_handler_http;
2482 else
2483 /* if not converting to HTTP over the proxy, enforce tunneling */
2484 conn->bits.tunnel_proxy = TRUE;
2485 }
2486 conn->bits.httpproxy = TRUE;
2487 #endif
2488 }
2489 else {
2490 conn->bits.httpproxy = FALSE; /* not an HTTP proxy */
2491 conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
2492 }
2493
2494 if(conn->socks_proxy.host.rawalloc) {
2495 if(!conn->http_proxy.host.rawalloc) {
2496 /* once a socks proxy */
2497 if(!conn->socks_proxy.user) {
2498 conn->socks_proxy.user = conn->http_proxy.user;
2499 conn->http_proxy.user = NULL;
2500 Curl_safefree(conn->socks_proxy.passwd);
2501 conn->socks_proxy.passwd = conn->http_proxy.passwd;
2502 conn->http_proxy.passwd = NULL;
2503 }
2504 }
2505 conn->bits.socksproxy = TRUE;
2506 }
2507 else
2508 conn->bits.socksproxy = FALSE; /* not a socks proxy */
2509 }
2510 else {
2511 conn->bits.socksproxy = FALSE;
2512 conn->bits.httpproxy = FALSE;
2513 }
2514 conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
2515
2516 if(!conn->bits.proxy) {
2517 /* we are not using the proxy after all... */
2518 conn->bits.proxy = FALSE;
2519 conn->bits.httpproxy = FALSE;
2520 conn->bits.socksproxy = FALSE;
2521 conn->bits.proxy_user_passwd = FALSE;
2522 conn->bits.tunnel_proxy = FALSE;
2523 /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
2524 to signal that CURLPROXY_HTTPS is not used for this connection */
2525 conn->http_proxy.proxytype = CURLPROXY_HTTP;
2526 }
2527
2528 out:
2529
2530 free(socksproxy);
2531 free(proxy);
2532 return result;
2533 }
2534 #endif /* CURL_DISABLE_PROXY */
2535
2536 /*
2537 * Curl_parse_login_details()
2538 *
2539 * This is used to parse a login string for username, password and options in
2540 * the following formats:
2541 *
2542 * user
2543 * user:password
2544 * user:password;options
2545 * user;options
2546 * user;options:password
2547 * :password
2548 * :password;options
2549 * ;options
2550 * ;options:password
2551 *
2552 * Parameters:
2553 *
2554 * login [in] - login string.
2555 * len [in] - length of the login string.
2556 * userp [in/out] - address where a pointer to newly allocated memory
2557 * holding the user will be stored upon completion.
2558 * passwdp [in/out] - address where a pointer to newly allocated memory
2559 * holding the password will be stored upon completion.
2560 * optionsp [in/out] - OPTIONAL address where a pointer to newly allocated
2561 * memory holding the options will be stored upon
2562 * completion.
2563 *
2564 * Returns CURLE_OK on success.
2565 */
2566 CURLcode Curl_parse_login_details(const char *login, const size_t len,
2567 char **userp, char **passwdp,
2568 char **optionsp)
2569 {
2570 char *ubuf = NULL;
2571 char *pbuf = NULL;
2572 const char *psep = NULL;
2573 const char *osep = NULL;
2574 size_t ulen;
2575 size_t plen;
2576 size_t olen;
2577
2578 DEBUGASSERT(userp);
2579 DEBUGASSERT(passwdp);
2580
2581 /* Attempt to find the password separator */
2582 psep = memchr(login, ':', len);
2583
2584 /* Attempt to find the options separator */
2585 if(optionsp)
2586 osep = memchr(login, ';', len);
2587
2588 /* Calculate the portion lengths */
2589 ulen = (psep ?
2590 (size_t)(osep && psep > osep ? osep - login : psep - login) :
2591 (osep ? (size_t)(osep - login) : len));
2592 plen = (psep ?
2593 (osep && osep > psep ? (size_t)(osep - psep) :
2594 (size_t)(login + len - psep)) - 1 : 0);
2595 olen = (osep ?
2596 (psep && psep > osep ? (size_t)(psep - osep) :
2597 (size_t)(login + len - osep)) - 1 : 0);
2598
2599 /* Clone the user portion buffer, which can be zero length */
2600 ubuf = Curl_memdup0(login, ulen);
2601 if(!ubuf)
2602 goto error;
2603
2604 /* Clone the password portion buffer */
2605 if(psep) {
2606 pbuf = Curl_memdup0(&psep[1], plen);
2607 if(!pbuf)
2608 goto error;
2609 }
2610
2611 /* Allocate the options portion buffer */
2612 if(optionsp) {
2613 char *obuf = NULL;
2614 if(olen) {
2615 obuf = Curl_memdup0(&osep[1], olen);
2616 if(!obuf)
2617 goto error;
2618 }
2619 *optionsp = obuf;
2620 }
2621 *userp = ubuf;
2622 *passwdp = pbuf;
2623 return CURLE_OK;
2624 error:
2625 free(ubuf);
2626 free(pbuf);
2627 return CURLE_OUT_OF_MEMORY;
2628 }
2629
2630 /*************************************************************
2631 * Figure out the remote port number and fix it in the URL
2632 *
2633 * No matter if we use a proxy or not, we have to figure out the remote
2634 * port number of various reasons.
2635 *
2636 * The port number embedded in the URL is replaced, if necessary.
2637 *************************************************************/
2638 static CURLcode parse_remote_port(struct Curl_easy *data,
2639 struct connectdata *conn)
2640 {
2641
2642 if(data->set.use_port && data->state.allow_port) {
2643 /* if set, we use this instead of the port possibly given in the URL */
2644 char portbuf[16];
2645 CURLUcode uc;
2646 conn->remote_port = data->set.use_port;
2647 msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port);
2648 uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
2649 if(uc)
2650 return CURLE_OUT_OF_MEMORY;
2651 }
2652
2653 return CURLE_OK;
2654 }
2655
2656 static bool str_has_ctrl(const char *input)
2657 {
2658 const unsigned char *str = (const unsigned char *)input;
2659 while(*str) {
2660 if(*str < 0x20)
2661 return TRUE;
2662 str++;
2663 }
2664 return FALSE;
2665 }
2666
2667 /*
2668 * Override the login details from the URL with that in the CURLOPT_USERPWD
2669 * option or a .netrc file, if applicable.
2670 */
2671 static CURLcode override_login(struct Curl_easy *data,
2672 struct connectdata *conn)
2673 {
2674 CURLUcode uc;
2675 char **userp = &conn->user;
2676 char **passwdp = &conn->passwd;
2677 char **optionsp = &conn->options;
2678
2679 if(data->set.str[STRING_OPTIONS]) {
2680 free(*optionsp);
2681 *optionsp = strdup(data->set.str[STRING_OPTIONS]);
2682 if(!*optionsp)
2683 return CURLE_OUT_OF_MEMORY;
2684 }
2685
2686 #ifndef CURL_DISABLE_NETRC
2687 if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
2688 Curl_safefree(*userp);
2689 Curl_safefree(*passwdp);
2690 }
2691 conn->bits.netrc = FALSE;
2692 if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
2693 int ret;
2694 bool url_provided = FALSE;
2695
2696 if(data->state.aptr.user &&
2697 (data->state.creds_from != CREDS_NETRC)) {
2698 /* there was a username with a length in the URL. Use the URL decoded
2699 version */
2700 userp = &data->state.aptr.user;
2701 url_provided = TRUE;
2702 }
2703
2704 if(!*passwdp) {
2705 ret = Curl_parsenetrc(&data->state.netrc, conn->host.name,
2706 userp, passwdp,
2707 data->set.str[STRING_NETRC_FILE]);
2708 if(ret > 0) {
2709 infof(data, "Couldn't find host %s in the %s file; using defaults",
2710 conn->host.name,
2711 (data->set.str[STRING_NETRC_FILE] ?
2712 data->set.str[STRING_NETRC_FILE] : ".netrc"));
2713 }
2714 else if(ret < 0) {
2715 failf(data, ".netrc parser error");
2716 return CURLE_READ_ERROR;
2717 }
2718 else {
2719 if(!(conn->handler->flags&PROTOPT_USERPWDCTRL)) {
2720 /* if the protocol can't handle control codes in credentials, make
2721 sure there are none */
2722 if(str_has_ctrl(*userp) || str_has_ctrl(*passwdp)) {
2723 failf(data, "control code detected in .netrc credentials");
2724 return CURLE_READ_ERROR;
2725 }
2726 }
2727 /* set bits.netrc TRUE to remember that we got the name from a .netrc
2728 file, so that it is safe to use even if we followed a Location: to a
2729 different host or similar. */
2730 conn->bits.netrc = TRUE;
2731 }
2732 }
2733 if(url_provided) {
2734 Curl_safefree(conn->user);
2735 conn->user = strdup(*userp);
2736 if(!conn->user)
2737 return CURLE_OUT_OF_MEMORY;
2738 }
2739 /* no user was set but a password, set a blank user */
2740 if(!*userp && *passwdp) {
2741 *userp = strdup("");
2742 if(!*userp)
2743 return CURLE_OUT_OF_MEMORY;
2744 }
2745 }
2746 #endif
2747
2748 /* for updated strings, we update them in the URL */
2749 if(*userp) {
2750 CURLcode result;
2751 if(data->state.aptr.user != *userp) {
2752 /* nothing to do then */
2753 result = Curl_setstropt(&data->state.aptr.user, *userp);
2754 if(result)
2755 return result;
2756 data->state.creds_from = CREDS_NETRC;
2757 }
2758 }
2759 if(data->state.aptr.user) {
2760 uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
2761 CURLU_URLENCODE);
2762 if(uc)
2763 return Curl_uc_to_curlcode(uc);
2764 if(!*userp) {
2765 *userp = strdup(data->state.aptr.user);
2766 if(!*userp)
2767 return CURLE_OUT_OF_MEMORY;
2768 }
2769 }
2770 if(*passwdp) {
2771 CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
2772 if(result)
2773 return result;
2774 data->state.creds_from = CREDS_NETRC;
2775 }
2776 if(data->state.aptr.passwd) {
2777 uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
2778 data->state.aptr.passwd, CURLU_URLENCODE);
2779 if(uc)
2780 return Curl_uc_to_curlcode(uc);
2781 if(!*passwdp) {
2782 *passwdp = strdup(data->state.aptr.passwd);
2783 if(!*passwdp)
2784 return CURLE_OUT_OF_MEMORY;
2785 }
2786 }
2787
2788 return CURLE_OK;
2789 }
2790
2791 /*
2792 * Set the login details so they are available in the connection
2793 */
2794 static CURLcode set_login(struct Curl_easy *data,
2795 struct connectdata *conn)
2796 {
2797 CURLcode result = CURLE_OK;
2798 const char *setuser = CURL_DEFAULT_USER;
2799 const char *setpasswd = CURL_DEFAULT_PASSWORD;
2800
2801 /* If our protocol needs a password and we have none, use the defaults */
2802 if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user)
2803 ;
2804 else {
2805 setuser = "";
2806 setpasswd = "";
2807 }
2808 /* Store the default user */
2809 if(!conn->user) {
2810 conn->user = strdup(setuser);
2811 if(!conn->user)
2812 return CURLE_OUT_OF_MEMORY;
2813 }
2814
2815 /* Store the default password */
2816 if(!conn->passwd) {
2817 conn->passwd = strdup(setpasswd);
2818 if(!conn->passwd)
2819 result = CURLE_OUT_OF_MEMORY;
2820 }
2821
2822 return result;
2823 }
2824
2825 /*
2826 * Parses a "host:port" string to connect to.
2827 * The hostname and the port may be empty; in this case, NULL is returned for
2828 * the hostname and -1 for the port.
2829 */
2830 static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
2831 const char *host,
2832 char **hostname_result,
2833 int *port_result)
2834 {
2835 char *host_dup;
2836 char *hostptr;
2837 char *host_portno;
2838 char *portptr;
2839 int port = -1;
2840 CURLcode result = CURLE_OK;
2841
2842 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
2843 (void) data;
2844 #endif
2845
2846 *hostname_result = NULL;
2847 *port_result = -1;
2848
2849 if(!host || !*host)
2850 return CURLE_OK;
2851
2852 host_dup = strdup(host);
2853 if(!host_dup)
2854 return CURLE_OUT_OF_MEMORY;
2855
2856 hostptr = host_dup;
2857
2858 /* start scanning for port number at this point */
2859 portptr = hostptr;
2860
2861 /* detect and extract RFC6874-style IPv6-addresses */
2862 if(*hostptr == '[') {
2863 #ifdef USE_IPV6
2864 char *ptr = ++hostptr; /* advance beyond the initial bracket */
2865 while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
2866 ptr++;
2867 if(*ptr == '%') {
2868 /* There might be a zone identifier */
2869 if(strncmp("%25", ptr, 3))
2870 infof(data, "Please URL encode %% as %%25, see RFC 6874.");
2871 ptr++;
2872 /* Allow unreserved characters as defined in RFC 3986 */
2873 while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
2874 (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
2875 ptr++;
2876 }
2877 if(*ptr == ']')
2878 /* yeps, it ended nicely with a bracket as well */
2879 *ptr++ = '\0';
2880 else
2881 infof(data, "Invalid IPv6 address format");
2882 portptr = ptr;
2883 /* Note that if this did not end with a bracket, we still advanced the
2884 * hostptr first, but I cannot see anything wrong with that as no host
2885 * name nor a numeric can legally start with a bracket.
2886 */
2887 #else
2888 failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
2889 result = CURLE_NOT_BUILT_IN;
2890 goto error;
2891 #endif
2892 }
2893
2894 /* Get port number off server.com:1080 */
2895 host_portno = strchr(portptr, ':');
2896 if(host_portno) {
2897 char *endp = NULL;
2898 *host_portno = '\0'; /* cut off number from hostname */
2899 host_portno++;
2900 if(*host_portno) {
2901 long portparse = strtol(host_portno, &endp, 10);
2902 if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
2903 failf(data, "No valid port number in connect to host string (%s)",
2904 host_portno);
2905 result = CURLE_SETOPT_OPTION_SYNTAX;
2906 goto error;
2907 }
2908 else
2909 port = (int)portparse; /* we know it will fit */
2910 }
2911 }
2912
2913 /* now, clone the cleaned hostname */
2914 DEBUGASSERT(hostptr);
2915 *hostname_result = strdup(hostptr);
2916 if(!*hostname_result) {
2917 result = CURLE_OUT_OF_MEMORY;
2918 goto error;
2919 }
2920
2921 *port_result = port;
2922
2923 error:
2924 free(host_dup);
2925 return result;
2926 }
2927
2928 /*
2929 * Parses one "connect to" string in the form:
2930 * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
2931 */
2932 static CURLcode parse_connect_to_string(struct Curl_easy *data,
2933 struct connectdata *conn,
2934 const char *conn_to_host,
2935 char **host_result,
2936 int *port_result)
2937 {
2938 CURLcode result = CURLE_OK;
2939 const char *ptr = conn_to_host;
2940 bool host_match = FALSE;
2941 bool port_match = FALSE;
2942
2943 *host_result = NULL;
2944 *port_result = -1;
2945
2946 if(*ptr == ':') {
2947 /* an empty hostname always matches */
2948 host_match = TRUE;
2949 ptr++;
2950 }
2951 else {
2952 /* check whether the URL's hostname matches */
2953 size_t hostname_to_match_len;
2954 char *hostname_to_match = aprintf("%s%s%s",
2955 conn->bits.ipv6_ip ? "[" : "",
2956 conn->host.name,
2957 conn->bits.ipv6_ip ? "]" : "");
2958 if(!hostname_to_match)
2959 return CURLE_OUT_OF_MEMORY;
2960 hostname_to_match_len = strlen(hostname_to_match);
2961 host_match = strncasecompare(ptr, hostname_to_match,
2962 hostname_to_match_len);
2963 free(hostname_to_match);
2964 ptr += hostname_to_match_len;
2965
2966 host_match = host_match && *ptr == ':';
2967 ptr++;
2968 }
2969
2970 if(host_match) {
2971 if(*ptr == ':') {
2972 /* an empty port always matches */
2973 port_match = TRUE;
2974 ptr++;
2975 }
2976 else {
2977 /* check whether the URL's port matches */
2978 char *ptr_next = strchr(ptr, ':');
2979 if(ptr_next) {
2980 char *endp = NULL;
2981 long port_to_match = strtol(ptr, &endp, 10);
2982 if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
2983 port_match = TRUE;
2984 ptr = ptr_next + 1;
2985 }
2986 }
2987 }
2988 }
2989
2990 if(host_match && port_match) {
2991 /* parse the hostname and port to connect to */
2992 result = parse_connect_to_host_port(data, ptr, host_result, port_result);
2993 }
2994
2995 return result;
2996 }
2997
2998 /*
2999 * Processes all strings in the "connect to" slist, and uses the "connect
3000 * to host" and "connect to port" of the first string that matches.
3001 */
3002 static CURLcode parse_connect_to_slist(struct Curl_easy *data,
3003 struct connectdata *conn,
3004 struct curl_slist *conn_to_host)
3005 {
3006 CURLcode result = CURLE_OK;
3007 char *host = NULL;
3008 int port = -1;
3009
3010 while(conn_to_host && !host && port == -1) {
3011 result = parse_connect_to_string(data, conn, conn_to_host->data,
3012 &host, &port);
3013 if(result)
3014 return result;
3015
3016 if(host && *host) {
3017 conn->conn_to_host.rawalloc = host;
3018 conn->conn_to_host.name = host;
3019 conn->bits.conn_to_host = TRUE;
3020
3021 infof(data, "Connecting to hostname: %s", host);
3022 }
3023 else {
3024 /* no "connect to host" */
3025 conn->bits.conn_to_host = FALSE;
3026 Curl_safefree(host);
3027 }
3028
3029 if(port >= 0) {
3030 conn->conn_to_port = port;
3031 conn->bits.conn_to_port = TRUE;
3032 infof(data, "Connecting to port: %d", port);
3033 }
3034 else {
3035 /* no "connect to port" */
3036 conn->bits.conn_to_port = FALSE;
3037 port = -1;
3038 }
3039
3040 conn_to_host = conn_to_host->next;
3041 }
3042
3043 #ifndef CURL_DISABLE_ALTSVC
3044 if(data->asi && !host && (port == -1) &&
3045 ((conn->handler->protocol == CURLPROTO_HTTPS) ||
3046 #ifdef DEBUGBUILD
3047 /* allow debug builds to circumvent the HTTPS restriction */
3048 getenv("CURL_ALTSVC_HTTP")
3049 #else
3050 0
3051 #endif
3052 )) {
3053 /* no connect_to match, try alt-svc! */
3054 enum alpnid srcalpnid = ALPN_none;
3055 bool use_alt_svc = FALSE;
3056 bool hit = FALSE;
3057 struct altsvc *as = NULL;
3058 const int allowed_versions = ( ALPN_h1
3059 #ifdef USE_HTTP2
3060 | ALPN_h2
3061 #endif
3062 #ifdef USE_HTTP3
3063 | ALPN_h3
3064 #endif
3065 ) & data->asi->flags;
3066 static enum alpnid alpn_ids[] = {
3067 #ifdef USE_HTTP3
3068 ALPN_h3,
3069 #endif
3070 #ifdef USE_HTTP2
3071 ALPN_h2,
3072 #endif
3073 ALPN_h1,
3074 };
3075 size_t i;
3076
3077 switch(data->state.httpwant) {
3078 case CURL_HTTP_VERSION_1_0:
3079 break;
3080 case CURL_HTTP_VERSION_1_1:
3081 use_alt_svc = TRUE;
3082 srcalpnid = ALPN_h1; /* only regard alt-svc advice for http/1.1 */
3083 break;
3084 case CURL_HTTP_VERSION_2_0:
3085 use_alt_svc = TRUE;
3086 srcalpnid = ALPN_h2; /* only regard alt-svc advice for h2 */
3087 break;
3088 case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE:
3089 break;
3090 case CURL_HTTP_VERSION_3:
3091 use_alt_svc = TRUE;
3092 srcalpnid = ALPN_h3; /* only regard alt-svc advice for h3 */
3093 break;
3094 case CURL_HTTP_VERSION_3ONLY:
3095 break;
3096 default: /* no specific HTTP version wanted, look at all of alt-svc */
3097 use_alt_svc = TRUE;
3098 srcalpnid = ALPN_none;
3099 break;
3100 }
3101 if(!use_alt_svc)
3102 return CURLE_OK;
3103
3104 host = conn->host.rawalloc;
3105 DEBUGF(infof(data, "check Alt-Svc for host %s", host));
3106 if(srcalpnid == ALPN_none) {
3107 /* scan all alt-svc protocol ids in order or relevance */
3108 for(i = 0; !hit && (i < ARRAYSIZE(alpn_ids)); ++i) {
3109 srcalpnid = alpn_ids[i];
3110 hit = Curl_altsvc_lookup(data->asi,
3111 srcalpnid, host, conn->remote_port, /* from */
3112 &as /* to */,
3113 allowed_versions);
3114 }
3115 }
3116 else {
3117 /* look for a specific alt-svc protocol id */
3118 hit = Curl_altsvc_lookup(data->asi,
3119 srcalpnid, host, conn->remote_port, /* from */
3120 &as /* to */,
3121 allowed_versions);
3122 }
3123
3124
3125 if(hit) {
3126 char *hostd = strdup((char *)as->dst.host);
3127 if(!hostd)
3128 return CURLE_OUT_OF_MEMORY;
3129 conn->conn_to_host.rawalloc = hostd;
3130 conn->conn_to_host.name = hostd;
3131 conn->bits.conn_to_host = TRUE;
3132 conn->conn_to_port = as->dst.port;
3133 conn->bits.conn_to_port = TRUE;
3134 conn->bits.altused = TRUE;
3135 infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d",
3136 Curl_alpnid2str(srcalpnid), host, conn->remote_port,
3137 Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
3138 if(srcalpnid != as->dst.alpnid) {
3139 /* protocol version switch */
3140 switch(as->dst.alpnid) {
3141 case ALPN_h1:
3142 data->state.httpwant = CURL_HTTP_VERSION_1_1;
3143 break;
3144 case ALPN_h2:
3145 data->state.httpwant = CURL_HTTP_VERSION_2_0;
3146 break;
3147 case ALPN_h3:
3148 conn->transport = TRNSPRT_QUIC;
3149 data->state.httpwant = CURL_HTTP_VERSION_3;
3150 break;
3151 default: /* should not be possible */
3152 break;
3153 }
3154 }
3155 }
3156 }
3157 #endif
3158
3159 return result;
3160 }
3161
3162 #ifdef USE_UNIX_SOCKETS
3163 static CURLcode resolve_unix(struct Curl_easy *data,
3164 struct connectdata *conn,
3165 char *unix_path)
3166 {
3167 struct Curl_dns_entry *hostaddr = NULL;
3168 bool longpath = FALSE;
3169
3170 DEBUGASSERT(unix_path);
3171 DEBUGASSERT(conn->dns_entry == NULL);
3172
3173 /* Unix domain sockets are local. The host gets ignored, just use the
3174 * specified domain socket address. Do not cache "DNS entries". There is
3175 * no DNS involved and we already have the filesystem path available. */
3176 hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
3177 if(!hostaddr)
3178 return CURLE_OUT_OF_MEMORY;
3179
3180 hostaddr->addr = Curl_unix2addr(unix_path, &longpath,
3181 conn->bits.abstract_unix_socket);
3182 if(!hostaddr->addr) {
3183 if(longpath)
3184 /* Long paths are not supported for now */
3185 failf(data, "Unix socket path too long: '%s'", unix_path);
3186 free(hostaddr);
3187 return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY;
3188 }
3189
3190 hostaddr->refcount = 1; /* connection is the only one holding this */
3191 conn->dns_entry = hostaddr;
3192 return CURLE_OK;
3193 }
3194 #endif
3195
3196 /*************************************************************
3197 * Resolve the address of the server or proxy
3198 *************************************************************/
3199 static CURLcode resolve_server(struct Curl_easy *data,
3200 struct connectdata *conn,
3201 bool *async)
3202 {
3203 struct hostname *ehost;
3204 timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
3205 const char *peertype = "host";
3206 int rc;
3207 #ifdef USE_UNIX_SOCKETS
3208 char *unix_path = conn->unix_domain_socket;
3209
3210 #ifndef CURL_DISABLE_PROXY
3211 if(!unix_path && CONN_IS_PROXIED(conn) && conn->socks_proxy.host.name &&
3212 !strncmp(UNIX_SOCKET_PREFIX"/",
3213 conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
3214 unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
3215 #endif
3216
3217 if(unix_path) {
3218 /* TODO, this only works if previous transport is TRNSPRT_TCP. Check it? */
3219 conn->transport = TRNSPRT_UNIX;
3220 return resolve_unix(data, conn, unix_path);
3221 }
3222 #endif
3223
3224 DEBUGASSERT(conn->dns_entry == NULL);
3225
3226 #ifndef CURL_DISABLE_PROXY
3227 if(CONN_IS_PROXIED(conn)) {
3228 ehost = conn->bits.socksproxy ? &conn->socks_proxy.host :
3229 &conn->http_proxy.host;
3230 peertype = "proxy";
3231 }
3232 else
3233 #endif
3234 {
3235 ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
3236 /* If not connecting via a proxy, extract the port from the URL, if it is
3237 * there, thus overriding any defaults that might have been set above. */
3238 conn->primary.remote_port = conn->bits.conn_to_port ? conn->conn_to_port :
3239 conn->remote_port;
3240 }
3241
3242 /* Resolve target host right on */
3243 conn->hostname_resolve = strdup(ehost->name);
3244 if(!conn->hostname_resolve)
3245 return CURLE_OUT_OF_MEMORY;
3246
3247 rc = Curl_resolv_timeout(data, conn->hostname_resolve,
3248 conn->primary.remote_port,
3249 &conn->dns_entry, timeout_ms);
3250 if(rc == CURLRESOLV_PENDING)
3251 *async = TRUE;
3252 else if(rc == CURLRESOLV_TIMEDOUT) {
3253 failf(data, "Failed to resolve %s '%s' with timeout after %"
3254 FMT_TIMEDIFF_T " ms", peertype, ehost->dispname,
3255 Curl_timediff(Curl_now(), data->progress.t_startsingle));
3256 return CURLE_OPERATION_TIMEDOUT;
3257 }
3258 else if(!conn->dns_entry) {
3259 failf(data, "Could not resolve %s: %s", peertype, ehost->dispname);
3260 return CURLE_COULDNT_RESOLVE_HOST;
3261 }
3262
3263 return CURLE_OK;
3264 }
3265
3266 /*
3267 * Cleanup the connection `temp`, just allocated for `data`, before using the
3268 * previously `existing` one for `data`. All relevant info is copied over
3269 * and `temp` is freed.
3270 */
3271 static void reuse_conn(struct Curl_easy *data,
3272 struct connectdata *temp,
3273 struct connectdata *existing)
3274 {
3275 /* get the user+password information from the temp struct since it may
3276 * be new for this request even when we reuse an existing connection */
3277 if(temp->user) {
3278 /* use the new username and password though */
3279 Curl_safefree(existing->user);
3280 Curl_safefree(existing->passwd);
3281 existing->user = temp->user;
3282 existing->passwd = temp->passwd;
3283 temp->user = NULL;
3284 temp->passwd = NULL;
3285 }
3286
3287 #ifndef CURL_DISABLE_PROXY
3288 existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
3289 if(existing->bits.proxy_user_passwd) {
3290 /* use the new proxy username and proxy password though */
3291 Curl_safefree(existing->http_proxy.user);
3292 Curl_safefree(existing->socks_proxy.user);
3293 Curl_safefree(existing->http_proxy.passwd);
3294 Curl_safefree(existing->socks_proxy.passwd);
3295 existing->http_proxy.user = temp->http_proxy.user;
3296 existing->socks_proxy.user = temp->socks_proxy.user;
3297 existing->http_proxy.passwd = temp->http_proxy.passwd;
3298 existing->socks_proxy.passwd = temp->socks_proxy.passwd;
3299 temp->http_proxy.user = NULL;
3300 temp->socks_proxy.user = NULL;
3301 temp->http_proxy.passwd = NULL;
3302 temp->socks_proxy.passwd = NULL;
3303 }
3304 #endif
3305
3306 /* Finding a connection for reuse in the cpool matches, among other
3307 * things on the "remote-relevant" hostname. This is not necessarily
3308 * the authority of the URL, e.g. conn->host. For example:
3309 * - we use a proxy (not tunneling). we want to send all requests
3310 * that use the same proxy on this connection.
3311 * - we have a "connect-to" setting that may redirect the hostname of
3312 * a new request to the same remote endpoint of an existing conn.
3313 * We want to reuse an existing conn to the remote endpoint.
3314 * Since connection reuse does not match on conn->host necessarily, we
3315 * switch `existing` conn to `temp` conn's host settings.
3316 * TODO: is this correct in the case of TLS connections that have
3317 * used the original hostname in SNI to negotiate? Do we send
3318 * requests for another host through the different SNI?
3319 */
3320 Curl_free_idnconverted_hostname(&existing->host);
3321 Curl_free_idnconverted_hostname(&existing->conn_to_host);
3322 Curl_safefree(existing->host.rawalloc);
3323 Curl_safefree(existing->conn_to_host.rawalloc);
3324 existing->host = temp->host;
3325 temp->host.rawalloc = NULL;
3326 temp->host.encalloc = NULL;
3327 existing->conn_to_host = temp->conn_to_host;
3328 temp->conn_to_host.rawalloc = NULL;
3329 existing->conn_to_port = temp->conn_to_port;
3330 existing->remote_port = temp->remote_port;
3331 Curl_safefree(existing->hostname_resolve);
3332
3333 existing->hostname_resolve = temp->hostname_resolve;
3334 temp->hostname_resolve = NULL;
3335
3336 /* reuse init */
3337 existing->bits.reuse = TRUE; /* yes, we are reusing here */
3338
3339 Curl_conn_free(data, temp);
3340 }
3341
3342 /**
3343 * create_conn() sets up a new connectdata struct, or reuses an already
3344 * existing one, and resolves hostname.
3345 *
3346 * if this function returns CURLE_OK and *async is set to TRUE, the resolve
3347 * response will be coming asynchronously. If *async is FALSE, the name is
3348 * already resolved.
3349 *
3350 * @param data The sessionhandle pointer
3351 * @param in_connect is set to the next connection data pointer
3352 * @param async is set TRUE when an async DNS resolution is pending
3353 * @see Curl_setup_conn()
3354 *
3355 */
3356
3357 static CURLcode create_conn(struct Curl_easy *data,
3358 struct connectdata **in_connect,
3359 bool *async)
3360 {
3361 CURLcode result = CURLE_OK;
3362 struct connectdata *conn;
3363 struct connectdata *existing = NULL;
3364 bool reuse;
3365 bool connections_available = TRUE;
3366 bool force_reuse = FALSE;
3367 bool waitpipe = FALSE;
3368
3369 *async = FALSE;
3370 *in_connect = NULL;
3371
3372 /*************************************************************
3373 * Check input data
3374 *************************************************************/
3375 if(!data->state.url) {
3376 result = CURLE_URL_MALFORMAT;
3377 goto out;
3378 }
3379
3380 /* First, split up the current URL in parts so that we can use the
3381 parts for checking against the already present connections. In order
3382 to not have to modify everything at once, we allocate a temporary
3383 connection data struct and fill in for comparison purposes. */
3384 conn = allocate_conn(data);
3385
3386 if(!conn) {
3387 result = CURLE_OUT_OF_MEMORY;
3388 goto out;
3389 }
3390
3391 /* We must set the return variable as soon as possible, so that our
3392 parent can cleanup any possible allocs we may have done before
3393 any failure */
3394 *in_connect = conn;
3395
3396 result = parseurlandfillconn(data, conn);
3397 if(result)
3398 goto out;
3399
3400 if(data->set.str[STRING_SASL_AUTHZID]) {
3401 conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
3402 if(!conn->sasl_authzid) {
3403 result = CURLE_OUT_OF_MEMORY;
3404 goto out;
3405 }
3406 }
3407
3408 if(data->set.str[STRING_BEARER]) {
3409 conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
3410 if(!conn->oauth_bearer) {
3411 result = CURLE_OUT_OF_MEMORY;
3412 goto out;
3413 }
3414 }
3415
3416 #ifdef USE_UNIX_SOCKETS
3417 if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
3418 conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
3419 if(!conn->unix_domain_socket) {
3420 result = CURLE_OUT_OF_MEMORY;
3421 goto out;
3422 }
3423 conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
3424 }
3425 #endif
3426
3427 /* After the Unix socket init but before the proxy vars are used, parse and
3428 initialize the proxy vars */
3429 #ifndef CURL_DISABLE_PROXY
3430 result = create_conn_helper_init_proxy(data, conn);
3431 if(result)
3432 goto out;
3433
3434 /*************************************************************
3435 * If the protocol is using SSL and HTTP proxy is used, we set
3436 * the tunnel_proxy bit.
3437 *************************************************************/
3438 if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
3439 conn->bits.tunnel_proxy = TRUE;
3440 #endif
3441
3442 /*************************************************************
3443 * Figure out the remote port number and fix it in the URL
3444 *************************************************************/
3445 result = parse_remote_port(data, conn);
3446 if(result)
3447 goto out;
3448
3449 /* Check for overridden login details and set them accordingly so that
3450 they are known when protocol->setup_connection is called! */
3451 result = override_login(data, conn);
3452 if(result)
3453 goto out;
3454
3455 result = set_login(data, conn); /* default credentials */
3456 if(result)
3457 goto out;
3458
3459 /*************************************************************
3460 * Process the "connect to" linked list of hostname/port mappings.
3461 * Do this after the remote port number has been fixed in the URL.
3462 *************************************************************/
3463 result = parse_connect_to_slist(data, conn, data->set.connect_to);
3464 if(result)
3465 goto out;
3466
3467 /*************************************************************
3468 * IDN-convert the proxy hostnames
3469 *************************************************************/
3470 #ifndef CURL_DISABLE_PROXY
3471 if(conn->bits.httpproxy) {
3472 result = Curl_idnconvert_hostname(&conn->http_proxy.host);
3473 if(result)
3474 return result;
3475 }
3476 if(conn->bits.socksproxy) {
3477 result = Curl_idnconvert_hostname(&conn->socks_proxy.host);
3478 if(result)
3479 return result;
3480 }
3481 #endif
3482 if(conn->bits.conn_to_host) {
3483 result = Curl_idnconvert_hostname(&conn->conn_to_host);
3484 if(result)
3485 return result;
3486 }
3487
3488 /*************************************************************
3489 * Check whether the host and the "connect to host" are equal.
3490 * Do this after the hostnames have been IDN-converted.
3491 *************************************************************/
3492 if(conn->bits.conn_to_host &&
3493 strcasecompare(conn->conn_to_host.name, conn->host.name)) {
3494 conn->bits.conn_to_host = FALSE;
3495 }
3496
3497 /*************************************************************
3498 * Check whether the port and the "connect to port" are equal.
3499 * Do this after the remote port number has been fixed in the URL.
3500 *************************************************************/
3501 if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
3502 conn->bits.conn_to_port = FALSE;
3503 }
3504
3505 #ifndef CURL_DISABLE_PROXY
3506 /*************************************************************
3507 * If the "connect to" feature is used with an HTTP proxy,
3508 * we set the tunnel_proxy bit.
3509 *************************************************************/
3510 if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
3511 conn->bits.httpproxy)
3512 conn->bits.tunnel_proxy = TRUE;
3513 #endif
3514
3515 /*************************************************************
3516 * Setup internals depending on protocol. Needs to be done after
3517 * we figured out what/if proxy to use.
3518 *************************************************************/
3519 result = setup_connection_internals(data, conn);
3520 if(result)
3521 goto out;
3522
3523 /***********************************************************************
3524 * file: is a special case in that it does not need a network connection
3525 ***********************************************************************/
3526 #ifndef CURL_DISABLE_FILE
3527 if(conn->handler->flags & PROTOPT_NONETWORK) {
3528 bool done;
3529 /* this is supposed to be the connect function so we better at least check
3530 that the file is present here! */
3531 DEBUGASSERT(conn->handler->connect_it);
3532 data->info.conn_scheme = conn->handler->scheme;
3533 /* conn_protocol can only provide "old" protocols */
3534 data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
3535 result = conn->handler->connect_it(data, &done);
3536
3537 /* Setup a "faked" transfer that will do nothing */
3538 if(!result) {
3539 Curl_attach_connection(data, conn);
3540 result = Curl_cpool_add_conn(data, conn);
3541 if(result)
3542 goto out;
3543
3544 /*
3545 * Setup whatever necessary for a resumed transfer
3546 */
3547 result = setup_range(data);
3548 if(result) {
3549 DEBUGASSERT(conn->handler->done);
3550 /* we ignore the return code for the protocol-specific DONE */
3551 (void)conn->handler->done(data, result, FALSE);
3552 goto out;
3553 }
3554 Curl_xfer_setup_nop(data);
3555 }
3556
3557 /* since we skip do_init() */
3558 Curl_init_do(data, conn);
3559
3560 goto out;
3561 }
3562 #endif
3563
3564 /* Setup filter for network connections */
3565 conn->recv[FIRSTSOCKET] = Curl_cf_recv;
3566 conn->send[FIRSTSOCKET] = Curl_cf_send;
3567 conn->recv[SECONDARYSOCKET] = Curl_cf_recv;
3568 conn->send[SECONDARYSOCKET] = Curl_cf_send;
3569 conn->bits.tcp_fastopen = data->set.tcp_fastopen;
3570
3571 /* Complete the easy's SSL configuration for connection cache matching */
3572 result = Curl_ssl_easy_config_complete(data);
3573 if(result)
3574 goto out;
3575
3576 /* FIXME: do we really want to run this every time we add a transfer? */
3577 Curl_cpool_prune_dead(data);
3578
3579 /*************************************************************
3580 * Check the current list of connections to see if we can
3581 * reuse an already existing one or if we have to create a
3582 * new one.
3583 *************************************************************/
3584
3585 DEBUGASSERT(conn->user);
3586 DEBUGASSERT(conn->passwd);
3587
3588 /* reuse_fresh is TRUE if we are told to use a new connection by force, but
3589 we only acknowledge this option if this is not a reused connection
3590 already (which happens due to follow-location or during an HTTP
3591 authentication phase). CONNECT_ONLY transfers also refuse reuse. */
3592 if((data->set.reuse_fresh && !data->state.followlocation) ||
3593 data->set.connect_only)
3594 reuse = FALSE;
3595 else
3596 reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
3597
3598 if(reuse) {
3599 /*
3600 * We already have a connection for this, we got the former connection in
3601 * `existing` and thus we need to cleanup the one we just
3602 * allocated before we can move along and use `existing`.
3603 */
3604 reuse_conn(data, conn, existing);
3605 conn = existing;
3606 *in_connect = conn;
3607
3608 #ifndef CURL_DISABLE_PROXY
3609 infof(data, "Re-using existing connection with %s %s",
3610 conn->bits.proxy ? "proxy" : "host",
3611 conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
3612 conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
3613 conn->host.dispname);
3614 #else
3615 infof(data, "Re-using existing connection with host %s",
3616 conn->host.dispname);
3617 #endif
3618 }
3619 else {
3620 /* We have decided that we want a new connection. However, we may not
3621 be able to do that if we have reached the limit of how many
3622 connections we are allowed to open. */
3623
3624 if(conn->handler->flags & PROTOPT_ALPN) {
3625 /* The protocol wants it, so set the bits if enabled in the easy handle
3626 (default) */
3627 if(data->set.ssl_enable_alpn)
3628 conn->bits.tls_enable_alpn = TRUE;
3629 }
3630
3631 if(waitpipe)
3632 /* There is a connection that *might* become usable for multiplexing
3633 "soon", and we wait for that */
3634 connections_available = FALSE;
3635 else {
3636 switch(Curl_cpool_check_limits(data, conn)) {
3637 case CPOOL_LIMIT_DEST:
3638 infof(data, "No more connections allowed to host");
3639 connections_available = FALSE;
3640 break;
3641 case CPOOL_LIMIT_TOTAL:
3642 #ifndef CURL_DISABLE_DOH
3643 if(data->set.dohfor_mid >= 0)
3644 infof(data, "Allowing DoH to override max connection limit");
3645 else
3646 #endif
3647 {
3648 infof(data, "No connections available in cache");
3649 connections_available = FALSE;
3650 }
3651 break;
3652 default:
3653 break;
3654 }
3655 }
3656
3657 if(!connections_available) {
3658 infof(data, "No connections available.");
3659
3660 Curl_conn_free(data, conn);
3661 *in_connect = NULL;
3662
3663 result = CURLE_NO_CONNECTION_AVAILABLE;
3664 goto out;
3665 }
3666 else {
3667 /*
3668 * This is a brand new connection, so let's store it in the connection
3669 * cache of ours!
3670 */
3671 result = Curl_ssl_conn_config_init(data, conn);
3672 if(result) {
3673 DEBUGF(fprintf(stderr, "Error: init connection ssl config\n"));
3674 goto out;
3675 }
3676
3677 Curl_attach_connection(data, conn);
3678 result = Curl_cpool_add_conn(data, conn);
3679 if(result)
3680 goto out;
3681 }
3682
3683 #if defined(USE_NTLM)
3684 /* If NTLM is requested in a part of this connection, make sure we do not
3685 assume the state is fine as this is a fresh connection and NTLM is
3686 connection based. */
3687 if((data->state.authhost.picked & CURLAUTH_NTLM) &&
3688 data->state.authhost.done) {
3689 infof(data, "NTLM picked AND auth done set, clear picked");
3690 data->state.authhost.picked = CURLAUTH_NONE;
3691 data->state.authhost.done = FALSE;
3692 }
3693
3694 if((data->state.authproxy.picked & CURLAUTH_NTLM) &&
3695 data->state.authproxy.done) {
3696 infof(data, "NTLM-proxy picked AND auth done set, clear picked");
3697 data->state.authproxy.picked = CURLAUTH_NONE;
3698 data->state.authproxy.done = FALSE;
3699 }
3700 #endif
3701 }
3702
3703 /* Setup and init stuff before DO starts, in preparing for the transfer. */
3704 Curl_init_do(data, conn);
3705
3706 /*
3707 * Setup whatever necessary for a resumed transfer
3708 */
3709 result = setup_range(data);
3710 if(result)
3711 goto out;
3712
3713 /* Continue connectdata initialization here. */
3714
3715 if(conn->bits.reuse) {
3716 /* We are reusing the connection - no need to resolve anything, and
3717 idnconvert_hostname() was called already in create_conn() for the reuse
3718 case. */
3719 *async = FALSE;
3720 }
3721 else {
3722 /*************************************************************
3723 * Resolve the address of the server or proxy
3724 *************************************************************/
3725 result = resolve_server(data, conn, async);
3726 if(result)
3727 goto out;
3728 }
3729
3730 /* persist the scheme and handler the transfer is using */
3731 data->info.conn_scheme = conn->handler->scheme;
3732 /* conn_protocol can only provide "old" protocols */
3733 data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
3734 data->info.used_proxy =
3735 #ifdef CURL_DISABLE_PROXY
3736 0
3737 #else
3738 conn->bits.proxy
3739 #endif
3740 ;
3741
3742 /* Everything general done, inform filters that they need
3743 * to prepare for a data transfer. */
3744 result = Curl_conn_ev_data_setup(data);
3745
3746 out:
3747 return result;
3748 }
3749
3750 /* Curl_setup_conn() is called after the name resolve initiated in
3751 * create_conn() is all done.
3752 *
3753 * Curl_setup_conn() also handles reused connections
3754 */
3755 CURLcode Curl_setup_conn(struct Curl_easy *data,
3756 bool *protocol_done)
3757 {
3758 CURLcode result = CURLE_OK;
3759 struct connectdata *conn = data->conn;
3760
3761 Curl_pgrsTime(data, TIMER_NAMELOOKUP);
3762
3763 if(conn->handler->flags & PROTOPT_NONETWORK) {
3764 /* nothing to setup when not using a network */
3765 *protocol_done = TRUE;
3766 return result;
3767 }
3768
3769 /* set start time here for timeout purposes in the connect procedure, it
3770 is later set again for the progress meter purpose */
3771 conn->now = Curl_now();
3772 if(!conn->bits.reuse)
3773 result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry,
3774 CURL_CF_SSL_DEFAULT);
3775 if(!result)
3776 result = Curl_headers_init(data);
3777
3778 /* not sure we need this flag to be passed around any more */
3779 *protocol_done = FALSE;
3780 return result;
3781 }
3782
3783 CURLcode Curl_connect(struct Curl_easy *data,
3784 bool *asyncp,
3785 bool *protocol_done)
3786 {
3787 CURLcode result;
3788 struct connectdata *conn;
3789
3790 *asyncp = FALSE; /* assume synchronous resolves by default */
3791
3792 /* Set the request to virgin state based on transfer settings */
3793 Curl_req_hard_reset(&data->req, data);
3794
3795 /* call the stuff that needs to be called */
3796 result = create_conn(data, &conn, asyncp);
3797
3798 if(!result) {
3799 if(CONN_INUSE(conn) > 1)
3800 /* multiplexed */
3801 *protocol_done = TRUE;
3802 else if(!*asyncp) {
3803 /* DNS resolution is done: that is either because this is a reused
3804 connection, in which case DNS was unnecessary, or because DNS
3805 really did finish already (synch resolver/fast async resolve) */
3806 result = Curl_setup_conn(data, protocol_done);
3807 }
3808 }
3809
3810 if(result == CURLE_NO_CONNECTION_AVAILABLE) {
3811 return result;
3812 }
3813 else if(result && conn) {
3814 /* We are not allowed to return failure with memory left allocated in the
3815 connectdata struct, free those here */
3816 Curl_detach_connection(data);
3817 Curl_cpool_disconnect(data, conn, TRUE);
3818 }
3819
3820 return result;
3821 }
3822
3823 /*
3824 * Curl_init_do() inits the readwrite session. This is inited each time (in
3825 * the DO function before the protocol-specific DO functions are invoked) for
3826 * a transfer, sometimes multiple times on the same Curl_easy. Make sure
3827 * nothing in here depends on stuff that are setup dynamically for the
3828 * transfer.
3829 *
3830 * Allow this function to get called with 'conn' set to NULL.
3831 */
3832
3833 CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
3834 {
3835 /* if this is a pushed stream, we need this: */
3836 CURLcode result;
3837
3838 if(conn) {
3839 conn->bits.do_more = FALSE; /* by default there is no curl_do_more() to
3840 use */
3841 /* if the protocol used does not support wildcards, switch it off */
3842 if(data->state.wildcardmatch &&
3843 !(conn->handler->flags & PROTOPT_WILDCARD))
3844 data->state.wildcardmatch = FALSE;
3845 }
3846
3847 data->state.done = FALSE; /* *_done() is not called yet */
3848
3849 if(data->req.no_body)
3850 /* in HTTP lingo, no body means using the HEAD request... */
3851 data->state.httpreq = HTTPREQ_HEAD;
3852
3853 result = Curl_req_start(&data->req, data);
3854 if(!result) {
3855 Curl_speedinit(data);
3856 Curl_pgrsSetUploadCounter(data, 0);
3857 Curl_pgrsSetDownloadCounter(data, 0);
3858 }
3859 return result;
3860 }
3861
3862 #if defined(USE_HTTP2) || defined(USE_HTTP3)
3863
3864 #ifdef USE_NGHTTP2
3865
3866 static void priority_remove_child(struct Curl_easy *parent,
3867 struct Curl_easy *child)
3868 {
3869 struct Curl_data_prio_node **pnext = &parent->set.priority.children;
3870 struct Curl_data_prio_node *pnode = parent->set.priority.children;
3871
3872 DEBUGASSERT(child->set.priority.parent == parent);
3873 while(pnode && pnode->data != child) {
3874 pnext = &pnode->next;
3875 pnode = pnode->next;
3876 }
3877
3878 DEBUGASSERT(pnode);
3879 if(pnode) {
3880 *pnext = pnode->next;
3881 free(pnode);
3882 }
3883
3884 child->set.priority.parent = 0;
3885 child->set.priority.exclusive = FALSE;
3886 }
3887
3888 CURLcode Curl_data_priority_add_child(struct Curl_easy *parent,
3889 struct Curl_easy *child,
3890 bool exclusive)
3891 {
3892 if(child->set.priority.parent) {
3893 priority_remove_child(child->set.priority.parent, child);
3894 }
3895
3896 if(parent) {
3897 struct Curl_data_prio_node **tail;
3898 struct Curl_data_prio_node *pnode;
3899
3900 pnode = calloc(1, sizeof(*pnode));
3901 if(!pnode)
3902 return CURLE_OUT_OF_MEMORY;
3903 pnode->data = child;
3904
3905 if(parent->set.priority.children && exclusive) {
3906 /* exclusive: move all existing children underneath the new child */
3907 struct Curl_data_prio_node *node = parent->set.priority.children;
3908 while(node) {
3909 node->data->set.priority.parent = child;
3910 node = node->next;
3911 }
3912
3913 tail = &child->set.priority.children;
3914 while(*tail)
3915 tail = &(*tail)->next;
3916
3917 DEBUGASSERT(!*tail);
3918 *tail = parent->set.priority.children;
3919 parent->set.priority.children = 0;
3920 }
3921
3922 tail = &parent->set.priority.children;
3923 while(*tail) {
3924 (*tail)->data->set.priority.exclusive = FALSE;
3925 tail = &(*tail)->next;
3926 }
3927
3928 DEBUGASSERT(!*tail);
3929 *tail = pnode;
3930 }
3931
3932 child->set.priority.parent = parent;
3933 child->set.priority.exclusive = exclusive;
3934 return CURLE_OK;
3935 }
3936
3937 #endif /* USE_NGHTTP2 */
3938
3939 #ifdef USE_NGHTTP2
3940 static void data_priority_cleanup(struct Curl_easy *data)
3941 {
3942 while(data->set.priority.children) {
3943 struct Curl_easy *tmp = data->set.priority.children->data;
3944 priority_remove_child(data, tmp);
3945 if(data->set.priority.parent)
3946 Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE);
3947 }
3948
3949 if(data->set.priority.parent)
3950 priority_remove_child(data->set.priority.parent, data);
3951 }
3952 #endif
3953
3954 void Curl_data_priority_clear_state(struct Curl_easy *data)
3955 {
3956 memset(&data->state.priority, 0, sizeof(data->state.priority));
3957 }
3958
3959 #endif /* defined(USE_HTTP2) || defined(USE_HTTP3) */
3960