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