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