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