1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * SPDX-License-Identifier: curl
23 ***************************************************************************/
25 #include "curl_setup.h"
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
33 #ifdef HAVE_ARPA_INET_H
34 #include <arpa/inet.h>
39 #ifdef HAVE_IPHLPAPI_H
42 #ifdef HAVE_SYS_IOCTL_H
43 #include <sys/ioctl.h>
45 #ifdef HAVE_SYS_PARAM_H
46 #include <sys/param.h>
59 #error "We can't compile without socket() support!"
67 #if defined(WIN32) && defined(UNICODE)
68 #define IDN2_LOOKUP(name, host, flags) \
69 idn2_lookup_u8((const uint8_t *)name, (uint8_t **)host, flags)
71 #define IDN2_LOOKUP(name, host, flags) \
72 idn2_lookup_ul((const char *)name, (char **)host, flags)
75 #elif defined(USE_WIN32_IDN)
76 /* prototype for Curl_win32_idn_to_ascii() */
77 bool Curl_win32_idn_to_ascii(const char *in, char **out);
78 #endif /* USE_LIBIDN2 */
86 #include "vtls/vtls.h"
97 #include "content_encoding.h"
98 #include "http_digest.h"
99 #include "http_negotiate.h"
103 #include "speedcheck.h"
104 #include "warnless.h"
106 #include "urlapi-int.h"
107 #include "system_win32.h"
111 /* And now for the protocols */
119 #include "curl_ldap.h"
120 #include "vssh/ssh.h"
124 #include "inet_ntop.h"
125 #include "http_ntlm.h"
126 #include "curl_rtmp.h"
129 #include "http_proxy.h"
130 #include "conncache.h"
131 #include "multihandle.h"
138 /* The last 3 #include files should be in this order */
139 #include "curl_printf.h"
140 #include "curl_memory.h"
141 #include "memdebug.h"
143 static void conn_free(struct connectdata *conn);
145 /* Some parts of the code (e.g. chunked encoding) assume this buffer has at
146 * more than just a few bytes to play with. Don't let it become too small or
147 * bad things will happen.
149 #if READBUFFER_SIZE < READBUFFER_MIN
150 # error READBUFFER_SIZE is too small
153 #ifdef USE_UNIX_SOCKETS
154 #define UNIX_SOCKET_PREFIX "localhost"
157 /* Reject URLs exceeding this length */
158 #define MAX_URL_LEN 0xffff
161 * get_protocol_family()
163 * This is used to return the protocol family for a given protocol.
167 * 'h' [in] - struct Curl_handler pointer.
169 * Returns the family as a single bit protocol identifier.
171 static curl_prot_t get_protocol_family(const struct Curl_handler *h)
174 DEBUGASSERT(h->family);
180 * Protocol table. Schemes (roughly) in 2019 popularity order:
182 * HTTPS, HTTP, FTP, FTPS, SFTP, FILE, SCP, SMTP, LDAP, IMAPS, TELNET, IMAP,
183 * LDAPS, SMTPS, TFTP, SMB, POP3, GOPHER POP3S, RTSP, RTMP, SMBS, DICT
185 static const struct Curl_handler * const protocols[] = {
187 #if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
191 #ifndef CURL_DISABLE_HTTP
195 #ifdef USE_WEBSOCKETS
196 #if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
200 #ifndef CURL_DISABLE_HTTP
205 #ifndef CURL_DISABLE_FTP
209 #if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
217 #ifndef CURL_DISABLE_FILE
221 #if defined(USE_SSH) && !defined(USE_WOLFSSH)
225 #ifndef CURL_DISABLE_SMTP
232 #ifndef CURL_DISABLE_LDAP
234 #if !defined(CURL_DISABLE_LDAPS) && \
235 ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
236 (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
241 #ifndef CURL_DISABLE_IMAP
248 #ifndef CURL_DISABLE_TELNET
249 &Curl_handler_telnet,
252 #ifndef CURL_DISABLE_TFTP
256 #ifndef CURL_DISABLE_POP3
263 #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
264 (SIZEOF_CURL_OFF_T > 4)
271 #ifndef CURL_DISABLE_RTSP
275 #ifndef CURL_DISABLE_MQTT
279 #ifndef CURL_DISABLE_GOPHER
280 &Curl_handler_gopher,
282 &Curl_handler_gophers,
290 &Curl_handler_rtmpte,
292 &Curl_handler_rtmpts,
295 #ifndef CURL_DISABLE_DICT
299 (struct Curl_handler *) NULL
303 * Dummy handler for undefined protocol schemes.
306 static const struct Curl_handler Curl_handler_dummy = {
307 "<no protocol>", /* scheme */
308 ZERO_NULL, /* setup_connection */
309 ZERO_NULL, /* do_it */
310 ZERO_NULL, /* done */
311 ZERO_NULL, /* do_more */
312 ZERO_NULL, /* connect_it */
313 ZERO_NULL, /* connecting */
314 ZERO_NULL, /* doing */
315 ZERO_NULL, /* proto_getsock */
316 ZERO_NULL, /* doing_getsock */
317 ZERO_NULL, /* domore_getsock */
318 ZERO_NULL, /* perform_getsock */
319 ZERO_NULL, /* disconnect */
320 ZERO_NULL, /* readwrite */
321 ZERO_NULL, /* connection_check */
322 ZERO_NULL, /* attach connection */
326 PROTOPT_NONE /* flags */
329 void Curl_freeset(struct Curl_easy *data)
331 /* Free all dynamic strings stored in the data->set substructure. */
335 for(i = (enum dupstring)0; i < STRING_LAST; i++) {
336 Curl_safefree(data->set.str[i]);
339 for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
340 Curl_safefree(data->set.blobs[j]);
343 if(data->state.referer_alloc) {
344 Curl_safefree(data->state.referer);
345 data->state.referer_alloc = FALSE;
347 data->state.referer = NULL;
348 if(data->state.url_alloc) {
349 Curl_safefree(data->state.url);
350 data->state.url_alloc = FALSE;
352 data->state.url = NULL;
354 Curl_mime_cleanpart(&data->set.mimepost);
357 /* free the URL pieces */
358 static void up_free(struct Curl_easy *data)
360 struct urlpieces *up = &data->state.up;
361 Curl_safefree(up->scheme);
362 Curl_safefree(up->hostname);
363 Curl_safefree(up->port);
364 Curl_safefree(up->user);
365 Curl_safefree(up->password);
366 Curl_safefree(up->options);
367 Curl_safefree(up->path);
368 Curl_safefree(up->query);
369 curl_url_cleanup(data->state.uh);
370 data->state.uh = NULL;
374 * This is the internal function curl_easy_cleanup() calls. This should
375 * cleanup and free all resources associated with this sessionhandle.
377 * We ignore SIGPIPE when this is called from curl_easy_cleanup.
380 CURLcode Curl_close(struct Curl_easy **datap)
382 struct Curl_multi *m;
383 struct Curl_easy *data;
385 if(!datap || !*datap)
391 Curl_expire_clear(data); /* shut off timers */
393 /* Detach connection if any is left. This should not be normal, but can be
394 the case for example with CONNECT_ONLY + recv/send (test 556) */
395 Curl_detach_connection(data);
398 /* This handle is still part of a multi handle, take care of this first
399 and detach this handle from there. */
400 curl_multi_remove_handle(data->multi, data);
402 if(data->multi_easy) {
403 /* when curl_easy_perform() is used, it creates its own multi handle to
404 use and this is the one */
405 curl_multi_cleanup(data->multi_easy);
406 data->multi_easy = NULL;
409 /* Destroy the timeout list that is held in the easy handle. It is
410 /normally/ done by curl_multi_remove_handle() but this is "just in
412 Curl_llist_destroy(&data->state.timeoutlist, NULL);
414 data->magic = 0; /* force a clear AFTER the possibly enforced removal from
415 the multi handle, since that function uses the magic
418 if(data->state.rangestringalloc)
419 free(data->state.range);
421 /* freed here just in case DONE wasn't called */
422 Curl_free_request_state(data);
424 /* Close down all open SSL info and sessions */
425 Curl_ssl_close_all(data);
426 Curl_safefree(data->state.first_host);
427 Curl_safefree(data->state.scratch);
428 Curl_ssl_free_certinfo(data);
430 /* Cleanup possible redirect junk */
431 free(data->req.newurl);
432 data->req.newurl = NULL;
434 if(data->state.referer_alloc) {
435 Curl_safefree(data->state.referer);
436 data->state.referer_alloc = FALSE;
438 data->state.referer = NULL;
441 Curl_safefree(data->state.buffer);
442 Curl_dyn_free(&data->state.headerb);
443 Curl_safefree(data->state.ulbuf);
444 Curl_flush_cookies(data, TRUE);
445 Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
446 Curl_altsvc_cleanup(&data->asi);
447 Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
448 Curl_hsts_cleanup(&data->hsts);
449 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
450 Curl_http_auth_cleanup_digest(data);
452 Curl_safefree(data->info.contenttype);
453 Curl_safefree(data->info.wouldredirect);
455 /* this destroys the channel and we cannot use it anymore after this */
456 Curl_resolver_cancel(data);
457 Curl_resolver_cleanup(data->state.async.resolver);
459 Curl_http2_cleanup_dependencies(data);
461 /* No longer a dirty share, if it exists */
463 Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
464 data->share->dirty--;
465 Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
468 Curl_safefree(data->state.aptr.proxyuserpwd);
469 Curl_safefree(data->state.aptr.uagent);
470 Curl_safefree(data->state.aptr.userpwd);
471 Curl_safefree(data->state.aptr.accept_encoding);
472 Curl_safefree(data->state.aptr.te);
473 Curl_safefree(data->state.aptr.rangeline);
474 Curl_safefree(data->state.aptr.ref);
475 Curl_safefree(data->state.aptr.host);
476 Curl_safefree(data->state.aptr.cookiehost);
477 Curl_safefree(data->state.aptr.rtsp_transport);
478 Curl_safefree(data->state.aptr.user);
479 Curl_safefree(data->state.aptr.passwd);
480 Curl_safefree(data->state.aptr.proxyuser);
481 Curl_safefree(data->state.aptr.proxypasswd);
483 #ifndef CURL_DISABLE_DOH
485 Curl_dyn_free(&data->req.doh->probe[0].serverdoh);
486 Curl_dyn_free(&data->req.doh->probe[1].serverdoh);
487 curl_slist_free_all(data->req.doh->headers);
488 Curl_safefree(data->req.doh);
492 /* destruct wildcard structures if it is needed */
493 Curl_wildcard_dtor(&data->wildcard);
495 Curl_headers_cleanup(data);
501 * Initialize the UserDefined fields within a Curl_easy.
502 * This may be safely called on a new or existing Curl_easy.
504 CURLcode Curl_init_userdefined(struct Curl_easy *data)
506 struct UserDefined *set = &data->set;
507 CURLcode result = CURLE_OK;
509 set->out = stdout; /* default output to stdout */
510 set->in_set = stdin; /* default input from stdin */
511 set->err = stderr; /* default stderr to stderr */
513 /* use fwrite as default function to store output */
514 set->fwrite_func = (curl_write_callback)fwrite;
516 /* use fread as default function to read input */
517 set->fread_func_set = (curl_read_callback)fread;
518 set->is_fread_set = 0;
520 set->seek_func = ZERO_NULL;
521 set->seek_client = ZERO_NULL;
523 set->filesize = -1; /* we don't know the size */
524 set->postfieldsize = -1; /* unknown size */
525 set->maxredirs = -1; /* allow any amount by default */
527 set->method = HTTPREQ_GET; /* Default HTTP request */
528 #ifndef CURL_DISABLE_RTSP
529 set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
531 #ifndef CURL_DISABLE_FTP
532 set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
533 set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
534 set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */
535 set->ftp_filemethod = FTPFILE_MULTICWD;
536 set->ftp_skip_ip = TRUE; /* skip PASV IP by default */
538 set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
540 /* Set the default size of the SSL session ID cache */
541 set->general_ssl.max_ssl_sessions = 5;
544 set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
545 set->httpauth = CURLAUTH_BASIC; /* defaults to basic */
547 #ifndef CURL_DISABLE_PROXY
548 set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
549 /* SOCKS5 proxy auth defaults to username/password + GSS-API */
550 set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI;
553 /* make libcurl quiet by default: */
554 set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
556 Curl_mime_initpart(&set->mimepost, data);
559 * libcurl 7.10 introduced SSL verification *by default*! This needs to be
560 * switched off unless wanted.
562 #ifndef CURL_DISABLE_DOH
563 set->doh_verifyhost = TRUE;
564 set->doh_verifypeer = TRUE;
566 set->ssl.primary.verifypeer = TRUE;
567 set->ssl.primary.verifyhost = TRUE;
569 set->ssl.primary.authtype = CURL_TLSAUTH_NONE;
571 /* defaults to any auth type */
572 set->ssh_auth_types = CURLSSH_AUTH_DEFAULT;
573 set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by
575 #ifndef CURL_DISABLE_PROXY
576 set->proxy_ssl = set->ssl;
579 set->new_file_perms = 0644; /* Default permissions */
580 set->new_directory_perms = 0755; /* Default permissions */
581 set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL;
582 set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP |
585 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
587 * disallow unprotected protection negotiation NEC reference implementation
588 * seem not to follow rfc1961 section 4.3/4.4
590 set->socks5_gssapi_nec = FALSE;
593 /* Set the default CA cert bundle/path detected/specified at build time.
595 * If Schannel is the selected SSL backend then these locations are
596 * ignored. We allow setting CA location for schannel only when explicitly
597 * specified by the user via CURLOPT_CAINFO / --cacert.
599 if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
600 #if defined(CURL_CA_BUNDLE)
601 result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
605 result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
610 #if defined(CURL_CA_PATH)
611 result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
615 result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
621 #ifndef CURL_DISABLE_FTP
622 set->wildcard_enabled = FALSE;
623 set->chunk_bgn = ZERO_NULL;
624 set->chunk_end = ZERO_NULL;
625 set->fnmatch = ZERO_NULL;
627 set->tcp_keepalive = FALSE;
628 set->tcp_keepintvl = 60;
629 set->tcp_keepidle = 60;
630 set->tcp_fastopen = FALSE;
631 set->tcp_nodelay = TRUE;
632 set->ssl_enable_alpn = TRUE;
633 set->expect_100_timeout = 1000L; /* Wait for a second by default. */
634 set->sep_headers = TRUE; /* separated header lists by default */
635 set->buffer_size = READBUFFER_SIZE;
636 set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
637 set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
638 set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
639 set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
640 set->maxage_conn = 118;
641 set->maxlifetime_conn = 0;
642 set->http09_allowed = FALSE;
645 CURL_HTTP_VERSION_2TLS
647 CURL_HTTP_VERSION_1_1
650 Curl_http2_init_userset(set);
657 * @param curl is a pointer to a sessionhandle pointer that gets set by this
662 CURLcode Curl_open(struct Curl_easy **curl)
665 struct Curl_easy *data;
667 /* Very simple start-up: alloc the struct, init it with zeroes and return */
668 data = calloc(1, sizeof(struct Curl_easy));
670 /* this is a very serious error */
671 DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n"));
672 return CURLE_OUT_OF_MEMORY;
675 data->magic = CURLEASY_MAGIC_NUMBER;
677 result = Curl_resolver_init(data, &data->state.async.resolver);
679 DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
684 result = Curl_init_userdefined(data);
686 Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
689 /* most recent connection is not yet defined */
690 data->state.lastconnect_id = -1;
692 data->progress.flags |= PGRS_HIDE;
693 data->state.current_speed = -1; /* init to negative == impossible */
697 Curl_resolver_cleanup(data->state.async.resolver);
698 Curl_dyn_free(&data->state.headerb);
709 #ifdef USE_RECV_BEFORE_SEND_WORKAROUND
710 static void conn_reset_postponed_data(struct connectdata *conn, int num)
712 struct postponed_data * const psnd = &(conn->postponed[num]);
714 DEBUGASSERT(psnd->allocated_size > 0);
715 DEBUGASSERT(psnd->recv_size <= psnd->allocated_size);
716 DEBUGASSERT(psnd->recv_size ?
717 (psnd->recv_processed < psnd->recv_size) :
718 (psnd->recv_processed == 0));
719 DEBUGASSERT(psnd->bindsock != CURL_SOCKET_BAD);
722 psnd->allocated_size = 0;
724 psnd->recv_processed = 0;
726 psnd->bindsock = CURL_SOCKET_BAD; /* used only for DEBUGASSERT */
727 #endif /* DEBUGBUILD */
730 DEBUGASSERT(psnd->allocated_size == 0);
731 DEBUGASSERT(psnd->recv_size == 0);
732 DEBUGASSERT(psnd->recv_processed == 0);
733 DEBUGASSERT(psnd->bindsock == CURL_SOCKET_BAD);
737 static void conn_reset_all_postponed_data(struct connectdata *conn)
739 conn_reset_postponed_data(conn, 0);
740 conn_reset_postponed_data(conn, 1);
742 #else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
743 /* Use "do-nothing" macro instead of function when workaround not used */
744 #define conn_reset_all_postponed_data(c) do {} while(0)
745 #endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
748 static void conn_shutdown(struct Curl_easy *data, struct connectdata *conn)
752 infof(data, "Closing connection %ld", conn->connection_id);
754 /* possible left-overs from the async name resolvers */
755 Curl_resolver_cancel(data);
757 /* close the SSL stuff before we close any sockets since they will/may
758 write to the sockets */
759 Curl_ssl_close(data, conn, FIRSTSOCKET);
760 #ifndef CURL_DISABLE_FTP
761 Curl_ssl_close(data, conn, SECONDARYSOCKET);
764 /* close possibly still open sockets */
765 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
766 Curl_closesocket(data, conn, conn->sock[SECONDARYSOCKET]);
767 if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
768 Curl_closesocket(data, conn, conn->sock[FIRSTSOCKET]);
769 if(CURL_SOCKET_BAD != conn->tempsock[0])
770 Curl_closesocket(data, conn, conn->tempsock[0]);
771 if(CURL_SOCKET_BAD != conn->tempsock[1])
772 Curl_closesocket(data, conn, conn->tempsock[1]);
775 static void conn_free(struct connectdata *conn)
779 Curl_free_idnconverted_hostname(&conn->host);
780 Curl_free_idnconverted_hostname(&conn->conn_to_host);
781 #ifndef CURL_DISABLE_PROXY
782 Curl_free_idnconverted_hostname(&conn->http_proxy.host);
783 Curl_free_idnconverted_hostname(&conn->socks_proxy.host);
784 Curl_safefree(conn->http_proxy.user);
785 Curl_safefree(conn->socks_proxy.user);
786 Curl_safefree(conn->http_proxy.passwd);
787 Curl_safefree(conn->socks_proxy.passwd);
788 Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
789 Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
790 Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
792 Curl_safefree(conn->user);
793 Curl_safefree(conn->passwd);
794 Curl_safefree(conn->sasl_authzid);
795 Curl_safefree(conn->options);
796 Curl_safefree(conn->oauth_bearer);
797 Curl_dyn_free(&conn->trailer);
798 Curl_safefree(conn->host.rawalloc); /* host name buffer */
799 Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
800 Curl_safefree(conn->hostname_resolve);
801 Curl_safefree(conn->secondaryhostname);
802 Curl_safefree(conn->connect_state);
804 conn_reset_all_postponed_data(conn);
805 Curl_llist_destroy(&conn->easyq, NULL);
806 Curl_safefree(conn->localdev);
807 Curl_free_primary_ssl_config(&conn->ssl_config);
809 #ifdef USE_UNIX_SOCKETS
810 Curl_safefree(conn->unix_domain_socket);
814 Curl_safefree(conn->ssl_extra);
816 free(conn); /* free all the connection oriented data */
820 * Disconnects the given connection. Note the connection may not be the
821 * primary connection, like when freeing room in the connection cache or
822 * killing of a dead old connection.
824 * A connection needs an easy handle when closing down. We support this passed
825 * in separately since the connection to get closed here is often already
826 * disassociated from an easy handle.
828 * This function MUST NOT reset state in the Curl_easy struct if that
829 * isn't strictly bound to the life-time of *this* particular connection.
833 void Curl_disconnect(struct Curl_easy *data,
834 struct connectdata *conn, bool dead_connection)
836 /* there must be a connection to close */
839 /* it must be removed from the connection cache */
840 DEBUGASSERT(!conn->bundle);
842 /* there must be an associated transfer */
845 /* the transfer must be detached from the connection */
846 DEBUGASSERT(!data->conn);
849 * If this connection isn't marked to force-close, leave it open if there
850 * are other users of it
852 if(CONN_INUSE(conn) && !dead_connection) {
853 DEBUGF(infof(data, "Curl_disconnect when inuse: %zu", CONN_INUSE(conn)));
857 if(conn->dns_entry) {
858 Curl_resolv_unlock(data, conn->dns_entry);
859 conn->dns_entry = NULL;
862 /* Cleanup NTLM connection-related data */
863 Curl_http_auth_cleanup_ntlm(conn);
865 /* Cleanup NEGOTIATE connection-related data */
866 Curl_http_auth_cleanup_negotiate(conn);
868 if(conn->connect_only)
869 /* treat the connection as dead in CONNECT_ONLY situations */
870 dead_connection = TRUE;
872 /* temporarily attach the connection to this transfer handle for the
873 disconnect and shutdown */
874 Curl_attach_connection(data, conn);
876 if(conn->handler->disconnect)
877 /* This is set if protocol-specific cleanups should be made */
878 conn->handler->disconnect(data, conn, dead_connection);
880 conn_shutdown(data, conn);
882 /* detach it again */
883 Curl_detach_connection(data);
889 * This function should return TRUE if the socket is to be assumed to
890 * be dead. Most commonly this happens when the server has closed the
891 * connection due to inactivity.
893 static bool SocketIsDead(curl_socket_t sock)
898 sval = SOCKET_READABLE(sock, 0);
907 * IsMultiplexingPossible()
909 * Return a bitmask with the available multiplexing options for the given
910 * requested connection.
912 static int IsMultiplexingPossible(const struct Curl_easy *handle,
913 const struct connectdata *conn)
917 /* If a HTTP protocol and multiplexing is enabled */
918 if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
919 (!conn->bits.protoconnstart || !conn->bits.close)) {
921 if(Curl_multiplex_wanted(handle->multi) &&
922 (handle->state.httpwant >= CURL_HTTP_VERSION_2))
924 avail |= CURLPIPE_MULTIPLEX;
929 #ifndef CURL_DISABLE_PROXY
931 proxy_info_matches(const struct proxy_info *data,
932 const struct proxy_info *needle)
934 if((data->proxytype == needle->proxytype) &&
935 (data->port == needle->port) &&
936 Curl_safe_strcasecompare(data->host.name, needle->host.name))
943 socks_proxy_info_matches(const struct proxy_info *data,
944 const struct proxy_info *needle)
946 if(!proxy_info_matches(data, needle))
949 /* the user information is case-sensitive
950 or at least it is not defined as case-insensitive
951 see https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1 */
953 /* curl_strequal does a case insensitive comparison,
954 so do not use it here! */
955 if(Curl_timestrcmp(data->user, needle->user) ||
956 Curl_timestrcmp(data->passwd, needle->passwd))
961 /* disabled, won't get called */
962 #define proxy_info_matches(x,y) FALSE
963 #define socks_proxy_info_matches(x,y) FALSE
966 /* A connection has to have been idle for a shorter time than 'maxage_conn'
967 (the success rate is just too low after this), or created less than
968 'maxlifetime_conn' ago, to be subject for reuse. */
970 static bool conn_maxage(struct Curl_easy *data,
971 struct connectdata *conn,
974 timediff_t idletime, lifetime;
976 idletime = Curl_timediff(now, conn->lastused);
977 idletime /= 1000; /* integer seconds is fine */
979 if(idletime > data->set.maxage_conn) {
980 infof(data, "Too old connection (%ld seconds idle), disconnect it",
985 lifetime = Curl_timediff(now, conn->created);
986 lifetime /= 1000; /* integer seconds is fine */
988 if(data->set.maxlifetime_conn && lifetime > data->set.maxlifetime_conn) {
990 "Too old connection (%ld seconds since creation), disconnect it",
1000 * This function checks if the given connection is dead and extracts it from
1001 * the connection cache if so.
1003 * When this is called as a Curl_conncache_foreach() callback, the connection
1004 * cache lock is held!
1006 * Returns TRUE if the connection was dead and extracted.
1008 static bool extract_if_dead(struct connectdata *conn,
1009 struct Curl_easy *data)
1011 if(!CONN_INUSE(conn)) {
1012 /* The check for a dead socket makes sense only if the connection isn't in
1015 struct curltime now = Curl_now();
1016 if(conn_maxage(data, conn, now)) {
1017 /* avoid check if already too old */
1020 else if(conn->handler->connection_check) {
1021 /* The protocol has a special method for checking the state of the
1022 connection. Use it to check if the connection is dead. */
1025 /* briefly attach the connection to this transfer for the purpose of
1027 Curl_attach_connection(data, conn);
1029 state = conn->handler->connection_check(data, conn, CONNCHECK_ISDEAD);
1030 dead = (state & CONNRESULT_DEAD);
1031 /* detach the connection again */
1032 Curl_detach_connection(data);
1036 /* Use the general method for determining the death of a connection */
1037 dead = SocketIsDead(conn->sock[FIRSTSOCKET]);
1041 infof(data, "Connection %ld seems to be dead", conn->connection_id);
1042 Curl_conncache_remove_conn(data, conn, FALSE);
1050 struct Curl_easy *data;
1051 struct connectdata *extracted;
1055 * Wrapper to use extract_if_dead() function in Curl_conncache_foreach()
1058 static int call_extract_if_dead(struct Curl_easy *data,
1059 struct connectdata *conn, void *param)
1061 struct prunedead *p = (struct prunedead *)param;
1062 if(extract_if_dead(conn, data)) {
1063 /* stop the iteration here, pass back the connection that was extracted */
1064 p->extracted = conn;
1067 return 0; /* continue iteration */
1071 * This function scans the connection cache for half-open/dead connections,
1072 * closes and removes them. The cleanup is done at most once per second.
1074 * When called, this transfer has no connection attached.
1076 static void prune_dead_connections(struct Curl_easy *data)
1078 struct curltime now = Curl_now();
1081 DEBUGASSERT(!data->conn); /* no connection */
1082 CONNCACHE_LOCK(data);
1084 Curl_timediff(now, data->state.conn_cache->last_cleanup);
1085 CONNCACHE_UNLOCK(data);
1087 if(elapsed >= 1000L) {
1088 struct prunedead prune;
1090 prune.extracted = NULL;
1091 while(Curl_conncache_foreach(data, data->state.conn_cache, &prune,
1092 call_extract_if_dead)) {
1095 /* remove connection from cache */
1096 Curl_conncache_remove_conn(data, prune.extracted, TRUE);
1099 Curl_disconnect(data, prune.extracted, TRUE);
1101 CONNCACHE_LOCK(data);
1102 data->state.conn_cache->last_cleanup = now;
1103 CONNCACHE_UNLOCK(data);
1108 static bool ssh_config_matches(struct connectdata *one,
1109 struct connectdata *two)
1111 return (Curl_safecmp(one->proto.sshc.rsa, two->proto.sshc.rsa) &&
1112 Curl_safecmp(one->proto.sshc.rsa_pub, two->proto.sshc.rsa_pub));
1115 #define ssh_config_matches(x,y) FALSE
1119 * Given one filled in connection struct (named needle), this function should
1120 * detect if there already is one that has all the significant details
1121 * exactly the same and thus should be used instead.
1123 * If there is a match, this function returns TRUE - and has marked the
1124 * connection as 'in-use'. It must later be called with ConnectionDone() to
1125 * return back to 'idle' (unused) state.
1127 * The force_reuse flag is set if the connection must be used.
1130 ConnectionExists(struct Curl_easy *data,
1131 struct connectdata *needle,
1132 struct connectdata **usethis,
1136 struct connectdata *check;
1137 struct connectdata *chosen = 0;
1138 bool foundPendingCandidate = FALSE;
1139 bool canmultiplex = IsMultiplexingPossible(data, needle);
1140 struct connectbundle *bundle;
1143 bool wantNTLMhttp = ((data->state.authhost.want &
1144 (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
1145 (needle->handler->protocol & PROTO_FAMILY_HTTP));
1146 #ifndef CURL_DISABLE_PROXY
1147 bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd &&
1148 ((data->state.authproxy.want &
1149 (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
1150 (needle->handler->protocol & PROTO_FAMILY_HTTP)));
1152 bool wantProxyNTLMhttp = FALSE;
1156 *force_reuse = FALSE;
1159 /* Look up the bundle with all the connections to this particular host.
1160 Locks the connection cache, beware of early returns! */
1161 bundle = Curl_conncache_find_bundle(data, needle, data->state.conn_cache);
1163 /* Max pipe length is zero (unlimited) for multiplexed connections */
1164 struct Curl_llist_element *curr;
1166 infof(data, "Found bundle for host: %p [%s]",
1167 (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ?
1168 "can multiplex" : "serially"));
1170 /* We can't multiplex if we don't know anything about the server */
1172 if(bundle->multiuse == BUNDLE_UNKNOWN) {
1173 if(data->set.pipewait) {
1174 infof(data, "Server doesn't support multiplex yet, wait");
1176 CONNCACHE_UNLOCK(data);
1177 return FALSE; /* no re-use */
1180 infof(data, "Server doesn't support multiplex (yet)");
1181 canmultiplex = FALSE;
1183 if((bundle->multiuse == BUNDLE_MULTIPLEX) &&
1184 !Curl_multiplex_wanted(data->multi)) {
1185 infof(data, "Could multiplex, but not asked to");
1186 canmultiplex = FALSE;
1188 if(bundle->multiuse == BUNDLE_NO_MULTIUSE) {
1189 infof(data, "Can not multiplex, even if we wanted to");
1190 canmultiplex = FALSE;
1194 curr = bundle->conn_list.head;
1197 size_t multiplexed = 0;
1200 * Note that if we use a HTTP proxy in normal mode (no tunneling), we
1201 * check connections to that proxy and not to the actual remote server.
1206 if(check->connect_only || check->bits.close)
1207 /* connect-only or to-be-closed connections will not be reused */
1210 if(extract_if_dead(check, data)) {
1212 Curl_disconnect(data, check, TRUE);
1216 if(data->set.ipver != CURL_IPRESOLVE_WHATEVER
1217 && data->set.ipver != check->ip_version) {
1218 /* skip because the connection is not via the requested IP version */
1222 if(bundle->multiuse == BUNDLE_MULTIPLEX)
1223 multiplexed = CONN_INUSE(check);
1227 /* can only happen within multi handles, and means that another easy
1228 handle is using this connection */
1232 if(Curl_resolver_asynch()) {
1233 /* primary_ip[0] is NUL only if the resolving of the name hasn't
1234 completed yet and until then we don't re-use this connection */
1235 if(!check->primary_ip[0]) {
1237 "Connection #%ld is still name resolving, can't reuse",
1238 check->connection_id);
1243 if(check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) {
1244 foundPendingCandidate = TRUE;
1245 /* Don't pick a connection that hasn't connected yet */
1246 infof(data, "Connection #%ld isn't open enough, can't reuse",
1247 check->connection_id);
1252 #ifdef USE_UNIX_SOCKETS
1253 if(needle->unix_domain_socket) {
1254 if(!check->unix_domain_socket)
1256 if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
1258 if(needle->bits.abstract_unix_socket !=
1259 check->bits.abstract_unix_socket)
1262 else if(check->unix_domain_socket)
1266 if((needle->handler->flags&PROTOPT_SSL) !=
1267 (check->handler->flags&PROTOPT_SSL))
1268 /* don't do mixed SSL and non-SSL connections */
1269 if(get_protocol_family(check->handler) !=
1270 needle->handler->protocol || !check->bits.tls_upgraded)
1271 /* except protocols that have been upgraded via TLS */
1274 #ifndef CURL_DISABLE_PROXY
1275 if(needle->bits.httpproxy != check->bits.httpproxy ||
1276 needle->bits.socksproxy != check->bits.socksproxy)
1279 if(needle->bits.socksproxy &&
1280 !socks_proxy_info_matches(&needle->socks_proxy,
1281 &check->socks_proxy))
1284 if(needle->bits.conn_to_host != check->bits.conn_to_host)
1285 /* don't mix connections that use the "connect to host" feature and
1286 * connections that don't use this feature */
1289 if(needle->bits.conn_to_port != check->bits.conn_to_port)
1290 /* don't mix connections that use the "connect to port" feature and
1291 * connections that don't use this feature */
1294 #ifndef CURL_DISABLE_PROXY
1295 if(needle->bits.httpproxy) {
1296 if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy))
1299 if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy)
1302 if(needle->http_proxy.proxytype == CURLPROXY_HTTPS) {
1303 /* use https proxy */
1304 if(needle->handler->flags&PROTOPT_SSL) {
1305 /* use double layer ssl */
1306 if(!Curl_ssl_config_matches(&needle->proxy_ssl_config,
1307 &check->proxy_ssl_config))
1309 if(check->proxy_ssl[FIRSTSOCKET].state != ssl_connection_complete)
1313 if(!Curl_ssl_config_matches(&needle->ssl_config,
1314 &check->ssl_config))
1316 if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete)
1322 if(!canmultiplex && CONN_INUSE(check))
1323 /* this request can't be multiplexed but the checked connection is
1324 already in use so we skip it */
1327 if(CONN_INUSE(check)) {
1328 /* Subject for multiplex use if 'checks' belongs to the same multi
1329 handle as 'data' is. */
1330 struct Curl_llist_element *e = check->easyq.head;
1331 struct Curl_easy *entry = e->ptr;
1332 if(entry->multi != data->multi)
1336 if(needle->localdev || needle->localport) {
1337 /* If we are bound to a specific local end (IP+port), we must not
1338 re-use a random other one, although if we didn't ask for a
1339 particular one we can reuse one that was bound.
1341 This comparison is a bit rough and too strict. Since the input
1342 parameters can be specified in numerous ways and still end up the
1343 same it would take a lot of processing to make it really accurate.
1344 Instead, this matching will assume that re-uses of bound connections
1345 will most likely also re-use the exact same binding parameters and
1346 missing out a few edge cases shouldn't hurt anyone very much.
1348 if((check->localport != needle->localport) ||
1349 (check->localportrange != needle->localportrange) ||
1350 (needle->localdev &&
1351 (!check->localdev || strcmp(check->localdev, needle->localdev))))
1355 if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
1356 /* This protocol requires credentials per connection,
1357 so verify that we're using the same name and password as well */
1358 if(Curl_timestrcmp(needle->user, check->user) ||
1359 Curl_timestrcmp(needle->passwd, check->passwd) ||
1360 Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) ||
1361 Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) {
1362 /* one of them was different */
1367 /* If multiplexing isn't enabled on the h2 connection and h1 is
1368 explicitly requested, handle it: */
1369 if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
1370 (check->httpversion >= 20) &&
1371 (data->state.httpwant < CURL_HTTP_VERSION_2_0))
1374 if(get_protocol_family(needle->handler) == PROTO_FAMILY_SSH) {
1375 if(!ssh_config_matches(needle, check))
1379 if((needle->handler->flags&PROTOPT_SSL)
1380 #ifndef CURL_DISABLE_PROXY
1381 || !needle->bits.httpproxy || needle->bits.tunnel_proxy
1384 /* The requested connection does not use a HTTP proxy or it uses SSL or
1385 it is a non-SSL protocol tunneled or it is a non-SSL protocol which
1386 is allowed to be upgraded via TLS */
1388 if((strcasecompare(needle->handler->scheme, check->handler->scheme) ||
1389 (get_protocol_family(check->handler) ==
1390 needle->handler->protocol && check->bits.tls_upgraded)) &&
1391 (!needle->bits.conn_to_host || strcasecompare(
1392 needle->conn_to_host.name, check->conn_to_host.name)) &&
1393 (!needle->bits.conn_to_port ||
1394 needle->conn_to_port == check->conn_to_port) &&
1395 strcasecompare(needle->host.name, check->host.name) &&
1396 needle->remote_port == check->remote_port) {
1397 /* The schemes match or the protocol family is the same and the
1398 previous connection was TLS upgraded, and the hostname and host
1400 if(needle->handler->flags & PROTOPT_SSL) {
1401 /* This is a SSL connection so verify that we're using the same
1402 SSL options as well */
1403 if(!Curl_ssl_config_matches(&needle->ssl_config,
1404 &check->ssl_config)) {
1406 "Connection #%ld has different SSL parameters, "
1408 check->connection_id));
1411 if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) {
1412 foundPendingCandidate = TRUE;
1414 "Connection #%ld has not started SSL connect, "
1416 check->connection_id));
1424 /* The requested connection is using the same HTTP proxy in normal
1425 mode (no tunneling) */
1430 #if defined(USE_NTLM)
1431 /* If we are looking for an HTTP+NTLM connection, check if this is
1432 already authenticating with the right credentials. If not, keep
1433 looking so that we can reuse NTLM connections if
1434 possible. (Especially we must not reuse the same connection if
1435 partway through a handshake!) */
1437 if(Curl_timestrcmp(needle->user, check->user) ||
1438 Curl_timestrcmp(needle->passwd, check->passwd)) {
1440 /* we prefer a credential match, but this is at least a connection
1441 that can be reused and "upgraded" to NTLM */
1442 if(check->http_ntlm_state == NTLMSTATE_NONE)
1447 else if(check->http_ntlm_state != NTLMSTATE_NONE) {
1448 /* Connection is using NTLM auth but we don't want NTLM */
1452 #ifndef CURL_DISABLE_PROXY
1453 /* Same for Proxy NTLM authentication */
1454 if(wantProxyNTLMhttp) {
1455 /* Both check->http_proxy.user and check->http_proxy.passwd can be
1457 if(!check->http_proxy.user || !check->http_proxy.passwd)
1460 if(Curl_timestrcmp(needle->http_proxy.user,
1461 check->http_proxy.user) ||
1462 Curl_timestrcmp(needle->http_proxy.passwd,
1463 check->http_proxy.passwd))
1466 else if(check->proxy_ntlm_state != NTLMSTATE_NONE) {
1467 /* Proxy connection is using NTLM auth but we don't want NTLM */
1471 if(wantNTLMhttp || wantProxyNTLMhttp) {
1472 /* Credentials are already checked, we can use this connection */
1476 (check->http_ntlm_state != NTLMSTATE_NONE)) ||
1477 (wantProxyNTLMhttp &&
1478 (check->proxy_ntlm_state != NTLMSTATE_NONE))) {
1479 /* We must use this connection, no other */
1480 *force_reuse = TRUE;
1484 /* Continue look up for a better connection */
1489 /* We can multiplex if we want to. Let's continue looking for
1490 the optimal connection to use. */
1493 /* We have the optimal connection. Let's stop looking. */
1499 /* If multiplexed, make sure we don't go over concurrency limit */
1500 if(check->bits.multiplex) {
1501 /* Multiplexed connections can only be HTTP/2 for now */
1502 struct http_conn *httpc = &check->proto.httpc;
1503 if(multiplexed >= httpc->settings.max_concurrent_streams) {
1504 infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
1508 else if(multiplexed >=
1509 Curl_multi_max_concurrent_streams(data->multi)) {
1510 infof(data, "client side MAX_CONCURRENT_STREAMS reached"
1517 /* When not multiplexed, we have a match here! */
1519 infof(data, "Multiplexed connection found");
1523 /* We have found a connection. Let's stop searching. */
1532 /* mark it as used before releasing the lock */
1533 Curl_attach_connection(data, chosen);
1534 CONNCACHE_UNLOCK(data);
1536 return TRUE; /* yes, we found one to use! */
1538 CONNCACHE_UNLOCK(data);
1540 if(foundPendingCandidate && data->set.pipewait) {
1542 "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
1546 return FALSE; /* no matching connecting exists */
1550 * verboseconnect() displays verbose information after a connect
1552 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1553 void Curl_verboseconnect(struct Curl_easy *data,
1554 struct connectdata *conn)
1556 if(data->set.verbose)
1557 infof(data, "Connected to %s (%s) port %u (#%ld)",
1558 #ifndef CURL_DISABLE_PROXY
1559 conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
1560 conn->bits.httpproxy ? conn->http_proxy.host.dispname :
1562 conn->bits.conn_to_host ? conn->conn_to_host.dispname :
1563 conn->host.dispname,
1564 conn->primary_ip, conn->port, conn->connection_id);
1569 * Helpers for IDNA conversions.
1571 bool Curl_is_ASCII_name(const char *hostname)
1573 /* get an UNSIGNED local version of the pointer */
1574 const unsigned char *ch = (const unsigned char *)hostname;
1576 if(!hostname) /* bad input, consider it ASCII! */
1587 * Perform any necessary IDN conversion of hostname
1589 CURLcode Curl_idnconvert_hostname(struct Curl_easy *data,
1590 struct hostname *host)
1595 #elif defined(CURL_DISABLE_VERBOSE_STRINGS)
1599 /* set the name we use to display the host name */
1600 host->dispname = host->name;
1602 /* Check name for non-ASCII and convert hostname to ACE form if we can */
1603 if(!Curl_is_ASCII_name(host->name)) {
1605 if(idn2_check_version(IDN2_VERSION)) {
1606 char *ace_hostname = NULL;
1607 #if IDN2_VERSION_NUMBER >= 0x00140000
1608 /* IDN2_NFC_INPUT: Normalize input string using normalization form C.
1609 IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional
1611 int flags = IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL;
1613 int flags = IDN2_NFC_INPUT;
1615 int rc = IDN2_LOOKUP(host->name, &ace_hostname, flags);
1617 /* fallback to TR46 Transitional mode for better IDNA2003
1619 rc = IDN2_LOOKUP(host->name, &ace_hostname,
1622 host->encalloc = (char *)ace_hostname;
1623 /* change the name pointer to point to the encoded hostname */
1624 host->name = host->encalloc;
1627 failf(data, "Failed to convert %s to ACE; %s", host->name,
1629 return CURLE_URL_MALFORMAT;
1632 #elif defined(USE_WIN32_IDN)
1633 char *ace_hostname = NULL;
1635 if(Curl_win32_idn_to_ascii(host->name, &ace_hostname)) {
1636 host->encalloc = ace_hostname;
1637 /* change the name pointer to point to the encoded hostname */
1638 host->name = host->encalloc;
1641 char buffer[STRERROR_LEN];
1642 failf(data, "Failed to convert %s to ACE; %s", host->name,
1643 Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
1644 return CURLE_URL_MALFORMAT;
1647 infof(data, "IDN support not present, can't parse Unicode domains");
1654 * Frees data allocated by idnconvert_hostname()
1656 void Curl_free_idnconverted_hostname(struct hostname *host)
1658 #if defined(USE_LIBIDN2)
1659 if(host->encalloc) {
1660 idn2_free(host->encalloc); /* must be freed with idn2_free() since this was
1661 allocated by libidn */
1662 host->encalloc = NULL;
1664 #elif defined(USE_WIN32_IDN)
1665 free(host->encalloc); /* must be freed with free() since this was
1666 allocated by Curl_win32_idn_to_ascii */
1667 host->encalloc = NULL;
1674 * Allocate and initialize a new connectdata object.
1676 static struct connectdata *allocate_conn(struct Curl_easy *data)
1678 struct connectdata *conn = calloc(1, sizeof(struct connectdata));
1683 /* The SSL backend-specific data (ssl_backend_data) objects are allocated as
1684 a separate array to ensure suitable alignment.
1685 Note that these backend pointers can be swapped by vtls (eg ssl backend
1686 data becomes proxy backend data). */
1688 size_t onesize = Curl_ssl->sizeof_ssl_backend_data;
1689 size_t totalsize = onesize;
1692 #ifndef CURL_DISABLE_FTP
1695 #ifndef CURL_DISABLE_PROXY
1699 ssl = calloc(1, totalsize);
1704 conn->ssl_extra = ssl;
1705 conn->ssl[FIRSTSOCKET].backend = (void *)ssl;
1706 #ifndef CURL_DISABLE_FTP
1708 conn->ssl[SECONDARYSOCKET].backend = (void *)ssl;
1710 #ifndef CURL_DISABLE_PROXY
1712 conn->proxy_ssl[FIRSTSOCKET].backend = (void *)ssl;
1713 #ifndef CURL_DISABLE_FTP
1715 conn->proxy_ssl[SECONDARYSOCKET].backend = (void *)ssl;
1721 conn->handler = &Curl_handler_dummy; /* Be sure we have a handler defined
1722 already from start to avoid NULL
1723 situations and checks */
1725 /* and we setup a few fields in case we end up actually using this struct */
1727 conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
1728 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
1729 conn->tempsock[0] = CURL_SOCKET_BAD; /* no file descriptor */
1730 conn->tempsock[1] = CURL_SOCKET_BAD; /* no file descriptor */
1731 conn->connection_id = -1; /* no ID */
1732 conn->port = -1; /* unknown at this point */
1733 conn->remote_port = -1; /* unknown at this point */
1734 #if defined(USE_RECV_BEFORE_SEND_WORKAROUND) && defined(DEBUGBUILD)
1735 conn->postponed[0].bindsock = CURL_SOCKET_BAD; /* no file descriptor */
1736 conn->postponed[1].bindsock = CURL_SOCKET_BAD; /* no file descriptor */
1737 #endif /* USE_RECV_BEFORE_SEND_WORKAROUND && DEBUGBUILD */
1739 /* Default protocol-independent behavior doesn't support persistent
1740 connections, so we set this to force-close. Protocols that support
1741 this need to set this to FALSE in their "curl_do" functions. */
1742 connclose(conn, "Default to force-close");
1744 /* Store creation time to help future close decision making */
1745 conn->created = Curl_now();
1747 /* Store current time to give a baseline to keepalive connection times. */
1748 conn->keepalive = Curl_now();
1750 #ifndef CURL_DISABLE_PROXY
1751 conn->http_proxy.proxytype = data->set.proxytype;
1752 conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
1754 /* note that these two proxy bits are now just on what looks to be
1755 requested, they may be altered down the road */
1756 conn->bits.proxy = (data->set.str[STRING_PROXY] &&
1757 *data->set.str[STRING_PROXY]) ? TRUE : FALSE;
1758 conn->bits.httpproxy = (conn->bits.proxy &&
1759 (conn->http_proxy.proxytype == CURLPROXY_HTTP ||
1760 conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
1761 conn->http_proxy.proxytype == CURLPROXY_HTTPS)) ?
1763 conn->bits.socksproxy = (conn->bits.proxy &&
1764 !conn->bits.httpproxy) ? TRUE : FALSE;
1766 if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
1767 conn->bits.proxy = TRUE;
1768 conn->bits.socksproxy = TRUE;
1771 conn->bits.proxy_user_passwd =
1772 (data->state.aptr.proxyuser) ? TRUE : FALSE;
1773 conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
1774 #endif /* CURL_DISABLE_PROXY */
1776 #ifndef CURL_DISABLE_FTP
1777 conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
1778 conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
1780 conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus;
1781 conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer;
1782 conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost;
1783 conn->ssl_config.ssl_options = data->set.ssl.primary.ssl_options;
1784 #ifndef CURL_DISABLE_PROXY
1785 conn->proxy_ssl_config.verifystatus =
1786 data->set.proxy_ssl.primary.verifystatus;
1787 conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer;
1788 conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost;
1789 conn->proxy_ssl_config.ssl_options = data->set.proxy_ssl.primary.ssl_options;
1791 conn->ip_version = data->set.ipver;
1792 conn->connect_only = data->set.connect_only;
1793 conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
1795 #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
1796 defined(NTLM_WB_ENABLED)
1797 conn->ntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
1798 conn->proxyntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
1801 /* Initialize the easy handle list */
1802 Curl_llist_init(&conn->easyq, NULL);
1805 conn->data_prot = PROT_CLEAR;
1808 /* Store the local bind parameters that will be used for this connection */
1809 if(data->set.str[STRING_DEVICE]) {
1810 conn->localdev = strdup(data->set.str[STRING_DEVICE]);
1814 conn->localportrange = data->set.localportrange;
1815 conn->localport = data->set.localport;
1817 /* the close socket stuff needs to be copied to the connection struct as
1818 it may live on without (this specific) Curl_easy */
1819 conn->fclosesocket = data->set.fclosesocket;
1820 conn->closesocket_client = data->set.closesocket_client;
1821 conn->lastused = Curl_now(); /* used now */
1826 Curl_llist_destroy(&conn->easyq, NULL);
1827 free(conn->localdev);
1829 free(conn->ssl_extra);
1835 /* returns the handler if the given scheme is built-in */
1836 const struct Curl_handler *Curl_builtin_scheme(const char *scheme,
1839 const struct Curl_handler * const *pp;
1840 const struct Curl_handler *p;
1841 /* Scan protocol handler table and match against 'scheme'. The handler may
1842 be changed later when the protocol specific setup function is called. */
1843 if(schemelen == CURL_ZERO_TERMINATED)
1844 schemelen = strlen(scheme);
1845 for(pp = protocols; (p = *pp) != NULL; pp++)
1846 if(strncasecompare(p->scheme, scheme, schemelen) && !p->scheme[schemelen])
1847 /* Protocol found in table. */
1849 return NULL; /* not found */
1853 static CURLcode findprotocol(struct Curl_easy *data,
1854 struct connectdata *conn,
1855 const char *protostr)
1857 const struct Curl_handler *p = Curl_builtin_scheme(protostr,
1858 CURL_ZERO_TERMINATED);
1860 if(p && /* Protocol found in table. Check if allowed */
1861 (data->set.allowed_protocols & p->protocol)) {
1863 /* it is allowed for "normal" request, now do an extra check if this is
1864 the result of a redirect */
1865 if(data->state.this_is_a_follow &&
1866 !(data->set.redir_protocols & p->protocol))
1870 /* Perform setup complement if some. */
1871 conn->handler = conn->given = p;
1873 /* 'port' and 'remote_port' are set in setup_connection_internals() */
1878 /* The protocol was not found in the table, but we don't have to assign it
1879 to anything since it is already assigned to a dummy-struct in the
1880 create_conn() function when the connectdata struct is allocated. */
1881 failf(data, "Protocol \"%s\" not supported or disabled in " LIBCURL_NAME,
1884 return CURLE_UNSUPPORTED_PROTOCOL;
1888 CURLcode Curl_uc_to_curlcode(CURLUcode uc)
1892 return CURLE_URL_MALFORMAT;
1893 case CURLUE_UNSUPPORTED_SCHEME:
1894 return CURLE_UNSUPPORTED_PROTOCOL;
1895 case CURLUE_OUT_OF_MEMORY:
1896 return CURLE_OUT_OF_MEMORY;
1897 case CURLUE_USER_NOT_ALLOWED:
1898 return CURLE_LOGIN_DENIED;
1904 * If the URL was set with an IPv6 numerical address with a zone id part, set
1905 * the scope_id based on that!
1908 static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
1909 struct connectdata *conn)
1912 CURLUcode uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
1913 #ifdef CURL_DISABLE_VERBOSE_STRINGS
1919 unsigned long scope = strtoul(zoneid, &endp, 10);
1920 if(!*endp && (scope < UINT_MAX))
1921 /* A plain number, use it directly as a scope id. */
1922 conn->scope_id = (unsigned int)scope;
1923 #if defined(HAVE_IF_NAMETOINDEX)
1925 #elif defined(WIN32)
1926 else if(Curl_if_nametoindex) {
1929 #if defined(HAVE_IF_NAMETOINDEX) || defined(WIN32)
1930 /* Zone identifier is not numeric */
1931 unsigned int scopeidx = 0;
1933 scopeidx = Curl_if_nametoindex(zoneid);
1935 scopeidx = if_nametoindex(zoneid);
1938 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1939 char buffer[STRERROR_LEN];
1940 infof(data, "Invalid zoneid: %s; %s", zoneid,
1941 Curl_strerror(errno, buffer, sizeof(buffer)));
1945 conn->scope_id = scopeidx;
1947 #endif /* HAVE_IF_NAMETOINDEX || WIN32 */
1953 #define zonefrom_url(a,b,c) Curl_nop_stmt
1957 * Parse URL and fill in the relevant members of the connection struct.
1959 static CURLcode parseurlandfillconn(struct Curl_easy *data,
1960 struct connectdata *conn)
1966 bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
1968 up_free(data); /* cleanup previous leftovers first */
1972 uh = data->state.uh = curl_url_dup(data->set.uh);
1975 uh = data->state.uh = curl_url();
1979 return CURLE_OUT_OF_MEMORY;
1981 if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
1982 !Curl_is_absolute_url(data->state.url, NULL, 0, TRUE)) {
1983 char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL],
1986 return CURLE_OUT_OF_MEMORY;
1987 if(data->state.url_alloc)
1988 free(data->state.url);
1989 data->state.url = url;
1990 data->state.url_alloc = TRUE;
1995 uc = curl_url_set(uh, CURLUPART_URL, data->state.url,
1996 CURLU_GUESS_SCHEME |
1997 CURLU_NON_SUPPORT_SCHEME |
1998 (data->set.disallow_username_in_url ?
1999 CURLU_DISALLOW_USER : 0) |
2000 (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
2002 DEBUGF(infof(data, "curl_url_set rejected %s: %s", data->state.url,
2003 curl_url_strerror(uc)));
2004 return Curl_uc_to_curlcode(uc);
2007 /* after it was parsed, get the generated normalized version */
2008 uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
2010 return Curl_uc_to_curlcode(uc);
2011 if(data->state.url_alloc)
2012 free(data->state.url);
2013 data->state.url = newurl;
2014 data->state.url_alloc = TRUE;
2017 uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
2019 return Curl_uc_to_curlcode(uc);
2021 uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
2023 if(!strcasecompare("file", data->state.up.scheme))
2024 return CURLE_OUT_OF_MEMORY;
2026 else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
2027 failf(data, "Too long host name (maximum is %d)", MAX_URL_LEN);
2028 return CURLE_URL_MALFORMAT;
2030 hostname = data->state.up.hostname;
2032 if(hostname && hostname[0] == '[') {
2033 /* This looks like an IPv6 address literal. See if there is an address
2036 conn->bits.ipv6_ip = TRUE;
2037 /* cut off the brackets! */
2039 hlen = strlen(hostname);
2040 hostname[hlen - 1] = 0;
2042 zonefrom_url(uh, data, conn);
2045 /* make sure the connect struct gets its own copy of the host name */
2046 conn->host.rawalloc = strdup(hostname ? hostname : "");
2047 if(!conn->host.rawalloc)
2048 return CURLE_OUT_OF_MEMORY;
2049 conn->host.name = conn->host.rawalloc;
2051 /*************************************************************
2052 * IDN-convert the hostnames
2053 *************************************************************/
2054 result = Curl_idnconvert_hostname(data, &conn->host);
2057 if(conn->bits.conn_to_host) {
2058 result = Curl_idnconvert_hostname(data, &conn->conn_to_host);
2062 #ifndef CURL_DISABLE_PROXY
2063 if(conn->bits.httpproxy) {
2064 result = Curl_idnconvert_hostname(data, &conn->http_proxy.host);
2068 if(conn->bits.socksproxy) {
2069 result = Curl_idnconvert_hostname(data, &conn->socks_proxy.host);
2075 #ifndef CURL_DISABLE_HSTS
2077 if(data->hsts && strcasecompare("http", data->state.up.scheme)) {
2078 /* This MUST use the IDN decoded name */
2079 if(Curl_hsts(data->hsts, conn->host.name, TRUE)) {
2081 Curl_safefree(data->state.up.scheme);
2082 uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0);
2084 return Curl_uc_to_curlcode(uc);
2085 if(data->state.url_alloc)
2086 Curl_safefree(data->state.url);
2087 /* after update, get the updated version */
2088 uc = curl_url_get(uh, CURLUPART_URL, &url, 0);
2090 return Curl_uc_to_curlcode(uc);
2091 uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
2094 return Curl_uc_to_curlcode(uc);
2096 data->state.url = url;
2097 data->state.url_alloc = TRUE;
2098 infof(data, "Switched from HTTP to HTTPS due to HSTS => %s",
2104 result = findprotocol(data, conn, data->state.up.scheme);
2109 * User name and password set with their own options override the
2110 * credentials possibly set in the URL.
2112 if(!data->state.aptr.passwd) {
2113 uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
2116 result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL,
2117 conn->handler->flags&PROTOPT_USERPWDCTRL ?
2118 REJECT_ZERO : REJECT_CTRL);
2121 conn->passwd = decoded;
2122 result = Curl_setstropt(&data->state.aptr.passwd, decoded);
2126 else if(uc != CURLUE_NO_PASSWORD)
2127 return Curl_uc_to_curlcode(uc);
2130 if(!data->set.str[STRING_USERNAME]) {
2131 /* we don't use the URL API's URL decoder option here since it rejects
2132 control codes and we want to allow them for some schemes in the user
2133 and password fields */
2134 uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
2137 result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL,
2138 conn->handler->flags&PROTOPT_USERPWDCTRL ?
2139 REJECT_ZERO : REJECT_CTRL);
2142 conn->user = decoded;
2143 result = Curl_setstropt(&data->state.aptr.user, decoded);
2145 else if(uc != CURLUE_NO_USER)
2146 return Curl_uc_to_curlcode(uc);
2147 else if(data->state.aptr.passwd) {
2148 /* no user was set but a password, set a blank user */
2149 result = Curl_setstropt(&data->state.aptr.user, "");
2155 uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
2158 conn->options = strdup(data->state.up.options);
2160 return CURLE_OUT_OF_MEMORY;
2162 else if(uc != CURLUE_NO_OPTIONS)
2163 return Curl_uc_to_curlcode(uc);
2165 uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path,
2168 return Curl_uc_to_curlcode(uc);
2170 uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port,
2171 CURLU_DEFAULT_PORT);
2173 if(!strcasecompare("file", data->state.up.scheme))
2174 return CURLE_OUT_OF_MEMORY;
2177 unsigned long port = strtoul(data->state.up.port, NULL, 10);
2178 conn->port = conn->remote_port =
2179 (data->set.use_port && data->state.allow_port) ?
2180 data->set.use_port : curlx_ultous(port);
2183 (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
2186 if(data->set.scope_id)
2187 /* Override any scope that was set above. */
2188 conn->scope_id = data->set.scope_id;
2196 * If we're doing a resumed transfer, we need to setup our stuff
2199 static CURLcode setup_range(struct Curl_easy *data)
2201 struct UrlState *s = &data->state;
2202 s->resume_from = data->set.set_resume_from;
2203 if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
2204 if(s->rangestringalloc)
2208 s->range = aprintf("%" CURL_FORMAT_CURL_OFF_T "-", s->resume_from);
2210 s->range = strdup(data->set.str[STRING_SET_RANGE]);
2212 s->rangestringalloc = (s->range) ? TRUE : FALSE;
2215 return CURLE_OUT_OF_MEMORY;
2217 /* tell ourselves to fetch this range */
2218 s->use_range = TRUE; /* enable range download */
2221 s->use_range = FALSE; /* disable range download */
2228 * setup_connection_internals() -
2230 * Setup connection internals specific to the requested protocol in the
2231 * Curl_easy. This is inited and setup before the connection is made but
2232 * is about the particular protocol that is to be used.
2234 * This MUST get called after proxy magic has been figured out.
2236 static CURLcode setup_connection_internals(struct Curl_easy *data,
2237 struct connectdata *conn)
2239 const struct Curl_handler *p;
2242 /* Perform setup complement if some. */
2245 if(p->setup_connection) {
2246 result = (*p->setup_connection)(data, conn);
2251 p = conn->handler; /* May have changed. */
2255 /* we check for -1 here since if proxy was detected already, this
2256 was very likely already set to the proxy port */
2257 conn->port = p->defport;
2263 * Curl_free_request_state() should free temp data that was allocated in the
2264 * Curl_easy for this single request.
2267 void Curl_free_request_state(struct Curl_easy *data)
2269 Curl_safefree(data->req.p.http);
2270 Curl_safefree(data->req.newurl);
2272 #ifndef CURL_DISABLE_DOH
2274 Curl_close(&data->req.doh->probe[0].easy);
2275 Curl_close(&data->req.doh->probe[1].easy);
2281 #ifndef CURL_DISABLE_PROXY
2283 #ifndef CURL_DISABLE_HTTP
2284 /****************************************************************
2285 * Detect what (if any) proxy to use. Remember that this selects a host
2286 * name and is not limited to HTTP proxies only.
2287 * The returned pointer must be freed by the caller (unless NULL)
2288 ****************************************************************/
2289 static char *detect_proxy(struct Curl_easy *data,
2290 struct connectdata *conn)
2294 /* If proxy was not specified, we check for default proxy environment
2295 * variables, to enable i.e Lynx compliance:
2297 * http_proxy=http://some.server.dom:port/
2298 * https_proxy=http://some.server.dom:port/
2299 * ftp_proxy=http://some.server.dom:port/
2300 * no_proxy=domain1.dom,host.domain2.dom
2301 * (a comma-separated list of hosts which should
2302 * not be proxied, or an asterisk to override
2303 * all proxy variables)
2304 * all_proxy=http://some.server.dom:port/
2305 * (seems to exist for the CERN www lib. Probably
2306 * the first to check for.)
2308 * For compatibility, the all-uppercase versions of these variables are
2309 * checked if the lowercase versions don't exist.
2311 char proxy_env[128];
2312 const char *protop = conn->handler->scheme;
2313 char *envp = proxy_env;
2315 #ifdef CURL_DISABLE_VERBOSE_STRINGS
2319 /* Now, build <protocol>_proxy and check for such a one to use */
2321 *envp++ = Curl_raw_tolower(*protop++);
2324 strcpy(envp, "_proxy");
2326 /* read the protocol proxy: */
2327 prox = curl_getenv(proxy_env);
2330 * We don't try the uppercase version of HTTP_PROXY because of
2333 * When curl is used in a webserver application
2334 * environment (cgi or php), this environment variable can
2335 * be controlled by the web server user by setting the
2336 * http header 'Proxy:' to some value.
2338 * This can cause 'internal' http/ftp requests to be
2339 * arbitrarily redirected by any external attacker.
2341 if(!prox && !strcasecompare("http_proxy", proxy_env)) {
2342 /* There was no lowercase variable, try the uppercase version: */
2343 Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
2344 prox = curl_getenv(proxy_env);
2349 proxy = prox; /* use this */
2352 envp = (char *)"all_proxy";
2353 proxy = curl_getenv(envp); /* default proxy to use */
2355 envp = (char *)"ALL_PROXY";
2356 proxy = curl_getenv(envp);
2360 infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
2364 #endif /* CURL_DISABLE_HTTP */
2367 * If this is supposed to use a proxy, we need to figure out the proxy
2368 * host name, so that we can re-use an existing connection
2369 * that may exist registered to the same proxy host.
2371 static CURLcode parse_proxy(struct Curl_easy *data,
2372 struct connectdata *conn, char *proxy,
2373 curl_proxytype proxytype)
2375 char *portptr = NULL;
2377 char *proxyuser = NULL;
2378 char *proxypasswd = NULL;
2382 struct proxy_info *proxyinfo;
2383 CURLU *uhp = curl_url();
2384 CURLcode result = CURLE_OK;
2385 char *scheme = NULL;
2386 #ifdef USE_UNIX_SOCKETS
2388 bool is_unix_proxy = FALSE;
2393 result = CURLE_OUT_OF_MEMORY;
2397 /* When parsing the proxy, allowing non-supported schemes since we have
2398 these made up ones for proxies. Guess scheme for URLs without it. */
2399 uc = curl_url_set(uhp, CURLUPART_URL, proxy,
2400 CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
2402 /* parsed okay as a URL */
2403 uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, 0);
2405 result = CURLE_OUT_OF_MEMORY;
2409 if(strcasecompare("https", scheme))
2410 proxytype = CURLPROXY_HTTPS;
2411 else if(strcasecompare("socks5h", scheme))
2412 proxytype = CURLPROXY_SOCKS5_HOSTNAME;
2413 else if(strcasecompare("socks5", scheme))
2414 proxytype = CURLPROXY_SOCKS5;
2415 else if(strcasecompare("socks4a", scheme))
2416 proxytype = CURLPROXY_SOCKS4A;
2417 else if(strcasecompare("socks4", scheme) ||
2418 strcasecompare("socks", scheme))
2419 proxytype = CURLPROXY_SOCKS4;
2420 else if(strcasecompare("http", scheme))
2421 ; /* leave it as HTTP or HTTP/1.0 */
2423 /* Any other xxx:// reject! */
2424 failf(data, "Unsupported proxy scheme for \'%s\'", proxy);
2425 result = CURLE_COULDNT_CONNECT;
2430 failf(data, "Unsupported proxy syntax in \'%s\'", proxy);
2431 result = CURLE_COULDNT_RESOLVE_PROXY;
2436 if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY))
2438 if(proxytype == CURLPROXY_HTTPS) {
2439 failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
2440 "HTTPS-proxy support.", proxy);
2441 result = CURLE_NOT_BUILT_IN;
2446 proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
2447 proxytype == CURLPROXY_SOCKS5 ||
2448 proxytype == CURLPROXY_SOCKS4A ||
2449 proxytype == CURLPROXY_SOCKS4;
2451 proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy;
2452 proxyinfo->proxytype = proxytype;
2454 /* Is there a username and password given in this proxy url? */
2455 uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
2456 if(uc && (uc != CURLUE_NO_USER))
2458 uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
2459 if(uc && (uc != CURLUE_NO_PASSWORD))
2462 if(proxyuser || proxypasswd) {
2463 Curl_safefree(proxyinfo->user);
2464 proxyinfo->user = proxyuser;
2465 result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser);
2469 Curl_safefree(proxyinfo->passwd);
2471 proxypasswd = strdup("");
2473 result = CURLE_OUT_OF_MEMORY;
2477 proxyinfo->passwd = proxypasswd;
2478 result = Curl_setstropt(&data->state.aptr.proxypasswd, proxypasswd);
2482 conn->bits.proxy_user_passwd = TRUE; /* enable it */
2485 (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
2488 port = (int)strtol(portptr, NULL, 10);
2492 if(data->set.proxyport)
2493 /* None given in the proxy string, then get the default one if it is
2495 port = (int)data->set.proxyport;
2497 if(proxytype == CURLPROXY_HTTPS)
2498 port = CURL_DEFAULT_HTTPS_PROXY_PORT;
2500 port = CURL_DEFAULT_PROXY_PORT;
2504 proxyinfo->port = port;
2505 if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc)
2509 /* now, clone the proxy host name */
2510 uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
2512 result = CURLE_OUT_OF_MEMORY;
2515 #ifdef USE_UNIX_SOCKETS
2516 if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) {
2517 uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE);
2519 result = CURLE_OUT_OF_MEMORY;
2522 /* path will be "/", if no path was was found */
2523 if(strcmp("/", path)) {
2524 is_unix_proxy = TRUE;
2526 host = aprintf(UNIX_SOCKET_PREFIX"%s", path);
2528 result = CURLE_OUT_OF_MEMORY;
2531 Curl_safefree(proxyinfo->host.rawalloc);
2532 proxyinfo->host.rawalloc = host;
2533 proxyinfo->host.name = host;
2538 if(!is_unix_proxy) {
2540 Curl_safefree(proxyinfo->host.rawalloc);
2541 proxyinfo->host.rawalloc = host;
2542 if(host[0] == '[') {
2543 /* this is a numerical IPv6, strip off the brackets */
2544 size_t len = strlen(host);
2545 host[len-1] = 0; /* clear the trailing bracket */
2547 zonefrom_url(uhp, data, conn);
2549 proxyinfo->host.name = host;
2551 #ifdef USE_UNIX_SOCKETS
2560 #ifdef USE_UNIX_SOCKETS
2563 curl_url_cleanup(uhp);
2568 * Extract the user and password from the authentication string
2570 static CURLcode parse_proxy_auth(struct Curl_easy *data,
2571 struct connectdata *conn)
2573 const char *proxyuser = data->state.aptr.proxyuser ?
2574 data->state.aptr.proxyuser : "";
2575 const char *proxypasswd = data->state.aptr.proxypasswd ?
2576 data->state.aptr.proxypasswd : "";
2577 CURLcode result = CURLE_OK;
2580 result = Curl_urldecode(proxyuser, 0, &conn->http_proxy.user, NULL,
2583 result = Curl_setstropt(&data->state.aptr.proxyuser,
2584 conn->http_proxy.user);
2586 if(!result && proxypasswd) {
2587 result = Curl_urldecode(proxypasswd, 0, &conn->http_proxy.passwd,
2590 result = Curl_setstropt(&data->state.aptr.proxypasswd,
2591 conn->http_proxy.passwd);
2596 /* create_conn helper to parse and init proxy values. to be called after unix
2597 socket init but before any proxy vars are evaluated. */
2598 static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
2599 struct connectdata *conn)
2602 char *socksproxy = NULL;
2603 char *no_proxy = NULL;
2604 CURLcode result = CURLE_OK;
2606 /*************************************************************
2607 * Extract the user and password from the authentication string
2608 *************************************************************/
2609 if(conn->bits.proxy_user_passwd) {
2610 result = parse_proxy_auth(data, conn);
2615 /*************************************************************
2616 * Detect what (if any) proxy to use
2617 *************************************************************/
2618 if(data->set.str[STRING_PROXY]) {
2619 proxy = strdup(data->set.str[STRING_PROXY]);
2620 /* if global proxy is set, this is it */
2622 failf(data, "memory shortage");
2623 result = CURLE_OUT_OF_MEMORY;
2628 if(data->set.str[STRING_PRE_PROXY]) {
2629 socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
2630 /* if global socks proxy is set, this is it */
2632 failf(data, "memory shortage");
2633 result = CURLE_OUT_OF_MEMORY;
2638 if(!data->set.str[STRING_NOPROXY]) {
2639 const char *p = "no_proxy";
2640 no_proxy = curl_getenv(p);
2643 no_proxy = curl_getenv(p);
2646 infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
2650 if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
2651 data->set.str[STRING_NOPROXY] : no_proxy)) {
2652 Curl_safefree(proxy);
2653 Curl_safefree(socksproxy);
2655 #ifndef CURL_DISABLE_HTTP
2656 else if(!proxy && !socksproxy)
2657 /* if the host is not in the noproxy list, detect proxy. */
2658 proxy = detect_proxy(data, conn);
2659 #endif /* CURL_DISABLE_HTTP */
2661 Curl_safefree(no_proxy);
2663 #ifdef USE_UNIX_SOCKETS
2664 /* For the time being do not mix proxy and unix domain sockets. See #1274 */
2665 if(proxy && conn->unix_domain_socket) {
2671 if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
2672 free(proxy); /* Don't bother with an empty proxy string or if the
2673 protocol doesn't work with network */
2676 if(socksproxy && (!*socksproxy ||
2677 (conn->handler->flags & PROTOPT_NONETWORK))) {
2678 free(socksproxy); /* Don't bother with an empty socks proxy string or if
2679 the protocol doesn't work with network */
2683 /***********************************************************************
2684 * If this is supposed to use a proxy, we need to figure out the proxy host
2685 * name, proxy type and port number, so that we can re-use an existing
2686 * connection that may exist registered to the same proxy host.
2687 ***********************************************************************/
2688 if(proxy || socksproxy) {
2689 curl_proxytype ptype = (curl_proxytype)conn->http_proxy.proxytype;
2691 result = parse_proxy(data, conn, proxy, ptype);
2692 Curl_safefree(proxy); /* parse_proxy copies the proxy string */
2698 result = parse_proxy(data, conn, socksproxy, ptype);
2699 /* parse_proxy copies the socks proxy string */
2700 Curl_safefree(socksproxy);
2705 if(conn->http_proxy.host.rawalloc) {
2706 #ifdef CURL_DISABLE_HTTP
2707 /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */
2708 result = CURLE_UNSUPPORTED_PROTOCOL;
2711 /* force this connection's protocol to become HTTP if compatible */
2712 if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) {
2713 if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) &&
2714 !conn->bits.tunnel_proxy)
2715 conn->handler = &Curl_handler_http;
2717 /* if not converting to HTTP over the proxy, enforce tunneling */
2718 conn->bits.tunnel_proxy = TRUE;
2720 conn->bits.httpproxy = TRUE;
2724 conn->bits.httpproxy = FALSE; /* not a HTTP proxy */
2725 conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
2728 if(conn->socks_proxy.host.rawalloc) {
2729 if(!conn->http_proxy.host.rawalloc) {
2730 /* once a socks proxy */
2731 if(!conn->socks_proxy.user) {
2732 conn->socks_proxy.user = conn->http_proxy.user;
2733 conn->http_proxy.user = NULL;
2734 Curl_safefree(conn->socks_proxy.passwd);
2735 conn->socks_proxy.passwd = conn->http_proxy.passwd;
2736 conn->http_proxy.passwd = NULL;
2739 conn->bits.socksproxy = TRUE;
2742 conn->bits.socksproxy = FALSE; /* not a socks proxy */
2745 conn->bits.socksproxy = FALSE;
2746 conn->bits.httpproxy = FALSE;
2748 conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
2750 if(!conn->bits.proxy) {
2751 /* we aren't using the proxy after all... */
2752 conn->bits.proxy = FALSE;
2753 conn->bits.httpproxy = FALSE;
2754 conn->bits.socksproxy = FALSE;
2755 conn->bits.proxy_user_passwd = FALSE;
2756 conn->bits.tunnel_proxy = FALSE;
2757 /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
2758 to signal that CURLPROXY_HTTPS is not used for this connection */
2759 conn->http_proxy.proxytype = CURLPROXY_HTTP;
2768 #endif /* CURL_DISABLE_PROXY */
2771 * Curl_parse_login_details()
2773 * This is used to parse a login string for user name, password and options in
2774 * the following formats:
2778 * user:password;options
2780 * user;options:password
2788 * login [in] - The login string.
2789 * len [in] - The length of the login string.
2790 * userp [in/out] - The address where a pointer to newly allocated memory
2791 * holding the user will be stored upon completion.
2792 * passwdp [in/out] - The address where a pointer to newly allocated memory
2793 * holding the password will be stored upon completion.
2794 * optionsp [in/out] - The address where a pointer to newly allocated memory
2795 * holding the options will be stored upon completion.
2797 * Returns CURLE_OK on success.
2799 CURLcode Curl_parse_login_details(const char *login, const size_t len,
2800 char **userp, char **passwdp,
2803 CURLcode result = CURLE_OK;
2807 const char *psep = NULL;
2808 const char *osep = NULL;
2813 /* the input length check is because this is called directly from setopt
2814 and isn't going through the regular string length check */
2815 size_t llen = strlen(login);
2816 if(llen > CURL_MAX_INPUT_LENGTH)
2817 return CURLE_BAD_FUNCTION_ARGUMENT;
2819 /* Attempt to find the password separator */
2821 psep = strchr(login, ':');
2823 /* Within the constraint of the login string */
2824 if(psep >= login + len)
2828 /* Attempt to find the options separator */
2830 osep = strchr(login, ';');
2832 /* Within the constraint of the login string */
2833 if(osep >= login + len)
2837 /* Calculate the portion lengths */
2839 (size_t)(osep && psep > osep ? osep - login : psep - login) :
2840 (osep ? (size_t)(osep - login) : len));
2842 (osep && osep > psep ? (size_t)(osep - psep) :
2843 (size_t)(login + len - psep)) - 1 : 0);
2845 (psep && psep > osep ? (size_t)(psep - osep) :
2846 (size_t)(login + len - osep)) - 1 : 0);
2848 /* Allocate the user portion buffer, which can be zero length */
2850 ubuf = malloc(ulen + 1);
2852 result = CURLE_OUT_OF_MEMORY;
2855 /* Allocate the password portion buffer */
2856 if(!result && passwdp && psep) {
2857 pbuf = malloc(plen + 1);
2860 result = CURLE_OUT_OF_MEMORY;
2864 /* Allocate the options portion buffer */
2865 if(!result && optionsp && olen) {
2866 obuf = malloc(olen + 1);
2870 result = CURLE_OUT_OF_MEMORY;
2875 /* Store the user portion if necessary */
2877 memcpy(ubuf, login, ulen);
2879 Curl_safefree(*userp);
2883 /* Store the password portion if necessary */
2885 memcpy(pbuf, psep + 1, plen);
2887 Curl_safefree(*passwdp);
2891 /* Store the options portion if necessary */
2893 memcpy(obuf, osep + 1, olen);
2895 Curl_safefree(*optionsp);
2903 /*************************************************************
2904 * Figure out the remote port number and fix it in the URL
2906 * No matter if we use a proxy or not, we have to figure out the remote
2907 * port number of various reasons.
2909 * The port number embedded in the URL is replaced, if necessary.
2910 *************************************************************/
2911 static CURLcode parse_remote_port(struct Curl_easy *data,
2912 struct connectdata *conn)
2915 if(data->set.use_port && data->state.allow_port) {
2916 /* if set, we use this instead of the port possibly given in the URL */
2919 conn->remote_port = data->set.use_port;
2920 msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port);
2921 uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
2923 return CURLE_OUT_OF_MEMORY;
2930 * Override the login details from the URL with that in the CURLOPT_USERPWD
2931 * option or a .netrc file, if applicable.
2933 static CURLcode override_login(struct Curl_easy *data,
2934 struct connectdata *conn)
2937 char **userp = &conn->user;
2938 char **passwdp = &conn->passwd;
2939 char **optionsp = &conn->options;
2941 if(data->set.str[STRING_OPTIONS]) {
2943 *optionsp = strdup(data->set.str[STRING_OPTIONS]);
2945 return CURLE_OUT_OF_MEMORY;
2948 #ifndef CURL_DISABLE_NETRC
2949 if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
2950 Curl_safefree(*userp);
2951 Curl_safefree(*passwdp);
2953 conn->bits.netrc = FALSE;
2954 if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
2956 bool url_provided = FALSE;
2958 if(data->state.aptr.user) {
2959 /* there was a user name in the URL. Use the URL decoded version */
2960 userp = &data->state.aptr.user;
2961 url_provided = TRUE;
2964 ret = Curl_parsenetrc(conn->host.name,
2966 data->set.str[STRING_NETRC_FILE]);
2968 infof(data, "Couldn't find host %s in the %s file; using defaults",
2969 conn->host.name, data->set.str[STRING_NETRC_FILE]);
2972 failf(data, ".netrc parser error");
2973 return CURLE_READ_ERROR;
2976 /* set bits.netrc TRUE to remember that we got the name from a .netrc
2977 file, so that it is safe to use even if we followed a Location: to a
2978 different host or similar. */
2979 conn->bits.netrc = TRUE;
2982 Curl_safefree(conn->user);
2983 conn->user = strdup(*userp);
2985 return CURLE_OUT_OF_MEMORY;
2987 /* no user was set but a password, set a blank user */
2988 if(userp && !*userp && *passwdp) {
2989 *userp = strdup("");
2991 return CURLE_OUT_OF_MEMORY;
2996 /* for updated strings, we update them in the URL */
2999 if(data->state.aptr.user != *userp) {
3000 /* nothing to do then */
3001 result = Curl_setstropt(&data->state.aptr.user, *userp);
3006 if(data->state.aptr.user) {
3007 uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
3010 return Curl_uc_to_curlcode(uc);
3012 *userp = strdup(data->state.aptr.user);
3014 return CURLE_OUT_OF_MEMORY;
3018 CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
3022 if(data->state.aptr.passwd) {
3023 uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
3024 data->state.aptr.passwd, CURLU_URLENCODE);
3026 return Curl_uc_to_curlcode(uc);
3028 *passwdp = strdup(data->state.aptr.passwd);
3030 return CURLE_OUT_OF_MEMORY;
3038 * Set the login details so they're available in the connection
3040 static CURLcode set_login(struct Curl_easy *data,
3041 struct connectdata *conn)
3043 CURLcode result = CURLE_OK;
3044 const char *setuser = CURL_DEFAULT_USER;
3045 const char *setpasswd = CURL_DEFAULT_PASSWORD;
3047 /* If our protocol needs a password and we have none, use the defaults */
3048 if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user)
3054 /* Store the default user */
3056 conn->user = strdup(setuser);
3058 return CURLE_OUT_OF_MEMORY;
3061 /* Store the default password */
3063 conn->passwd = strdup(setpasswd);
3065 result = CURLE_OUT_OF_MEMORY;
3072 * Parses a "host:port" string to connect to.
3073 * The hostname and the port may be empty; in this case, NULL is returned for
3074 * the hostname and -1 for the port.
3076 static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
3078 char **hostname_result,
3086 CURLcode result = CURLE_OK;
3088 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
3092 *hostname_result = NULL;
3098 host_dup = strdup(host);
3100 return CURLE_OUT_OF_MEMORY;
3104 /* start scanning for port number at this point */
3107 /* detect and extract RFC6874-style IPv6-addresses */
3108 if(*hostptr == '[') {
3110 char *ptr = ++hostptr; /* advance beyond the initial bracket */
3111 while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
3114 /* There might be a zone identifier */
3115 if(strncmp("%25", ptr, 3))
3116 infof(data, "Please URL encode %% as %%25, see RFC 6874.");
3118 /* Allow unreserved characters as defined in RFC 3986 */
3119 while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
3120 (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
3124 /* yeps, it ended nicely with a bracket as well */
3127 infof(data, "Invalid IPv6 address format");
3129 /* Note that if this didn't end with a bracket, we still advanced the
3130 * hostptr first, but I can't see anything wrong with that as no host
3131 * name nor a numeric can legally start with a bracket.
3134 failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
3135 result = CURLE_NOT_BUILT_IN;
3140 /* Get port number off server.com:1080 */
3141 host_portno = strchr(portptr, ':');
3144 *host_portno = '\0'; /* cut off number from host name */
3147 long portparse = strtol(host_portno, &endp, 10);
3148 if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
3149 failf(data, "No valid port number in connect to host string (%s)",
3151 result = CURLE_SETOPT_OPTION_SYNTAX;
3155 port = (int)portparse; /* we know it will fit */
3159 /* now, clone the cleaned host name */
3161 *hostname_result = strdup(hostptr);
3162 if(!*hostname_result) {
3163 result = CURLE_OUT_OF_MEMORY;
3168 *port_result = port;
3176 * Parses one "connect to" string in the form:
3177 * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
3179 static CURLcode parse_connect_to_string(struct Curl_easy *data,
3180 struct connectdata *conn,
3181 const char *conn_to_host,
3185 CURLcode result = CURLE_OK;
3186 const char *ptr = conn_to_host;
3187 int host_match = FALSE;
3188 int port_match = FALSE;
3190 *host_result = NULL;
3194 /* an empty hostname always matches */
3199 /* check whether the URL's hostname matches */
3200 size_t hostname_to_match_len;
3201 char *hostname_to_match = aprintf("%s%s%s",
3202 conn->bits.ipv6_ip ? "[" : "",
3204 conn->bits.ipv6_ip ? "]" : "");
3205 if(!hostname_to_match)
3206 return CURLE_OUT_OF_MEMORY;
3207 hostname_to_match_len = strlen(hostname_to_match);
3208 host_match = strncasecompare(ptr, hostname_to_match,
3209 hostname_to_match_len);
3210 free(hostname_to_match);
3211 ptr += hostname_to_match_len;
3213 host_match = host_match && *ptr == ':';
3219 /* an empty port always matches */
3224 /* check whether the URL's port matches */
3225 char *ptr_next = strchr(ptr, ':');
3228 long port_to_match = strtol(ptr, &endp, 10);
3229 if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
3237 if(host_match && port_match) {
3238 /* parse the hostname and port to connect to */
3239 result = parse_connect_to_host_port(data, ptr, host_result, port_result);
3246 * Processes all strings in the "connect to" slist, and uses the "connect
3247 * to host" and "connect to port" of the first string that matches.
3249 static CURLcode parse_connect_to_slist(struct Curl_easy *data,
3250 struct connectdata *conn,
3251 struct curl_slist *conn_to_host)
3253 CURLcode result = CURLE_OK;
3257 while(conn_to_host && !host && port == -1) {
3258 result = parse_connect_to_string(data, conn, conn_to_host->data,
3264 conn->conn_to_host.rawalloc = host;
3265 conn->conn_to_host.name = host;
3266 conn->bits.conn_to_host = TRUE;
3268 infof(data, "Connecting to hostname: %s", host);
3271 /* no "connect to host" */
3272 conn->bits.conn_to_host = FALSE;
3273 Curl_safefree(host);
3277 conn->conn_to_port = port;
3278 conn->bits.conn_to_port = TRUE;
3279 infof(data, "Connecting to port: %d", port);
3282 /* no "connect to port" */
3283 conn->bits.conn_to_port = FALSE;
3287 conn_to_host = conn_to_host->next;
3290 #ifndef CURL_DISABLE_ALTSVC
3291 if(data->asi && !host && (port == -1) &&
3292 ((conn->handler->protocol == CURLPROTO_HTTPS) ||
3294 /* allow debug builds to circumvent the HTTPS restriction */
3295 getenv("CURL_ALTSVC_HTTP")
3300 /* no connect_to match, try alt-svc! */
3301 enum alpnid srcalpnid;
3304 const int allowed_versions = ( ALPN_h1
3311 ) & data->asi->flags;
3313 host = conn->host.rawalloc;
3315 /* with h2 support, check that first */
3316 srcalpnid = ALPN_h2;
3317 hit = Curl_altsvc_lookup(data->asi,
3318 srcalpnid, host, conn->remote_port, /* from */
3324 srcalpnid = ALPN_h1;
3325 hit = Curl_altsvc_lookup(data->asi,
3326 srcalpnid, host, conn->remote_port, /* from */
3331 char *hostd = strdup((char *)as->dst.host);
3333 return CURLE_OUT_OF_MEMORY;
3334 conn->conn_to_host.rawalloc = hostd;
3335 conn->conn_to_host.name = hostd;
3336 conn->bits.conn_to_host = TRUE;
3337 conn->conn_to_port = as->dst.port;
3338 conn->bits.conn_to_port = TRUE;
3339 conn->bits.altused = TRUE;
3340 infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d",
3341 Curl_alpnid2str(srcalpnid), host, conn->remote_port,
3342 Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
3343 if(srcalpnid != as->dst.alpnid) {
3344 /* protocol version switch */
3345 switch(as->dst.alpnid) {
3347 conn->httpversion = 11;
3350 conn->httpversion = 20;
3353 conn->transport = TRNSPRT_QUIC;
3354 conn->httpversion = 30;
3356 default: /* shouldn't be possible */
3367 #ifdef USE_UNIX_SOCKETS
3368 static CURLcode resolve_unix(struct Curl_easy *data,
3369 struct connectdata *conn,
3372 struct Curl_dns_entry *hostaddr = NULL;
3373 bool longpath = FALSE;
3375 DEBUGASSERT(unix_path);
3376 DEBUGASSERT(conn->dns_entry == NULL);
3378 /* Unix domain sockets are local. The host gets ignored, just use the
3379 * specified domain socket address. Do not cache "DNS entries". There is
3380 * no DNS involved and we already have the filesystem path available. */
3381 hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
3383 return CURLE_OUT_OF_MEMORY;
3385 hostaddr->addr = Curl_unix2addr(unix_path, &longpath,
3386 conn->bits.abstract_unix_socket);
3387 if(!hostaddr->addr) {
3389 /* Long paths are not supported for now */
3390 failf(data, "Unix socket path too long: '%s'", unix_path);
3392 return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY;
3396 conn->dns_entry = hostaddr;
3401 #ifndef CURL_DISABLE_PROXY
3402 static CURLcode resolve_proxy(struct Curl_easy *data,
3403 struct connectdata *conn,
3406 struct Curl_dns_entry *hostaddr = NULL;
3407 struct hostname *host;
3408 timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
3411 DEBUGASSERT(conn->dns_entry == NULL);
3413 host = conn->bits.socksproxy ? &conn->socks_proxy.host :
3414 &conn->http_proxy.host;
3416 conn->hostname_resolve = strdup(host->name);
3417 if(!conn->hostname_resolve)
3418 return CURLE_OUT_OF_MEMORY;
3420 rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
3421 &hostaddr, timeout_ms);
3422 conn->dns_entry = hostaddr;
3423 if(rc == CURLRESOLV_PENDING)
3425 else if(rc == CURLRESOLV_TIMEDOUT)
3426 return CURLE_OPERATION_TIMEDOUT;
3427 else if(!hostaddr) {
3428 failf(data, "Couldn't resolve proxy '%s'", host->dispname);
3429 return CURLE_COULDNT_RESOLVE_PROXY;
3436 static CURLcode resolve_host(struct Curl_easy *data,
3437 struct connectdata *conn,
3440 struct Curl_dns_entry *hostaddr = NULL;
3441 struct hostname *connhost;
3442 timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
3445 DEBUGASSERT(conn->dns_entry == NULL);
3447 connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
3449 /* If not connecting via a proxy, extract the port from the URL, if it is
3450 * there, thus overriding any defaults that might have been set above. */
3451 conn->port = conn->bits.conn_to_port ? conn->conn_to_port :
3454 /* Resolve target host right on */
3455 conn->hostname_resolve = strdup(connhost->name);
3456 if(!conn->hostname_resolve)
3457 return CURLE_OUT_OF_MEMORY;
3459 rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
3460 &hostaddr, timeout_ms);
3461 conn->dns_entry = hostaddr;
3462 if(rc == CURLRESOLV_PENDING)
3464 else if(rc == CURLRESOLV_TIMEDOUT) {
3465 failf(data, "Failed to resolve host '%s' with timeout after %ld ms",
3467 Curl_timediff(Curl_now(), data->progress.t_startsingle));
3468 return CURLE_OPERATION_TIMEDOUT;
3470 else if(!hostaddr) {
3471 failf(data, "Could not resolve host: %s", connhost->dispname);
3472 return CURLE_COULDNT_RESOLVE_HOST;
3478 /* Perform a fresh resolve */
3479 static CURLcode resolve_fresh(struct Curl_easy *data,
3480 struct connectdata *conn,
3483 #ifdef USE_UNIX_SOCKETS
3484 char *unix_path = conn->unix_domain_socket;
3486 #ifndef CURL_DISABLE_PROXY
3487 if(!unix_path && conn->socks_proxy.host.name &&
3488 !strncmp(UNIX_SOCKET_PREFIX"/",
3489 conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
3490 unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
3494 conn->transport = TRNSPRT_UNIX;
3495 return resolve_unix(data, conn, unix_path);
3499 #ifndef CURL_DISABLE_PROXY
3500 if(CONN_IS_PROXIED(conn))
3501 return resolve_proxy(data, conn, async);
3504 return resolve_host(data, conn, async);
3507 /*************************************************************
3508 * Resolve the address of the server or proxy
3509 *************************************************************/
3510 static CURLcode resolve_server(struct Curl_easy *data,
3511 struct connectdata *conn,
3517 /* Resolve the name of the server or proxy */
3518 if(conn->bits.reuse) {
3519 /* We're reusing the connection - no need to resolve anything, and
3520 idnconvert_hostname() was called already in create_conn() for the re-use
3526 return resolve_fresh(data, conn, async);
3530 * Cleanup the connection just allocated before we can move along and use the
3531 * previously existing one. All relevant data is copied over and old_conn is
3532 * ready for freeing once this function returns.
3534 static void reuse_conn(struct Curl_easy *data,
3535 struct connectdata *old_conn,
3536 struct connectdata *conn)
3538 /* 'local_ip' and 'local_port' get filled with local's numerical
3539 ip address and port number whenever an outgoing connection is
3540 **established** from the primary socket to a remote address. */
3541 char local_ip[MAX_IPADR_LEN] = "";
3542 int local_port = -1;
3544 /* get the user+password information from the old_conn struct since it may
3545 * be new for this request even when we re-use an existing connection */
3546 if(old_conn->user) {
3547 /* use the new user name and password though */
3548 Curl_safefree(conn->user);
3549 Curl_safefree(conn->passwd);
3550 conn->user = old_conn->user;
3551 conn->passwd = old_conn->passwd;
3552 old_conn->user = NULL;
3553 old_conn->passwd = NULL;
3556 #ifndef CURL_DISABLE_PROXY
3557 conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
3558 if(conn->bits.proxy_user_passwd) {
3559 /* use the new proxy user name and proxy password though */
3560 Curl_safefree(conn->http_proxy.user);
3561 Curl_safefree(conn->socks_proxy.user);
3562 Curl_safefree(conn->http_proxy.passwd);
3563 Curl_safefree(conn->socks_proxy.passwd);
3564 conn->http_proxy.user = old_conn->http_proxy.user;
3565 conn->socks_proxy.user = old_conn->socks_proxy.user;
3566 conn->http_proxy.passwd = old_conn->http_proxy.passwd;
3567 conn->socks_proxy.passwd = old_conn->socks_proxy.passwd;
3568 old_conn->http_proxy.user = NULL;
3569 old_conn->socks_proxy.user = NULL;
3570 old_conn->http_proxy.passwd = NULL;
3571 old_conn->socks_proxy.passwd = NULL;
3575 Curl_free_idnconverted_hostname(&conn->host);
3576 Curl_free_idnconverted_hostname(&conn->conn_to_host);
3577 Curl_safefree(conn->host.rawalloc);
3578 Curl_safefree(conn->conn_to_host.rawalloc);
3579 conn->host = old_conn->host;
3580 old_conn->host.rawalloc = NULL;
3581 old_conn->host.encalloc = NULL;
3582 conn->conn_to_host = old_conn->conn_to_host;
3583 old_conn->conn_to_host.rawalloc = NULL;
3584 conn->conn_to_port = old_conn->conn_to_port;
3585 conn->remote_port = old_conn->remote_port;
3586 Curl_safefree(conn->hostname_resolve);
3588 conn->hostname_resolve = old_conn->hostname_resolve;
3589 old_conn->hostname_resolve = NULL;
3591 /* persist connection info in session handle */
3592 if(conn->transport == TRNSPRT_TCP) {
3593 Curl_conninfo_local(data, conn->sock[FIRSTSOCKET],
3594 local_ip, &local_port);
3596 Curl_persistconninfo(data, conn, local_ip, local_port);
3598 conn_reset_all_postponed_data(old_conn); /* free buffers */
3601 conn->bits.reuse = TRUE; /* yes, we're re-using here */
3603 conn_free(old_conn);
3607 * create_conn() sets up a new connectdata struct, or re-uses an already
3608 * existing one, and resolves host name.
3610 * if this function returns CURLE_OK and *async is set to TRUE, the resolve
3611 * response will be coming asynchronously. If *async is FALSE, the name is
3614 * @param data The sessionhandle pointer
3615 * @param in_connect is set to the next connection data pointer
3616 * @param async is set TRUE when an async DNS resolution is pending
3617 * @see Curl_setup_conn()
3621 static CURLcode create_conn(struct Curl_easy *data,
3622 struct connectdata **in_connect,
3625 CURLcode result = CURLE_OK;
3626 struct connectdata *conn;
3627 struct connectdata *conn_temp = NULL;
3629 bool connections_available = TRUE;
3630 bool force_reuse = FALSE;
3631 bool waitpipe = FALSE;
3632 size_t max_host_connections = Curl_multi_max_host_connections(data->multi);
3633 size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
3638 /*************************************************************
3640 *************************************************************/
3641 if(!data->state.url) {
3642 result = CURLE_URL_MALFORMAT;
3646 /* First, split up the current URL in parts so that we can use the
3647 parts for checking against the already present connections. In order
3648 to not have to modify everything at once, we allocate a temporary
3649 connection data struct and fill in for comparison purposes. */
3650 conn = allocate_conn(data);
3653 result = CURLE_OUT_OF_MEMORY;
3657 /* We must set the return variable as soon as possible, so that our
3658 parent can cleanup any possible allocs we may have done before
3662 result = parseurlandfillconn(data, conn);
3666 if(data->set.str[STRING_SASL_AUTHZID]) {
3667 conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
3668 if(!conn->sasl_authzid) {
3669 result = CURLE_OUT_OF_MEMORY;
3674 if(data->set.str[STRING_BEARER]) {
3675 conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
3676 if(!conn->oauth_bearer) {
3677 result = CURLE_OUT_OF_MEMORY;
3682 #ifdef USE_UNIX_SOCKETS
3683 if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
3684 conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
3685 if(!conn->unix_domain_socket) {
3686 result = CURLE_OUT_OF_MEMORY;
3689 conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
3693 /* After the unix socket init but before the proxy vars are used, parse and
3694 initialize the proxy vars */
3695 #ifndef CURL_DISABLE_PROXY
3696 result = create_conn_helper_init_proxy(data, conn);
3700 /*************************************************************
3701 * If the protocol is using SSL and HTTP proxy is used, we set
3702 * the tunnel_proxy bit.
3703 *************************************************************/
3704 if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
3705 conn->bits.tunnel_proxy = TRUE;
3708 /*************************************************************
3709 * Figure out the remote port number and fix it in the URL
3710 *************************************************************/
3711 result = parse_remote_port(data, conn);
3715 /* Check for overridden login details and set them accordingly so that
3716 they are known when protocol->setup_connection is called! */
3717 result = override_login(data, conn);
3721 result = set_login(data, conn); /* default credentials */
3725 /*************************************************************
3726 * Process the "connect to" linked list of hostname/port mappings.
3727 * Do this after the remote port number has been fixed in the URL.
3728 *************************************************************/
3729 result = parse_connect_to_slist(data, conn, data->set.connect_to);
3734 /*************************************************************
3735 * Check whether the host and the "connect to host" are equal.
3736 * Do this after the hostnames have been IDN-converted.
3737 *************************************************************/
3738 if(conn->bits.conn_to_host &&
3739 strcasecompare(conn->conn_to_host.name, conn->host.name)) {
3740 conn->bits.conn_to_host = FALSE;
3743 /*************************************************************
3744 * Check whether the port and the "connect to port" are equal.
3745 * Do this after the remote port number has been fixed in the URL.
3746 *************************************************************/
3747 if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
3748 conn->bits.conn_to_port = FALSE;
3751 #ifndef CURL_DISABLE_PROXY
3752 /*************************************************************
3753 * If the "connect to" feature is used with an HTTP proxy,
3754 * we set the tunnel_proxy bit.
3755 *************************************************************/
3756 if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
3757 conn->bits.httpproxy)
3758 conn->bits.tunnel_proxy = TRUE;
3761 /*************************************************************
3762 * Setup internals depending on protocol. Needs to be done after
3763 * we figured out what/if proxy to use.
3764 *************************************************************/
3765 result = setup_connection_internals(data, conn);
3769 conn->recv[FIRSTSOCKET] = Curl_recv_plain;
3770 conn->send[FIRSTSOCKET] = Curl_send_plain;
3771 conn->recv[SECONDARYSOCKET] = Curl_recv_plain;
3772 conn->send[SECONDARYSOCKET] = Curl_send_plain;
3774 conn->bits.tcp_fastopen = data->set.tcp_fastopen;
3776 /***********************************************************************
3777 * file: is a special case in that it doesn't need a network connection
3778 ***********************************************************************/
3779 #ifndef CURL_DISABLE_FILE
3780 if(conn->handler->flags & PROTOPT_NONETWORK) {
3782 /* this is supposed to be the connect function so we better at least check
3783 that the file is present here! */
3784 DEBUGASSERT(conn->handler->connect_it);
3785 Curl_persistconninfo(data, conn, NULL, -1);
3786 result = conn->handler->connect_it(data, &done);
3788 /* Setup a "faked" transfer that'll do nothing */
3790 conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */
3792 Curl_attach_connection(data, conn);
3793 result = Curl_conncache_add_conn(data);
3798 * Setup whatever necessary for a resumed transfer
3800 result = setup_range(data);
3802 DEBUGASSERT(conn->handler->done);
3803 /* we ignore the return code for the protocol-specific DONE */
3804 (void)conn->handler->done(data, result, FALSE);
3807 Curl_setup_transfer(data, -1, -1, FALSE, -1);
3810 /* since we skip do_init() */
3811 Curl_init_do(data, conn);
3817 /* Get a cloned copy of the SSL config situation stored in the
3818 connection struct. But to get this going nicely, we must first make
3819 sure that the strings in the master copy are pointing to the correct
3820 strings in the session handle strings array!
3822 Keep in mind that the pointers in the master copy are pointing to strings
3823 that will be freed as part of the Curl_easy struct, but all cloned
3824 copies will be separately allocated.
3826 data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH];
3827 data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE];
3828 data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
3829 data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
3830 data->set.ssl.primary.cipher_list =
3831 data->set.str[STRING_SSL_CIPHER_LIST];
3832 data->set.ssl.primary.cipher_list13 =
3833 data->set.str[STRING_SSL_CIPHER13_LIST];
3834 data->set.ssl.primary.pinned_key =
3835 data->set.str[STRING_SSL_PINNEDPUBLICKEY];
3836 data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT];
3837 data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
3838 data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES];
3840 #ifndef CURL_DISABLE_PROXY
3841 data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
3842 data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
3843 data->set.proxy_ssl.primary.cipher_list =
3844 data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
3845 data->set.proxy_ssl.primary.cipher_list13 =
3846 data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
3847 data->set.proxy_ssl.primary.pinned_key =
3848 data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
3849 data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
3850 data->set.proxy_ssl.primary.ca_info_blob =
3851 data->set.blobs[BLOB_CAINFO_PROXY];
3852 data->set.proxy_ssl.primary.issuercert =
3853 data->set.str[STRING_SSL_ISSUERCERT_PROXY];
3854 data->set.proxy_ssl.primary.issuercert_blob =
3855 data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
3856 data->set.proxy_ssl.primary.CRLfile =
3857 data->set.str[STRING_SSL_CRLFILE_PROXY];
3858 data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
3859 data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
3860 data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
3861 data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
3862 data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
3863 data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
3865 data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE];
3866 data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE];
3867 data->set.ssl.key = data->set.str[STRING_KEY];
3868 data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE];
3869 data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD];
3870 data->set.ssl.primary.clientcert = data->set.str[STRING_CERT];
3872 data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME];
3873 data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD];
3874 #ifndef CURL_DISABLE_PROXY
3875 data->set.proxy_ssl.primary.username =
3876 data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
3877 data->set.proxy_ssl.primary.password =
3878 data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
3881 data->set.ssl.key_blob = data->set.blobs[BLOB_KEY];
3883 if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary,
3884 &conn->ssl_config)) {
3885 result = CURLE_OUT_OF_MEMORY;
3889 #ifndef CURL_DISABLE_PROXY
3890 if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary,
3891 &conn->proxy_ssl_config)) {
3892 result = CURLE_OUT_OF_MEMORY;
3897 prune_dead_connections(data);
3899 /*************************************************************
3900 * Check the current list of connections to see if we can
3901 * re-use an already existing one or if we have to create a
3903 *************************************************************/
3905 DEBUGASSERT(conn->user);
3906 DEBUGASSERT(conn->passwd);
3908 /* reuse_fresh is TRUE if we are told to use a new connection by force, but
3909 we only acknowledge this option if this is not a re-used connection
3910 already (which happens due to follow-location or during a HTTP
3911 authentication phase). CONNECT_ONLY transfers also refuse reuse. */
3912 if((data->set.reuse_fresh && !data->state.this_is_a_follow) ||
3913 data->set.connect_only)
3916 reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe);
3920 * We already have a connection for this, we got the former connection in
3921 * the conn_temp variable and thus we need to cleanup the one we just
3922 * allocated before we can move along and use the previously existing one.
3924 reuse_conn(data, conn, conn_temp);
3928 #ifndef CURL_DISABLE_PROXY
3929 infof(data, "Re-using existing connection #%ld with %s %s",
3930 conn->connection_id,
3931 conn->bits.proxy?"proxy":"host",
3932 conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
3933 conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
3934 conn->host.dispname);
3936 infof(data, "Re-using existing connection #%ld with host %s",
3937 conn->connection_id, conn->host.dispname);
3941 /* We have decided that we want a new connection. However, we may not
3942 be able to do that if we have reached the limit of how many
3943 connections we are allowed to open. */
3945 if(conn->handler->flags & PROTOPT_ALPN) {
3946 /* The protocol wants it, so set the bits if enabled in the easy handle
3948 if(data->set.ssl_enable_alpn)
3949 conn->bits.tls_enable_alpn = TRUE;
3953 /* There is a connection that *might* become usable for multiplexing
3954 "soon", and we wait for that */
3955 connections_available = FALSE;
3957 /* this gets a lock on the conncache */
3958 struct connectbundle *bundle =
3959 Curl_conncache_find_bundle(data, conn, data->state.conn_cache);
3961 if(max_host_connections > 0 && bundle &&
3962 (bundle->num_connections >= max_host_connections)) {
3963 struct connectdata *conn_candidate;
3965 /* The bundle is full. Extract the oldest connection. */
3966 conn_candidate = Curl_conncache_extract_bundle(data, bundle);
3967 CONNCACHE_UNLOCK(data);
3970 Curl_disconnect(data, conn_candidate, FALSE);
3972 infof(data, "No more connections allowed to host: %zu",
3973 max_host_connections);
3974 connections_available = FALSE;
3978 CONNCACHE_UNLOCK(data);
3982 if(connections_available &&
3983 (max_total_connections > 0) &&
3984 (Curl_conncache_size(data) >= max_total_connections)) {
3985 struct connectdata *conn_candidate;
3987 /* The cache is full. Let's see if we can kill a connection. */
3988 conn_candidate = Curl_conncache_extract_oldest(data);
3990 Curl_disconnect(data, conn_candidate, FALSE);
3992 infof(data, "No connections available in cache");
3993 connections_available = FALSE;
3997 if(!connections_available) {
3998 infof(data, "No connections available.");
4003 result = CURLE_NO_CONNECTION_AVAILABLE;
4008 * This is a brand new connection, so let's store it in the connection
4011 Curl_attach_connection(data, conn);
4012 result = Curl_conncache_add_conn(data);
4017 #if defined(USE_NTLM)
4018 /* If NTLM is requested in a part of this connection, make sure we don't
4019 assume the state is fine as this is a fresh connection and NTLM is
4020 connection based. */
4021 if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
4022 data->state.authhost.done) {
4023 infof(data, "NTLM picked AND auth done set, clear picked");
4024 data->state.authhost.picked = CURLAUTH_NONE;
4025 data->state.authhost.done = FALSE;
4028 if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
4029 data->state.authproxy.done) {
4030 infof(data, "NTLM-proxy picked AND auth done set, clear picked");
4031 data->state.authproxy.picked = CURLAUTH_NONE;
4032 data->state.authproxy.done = FALSE;
4037 /* Setup and init stuff before DO starts, in preparing for the transfer. */
4038 Curl_init_do(data, conn);
4041 * Setup whatever necessary for a resumed transfer
4043 result = setup_range(data);
4047 /* Continue connectdata initialization here. */
4050 * Inherit the proper values from the urldata struct AFTER we have arranged
4051 * the persistent connection stuff
4053 conn->seek_func = data->set.seek_func;
4054 conn->seek_client = data->set.seek_client;
4056 /*************************************************************
4057 * Resolve the address of the server or proxy
4058 *************************************************************/
4059 result = resolve_server(data, conn, async);
4065 /* Curl_setup_conn() is called after the name resolve initiated in
4066 * create_conn() is all done.
4068 * Curl_setup_conn() also handles reused connections
4070 CURLcode Curl_setup_conn(struct Curl_easy *data,
4071 bool *protocol_done)
4073 CURLcode result = CURLE_OK;
4074 struct connectdata *conn = data->conn;
4076 Curl_pgrsTime(data, TIMER_NAMELOOKUP);
4078 if(conn->handler->flags & PROTOPT_NONETWORK) {
4079 /* nothing to setup when not using a network */
4080 *protocol_done = TRUE;
4083 *protocol_done = FALSE; /* default to not done */
4085 #ifndef CURL_DISABLE_PROXY
4086 /* set proxy_connect_closed to false unconditionally already here since it
4087 is used strictly to provide extra information to a parent function in the
4088 case of proxy CONNECT failures and we must make sure we don't have it
4089 lingering set from a previous invoke */
4090 conn->bits.proxy_connect_closed = FALSE;
4093 #ifdef CURL_DO_LINEEND_CONV
4094 data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
4095 #endif /* CURL_DO_LINEEND_CONV */
4097 /* set start time here for timeout purposes in the connect procedure, it
4098 is later set again for the progress meter purpose */
4099 conn->now = Curl_now();
4101 if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
4102 conn->bits.tcpconnect[FIRSTSOCKET] = FALSE;
4103 result = Curl_connecthost(data, conn, conn->dns_entry);
4108 Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
4109 if(conn->ssl[FIRSTSOCKET].use ||
4110 (conn->handler->protocol & PROTO_FAMILY_SSH))
4111 Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
4112 conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
4113 *protocol_done = TRUE;
4114 Curl_updateconninfo(data, conn, conn->sock[FIRSTSOCKET]);
4115 Curl_verboseconnect(data, conn);
4118 conn->now = Curl_now(); /* time this *after* the connect is done, we set
4119 this here perhaps a second time */
4123 CURLcode Curl_connect(struct Curl_easy *data,
4125 bool *protocol_done)
4128 struct connectdata *conn;
4130 *asyncp = FALSE; /* assume synchronous resolves by default */
4132 /* init the single-transfer specific data */
4133 Curl_free_request_state(data);
4134 memset(&data->req, 0, sizeof(struct SingleRequest));
4135 data->req.size = data->req.maxdownload = -1;
4137 /* call the stuff that needs to be called */
4138 result = create_conn(data, &conn, asyncp);
4141 if(CONN_INUSE(conn) > 1)
4143 *protocol_done = TRUE;
4145 /* DNS resolution is done: that's either because this is a reused
4146 connection, in which case DNS was unnecessary, or because DNS
4147 really did finish already (synch resolver/fast async resolve) */
4148 result = Curl_setup_conn(data, protocol_done);
4152 if(result == CURLE_NO_CONNECTION_AVAILABLE) {
4155 else if(result && conn) {
4156 /* We're not allowed to return failure with memory left allocated in the
4157 connectdata struct, free those here */
4158 Curl_detach_connection(data);
4159 Curl_conncache_remove_conn(data, conn, TRUE);
4160 Curl_disconnect(data, conn, TRUE);
4167 * Curl_init_do() inits the readwrite session. This is inited each time (in
4168 * the DO function before the protocol-specific DO functions are invoked) for
4169 * a transfer, sometimes multiple times on the same Curl_easy. Make sure
4170 * nothing in here depends on stuff that are setup dynamically for the
4173 * Allow this function to get called with 'conn' set to NULL.
4176 CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
4178 struct SingleRequest *k = &data->req;
4180 /* if this is a pushed stream, we need this: */
4181 CURLcode result = Curl_preconnect(data);
4186 conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
4188 /* if the protocol used doesn't support wildcards, switch it off */
4189 if(data->state.wildcardmatch &&
4190 !(conn->handler->flags & PROTOPT_WILDCARD))
4191 data->state.wildcardmatch = FALSE;
4194 data->state.done = FALSE; /* *_done() is not called yet */
4195 data->state.expect100header = FALSE;
4197 if(data->set.opt_no_body)
4198 /* in HTTP lingo, no body means using the HEAD request... */
4199 data->state.httpreq = HTTPREQ_HEAD;
4201 k->start = Curl_now(); /* start time */
4202 k->now = k->start; /* current time is now */
4203 k->header = TRUE; /* assume header */
4205 k->ignorebody = FALSE;
4207 Curl_speedinit(data);
4208 Curl_pgrsSetUploadCounter(data, 0);
4209 Curl_pgrsSetDownloadCounter(data, 0);