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