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