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