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 static bool str_has_ctrl(const char *input)
2725 {
2726 const unsigned char *str = (const unsigned char *)input;
2727 while(*str) {
2728 if(*str < 0x20)
2729 return TRUE;
2730 str++;
2731 }
2732 return FALSE;
2733 }
2734
2735 /*
2736 * Override the login details from the URL with that in the CURLOPT_USERPWD
2737 * option or a .netrc file, if applicable.
2738 */
2739 static CURLcode override_login(struct Curl_easy *data,
2740 struct connectdata *conn)
2741 {
2742 CURLUcode uc;
2743 char **userp = &conn->user;
2744 char **passwdp = &conn->passwd;
2745 char **optionsp = &conn->options;
2746
2747 if(data->set.str[STRING_OPTIONS]) {
2748 free(*optionsp);
2749 *optionsp = strdup(data->set.str[STRING_OPTIONS]);
2750 if(!*optionsp)
2751 return CURLE_OUT_OF_MEMORY;
2752 }
2753
2754 #ifndef CURL_DISABLE_NETRC
2755 if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
2756 Curl_safefree(*userp);
2757 Curl_safefree(*passwdp);
2758 }
2759 conn->bits.netrc = FALSE;
2760 if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
2761 int ret;
2762 bool url_provided = FALSE;
2763
2764 if(data->state.aptr.user) {
2765 /* there was a username with a length in the URL. Use the URL decoded
2766 version */
2767 userp = &data->state.aptr.user;
2768 url_provided = TRUE;
2769 }
2770
2771 if(!*passwdp) {
2772 ret = Curl_parsenetrc(conn->host.name,
2773 userp, passwdp,
2774 data->set.str[STRING_NETRC_FILE]);
2775 if(ret > 0) {
2776 infof(data, "Couldn't find host %s in the %s file; using defaults",
2777 conn->host.name,
2778 (data->set.str[STRING_NETRC_FILE] ?
2779 data->set.str[STRING_NETRC_FILE] : ".netrc"));
2780 }
2781 else if(ret < 0) {
2782 failf(data, ".netrc parser error");
2783 return CURLE_READ_ERROR;
2784 }
2785 else {
2786 if(!(conn->handler->flags&PROTOPT_USERPWDCTRL)) {
2787 /* if the protocol can't handle control codes in credentials, make
2788 sure there are none */
2789 if(str_has_ctrl(*userp) || str_has_ctrl(*passwdp)) {
2790 failf(data, "control code detected in .netrc credentials");
2791 return CURLE_READ_ERROR;
2792 }
2793 }
2794 /* set bits.netrc TRUE to remember that we got the name from a .netrc
2795 file, so that it is safe to use even if we followed a Location: to a
2796 different host or similar. */
2797 conn->bits.netrc = TRUE;
2798 }
2799 }
2800 if(url_provided) {
2801 Curl_safefree(conn->user);
2802 conn->user = strdup(*userp);
2803 if(!conn->user)
2804 return CURLE_OUT_OF_MEMORY;
2805 }
2806 /* no user was set but a password, set a blank user */
2807 if(!*userp && *passwdp) {
2808 *userp = strdup("");
2809 if(!*userp)
2810 return CURLE_OUT_OF_MEMORY;
2811 }
2812 }
2813 #endif
2814
2815 /* for updated strings, we update them in the URL */
2816 if(*userp) {
2817 CURLcode result;
2818 if(data->state.aptr.user != *userp) {
2819 /* nothing to do then */
2820 result = Curl_setstropt(&data->state.aptr.user, *userp);
2821 if(result)
2822 return result;
2823 }
2824 }
2825 if(data->state.aptr.user) {
2826 uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
2827 CURLU_URLENCODE);
2828 if(uc)
2829 return Curl_uc_to_curlcode(uc);
2830 if(!*userp) {
2831 *userp = strdup(data->state.aptr.user);
2832 if(!*userp)
2833 return CURLE_OUT_OF_MEMORY;
2834 }
2835 }
2836 if(*passwdp) {
2837 CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
2838 if(result)
2839 return result;
2840 }
2841 if(data->state.aptr.passwd) {
2842 uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
2843 data->state.aptr.passwd, CURLU_URLENCODE);
2844 if(uc)
2845 return Curl_uc_to_curlcode(uc);
2846 if(!*passwdp) {
2847 *passwdp = strdup(data->state.aptr.passwd);
2848 if(!*passwdp)
2849 return CURLE_OUT_OF_MEMORY;
2850 }
2851 }
2852
2853 return CURLE_OK;
2854 }
2855
2856 /*
2857 * Set the login details so they're available in the connection
2858 */
2859 static CURLcode set_login(struct Curl_easy *data,
2860 struct connectdata *conn)
2861 {
2862 CURLcode result = CURLE_OK;
2863 const char *setuser = CURL_DEFAULT_USER;
2864 const char *setpasswd = CURL_DEFAULT_PASSWORD;
2865
2866 /* If our protocol needs a password and we have none, use the defaults */
2867 if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user)
2868 ;
2869 else {
2870 setuser = "";
2871 setpasswd = "";
2872 }
2873 /* Store the default user */
2874 if(!conn->user) {
2875 conn->user = strdup(setuser);
2876 if(!conn->user)
2877 return CURLE_OUT_OF_MEMORY;
2878 }
2879
2880 /* Store the default password */
2881 if(!conn->passwd) {
2882 conn->passwd = strdup(setpasswd);
2883 if(!conn->passwd)
2884 result = CURLE_OUT_OF_MEMORY;
2885 }
2886
2887 return result;
2888 }
2889
2890 /*
2891 * Parses a "host:port" string to connect to.
2892 * The hostname and the port may be empty; in this case, NULL is returned for
2893 * the hostname and -1 for the port.
2894 */
2895 static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
2896 const char *host,
2897 char **hostname_result,
2898 int *port_result)
2899 {
2900 char *host_dup;
2901 char *hostptr;
2902 char *host_portno;
2903 char *portptr;
2904 int port = -1;
2905 CURLcode result = CURLE_OK;
2906
2907 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
2908 (void) data;
2909 #endif
2910
2911 *hostname_result = NULL;
2912 *port_result = -1;
2913
2914 if(!host || !*host)
2915 return CURLE_OK;
2916
2917 host_dup = strdup(host);
2918 if(!host_dup)
2919 return CURLE_OUT_OF_MEMORY;
2920
2921 hostptr = host_dup;
2922
2923 /* start scanning for port number at this point */
2924 portptr = hostptr;
2925
2926 /* detect and extract RFC6874-style IPv6-addresses */
2927 if(*hostptr == '[') {
2928 #ifdef ENABLE_IPV6
2929 char *ptr = ++hostptr; /* advance beyond the initial bracket */
2930 while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
2931 ptr++;
2932 if(*ptr == '%') {
2933 /* There might be a zone identifier */
2934 if(strncmp("%25", ptr, 3))
2935 infof(data, "Please URL encode %% as %%25, see RFC 6874.");
2936 ptr++;
2937 /* Allow unreserved characters as defined in RFC 3986 */
2938 while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
2939 (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
2940 ptr++;
2941 }
2942 if(*ptr == ']')
2943 /* yeps, it ended nicely with a bracket as well */
2944 *ptr++ = '\0';
2945 else
2946 infof(data, "Invalid IPv6 address format");
2947 portptr = ptr;
2948 /* Note that if this didn't end with a bracket, we still advanced the
2949 * hostptr first, but I can't see anything wrong with that as no host
2950 * name nor a numeric can legally start with a bracket.
2951 */
2952 #else
2953 failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
2954 result = CURLE_NOT_BUILT_IN;
2955 goto error;
2956 #endif
2957 }
2958
2959 /* Get port number off server.com:1080 */
2960 host_portno = strchr(portptr, ':');
2961 if(host_portno) {
2962 char *endp = NULL;
2963 *host_portno = '\0'; /* cut off number from host name */
2964 host_portno++;
2965 if(*host_portno) {
2966 long portparse = strtol(host_portno, &endp, 10);
2967 if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
2968 failf(data, "No valid port number in connect to host string (%s)",
2969 host_portno);
2970 result = CURLE_SETOPT_OPTION_SYNTAX;
2971 goto error;
2972 }
2973 else
2974 port = (int)portparse; /* we know it will fit */
2975 }
2976 }
2977
2978 /* now, clone the cleaned host name */
2979 DEBUGASSERT(hostptr);
2980 *hostname_result = strdup(hostptr);
2981 if(!*hostname_result) {
2982 result = CURLE_OUT_OF_MEMORY;
2983 goto error;
2984 }
2985
2986 *port_result = port;
2987
2988 error:
2989 free(host_dup);
2990 return result;
2991 }
2992
2993 /*
2994 * Parses one "connect to" string in the form:
2995 * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
2996 */
2997 static CURLcode parse_connect_to_string(struct Curl_easy *data,
2998 struct connectdata *conn,
2999 const char *conn_to_host,
3000 char **host_result,
3001 int *port_result)
3002 {
3003 CURLcode result = CURLE_OK;
3004 const char *ptr = conn_to_host;
3005 int host_match = FALSE;
3006 int port_match = FALSE;
3007
3008 *host_result = NULL;
3009 *port_result = -1;
3010
3011 if(*ptr == ':') {
3012 /* an empty hostname always matches */
3013 host_match = TRUE;
3014 ptr++;
3015 }
3016 else {
3017 /* check whether the URL's hostname matches */
3018 size_t hostname_to_match_len;
3019 char *hostname_to_match = aprintf("%s%s%s",
3020 conn->bits.ipv6_ip ? "[" : "",
3021 conn->host.name,
3022 conn->bits.ipv6_ip ? "]" : "");
3023 if(!hostname_to_match)
3024 return CURLE_OUT_OF_MEMORY;
3025 hostname_to_match_len = strlen(hostname_to_match);
3026 host_match = strncasecompare(ptr, hostname_to_match,
3027 hostname_to_match_len);
3028 free(hostname_to_match);
3029 ptr += hostname_to_match_len;
3030
3031 host_match = host_match && *ptr == ':';
3032 ptr++;
3033 }
3034
3035 if(host_match) {
3036 if(*ptr == ':') {
3037 /* an empty port always matches */
3038 port_match = TRUE;
3039 ptr++;
3040 }
3041 else {
3042 /* check whether the URL's port matches */
3043 char *ptr_next = strchr(ptr, ':');
3044 if(ptr_next) {
3045 char *endp = NULL;
3046 long port_to_match = strtol(ptr, &endp, 10);
3047 if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
3048 port_match = TRUE;
3049 ptr = ptr_next + 1;
3050 }
3051 }
3052 }
3053 }
3054
3055 if(host_match && port_match) {
3056 /* parse the hostname and port to connect to */
3057 result = parse_connect_to_host_port(data, ptr, host_result, port_result);
3058 }
3059
3060 return result;
3061 }
3062
3063 /*
3064 * Processes all strings in the "connect to" slist, and uses the "connect
3065 * to host" and "connect to port" of the first string that matches.
3066 */
3067 static CURLcode parse_connect_to_slist(struct Curl_easy *data,
3068 struct connectdata *conn,
3069 struct curl_slist *conn_to_host)
3070 {
3071 CURLcode result = CURLE_OK;
3072 char *host = NULL;
3073 int port = -1;
3074
3075 while(conn_to_host && !host && port == -1) {
3076 result = parse_connect_to_string(data, conn, conn_to_host->data,
3077 &host, &port);
3078 if(result)
3079 return result;
3080
3081 if(host && *host) {
3082 conn->conn_to_host.rawalloc = host;
3083 conn->conn_to_host.name = host;
3084 conn->bits.conn_to_host = TRUE;
3085
3086 infof(data, "Connecting to hostname: %s", host);
3087 }
3088 else {
3089 /* no "connect to host" */
3090 conn->bits.conn_to_host = FALSE;
3091 Curl_safefree(host);
3092 }
3093
3094 if(port >= 0) {
3095 conn->conn_to_port = port;
3096 conn->bits.conn_to_port = TRUE;
3097 infof(data, "Connecting to port: %d", port);
3098 }
3099 else {
3100 /* no "connect to port" */
3101 conn->bits.conn_to_port = FALSE;
3102 port = -1;
3103 }
3104
3105 conn_to_host = conn_to_host->next;
3106 }
3107
3108 #ifndef CURL_DISABLE_ALTSVC
3109 if(data->asi && !host && (port == -1) &&
3110 ((conn->handler->protocol == CURLPROTO_HTTPS) ||
3111 #ifdef CURLDEBUG
3112 /* allow debug builds to circumvent the HTTPS restriction */
3113 getenv("CURL_ALTSVC_HTTP")
3114 #else
3115 0
3116 #endif
3117 )) {
3118 /* no connect_to match, try alt-svc! */
3119 enum alpnid srcalpnid;
3120 bool hit;
3121 struct altsvc *as;
3122 const int allowed_versions = ( ALPN_h1
3123 #ifdef USE_HTTP2
3124 | ALPN_h2
3125 #endif
3126 #ifdef ENABLE_QUIC
3127 | ALPN_h3
3128 #endif
3129 ) & data->asi->flags;
3130
3131 host = conn->host.rawalloc;
3132 #ifdef USE_HTTP2
3133 /* with h2 support, check that first */
3134 srcalpnid = ALPN_h2;
3135 hit = Curl_altsvc_lookup(data->asi,
3136 srcalpnid, host, conn->remote_port, /* from */
3137 &as /* to */,
3138 allowed_versions);
3139 if(!hit)
3140 #endif
3141 {
3142 srcalpnid = ALPN_h1;
3143 hit = Curl_altsvc_lookup(data->asi,
3144 srcalpnid, host, conn->remote_port, /* from */
3145 &as /* to */,
3146 allowed_versions);
3147 }
3148 if(hit) {
3149 char *hostd = strdup((char *)as->dst.host);
3150 if(!hostd)
3151 return CURLE_OUT_OF_MEMORY;
3152 conn->conn_to_host.rawalloc = hostd;
3153 conn->conn_to_host.name = hostd;
3154 conn->bits.conn_to_host = TRUE;
3155 conn->conn_to_port = as->dst.port;
3156 conn->bits.conn_to_port = TRUE;
3157 conn->bits.altused = TRUE;
3158 infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d",
3159 Curl_alpnid2str(srcalpnid), host, conn->remote_port,
3160 Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
3161 if(srcalpnid != as->dst.alpnid) {
3162 /* protocol version switch */
3163 switch(as->dst.alpnid) {
3164 case ALPN_h1:
3165 conn->httpversion = 11;
3166 break;
3167 case ALPN_h2:
3168 conn->httpversion = 20;
3169 break;
3170 case ALPN_h3:
3171 conn->transport = TRNSPRT_QUIC;
3172 conn->httpversion = 30;
3173 break;
3174 default: /* shouldn't be possible */
3175 break;
3176 }
3177 }
3178 }
3179 }
3180 #endif
3181
3182 return result;
3183 }
3184
3185 #ifdef USE_UNIX_SOCKETS
3186 static CURLcode resolve_unix(struct Curl_easy *data,
3187 struct connectdata *conn,
3188 char *unix_path)
3189 {
3190 struct Curl_dns_entry *hostaddr = NULL;
3191 bool longpath = FALSE;
3192
3193 DEBUGASSERT(unix_path);
3194 DEBUGASSERT(conn->dns_entry == NULL);
3195
3196 /* Unix domain sockets are local. The host gets ignored, just use the
3197 * specified domain socket address. Do not cache "DNS entries". There is
3198 * no DNS involved and we already have the filesystem path available. */
3199 hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
3200 if(!hostaddr)
3201 return CURLE_OUT_OF_MEMORY;
3202
3203 hostaddr->addr = Curl_unix2addr(unix_path, &longpath,
3204 conn->bits.abstract_unix_socket);
3205 if(!hostaddr->addr) {
3206 if(longpath)
3207 /* Long paths are not supported for now */
3208 failf(data, "Unix socket path too long: '%s'", unix_path);
3209 free(hostaddr);
3210 return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY;
3211 }
3212
3213 hostaddr->inuse++;
3214 conn->dns_entry = hostaddr;
3215 return CURLE_OK;
3216 }
3217 #endif
3218
3219 #ifndef CURL_DISABLE_PROXY
3220 static CURLcode resolve_proxy(struct Curl_easy *data,
3221 struct connectdata *conn,
3222 bool *async)
3223 {
3224 struct Curl_dns_entry *hostaddr = NULL;
3225 struct hostname *host;
3226 timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
3227 int rc;
3228
3229 DEBUGASSERT(conn->dns_entry == NULL);
3230
3231 host = conn->bits.socksproxy ? &conn->socks_proxy.host :
3232 &conn->http_proxy.host;
3233
3234 conn->hostname_resolve = strdup(host->name);
3235 if(!conn->hostname_resolve)
3236 return CURLE_OUT_OF_MEMORY;
3237
3238 rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
3239 &hostaddr, timeout_ms);
3240 conn->dns_entry = hostaddr;
3241 if(rc == CURLRESOLV_PENDING)
3242 *async = TRUE;
3243 else if(rc == CURLRESOLV_TIMEDOUT)
3244 return CURLE_OPERATION_TIMEDOUT;
3245 else if(!hostaddr) {
3246 failf(data, "Couldn't resolve proxy '%s'", host->dispname);
3247 return CURLE_COULDNT_RESOLVE_PROXY;
3248 }
3249
3250 return CURLE_OK;
3251 }
3252 #endif
3253
3254 static CURLcode resolve_host(struct Curl_easy *data,
3255 struct connectdata *conn,
3256 bool *async)
3257 {
3258 struct Curl_dns_entry *hostaddr = NULL;
3259 struct hostname *connhost;
3260 timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
3261 int rc;
3262
3263 DEBUGASSERT(conn->dns_entry == NULL);
3264
3265 connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
3266
3267 /* If not connecting via a proxy, extract the port from the URL, if it is
3268 * there, thus overriding any defaults that might have been set above. */
3269 conn->port = conn->bits.conn_to_port ? conn->conn_to_port :
3270 conn->remote_port;
3271
3272 /* Resolve target host right on */
3273 conn->hostname_resolve = strdup(connhost->name);
3274 if(!conn->hostname_resolve)
3275 return CURLE_OUT_OF_MEMORY;
3276
3277 rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
3278 &hostaddr, timeout_ms);
3279 conn->dns_entry = hostaddr;
3280 if(rc == CURLRESOLV_PENDING)
3281 *async = TRUE;
3282 else if(rc == CURLRESOLV_TIMEDOUT) {
3283 failf(data, "Failed to resolve host '%s' with timeout after %"
3284 CURL_FORMAT_TIMEDIFF_T " ms", connhost->dispname,
3285 Curl_timediff(Curl_now(), data->progress.t_startsingle));
3286 return CURLE_OPERATION_TIMEDOUT;
3287 }
3288 else if(!hostaddr) {
3289 failf(data, "Could not resolve host: %s", connhost->dispname);
3290 return CURLE_COULDNT_RESOLVE_HOST;
3291 }
3292
3293 return CURLE_OK;
3294 }
3295
3296 /* Perform a fresh resolve */
3297 static CURLcode resolve_fresh(struct Curl_easy *data,
3298 struct connectdata *conn,
3299 bool *async)
3300 {
3301 #ifdef USE_UNIX_SOCKETS
3302 char *unix_path = conn->unix_domain_socket;
3303
3304 #ifndef CURL_DISABLE_PROXY
3305 if(!unix_path && conn->socks_proxy.host.name &&
3306 !strncmp(UNIX_SOCKET_PREFIX"/",
3307 conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
3308 unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
3309 #endif
3310
3311 if(unix_path) {
3312 conn->transport = TRNSPRT_UNIX;
3313 return resolve_unix(data, conn, unix_path);
3314 }
3315 #endif
3316
3317 #ifndef CURL_DISABLE_PROXY
3318 if(CONN_IS_PROXIED(conn))
3319 return resolve_proxy(data, conn, async);
3320 #endif
3321
3322 return resolve_host(data, conn, async);
3323 }
3324
3325 /*************************************************************
3326 * Resolve the address of the server or proxy
3327 *************************************************************/
3328 static CURLcode resolve_server(struct Curl_easy *data,
3329 struct connectdata *conn,
3330 bool *async)
3331 {
3332 DEBUGASSERT(conn);
3333 DEBUGASSERT(data);
3334
3335 /* Resolve the name of the server or proxy */
3336 if(conn->bits.reuse) {
3337 /* We're reusing the connection - no need to resolve anything, and
3338 idnconvert_hostname() was called already in create_conn() for the reuse
3339 case. */
3340 *async = FALSE;
3341 return CURLE_OK;
3342 }
3343
3344 return resolve_fresh(data, conn, async);
3345 }
3346
3347 /*
3348 * Cleanup the connection `temp`, just allocated for `data`, before using the
3349 * previously `existing` one for `data`. All relevant info is copied over
3350 * and `temp` is freed.
3351 */
3352 static void reuse_conn(struct Curl_easy *data,
3353 struct connectdata *temp,
3354 struct connectdata *existing)
3355 {
3356 /* get the user+password information from the temp struct since it may
3357 * be new for this request even when we reuse an existing connection */
3358 if(temp->user) {
3359 /* use the new user name and password though */
3360 Curl_safefree(existing->user);
3361 Curl_safefree(existing->passwd);
3362 existing->user = temp->user;
3363 existing->passwd = temp->passwd;
3364 temp->user = NULL;
3365 temp->passwd = NULL;
3366 }
3367
3368 #ifndef CURL_DISABLE_PROXY
3369 existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
3370 if(existing->bits.proxy_user_passwd) {
3371 /* use the new proxy user name and proxy password though */
3372 Curl_safefree(existing->http_proxy.user);
3373 Curl_safefree(existing->socks_proxy.user);
3374 Curl_safefree(existing->http_proxy.passwd);
3375 Curl_safefree(existing->socks_proxy.passwd);
3376 existing->http_proxy.user = temp->http_proxy.user;
3377 existing->socks_proxy.user = temp->socks_proxy.user;
3378 existing->http_proxy.passwd = temp->http_proxy.passwd;
3379 existing->socks_proxy.passwd = temp->socks_proxy.passwd;
3380 temp->http_proxy.user = NULL;
3381 temp->socks_proxy.user = NULL;
3382 temp->http_proxy.passwd = NULL;
3383 temp->socks_proxy.passwd = NULL;
3384 }
3385 #endif
3386
3387 /* Finding a connection for reuse in the cache matches, among other
3388 * things on the "remote-relevant" hostname. This is not necessarily
3389 * the authority of the URL, e.g. conn->host. For example:
3390 * - we use a proxy (not tunneling). we want to send all requests
3391 * that use the same proxy on this connection.
3392 * - we have a "connect-to" setting that may redirect the hostname of
3393 * a new request to the same remote endpoint of an existing conn.
3394 * We want to reuse an existing conn to the remote endpoint.
3395 * Since connection reuse does not match on conn->host necessarily, we
3396 * switch `existing` conn to `temp` conn's host settings.
3397 * TODO: is this correct in the case of TLS connections that have
3398 * used the original hostname in SNI to negotiate? Do we send
3399 * requests for another host through the different SNI?
3400 */
3401 Curl_free_idnconverted_hostname(&existing->host);
3402 Curl_free_idnconverted_hostname(&existing->conn_to_host);
3403 Curl_safefree(existing->host.rawalloc);
3404 Curl_safefree(existing->conn_to_host.rawalloc);
3405 existing->host = temp->host;
3406 temp->host.rawalloc = NULL;
3407 temp->host.encalloc = NULL;
3408 existing->conn_to_host = temp->conn_to_host;
3409 temp->conn_to_host.rawalloc = NULL;
3410 existing->conn_to_port = temp->conn_to_port;
3411 existing->remote_port = temp->remote_port;
3412 Curl_safefree(existing->hostname_resolve);
3413
3414 existing->hostname_resolve = temp->hostname_resolve;
3415 temp->hostname_resolve = NULL;
3416
3417 /* reuse init */
3418 existing->bits.reuse = TRUE; /* yes, we're reusing here */
3419
3420 conn_free(data, temp);
3421 }
3422
3423 /**
3424 * create_conn() sets up a new connectdata struct, or reuses an already
3425 * existing one, and resolves host name.
3426 *
3427 * if this function returns CURLE_OK and *async is set to TRUE, the resolve
3428 * response will be coming asynchronously. If *async is FALSE, the name is
3429 * already resolved.
3430 *
3431 * @param data The sessionhandle pointer
3432 * @param in_connect is set to the next connection data pointer
3433 * @param async is set TRUE when an async DNS resolution is pending
3434 * @see Curl_setup_conn()
3435 *
3436 */
3437
3438 static CURLcode create_conn(struct Curl_easy *data,
3439 struct connectdata **in_connect,
3440 bool *async)
3441 {
3442 CURLcode result = CURLE_OK;
3443 struct connectdata *conn;
3444 struct connectdata *existing = NULL;
3445 bool reuse;
3446 bool connections_available = TRUE;
3447 bool force_reuse = FALSE;
3448 bool waitpipe = FALSE;
3449 size_t max_host_connections = Curl_multi_max_host_connections(data->multi);
3450 size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
3451
3452 *async = FALSE;
3453 *in_connect = NULL;
3454
3455 /*************************************************************
3456 * Check input data
3457 *************************************************************/
3458 if(!data->state.url) {
3459 result = CURLE_URL_MALFORMAT;
3460 goto out;
3461 }
3462
3463 /* First, split up the current URL in parts so that we can use the
3464 parts for checking against the already present connections. In order
3465 to not have to modify everything at once, we allocate a temporary
3466 connection data struct and fill in for comparison purposes. */
3467 conn = allocate_conn(data);
3468
3469 if(!conn) {
3470 result = CURLE_OUT_OF_MEMORY;
3471 goto out;
3472 }
3473
3474 /* We must set the return variable as soon as possible, so that our
3475 parent can cleanup any possible allocs we may have done before
3476 any failure */
3477 *in_connect = conn;
3478
3479 result = parseurlandfillconn(data, conn);
3480 if(result)
3481 goto out;
3482
3483 if(data->set.str[STRING_SASL_AUTHZID]) {
3484 conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
3485 if(!conn->sasl_authzid) {
3486 result = CURLE_OUT_OF_MEMORY;
3487 goto out;
3488 }
3489 }
3490
3491 if(data->set.str[STRING_BEARER]) {
3492 conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
3493 if(!conn->oauth_bearer) {
3494 result = CURLE_OUT_OF_MEMORY;
3495 goto out;
3496 }
3497 }
3498
3499 #ifdef USE_UNIX_SOCKETS
3500 if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
3501 conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
3502 if(!conn->unix_domain_socket) {
3503 result = CURLE_OUT_OF_MEMORY;
3504 goto out;
3505 }
3506 conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
3507 }
3508 #endif
3509
3510 /* After the unix socket init but before the proxy vars are used, parse and
3511 initialize the proxy vars */
3512 #ifndef CURL_DISABLE_PROXY
3513 result = create_conn_helper_init_proxy(data, conn);
3514 if(result)
3515 goto out;
3516
3517 /*************************************************************
3518 * If the protocol is using SSL and HTTP proxy is used, we set
3519 * the tunnel_proxy bit.
3520 *************************************************************/
3521 if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
3522 conn->bits.tunnel_proxy = TRUE;
3523 #endif
3524
3525 /*************************************************************
3526 * Figure out the remote port number and fix it in the URL
3527 *************************************************************/
3528 result = parse_remote_port(data, conn);
3529 if(result)
3530 goto out;
3531
3532 /* Check for overridden login details and set them accordingly so that
3533 they are known when protocol->setup_connection is called! */
3534 result = override_login(data, conn);
3535 if(result)
3536 goto out;
3537
3538 result = set_login(data, conn); /* default credentials */
3539 if(result)
3540 goto out;
3541
3542 /*************************************************************
3543 * Process the "connect to" linked list of hostname/port mappings.
3544 * Do this after the remote port number has been fixed in the URL.
3545 *************************************************************/
3546 result = parse_connect_to_slist(data, conn, data->set.connect_to);
3547 if(result)
3548 goto out;
3549
3550 /*************************************************************
3551 * IDN-convert the proxy hostnames
3552 *************************************************************/
3553 #ifndef CURL_DISABLE_PROXY
3554 if(conn->bits.httpproxy) {
3555 result = Curl_idnconvert_hostname(&conn->http_proxy.host);
3556 if(result)
3557 return result;
3558 }
3559 if(conn->bits.socksproxy) {
3560 result = Curl_idnconvert_hostname(&conn->socks_proxy.host);
3561 if(result)
3562 return result;
3563 }
3564 #endif
3565 if(conn->bits.conn_to_host) {
3566 result = Curl_idnconvert_hostname(&conn->conn_to_host);
3567 if(result)
3568 return result;
3569 }
3570
3571 /*************************************************************
3572 * Check whether the host and the "connect to host" are equal.
3573 * Do this after the hostnames have been IDN-converted.
3574 *************************************************************/
3575 if(conn->bits.conn_to_host &&
3576 strcasecompare(conn->conn_to_host.name, conn->host.name)) {
3577 conn->bits.conn_to_host = FALSE;
3578 }
3579
3580 /*************************************************************
3581 * Check whether the port and the "connect to port" are equal.
3582 * Do this after the remote port number has been fixed in the URL.
3583 *************************************************************/
3584 if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
3585 conn->bits.conn_to_port = FALSE;
3586 }
3587
3588 #ifndef CURL_DISABLE_PROXY
3589 /*************************************************************
3590 * If the "connect to" feature is used with an HTTP proxy,
3591 * we set the tunnel_proxy bit.
3592 *************************************************************/
3593 if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
3594 conn->bits.httpproxy)
3595 conn->bits.tunnel_proxy = TRUE;
3596 #endif
3597
3598 /*************************************************************
3599 * Setup internals depending on protocol. Needs to be done after
3600 * we figured out what/if proxy to use.
3601 *************************************************************/
3602 result = setup_connection_internals(data, conn);
3603 if(result)
3604 goto out;
3605
3606 /***********************************************************************
3607 * file: is a special case in that it doesn't need a network connection
3608 ***********************************************************************/
3609 #ifndef CURL_DISABLE_FILE
3610 if(conn->handler->flags & PROTOPT_NONETWORK) {
3611 bool done;
3612 /* this is supposed to be the connect function so we better at least check
3613 that the file is present here! */
3614 DEBUGASSERT(conn->handler->connect_it);
3615 Curl_persistconninfo(data, conn, NULL, -1);
3616 result = conn->handler->connect_it(data, &done);
3617
3618 /* Setup a "faked" transfer that'll do nothing */
3619 if(!result) {
3620 Curl_attach_connection(data, conn);
3621 result = Curl_conncache_add_conn(data);
3622 if(result)
3623 goto out;
3624
3625 /*
3626 * Setup whatever necessary for a resumed transfer
3627 */
3628 result = setup_range(data);
3629 if(result) {
3630 DEBUGASSERT(conn->handler->done);
3631 /* we ignore the return code for the protocol-specific DONE */
3632 (void)conn->handler->done(data, result, FALSE);
3633 goto out;
3634 }
3635 Curl_setup_transfer(data, -1, -1, FALSE, -1);
3636 }
3637
3638 /* since we skip do_init() */
3639 Curl_init_do(data, conn);
3640
3641 goto out;
3642 }
3643 #endif
3644
3645 /* Setup filter for network connections */
3646 conn->recv[FIRSTSOCKET] = Curl_conn_recv;
3647 conn->send[FIRSTSOCKET] = Curl_conn_send;
3648 conn->recv[SECONDARYSOCKET] = Curl_conn_recv;
3649 conn->send[SECONDARYSOCKET] = Curl_conn_send;
3650 conn->bits.tcp_fastopen = data->set.tcp_fastopen;
3651
3652 /* Complete the easy's SSL configuration for connection cache matching */
3653 result = Curl_ssl_easy_config_complete(data);
3654 if(result)
3655 goto out;
3656
3657 prune_dead_connections(data);
3658
3659 /*************************************************************
3660 * Check the current list of connections to see if we can
3661 * reuse an already existing one or if we have to create a
3662 * new one.
3663 *************************************************************/
3664
3665 DEBUGASSERT(conn->user);
3666 DEBUGASSERT(conn->passwd);
3667
3668 /* reuse_fresh is TRUE if we are told to use a new connection by force, but
3669 we only acknowledge this option if this is not a reused connection
3670 already (which happens due to follow-location or during an HTTP
3671 authentication phase). CONNECT_ONLY transfers also refuse reuse. */
3672 if((data->set.reuse_fresh && !data->state.followlocation) ||
3673 data->set.connect_only)
3674 reuse = FALSE;
3675 else
3676 reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
3677
3678 if(reuse) {
3679 /*
3680 * We already have a connection for this, we got the former connection in
3681 * `existing` and thus we need to cleanup the one we just
3682 * allocated before we can move along and use `existing`.
3683 */
3684 reuse_conn(data, conn, existing);
3685 conn = existing;
3686 *in_connect = conn;
3687
3688 #ifndef CURL_DISABLE_PROXY
3689 infof(data, "Re-using existing connection with %s %s",
3690 conn->bits.proxy?"proxy":"host",
3691 conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
3692 conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
3693 conn->host.dispname);
3694 #else
3695 infof(data, "Re-using existing connection with host %s",
3696 conn->host.dispname);
3697 #endif
3698 }
3699 else {
3700 /* We have decided that we want a new connection. However, we may not
3701 be able to do that if we have reached the limit of how many
3702 connections we are allowed to open. */
3703
3704 if(conn->handler->flags & PROTOPT_ALPN) {
3705 /* The protocol wants it, so set the bits if enabled in the easy handle
3706 (default) */
3707 if(data->set.ssl_enable_alpn)
3708 conn->bits.tls_enable_alpn = TRUE;
3709 }
3710
3711 if(waitpipe)
3712 /* There is a connection that *might* become usable for multiplexing
3713 "soon", and we wait for that */
3714 connections_available = FALSE;
3715 else {
3716 /* this gets a lock on the conncache */
3717 struct connectbundle *bundle =
3718 Curl_conncache_find_bundle(data, conn, data->state.conn_cache);
3719
3720 if(max_host_connections > 0 && bundle &&
3721 (bundle->num_connections >= max_host_connections)) {
3722 struct connectdata *conn_candidate;
3723
3724 /* The bundle is full. Extract the oldest connection. */
3725 conn_candidate = Curl_conncache_extract_bundle(data, bundle);
3726 CONNCACHE_UNLOCK(data);
3727
3728 if(conn_candidate)
3729 Curl_disconnect(data, conn_candidate, FALSE);
3730 else {
3731 infof(data, "No more connections allowed to host: %zu",
3732 max_host_connections);
3733 connections_available = FALSE;
3734 }
3735 }
3736 else
3737 CONNCACHE_UNLOCK(data);
3738
3739 }
3740
3741 if(connections_available &&
3742 (max_total_connections > 0) &&
3743 (Curl_conncache_size(data) >= max_total_connections)) {
3744 struct connectdata *conn_candidate;
3745
3746 /* The cache is full. Let's see if we can kill a connection. */
3747 conn_candidate = Curl_conncache_extract_oldest(data);
3748 if(conn_candidate)
3749 Curl_disconnect(data, conn_candidate, FALSE);
3750 else {
3751 infof(data, "No connections available in cache");
3752 connections_available = FALSE;
3753 }
3754 }
3755
3756 if(!connections_available) {
3757 infof(data, "No connections available.");
3758
3759 conn_free(data, conn);
3760 *in_connect = NULL;
3761
3762 result = CURLE_NO_CONNECTION_AVAILABLE;
3763 goto out;
3764 }
3765 else {
3766 /*
3767 * This is a brand new connection, so let's store it in the connection
3768 * cache of ours!
3769 */
3770 result = Curl_ssl_conn_config_init(data, conn);
3771 if(result) {
3772 DEBUGF(fprintf(stderr, "Error: init connection ssl config\n"));
3773 goto out;
3774 }
3775
3776 Curl_attach_connection(data, conn);
3777 result = Curl_conncache_add_conn(data);
3778 if(result)
3779 goto out;
3780 }
3781
3782 #if defined(USE_NTLM)
3783 /* If NTLM is requested in a part of this connection, make sure we don't
3784 assume the state is fine as this is a fresh connection and NTLM is
3785 connection based. */
3786 if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
3787 data->state.authhost.done) {
3788 infof(data, "NTLM picked AND auth done set, clear picked");
3789 data->state.authhost.picked = CURLAUTH_NONE;
3790 data->state.authhost.done = FALSE;
3791 }
3792
3793 if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
3794 data->state.authproxy.done) {
3795 infof(data, "NTLM-proxy picked AND auth done set, clear picked");
3796 data->state.authproxy.picked = CURLAUTH_NONE;
3797 data->state.authproxy.done = FALSE;
3798 }
3799 #endif
3800 }
3801
3802 /* Setup and init stuff before DO starts, in preparing for the transfer. */
3803 Curl_init_do(data, conn);
3804
3805 /*
3806 * Setup whatever necessary for a resumed transfer
3807 */
3808 result = setup_range(data);
3809 if(result)
3810 goto out;
3811
3812 /* Continue connectdata initialization here. */
3813
3814 /*
3815 * Inherit the proper values from the urldata struct AFTER we have arranged
3816 * the persistent connection stuff
3817 */
3818 conn->seek_func = data->set.seek_func;
3819 conn->seek_client = data->set.seek_client;
3820
3821 /*************************************************************
3822 * Resolve the address of the server or proxy
3823 *************************************************************/
3824 result = resolve_server(data, conn, async);
3825 if(result)
3826 goto out;
3827
3828 /* Everything general done, inform filters that they need
3829 * to prepare for a data transfer.
3830 */
3831 result = Curl_conn_ev_data_setup(data);
3832
3833 out:
3834 return result;
3835 }
3836
3837 /* Curl_setup_conn() is called after the name resolve initiated in
3838 * create_conn() is all done.
3839 *
3840 * Curl_setup_conn() also handles reused connections
3841 */
3842 CURLcode Curl_setup_conn(struct Curl_easy *data,
3843 bool *protocol_done)
3844 {
3845 CURLcode result = CURLE_OK;
3846 struct connectdata *conn = data->conn;
3847
3848 Curl_pgrsTime(data, TIMER_NAMELOOKUP);
3849
3850 if(conn->handler->flags & PROTOPT_NONETWORK) {
3851 /* nothing to setup when not using a network */
3852 *protocol_done = TRUE;
3853 return result;
3854 }
3855
3856 #ifndef CURL_DISABLE_PROXY
3857 /* set proxy_connect_closed to false unconditionally already here since it
3858 is used strictly to provide extra information to a parent function in the
3859 case of proxy CONNECT failures and we must make sure we don't have it
3860 lingering set from a previous invoke */
3861 conn->bits.proxy_connect_closed = FALSE;
3862 #endif
3863
3864 #ifdef CURL_DO_LINEEND_CONV
3865 data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
3866 #endif /* CURL_DO_LINEEND_CONV */
3867
3868 /* set start time here for timeout purposes in the connect procedure, it
3869 is later set again for the progress meter purpose */
3870 conn->now = Curl_now();
3871 if(!conn->bits.reuse)
3872 result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry,
3873 CURL_CF_SSL_DEFAULT);
3874 /* not sure we need this flag to be passed around any more */
3875 *protocol_done = FALSE;
3876 return result;
3877 }
3878
3879 CURLcode Curl_connect(struct Curl_easy *data,
3880 bool *asyncp,
3881 bool *protocol_done)
3882 {
3883 CURLcode result;
3884 struct connectdata *conn;
3885
3886 *asyncp = FALSE; /* assume synchronous resolves by default */
3887
3888 /* init the single-transfer specific data */
3889 Curl_free_request_state(data);
3890 memset(&data->req, 0, sizeof(struct SingleRequest));
3891 data->req.size = data->req.maxdownload = -1;
3892 data->req.no_body = data->set.opt_no_body;
3893
3894 /* call the stuff that needs to be called */
3895 result = create_conn(data, &conn, asyncp);
3896
3897 if(!result) {
3898 if(CONN_INUSE(conn) > 1)
3899 /* multiplexed */
3900 *protocol_done = TRUE;
3901 else if(!*asyncp) {
3902 /* DNS resolution is done: that's either because this is a reused
3903 connection, in which case DNS was unnecessary, or because DNS
3904 really did finish already (synch resolver/fast async resolve) */
3905 result = Curl_setup_conn(data, protocol_done);
3906 }
3907 }
3908
3909 if(result == CURLE_NO_CONNECTION_AVAILABLE) {
3910 return result;
3911 }
3912 else if(result && conn) {
3913 /* We're not allowed to return failure with memory left allocated in the
3914 connectdata struct, free those here */
3915 Curl_detach_connection(data);
3916 Curl_conncache_remove_conn(data, conn, TRUE);
3917 Curl_disconnect(data, conn, TRUE);
3918 }
3919
3920 return result;
3921 }
3922
3923 /*
3924 * Curl_init_do() inits the readwrite session. This is inited each time (in
3925 * the DO function before the protocol-specific DO functions are invoked) for
3926 * a transfer, sometimes multiple times on the same Curl_easy. Make sure
3927 * nothing in here depends on stuff that are setup dynamically for the
3928 * transfer.
3929 *
3930 * Allow this function to get called with 'conn' set to NULL.
3931 */
3932
3933 CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
3934 {
3935 struct SingleRequest *k = &data->req;
3936
3937 /* if this is a pushed stream, we need this: */
3938 CURLcode result = Curl_preconnect(data);
3939 if(result)
3940 return result;
3941
3942 if(conn) {
3943 conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
3944 use */
3945 /* if the protocol used doesn't support wildcards, switch it off */
3946 if(data->state.wildcardmatch &&
3947 !(conn->handler->flags & PROTOPT_WILDCARD))
3948 data->state.wildcardmatch = FALSE;
3949 }
3950
3951 data->state.done = FALSE; /* *_done() is not called yet */
3952 data->state.expect100header = FALSE;
3953
3954 if(data->req.no_body)
3955 /* in HTTP lingo, no body means using the HEAD request... */
3956 data->state.httpreq = HTTPREQ_HEAD;
3957
3958 k->start = Curl_now(); /* start time */
3959 k->header = TRUE; /* assume header */
3960 k->bytecount = 0;
3961 k->ignorebody = FALSE;
3962
3963 Curl_client_cleanup(data);
3964 Curl_speedinit(data);
3965 Curl_pgrsSetUploadCounter(data, 0);
3966 Curl_pgrsSetDownloadCounter(data, 0);
3967
3968 return CURLE_OK;
3969 }
3970
3971 #if defined(USE_HTTP2) || defined(USE_HTTP3)
3972
3973 #ifdef USE_NGHTTP2
3974
3975 static void priority_remove_child(struct Curl_easy *parent,
3976 struct Curl_easy *child)
3977 {
3978 struct Curl_data_prio_node **pnext = &parent->set.priority.children;
3979 struct Curl_data_prio_node *pnode = parent->set.priority.children;
3980
3981 DEBUGASSERT(child->set.priority.parent == parent);
3982 while(pnode && pnode->data != child) {
3983 pnext = &pnode->next;
3984 pnode = pnode->next;
3985 }
3986
3987 DEBUGASSERT(pnode);
3988 if(pnode) {
3989 *pnext = pnode->next;
3990 free(pnode);
3991 }
3992
3993 child->set.priority.parent = 0;
3994 child->set.priority.exclusive = FALSE;
3995 }
3996
3997 CURLcode Curl_data_priority_add_child(struct Curl_easy *parent,
3998 struct Curl_easy *child,
3999 bool exclusive)
4000 {
4001 if(child->set.priority.parent) {
4002 priority_remove_child(child->set.priority.parent, child);
4003 }
4004
4005 if(parent) {
4006 struct Curl_data_prio_node **tail;
4007 struct Curl_data_prio_node *pnode;
4008
4009 pnode = calloc(1, sizeof(*pnode));
4010 if(!pnode)
4011 return CURLE_OUT_OF_MEMORY;
4012 pnode->data = child;
4013
4014 if(parent->set.priority.children && exclusive) {
4015 /* exclusive: move all existing children underneath the new child */
4016 struct Curl_data_prio_node *node = parent->set.priority.children;
4017 while(node) {
4018 node->data->set.priority.parent = child;
4019 node = node->next;
4020 }
4021
4022 tail = &child->set.priority.children;
4023 while(*tail)
4024 tail = &(*tail)->next;
4025
4026 DEBUGASSERT(!*tail);
4027 *tail = parent->set.priority.children;
4028 parent->set.priority.children = 0;
4029 }
4030
4031 tail = &parent->set.priority.children;
4032 while(*tail) {
4033 (*tail)->data->set.priority.exclusive = FALSE;
4034 tail = &(*tail)->next;
4035 }
4036
4037 DEBUGASSERT(!*tail);
4038 *tail = pnode;
4039 }
4040
4041 child->set.priority.parent = parent;
4042 child->set.priority.exclusive = exclusive;
4043 return CURLE_OK;
4044 }
4045
4046 #endif /* USE_NGHTTP2 */
4047
4048 #ifdef USE_NGHTTP2
4049 static void data_priority_cleanup(struct Curl_easy *data)
4050 {
4051 while(data->set.priority.children) {
4052 struct Curl_easy *tmp = data->set.priority.children->data;
4053 priority_remove_child(data, tmp);
4054 if(data->set.priority.parent)
4055 Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE);
4056 }
4057
4058 if(data->set.priority.parent)
4059 priority_remove_child(data->set.priority.parent, data);
4060 }
4061 #endif
4062
4063 void Curl_data_priority_clear_state(struct Curl_easy *data)
4064 {
4065 memset(&data->state.priority, 0, sizeof(data->state.priority));
4066 }
4067
4068 #endif /* defined(USE_HTTP2) || defined(USE_HTTP3) */
4069