Index: trunk/src/libs/curl-8.7.1/COPYING
===================================================================
--- trunk/src/libs/curl-8.7.1/COPYING	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/COPYING	(revision 104083)
@@ -0,0 +1,22 @@
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1996 - 2024, Daniel Stenberg, <daniel@haxx.se>, and many
+contributors, see the THANKS file.
+
+All rights reserved.
+
+Permission to use, copy, modify, and distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright
+notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
+NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization of the copyright holder.
Index: trunk/src/libs/curl-8.7.1/Makefile.kmk
===================================================================
--- trunk/src/libs/curl-8.7.1/Makefile.kmk	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/Makefile.kmk	(revision 104083)
@@ -0,0 +1,184 @@
+# $Id$
+## @file
+# Sub-Makefile for the libcurl library.
+#
+
+#
+# Copyright (C) 2009-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+SUB_DEPTH = ../../..
+include $(KBUILD_PATH)/subheader.kmk
+VBOX_PATH_LIBCURL = $(PATH_ROOT)/src/libs/curl-8.7.1
+
+LIBRARIES += VBox-libcurl
+VBox-libcurl_TEMPLATE       = VBoxR3RuntimeDllNonPedantic
+VBox-libcurl_SDKS           = VBoxZlib VBoxOpenSslStatic
+VBox-libcurl_DEFS           = \
+	CURL_STATICLIB \
+	OPENSSL_NO_ENGINE \
+	BUILDING_LIBCURL \
+	HAVE_CONFIG_H \
+	CURL_DISABLE_ALTSVC \
+	CURL_DISABLE_GOPHER \
+	CURL_DISABLE_FILE \
+	CURL_DISABLE_DICT \
+	CURL_DISABLE_HSTS \
+	CURL_DISABLE_IMAP \
+	CURL_DISABLE_MQTT \
+	CURL_DISABLE_NTLM \
+	CURL_DISABLE_POP3 \
+	CURL_DISABLE_RTSP \
+	CURL_DISABLE_SMTP \
+	CURL_DISABLE_TELNET
+VBox-libcurl_CFLAGS.win    += -wd4826 # formdata.c(390) : warning C4826: Conversion from 'char *' to 'curl_off_t' is sign-extended. This may cause unexpected runtime behavior.
+VBox-libcurl_CFLAGS.win    += -wd4310 # warnless.c(189) : warning C4310: cast truncates constant value
+VBox-libcurl_CFLAGS.win    += -wd4090 # openssl/lhash.h(198) : warning C4090: 'function' : different 'const' qualifiers
+VBox-libcurl_CFLAGS.win    += -wd4060 # curl-7.87.0/lib/connect.c(1588): warning C4060: switch statement contains no 'case' or 'default' labels
+if "$(VBOX_VCC_TOOL_STEM)" >= "VCC140"
+ VBox-libcurl_CFLAGS.win   += -wd4774 # mprintf.c(949): warning C4774: 'sprintf' : format string expected in argument 2 is not a string literal
+endif
+VBox-libcurl_INCS           = \
+	include \
+	$(VBox-libcurl_0_OUTDIR)/lib \
+	$(VBOX_PATH_LIBCURL)/lib
+VBox-libcurl_SOURCES        = \
+	lib/base64.c \
+	lib/bufq.c \
+	lib/bufref.c \
+	lib/conncache.c \
+	lib/connect.c \
+	lib/content_encoding.c \
+	lib/cookie.c \
+	lib/cf-haproxy.c \
+	lib/cf-h1-proxy.c \
+	lib/cf-https-connect.c \
+	lib/cf-socket.c \
+	lib/cfilters.c \
+	lib/curl_addrinfo.c \
+	lib/curl_get_line.c \
+	lib/curl_fnmatch.c \
+	lib/curl_memrchr.c \
+	lib/curl_range.c \
+	lib/curl_sasl.c \
+	lib/curl_trc.c \
+	lib/doh.c \
+	lib/dynbuf.c \
+	lib/dynhds.c \
+	lib/easy.c \
+	lib/escape.c \
+	lib/fileinfo.c \
+	lib/fopen.c \
+	lib/formdata.c \
+	lib/ftp.c \
+	lib/ftplistparser.c \
+	lib/getenv.c \
+	lib/getinfo.c \
+	lib/hash.c \
+	lib/headers.c \
+	lib/hmac.c \
+	lib/hostip.c \
+	lib/hostip4.c \
+	lib/hostip6.c \
+	lib/hostsyn.c \
+	lib/http.c \
+	lib/http1.c \
+	lib/http_aws_sigv4.c \
+	lib/http_chunks.c \
+	lib/http_digest.c \
+	lib/http_proxy.c \
+	lib/if2ip.c \
+	lib/idn.c \
+	lib/inet_ntop.c \
+	lib/inet_pton.c \
+	lib/llist.c \
+	lib/md5.c \
+	lib/mime.c \
+	lib/mprintf.c \
+	lib/multi.c \
+	lib/netrc.c \
+	lib/nonblock.c \
+	lib/noproxy.c \
+	lib/parsedate.c \
+	lib/pingpong.c \
+	lib/progress.c \
+	lib/rand.c \
+	lib/rename.c \
+	lib/select.c \
+	lib/sendf.c \
+	lib/setopt.c \
+	lib/sha256.c \
+	lib/share.c \
+	lib/slist.c \
+	lib/socketpair.c \
+	lib/socks.c \
+	lib/speedcheck.c \
+	lib/splay.c \
+	lib/strcase.c \
+	lib/strdup.c \
+	lib/strerror.c \
+	lib/strtok.c \
+	lib/strtoofft.c \
+	lib/tftp.c \
+	lib/timediff.c \
+	lib/timeval.c \
+	lib/transfer.c \
+	lib/url.c \
+	lib/urlapi.c \
+	lib/vtls/openssl.c \
+	lib/vtls/vtls.c \
+	lib/warnless.c \
+	lib/version.c \
+	lib/vauth/digest.c \
+	lib/vauth/vauth.c \
+	lib/vquic/vquic.c \
+	lib/vtls/hostcheck.c \
+	lib/vtls/keylog.c
+VBox-libcurl_SOURCES.win = \
+	lib/curl_multibyte.c \
+	lib/system_win32.c \
+	lib/version_win32.c
+VBox-libcurl_SOURCES.darwin = \
+	lib/macos.c
+
+# Use checked in config.h instead of running ./configure for it.
+VBox-libcurl_DEPS  = $(VBox-libcurl_0_OUTDIR)/lib/curl_config.h
+VBox-libcurl_CLEAN = $(VBox-libcurl_DEPS)
+$$(VBox-libcurl_0_OUTDIR)/lib/curl_config.h: $(VBOX_PATH_LIBCURL)/config.h.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH) | $$(dir $$@)
+	$(INSTALL_STAGING) -- "$^" "$@"
+
+ifdef VBOX_WITH_32_ON_64_MAIN_API # 32-bit edition.
+ LIBRARIES += VBox-libcurl-x86
+ VBox-libcurl-x86_TEMPLATE = VBoxR3DllNonPedantic-x86
+ VBox-libcurl-x86_EXTENDS  = VBox-libcurl
+ VBox-libcurl-x86_INCS     = \
+ 	include \
+ 	$(VBox-libcurl-x86_0_OUTDIR)/lib \
+ 	$(VBOX_PATH_LIBCURL)/lib
+ VBox-libcurl-x86_DEPS     = $(VBox-libcurl-x86_0_OUTDIR)/lib/curl_config.h
+ VBox-libcurl-x86_CLEAN    = $(VBox-libcurl-x86_DEPS)
+ $$(VBox-libcurl-x86_0_OUTDIR)/lib/curl_config.h: $(VBOX_PATH_LIBCURL)/config.h.$(KBUILD_TARGET).x86 | $$(dir $$@)
+	$(INSTALL_STAGING) -- "$^" "$@"
+
+endif
+
+include $(FILE_KBUILD_SUB_FOOTER)
+
Index: trunk/src/libs/curl-8.7.1/README
===================================================================
--- trunk/src/libs/curl-8.7.1/README	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/README	(revision 104083)
@@ -0,0 +1,55 @@
+                                  _   _ ____  _
+                              ___| | | |  _ \| |
+                             / __| | | | |_) | |
+                            | (__| |_| |  _ <| |___
+                             \___|\___/|_| \_\_____|
+
+README
+
+  Curl is a command line tool for transferring data specified with URL
+  syntax. Find out how to use curl by reading the curl.1 man page or the
+  MANUAL document. Find out how to install Curl by reading the INSTALL
+  document.
+
+  libcurl is the library curl is using to do its job. It is readily
+  available to be used by your software. Read the libcurl.3 man page to
+  learn how.
+
+  You find answers to the most frequent questions we get in the FAQ document.
+
+  Study the COPYING file for distribution terms.
+
+  Those documents and more can be found in the docs/ directory.
+
+CONTACT
+
+  If you have problems, questions, ideas or suggestions, please contact us
+  by posting to a suitable mailing list. See https://curl.se/mail/
+
+  All contributors to the project are listed in the THANKS document.
+
+WEBSITE
+
+  Visit the curl website for the latest news and downloads:
+
+        https://curl.se/
+
+GIT
+
+  To download the latest source code off the GIT server, do this:
+
+    git clone https://github.com/curl/curl.git
+
+  (you will get a directory named curl created, filled with the source code)
+
+SECURITY PROBLEMS
+
+  Report suspected security problems via our HackerOne page and not in public.
+
+    https://hackerone.com/curl
+
+NOTICE
+
+  Curl contains pieces of source code that is Copyright (c) 1998, 1999
+  Kungliga Tekniska Högskolan. This notice is included here to comply with the
+  distribution terms.
Index: trunk/src/libs/curl-8.7.1/config.h.darwin.amd64
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.darwin.amd64	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.darwin.amd64	(revision 104083)
@@ -0,0 +1,953 @@
+/* lib/config.h.  Generated from config.h.in by configure.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+/* #undef AS_TR_CPP */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+/* #undef CURL_CA_BUNDLE */
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 socklen_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Specifies the number of arguments to getservbyport_r */
+/* #undef GETSERVBYPORT_R_ARGS */
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+/* #undef GETSERVBYPORT_R_BUFSIZE */
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+/* #undef HAVE_CLOCK_GETTIME_MONOTONIC */
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+#define HAVE_FREEIFADDRS 1
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+/* #undef HAVE_GETHOSTBYADDR_R */
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* gethostbyaddr_r() takes 8 args */
+/* #undef HAVE_GETHOSTBYADDR_R_8 */
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+/* #undef HAVE_GETHOSTBYNAME_R */
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+/* #undef HAVE_GETHOSTBYNAME_R_6 */
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+/* #undef HAVE_GETSERVBYPORT_R */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#define HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+/* #undef HAVE_MALLOC_H */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+/* #undef HAVE_MSG_NOSIGNAL */
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+/* #undef HAVE_POLL */
+
+/* If you have a fine poll */
+/* #undef HAVE_POLL_FINE */
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+#define HAVE_SETMODE 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+#define HAVE_STRCASESTR 1
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+/* #undef HAVE_STROPTS_H */
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+/* #undef HAVE_TERMIO_H */
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* If you lack a fine basename() prototype */
+/* #undef NEED_BASENAME_PROTO */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* cpu-machine-OS */
+#define OS "i386-apple-darwin10.0.0d6"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 socklen_t
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG6_IS_VOID */
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV ssize_t
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5 
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 8
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+#define USE_OPENSSL
+
+/* if SSL is enabled */
+#define USE_SSLEAY
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* define this if you need it to compile thread-safe code */
+/* #undef _THREAD_SAFE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Type to use in place of socklen_t when system does not provide it. */
+/* #undef socklen_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
Index: trunk/src/libs/curl-8.7.1/config.h.darwin.arm64
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.darwin.arm64	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.darwin.arm64	(revision 104083)
@@ -0,0 +1,1056 @@
+/* lib/curl_config.h.  Generated from curl_config.h.in by configure.  */
+/* lib/curl_config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* to enable curl debug memory tracking */
+/* #undef CURLDEBUG */
+
+/* Location of default ca bundle */
+/* #undef CURL_CA_BUNDLE */
+
+/* define "1" to use built in CA store of SSL library */
+/* #undef CURL_CA_FALLBACK */
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* Default SSL backend */
+/* #undef CURL_DEFAULT_SSL_BACKEND */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable Gopher */
+/* #undef CURL_DISABLE_GOPHER */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable IMAP */
+/* #undef CURL_DISABLE_IMAP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable --libcurl C code generation option */
+/* #undef CURL_DISABLE_LIBCURL_OPTION */
+
+/* if the OpenSSL configuration won't be loaded automatically */
+/* #undef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG */
+
+/* to disable POP3 */
+/* #undef CURL_DISABLE_POP3 */
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable RTSP */
+/* #undef CURL_DISABLE_RTSP */
+
+/* to disable SMB/CIFS */
+/* #undef CURL_DISABLE_SMB */
+
+/* to disable SMTP */
+/* #undef CURL_DISABLE_SMTP */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable TLS-SRP authentication */
+/* #undef CURL_DISABLE_TLS_SRP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* Definition to make a library symbol externally visible. */
+#define CURL_EXTERN_SYMBOL __attribute__ ((__visibility__ ("default")))
+
+/* IP address type in sockaddr */
+#define CURL_SA_FAMILY_T sa_family_t
+
+/* built with multiple SSL backends */
+/* #undef CURL_WITH_MULTI_SSL */
+
+/* enable debug build options */
+/* #undef DEBUGBUILD */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type of arg 2 for gethostname. */
+#define GETHOSTNAME_TYPE_ARG2 size_t
+
+/* Specifies the number of arguments to getservbyport_r */
+/* #undef GETSERVBYPORT_R_ARGS */
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+/* #undef GETSERVBYPORT_R_BUFSIZE */
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the basename function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if using BoringSSL. */
+/* #undef HAVE_BORINGSSL */
+
+/* if BROTLI is in use */
+/* #undef HAVE_BROTLI */
+
+/* Define to 1 if you have the <brotli/decode.h> header file. */
+/* #undef HAVE_BROTLI_DECODE_H */
+
+/* Define to 1 if you have the __builtin_available function. */
+#define HAVE_BUILTIN_AVAILABLE 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+/* #undef HAVE_CLOCK_GETTIME_MONOTONIC */
+
+/* Define to 1 if you have the closesocket function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the CloseSocket camel case function. */
+/* #undef HAVE_CLOSESOCKET_CAMEL */
+
+/* Define to 1 if you have the connect function. */
+#define HAVE_CONNECT 1
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the `CyaSSL_CTX_UseSupportedCurve' function. */
+/* #undef HAVE_CYASSL_CTX_USESUPPORTEDCURVE */
+
+/* Define to 1 if you have the <cyassl/error-ssl.h> header file. */
+/* #undef HAVE_CYASSL_ERROR_SSL_H */
+
+/* Define to 1 if you have the `CyaSSL_get_peer_certificate' function. */
+/* #undef HAVE_CYASSL_GET_PEER_CERTIFICATE */
+
+/* Define to 1 if you have the <cyassl/options.h> header file. */
+/* #undef HAVE_CYASSL_OPTIONS_H */
+
+/* Define to 1 if you have the declaration of `getpwuid_r', and to 0 if you
+   don't. */
+#define HAVE_DECL_GETPWUID_R 1
+
+/* "Set if getpwuid_r() declaration is missing" */
+/* #undef HAVE_DECL_GETPWUID_R_MISSING */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fnmatch' function. */
+#define HAVE_FNMATCH 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+#define HAVE_FREEIFADDRS 1
+
+/* Define to 1 if you have the fsetxattr function. */
+#define HAVE_FSETXATTR 1
+
+/* fsetxattr() takes 5 args */
+/* #undef HAVE_FSETXATTR_5 */
+
+/* fsetxattr() takes 6 args */
+#define HAVE_FSETXATTR_6 1
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have the gai_strerror function. */
+#define HAVE_GAI_STRERROR 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if the getaddrinfo function is threadsafe. */
+#define HAVE_GETADDRINFO_THREADSAFE 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+/* #undef HAVE_GETHOSTBYADDR_R */
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* gethostbyaddr_r() takes 8 args */
+/* #undef HAVE_GETHOSTBYADDR_R_8 */
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+/* #undef HAVE_GETHOSTBYNAME_R */
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+/* #undef HAVE_GETHOSTBYNAME_R_6 */
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getpwuid_r' function. */
+#define HAVE_GETPWUID_R 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+/* #undef HAVE_GETSERVBYPORT_R */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* Define to 1 if you have the `gnutls_alpn_set_protocols' function. */
+/* #undef HAVE_GNUTLS_ALPN_SET_PROTOCOLS */
+
+/* Define to 1 if you have the `gnutls_certificate_set_x509_key_file2'
+   function. */
+/* #undef HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 */
+
+/* Define to 1 if you have the `gnutls_ocsp_req_init' function. */
+/* #undef HAVE_GNUTLS_OCSP_REQ_INIT */
+
+/* if you have the function gnutls_srp_verifier */
+/* #undef HAVE_GNUTLS_SRP */
+
+/* if you have GSS-API libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have GNU GSS */
+/* #undef HAVE_GSSGNU */
+
+/* if you have Heimdal */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have MIT Kerberos */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the <idn2.h> header file. */
+/* #undef HAVE_IDN2_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#define HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the `if_nametoindex' function. */
+#define HAVE_IF_NAMETOINDEX 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Define to 1 if you have the `ldap_init_fd' function. */
+/* #undef HAVE_LDAP_INIT_FD */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the `brotlidec' library (-lbrotlidec). */
+/* #undef HAVE_LIBBROTLIDEC */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn2' library (-lidn2). */
+/* #undef HAVE_LIBIDN2 */
+
+/* Define to 1 if using libressl. */
+/* #undef HAVE_LIBRESSL */
+
+/* Define to 1 if you have the <librtmp/rtmp.h> header file. */
+/* #undef HAVE_LIBRTMP_RTMP_H */
+
+/* Define to 1 if you have the `ssh' library (-lssh). */
+/* #undef HAVE_LIBSSH */
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the <libssh/libssh.h> header file. */
+/* #undef HAVE_LIBSSH_LIBSSH_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <linux/tcp.h> header file. */
+/* #undef HAVE_LINUX_TCP_H */
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the `mach_absolute_time' function. */
+#define HAVE_MACH_ABSOLUTE_TIME 1
+
+/* Define to 1 if you have the malloc.h header file. */
+/* #undef HAVE_MALLOC_H */
+
+/* Define to 1 if you have the memory.h header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the memrchr function or macro. */
+/* #undef HAVE_MEMRCHR */
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#define HAVE_MSG_NOSIGNAL 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if you have the <nghttp2/nghttp2.h> header file. */
+/* #undef HAVE_NGHTTP2_NGHTTP2_H */
+
+/* if you have an old MIT Kerberos version, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* if you have the function SRP_Calc_client_key */
+/* #undef HAVE_OPENSSL_SRP */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the `OpenSSL_version' function. */
+/* #undef HAVE_OPENSSL_VERSION */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the PK11_CreateManagedGenericObject function */
+/* #undef HAVE_PK11_CREATEMANAGEDGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+/* #undef HAVE_POLL */
+
+/* If you have a fine poll */
+/* #undef HAVE_POLL_FINE */
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* if you have <pthread.h> */
+#define HAVE_PTHREAD_H 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+#define HAVE_SETMODE 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if you have the socketpair function. */
+#define HAVE_SOCKETPAIR 1
+
+/* Define to 1 if you have the <socket.h> header file. */
+/* #undef HAVE_SOCKET_H */
+
+/* Define to 1 if you have the `SSLv2_client_method' function. */
+/* #undef HAVE_SSLV2_CLIENT_METHOD */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+/* #undef HAVE_STROPTS_H */
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <sys/xattr.h> header file. */
+#define HAVE_SYS_XATTR_H 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+/* #undef HAVE_TERMIO_H */
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define this if time_t is unsigned */
+/* #undef HAVE_TIME_T_UNSIGNED */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+#define HAVE_UTIMES 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define to 1 if you have the `wolfSSLv3_client_method' function. */
+/* #undef HAVE_WOLFSSLV3_CLIENT_METHOD */
+
+/* Define to 1 if you have the `wolfSSL_CTX_UseSupportedCurve' function. */
+/* #undef HAVE_WOLFSSL_CTX_USESUPPORTEDCURVE */
+
+/* Define to 1 if you have the `wolfSSL_get_peer_certificate' function. */
+/* #undef HAVE_WOLFSSL_GET_PEER_CERTIFICATE */
+
+/* Define to 1 if you have the `wolfSSL_UseALPN' function. */
+/* #undef HAVE_WOLFSSL_USEALPN */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+/* #undef HAVE_WRITABLE_ARGV */
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if you need the memory.h header file even with stdlib.h */
+/* #undef NEED_MEMORY_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
+/* #undef NEED_THREAD_SAFE */
+
+/* Define to enable NTLM delegation to winbind's ntlm_auth helper. */
+/* #undef NTLM_WB_ENABLED */
+
+/* Define absolute filename for winbind's ntlm_auth helper. */
+/* #undef NTLM_WB_FILE */
+
+/* cpu-machine-OS */
+#define OS "arm-apple-darwin20.1.0"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list: https://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5 
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+/* The number of bytes in type curl_off_t */
+#define SIZEOF_CURL_OFF_T 8
+
+/* The number of bytes in type int */
+#define SIZEOF_INT 4
+
+/* The number of bytes in type long */
+#define SIZEOF_LONG 8
+
+/* The number of bytes in type long long */
+/* #undef SIZEOF_LONG_LONG */
+
+/* The number of bytes in type off_t */
+#define SIZEOF_OFF_T 8
+
+/* The number of bytes in type short */
+#define SIZEOF_SHORT 2
+
+/* The number of bytes in type size_t */
+#define SIZEOF_SIZE_T 8
+
+/* The number of bytes in type time_t */
+#define SIZEOF_TIME_T 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to enable c-ares support */
+/* #undef USE_ARES */
+
+/* if CyaSSL/WolfSSL is enabled */
+/* #undef USE_CYASSL */
+
+/* to enable Apple OS native SSL/TLS support */
+/* #undef USE_DARWINSSL */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if GnuTLS uses nettle as crypto backend */
+/* #undef USE_GNUTLS_NETTLE */
+
+/* PSL support enabled */
+/* #undef USE_LIBPSL */
+
+/* if librtmp is in use */
+/* #undef USE_LIBRTMP */
+
+/* if libSSH is in use */
+/* #undef USE_LIBSSH */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if mbedTLS is enabled */
+/* #undef USE_MBEDTLS */
+
+/* if MesaLink is enabled */
+/* #undef USE_MESALINK */
+
+/* Define to enable metalink support */
+/* #undef USE_METALINK */
+
+/* if nghttp2 is in use */
+/* #undef USE_NGHTTP2 */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* Use OpenLDAP-specific code */
+/* #undef USE_OPENLDAP */
+
+/* if OpenSSL is in use */
+#define USE_OPENSSL
+
+/* if SSL is enabled */
+#define USE_SSLEAY
+
+/* if PolarSSL is enabled */
+/* #undef USE_POLARSSL */
+
+/* to enable Windows native SSL/TLS support */
+/* #undef USE_SCHANNEL */
+
+/* if you want POSIX threaded DNS lookup */
+/* #undef USE_THREADS_POSIX */
+
+/* if you want Win32 threaded DNS lookup */
+/* #undef USE_THREADS_WIN32 */
+
+/* Use TLS-SRP authentication */
+/* #undef USE_TLS_SRP */
+
+/* Use Unix domain sockets */
+#define USE_UNIX_SOCKETS 1
+
+/* Define to 1 if you have the `normaliz' (WinIDN) library (-lnormaliz). */
+/* #undef USE_WIN32_IDN */
+
+/* Define to 1 if you are building a Windows target with large file support.
+   */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* Use Windows LDAP implementation */
+/* #undef USE_WIN32_LDAP */
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_SMALL_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to 1 to provide own prototypes. */
+/* #undef WANT_IDN_PROTOTYPES */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
Index: trunk/src/libs/curl-8.7.1/config.h.darwin.x86
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.darwin.x86	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.darwin.x86	(revision 104083)
@@ -0,0 +1,953 @@
+/* lib/config.h.  Generated from config.h.in by configure.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+/* #undef AS_TR_CPP */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+/* #undef CURL_CA_BUNDLE */
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 socklen_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Specifies the number of arguments to getservbyport_r */
+/* #undef GETSERVBYPORT_R_ARGS */
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+/* #undef GETSERVBYPORT_R_BUFSIZE */
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+/* #undef HAVE_CLOCK_GETTIME_MONOTONIC */
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+#define HAVE_FREEIFADDRS 1
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+/* #undef HAVE_GETHOSTBYADDR_R */
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* gethostbyaddr_r() takes 8 args */
+/* #undef HAVE_GETHOSTBYADDR_R_8 */
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+/* #undef HAVE_GETHOSTBYNAME_R */
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+/* #undef HAVE_GETHOSTBYNAME_R_6 */
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+/* #undef HAVE_GETSERVBYPORT_R */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#define HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+/* #undef HAVE_MALLOC_H */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+/* #undef HAVE_MSG_NOSIGNAL */
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+/* #undef HAVE_POLL */
+
+/* If you have a fine poll */
+/* #undef HAVE_POLL_FINE */
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+#define HAVE_SETMODE 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+#define HAVE_STRCASESTR 1
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+/* #undef HAVE_STROPTS_H */
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+/* #undef HAVE_TERMIO_H */
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* If you lack a fine basename() prototype */
+/* #undef NEED_BASENAME_PROTO */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* cpu-machine-OS */
+#define OS "i386-apple-darwin9.5.0"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 socklen_t
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG6_IS_VOID */
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV ssize_t
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5 
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 4
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+#define USE_OPENSSL
+
+/* if SSL is enabled */
+#define USE_SSLEAY
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* define this if you need it to compile thread-safe code */
+/* #undef _THREAD_SAFE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Type to use in place of socklen_t when system does not provide it. */
+/* #undef socklen_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
Index: trunk/src/libs/curl-8.7.1/config.h.freebsd.amd64
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.freebsd.amd64	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.freebsd.amd64	(revision 104083)
@@ -0,0 +1,953 @@
+/* lib/config.h.  Generated from config.h.in by configure.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+/* #undef AS_TR_CPP */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+#define CURL_CA_BUNDLE "/usr/local/share/curl/curl-ca-bundle.crt"
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 size_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 6
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE 4096
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#define HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+#define HAVE_FREEIFADDRS 1
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#define HAVE_GETHOSTBYADDR_R 1
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* gethostbyaddr_r() takes 8 args */
+#define HAVE_GETHOSTBYADDR_R_8 1
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+#define HAVE_GETHOSTBYNAME_R_6 1
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#define HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#define HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+#define HAVE_INET_NTOA_R 1
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+#define HAVE_INET_NTOA_R_3 1
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+/* #undef HAVE_MALLOC_H */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#define HAVE_MSG_NOSIGNAL 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+#define HAVE_POLL 1
+
+/* If you have a fine poll */
+#define HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+#define HAVE_SETMODE 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+#define HAVE_STRCASESTR 1
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+/* #undef HAVE_STROPTS_H */
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+/* #undef HAVE_TERMIO_H */
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* If you lack a fine basename() prototype */
+/* #undef NEED_BASENAME_PROTO */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* cpu-machine-OS */
+#define OS "i386-unknown-freebsd7.0"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 socklen_t
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG6_IS_VOID */
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV int
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5 
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 4
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+/* #undef USE_OPENSSL */
+
+/* if SSL is enabled */
+/* #undef USE_SSLEAY */
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* define this if you need it to compile thread-safe code */
+/* #undef _THREAD_SAFE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Type to use in place of socklen_t when system does not provide it. */
+/* #undef socklen_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
Index: trunk/src/libs/curl-8.7.1/config.h.freebsd.x86
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.freebsd.x86	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.freebsd.x86	(revision 104083)
@@ -0,0 +1,953 @@
+/* lib/config.h.  Generated from config.h.in by configure.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+/* #undef AS_TR_CPP */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+#define CURL_CA_BUNDLE "/usr/local/share/curl/curl-ca-bundle.crt"
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 size_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 6
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE 4096
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#define HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+#define HAVE_FREEIFADDRS 1
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#define HAVE_GETHOSTBYADDR_R 1
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* gethostbyaddr_r() takes 8 args */
+#define HAVE_GETHOSTBYADDR_R_8 1
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+#define HAVE_GETHOSTBYNAME_R_6 1
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#define HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#define HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+#define HAVE_INET_NTOA_R 1
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+#define HAVE_INET_NTOA_R_3 1
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+/* #undef HAVE_MALLOC_H */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#define HAVE_MSG_NOSIGNAL 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+#define HAVE_POLL 1
+
+/* If you have a fine poll */
+#define HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+#define HAVE_SETMODE 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+#define HAVE_STRCASESTR 1
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+/* #undef HAVE_STROPTS_H */
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+/* #undef HAVE_TERMIO_H */
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* If you lack a fine basename() prototype */
+/* #undef NEED_BASENAME_PROTO */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* cpu-machine-OS */
+#define OS "i386-unknown-freebsd7.0"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 socklen_t
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG6_IS_VOID */
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV int
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5 
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 4
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+/* #undef USE_OPENSSL */
+
+/* if SSL is enabled */
+/* #undef USE_SSLEAY */
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* define this if you need it to compile thread-safe code */
+/* #undef _THREAD_SAFE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Type to use in place of socklen_t when system does not provide it. */
+/* #undef socklen_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
Index: trunk/src/libs/curl-8.7.1/config.h.linux.amd64
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.linux.amd64	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.linux.amd64	(revision 104083)
@@ -0,0 +1,953 @@
+/* lib/config.h.  Generated from config.h.in by configure.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+/* #undef AS_TR_CPP */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+#define CURL_CA_BUNDLE "/etc/ssl/certs/ca-certificates.crt"
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 socklen_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 unsigned int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 6
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE 4096
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#define HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+#define HAVE_FREEIFADDRS 1
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#define HAVE_GETHOSTBYADDR_R 1
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* gethostbyaddr_r() takes 8 args */
+#define HAVE_GETHOSTBYADDR_R_8 1
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+#define HAVE_GETHOSTBYNAME_R_6 1
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#define HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R 1 */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#define HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#define HAVE_MSG_NOSIGNAL 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+#define HAVE_POLL 1
+
+/* If you have a fine poll */
+#define HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+/* #undef HAVE_SETMODE */
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+/* #undef HAVE_STRCASESTR */
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+/* #undef HAVE_STRLCAT */
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+/* #define HAVE_STROPTS_H 1 - not on every distro (fedora 10 for instance). */
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+/* #undef HAVE_SYS_FILIO_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+#define HAVE_TERMIO_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* If you lack a fine basename() prototype */
+/* #undef NEED_BASENAME_PROTO */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* cpu-machine-OS */
+#define OS "x86_64-unknown-linux-gnu"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 socklen_t
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG6_IS_VOID */
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV ssize_t
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 8
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+#define USE_OPENSSL
+
+/* if SSL is enabled */
+#define USE_SSLEAY
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* define this if you need it to compile thread-safe code */
+/* #undef _THREAD_SAFE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Type to use in place of socklen_t when system does not provide it. */
+/* #undef socklen_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
Index: trunk/src/libs/curl-8.7.1/config.h.linux.arm64
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.linux.arm64	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.linux.arm64	(revision 104083)
@@ -0,0 +1,953 @@
+/* lib/config.h.  Generated from config.h.in by configure.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+/* #undef AS_TR_CPP */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+#define CURL_CA_BUNDLE "/etc/ssl/certs/ca-certificates.crt"
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 socklen_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 unsigned int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 6
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE 4096
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#define HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+#define HAVE_FREEIFADDRS 1
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#define HAVE_GETHOSTBYADDR_R 1
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* gethostbyaddr_r() takes 8 args */
+#define HAVE_GETHOSTBYADDR_R_8 1
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+#define HAVE_GETHOSTBYNAME_R_6 1
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#define HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R 1 */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#define HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#define HAVE_MSG_NOSIGNAL 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+#define HAVE_POLL 1
+
+/* If you have a fine poll */
+#define HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+/* #undef HAVE_SETMODE */
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+/* #undef HAVE_STRCASESTR */
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+/* #undef HAVE_STRLCAT */
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+/* #define HAVE_STROPTS_H 1 - not on every distro (fedora 10 for instance). */
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+/* #undef HAVE_SYS_FILIO_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+#define HAVE_TERMIO_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* If you lack a fine basename() prototype */
+/* #undef NEED_BASENAME_PROTO */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* cpu-machine-OS */
+#define OS "aarch64-unknown-linux-gnu"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 socklen_t
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG6_IS_VOID */
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV ssize_t
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 8
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+#define USE_OPENSSL
+
+/* if SSL is enabled */
+#define USE_SSLEAY
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* define this if you need it to compile thread-safe code */
+/* #undef _THREAD_SAFE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Type to use in place of socklen_t when system does not provide it. */
+/* #undef socklen_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
Index: trunk/src/libs/curl-8.7.1/config.h.linux.x86
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.linux.x86	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.linux.x86	(revision 104083)
@@ -0,0 +1,953 @@
+/* lib/config.h.  Generated from config.h.in by configure.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+/* #undef AS_TR_CPP */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+#define CURL_CA_BUNDLE "/etc/ssl/certs/ca-certificates.crt"
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+/* #undef ENABLE_IPV6 */
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 size_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 unsigned int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 6
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE 4096
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#define HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+#define HAVE_FREEIFADDRS 1
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#define HAVE_GETHOSTBYADDR_R 1
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* gethostbyaddr_r() takes 8 args */
+#define HAVE_GETHOSTBYADDR_R_8 1
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+#define HAVE_GETHOSTBYNAME_R_6 1
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#define HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#define HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#define HAVE_MSG_NOSIGNAL 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+#define HAVE_POLL 1
+
+/* If you have a fine poll */
+#define HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+/* #undef HAVE_SETMODE */
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+/* #undef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID */
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+/* #undef HAVE_STRCASESTR */
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+/* #undef HAVE_STRLCAT */
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+/* #define HAVE_STROPTS_H 1 - not on every distro (fedora 10 for instance). */
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+/* #undef HAVE_SYS_FILIO_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+#define HAVE_TERMIO_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* If you lack a fine basename() prototype */
+/* #undef NEED_BASENAME_PROTO */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* cpu-machine-OS */
+#define OS "i686-pc-linux-gnu"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 socklen_t
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG6_IS_VOID */
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV int
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 4
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+#define USE_OPENSSL
+
+/* if SSL is enabled */
+#define USE_SSLEAY
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#define _FILE_OFFSET_BITS 64
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* define this if you need it to compile thread-safe code */
+/* #undef _THREAD_SAFE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Type to use in place of socklen_t when system does not provide it. */
+/* #undef socklen_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
Index: trunk/src/libs/curl-8.7.1/config.h.os2.x86
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.os2.x86	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.os2.x86	(revision 104083)
@@ -0,0 +1,953 @@
+/* lib/config.h.  Generated from config.h.in by configure - edited for OS/2 by bird.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+/* #undef AS_TR_CPP */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+/* #undef CURL_CA_BUNDLE */
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+/*#define ENABLE_IPV6 1 - not on OS/2 */
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 int
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 int
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Specifies the number of arguments to getservbyport_r */
+/* #undef GETSERVBYPORT_R_ARGS */
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+/* #undef GETSERVBYPORT_R_BUFSIZE */
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+/* #undef HAVE_CLOCK_GETTIME_MONOTONIC */
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+/*#define HAVE_FREEADDRINFO 1*/
+
+/* Define to 1 if you have the freeifaddrs function. */
+/*#define HAVE_FREEIFADDRS 1*/
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+/*#define HAVE_GETfADDRINFO 1*/
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+/* #undef HAVE_GETHOSTBYADDR_R */
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* gethostbyaddr_r() takes 8 args */
+/* #undef HAVE_GETHOSTBYADDR_R_8 */
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+/* #undef HAVE_GETHOSTBYNAME_R */
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+/* #undef HAVE_GETHOSTBYNAME_R_6 */
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+/*#define HAVE_GETIFADDRS 1*/
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+/* #undef HAVE_GETSERVBYPORT_R */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+/*#define HAVE_IFADDRS_H 1*/
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+/* #undef HAVE_MALLOC_H */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+/* #undef HAVE_MSG_NOSIGNAL */
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+/* #undef HAVE_POLL */
+
+/* If you have a fine poll */
+/* #undef HAVE_POLL_FINE */
+
+/* Define to 1 if you have the <poll.h> header file. */
+/*#define HAVE_POLL_H 1*/
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+#define HAVE_SETMODE 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+#define HAVE_STRCASESTR 1
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+/* #undef HAVE_STROPTS_H */
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+/*#define HAVE_STRUCT_SOCKADDR_STORAGE 1*/
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+/*#define HAVE_SYS_POLL_H 1*/
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+/* #undef HAVE_TERMIO_H */
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* If you lack a fine basename() prototype */
+/* #undef NEED_BASENAME_PROTO */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* cpu-machine-OS */
+#define OS "i386-apple-darwin10.0.0d6"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 int
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG6_IS_VOID */
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV ssize_t
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5 
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 8
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+/* #undef USE_OPENSSL */
+
+/* if SSL is enabled */
+/* #undef USE_SSLEAY */
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* define this if you need it to compile thread-safe code */
+/* #undef _THREAD_SAFE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Type to use in place of socklen_t when system does not provide it. */
+#define socklen_t int
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 4
Index: trunk/src/libs/curl-8.7.1/config.h.solaris.amd64
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.solaris.amd64	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.solaris.amd64	(revision 104083)
@@ -0,0 +1,953 @@
+/* lib/config.h.  Generated from config.h.in by configure.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+/* #undef AS_TR_CPP */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+/* #undef CURL_CA_BUNDLE */
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 socklen_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 5
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE 4096
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+/* #undef HAVE_BOOL_T */
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#define HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+/* #undef HAVE_FREEIFADDRS */
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#define HAVE_GETHOSTBYADDR_R 1
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+#define HAVE_GETHOSTBYADDR_R_7 1
+
+/* gethostbyaddr_r() takes 8 args */
+/* #undef HAVE_GETHOSTBYADDR_R_8 */
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+#define HAVE_GETHOSTBYNAME_R_5 1
+
+/* gethostbyname_r() takes 6 args */
+/* #undef HAVE_GETHOSTBYNAME_R_6 */
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+/* #undef HAVE_GETIFADDRS */
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#define HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+/* #undef HAVE_IFADDRS_H */
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+/* #undef HAVE_IOCTL_FIONBIO */
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+/* #undef HAVE_IOCTL_SIOCGIFADDR */
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#define HAVE_LIBSOCKET 1
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+/* #undef HAVE_MSG_NOSIGNAL */
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+#define HAVE_POLL 1
+
+/* If you have a fine poll */
+#define HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+/* #undef HAVE_SETMODE */
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+/* #undef HAVE_STDBOOL_H */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+/* #undef HAVE_STRCASESTR */
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#define HAVE_STROPTS_H 1
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#define HAVE_SYS_UTIME_H 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+#define HAVE_TERMIO_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* If you lack a fine basename() prototype */
+/* #undef NEED_BASENAME_PROTO */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+#define NEED_REENTRANT 1
+
+/* cpu-machine-OS */
+#define OS "i386-pc-solaris2.10"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 void
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG6_IS_VOID 1
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV ssize_t
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5 
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 8
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+#define USE_OPENSSL
+
+/* if SSL is enabled */
+#define USE_SSLEAY
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* define this if you need it to compile thread-safe code */
+/* #undef _THREAD_SAFE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Type to use in place of socklen_t when system does not provide it. */
+/* #undef socklen_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
Index: trunk/src/libs/curl-8.7.1/config.h.solaris.sparc32
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.solaris.sparc32	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.solaris.sparc32	(revision 104083)
@@ -0,0 +1,953 @@
+/* lib/config.h.  Generated from config.h.in by configure.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+/* #undef AS_TR_CPP */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+/* #undef CURL_CA_BUNDLE */
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 size_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 5
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE 4096
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+/* #undef HAVE_BOOL_T */
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#define HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+/* #undef HAVE_FREEIFADDRS */
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#define HAVE_GETHOSTBYADDR_R 1
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+#define HAVE_GETHOSTBYADDR_R_7 1
+
+/* gethostbyaddr_r() takes 8 args */
+/* #undef HAVE_GETHOSTBYADDR_R_8 */
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+#define HAVE_GETHOSTBYNAME_R_5 1
+
+/* gethostbyname_r() takes 6 args */
+/* #undef HAVE_GETHOSTBYNAME_R_6 */
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+/* #undef HAVE_GETIFADDRS */
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#define HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+/* #undef HAVE_IFADDRS_H */
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+/* #undef HAVE_IOCTL_FIONBIO */
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+/* #undef HAVE_IOCTL_SIOCGIFADDR */
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#define HAVE_LIBSOCKET 1
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+/* #undef HAVE_MSG_NOSIGNAL */
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+#define HAVE_POLL 1
+
+/* If you have a fine poll */
+#define HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+/* #undef HAVE_SETMODE */
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+/* #undef HAVE_STDBOOL_H */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+/* #undef HAVE_STRCASESTR */
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#define HAVE_STROPTS_H 1
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#define HAVE_SYS_UTIME_H 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+#define HAVE_TERMIO_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* If you lack a fine basename() prototype */
+/* #undef NEED_BASENAME_PROTO */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+#define NEED_REENTRANT 1
+
+/* cpu-machine-OS */
+#define OS "i386-pc-solaris2.10"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 void
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG6_IS_VOID 1
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV int
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5 
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 4
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+/* #undef USE_OPENSSL */
+
+/* if SSL is enabled */
+/* #undef USE_SSLEAY */
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#define _FILE_OFFSET_BITS 64
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* define this if you need it to compile thread-safe code */
+/* #undef _THREAD_SAFE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Type to use in place of socklen_t when system does not provide it. */
+/* #undef socklen_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
Index: trunk/src/libs/curl-8.7.1/config.h.solaris.sparc64
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.solaris.sparc64	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.solaris.sparc64	(revision 104083)
@@ -0,0 +1,953 @@
+/* lib/config.h.  Generated from config.h.in by configure.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+/* #undef AS_TR_CPP */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+/* #undef CURL_CA_BUNDLE */
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 socklen_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 5
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE 4096
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+/* #undef HAVE_BOOL_T */
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#define HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+/* #undef HAVE_FREEIFADDRS */
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#define HAVE_GETHOSTBYADDR_R 1
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+#define HAVE_GETHOSTBYADDR_R_7 1
+
+/* gethostbyaddr_r() takes 8 args */
+/* #undef HAVE_GETHOSTBYADDR_R_8 */
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+#define HAVE_GETHOSTBYNAME_R_5 1
+
+/* gethostbyname_r() takes 6 args */
+/* #undef HAVE_GETHOSTBYNAME_R_6 */
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+/* #undef HAVE_GETIFADDRS */
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#define HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+/* #undef HAVE_IFADDRS_H */
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+/* #undef HAVE_IOCTL_FIONBIO */
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+/* #undef HAVE_IOCTL_SIOCGIFADDR */
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#define HAVE_LIBSOCKET 1
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+/* #undef HAVE_MSG_NOSIGNAL */
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+#define HAVE_POLL 1
+
+/* If you have a fine poll */
+#define HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+/* #undef HAVE_SETMODE */
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+/* #undef HAVE_STDBOOL_H */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+/* #undef HAVE_STRCASESTR */
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#define HAVE_STROPTS_H 1
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#define HAVE_SYS_UTIME_H 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+#define HAVE_TERMIO_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* If you lack a fine basename() prototype */
+/* #undef NEED_BASENAME_PROTO */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+#define NEED_REENTRANT 1
+
+/* cpu-machine-OS */
+#define OS "i386-pc-solaris2.10"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 void
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG6_IS_VOID 1
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV ssize_t
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5 
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 8
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+/* #undef USE_OPENSSL */
+
+/* if SSL is enabled */
+/* #undef USE_SSLEAY */
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* define this if you need it to compile thread-safe code */
+/* #undef _THREAD_SAFE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Type to use in place of socklen_t when system does not provide it. */
+/* #undef socklen_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
Index: trunk/src/libs/curl-8.7.1/config.h.solaris.x86
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.solaris.x86	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.solaris.x86	(revision 104083)
@@ -0,0 +1,953 @@
+/* lib/config.h.  Generated from config.h.in by configure.  */
+/* lib/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+/* #undef AS_TR_CPP */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+/* #undef CURL_CA_BUNDLE */
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 size_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 5
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE 4096
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+/* #undef HAVE_BOOL_T */
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#define HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+/* #undef HAVE_FREEIFADDRS */
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#define HAVE_GETHOSTBYADDR_R 1
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+#define HAVE_GETHOSTBYADDR_R_7 1
+
+/* gethostbyaddr_r() takes 8 args */
+/* #undef HAVE_GETHOSTBYADDR_R_8 */
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+#define HAVE_GETHOSTBYNAME_R_5 1
+
+/* gethostbyname_r() takes 6 args */
+/* #undef HAVE_GETHOSTBYNAME_R_6 */
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+/* #undef HAVE_GETIFADDRS */
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#define HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+/* #undef HAVE_IFADDRS_H */
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+/* #undef HAVE_IOCTL_FIONBIO */
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+/* #undef HAVE_IOCTL_SIOCGIFADDR */
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#define HAVE_LIBSOCKET 1
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+/* #undef HAVE_MSG_NOSIGNAL */
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+#define HAVE_POLL 1
+
+/* If you have a fine poll */
+#define HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+/* #undef HAVE_SETMODE */
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/* #undef HAVE_SSL_GET_SHUTDOWN */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+/* #undef HAVE_STDBOOL_H */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+/* #undef HAVE_STRCASESTR */
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#define HAVE_STROPTS_H 1
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#define HAVE_SYS_UTIME_H 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+#define HAVE_TERMIO_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* If you lack a fine basename() prototype */
+/* #undef NEED_BASENAME_PROTO */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+#define NEED_REENTRANT 1
+
+/* cpu-machine-OS */
+#define OS "i386-pc-solaris2.10"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 void
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG6_IS_VOID 1
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV int
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5 
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 4
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+#define USE_OPENSSL
+
+/* if SSL is enabled */
+#define USE_SSLEAY
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.83.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#define _FILE_OFFSET_BITS 64
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* define this if you need it to compile thread-safe code */
+/* #undef _THREAD_SAFE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Type to use in place of socklen_t when system does not provide it. */
+/* #undef socklen_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
Index: trunk/src/libs/curl-8.7.1/config.h.win.amd64
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.win.amd64	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.win.amd64	(revision 104083)
@@ -0,0 +1,569 @@
+#ifndef HEADER_CURL_CONFIG_WIN32_H
+#define HEADER_CURL_CONFIG_WIN32_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/*               Hand crafted config file for Windows               */
+/* ================================================================ */
+
+/* ---------------------------------------------------------------- */
+/*                          HEADER FILES                            */
+/* ---------------------------------------------------------------- */
+
+/* Begin VBox specific */
+#define CURL_DISABLE_LDAP 1
+#define CURL_DISABLE_DICT 1
+#define CURL_DISABLE_TFTP 1
+
+/* to make a symbol visible */
+#define CURL_EXTERN_SYMBOL 1
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+/* End VBox specific */
+
+/* Define if you have the <arpa/inet.h> header file. */
+/* #define HAVE_ARPA_INET_H 1 */
+
+/* Define if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define if you have the <crypto.h> header file. */
+/* #define HAVE_CRYPTO_H 1 */
+
+/* Define if you have the <err.h> header file. */
+/* #define HAVE_ERR_H 1 */
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <getopt.h> header file. */
+/* #define HAVE_GETOPT_H 1 */
+
+/* Define if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* Define if you need the malloc.h header file even with stdlib.h */
+#ifndef __SALFORDC__
+#define NEED_MALLOC_H 1
+#endif
+
+/* Define if you have the <netdb.h> header file. */
+/* #define HAVE_NETDB_H 1 */
+
+/* Define if you have the <netinet/in.h> header file. */
+/* #define HAVE_NETINET_IN_H 1 */
+
+/* Define if you have the <process.h> header file. */
+#ifndef __SALFORDC__
+#define HAVE_PROCESS_H 1
+#endif
+
+/* Define if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define if you have the <sgtty.h> header file. */
+/* #define HAVE_SGTTY_H 1 */
+
+/* Define if you have the <ssl.h> header file. */
+/* #define HAVE_SSL_H 1 */
+
+/* Define if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <sys/param.h> header file. */
+/* #define HAVE_SYS_PARAM_H 1 */
+
+/* Define if you have the <sys/select.h> header file. */
+/* #define HAVE_SYS_SELECT_H 1 */
+
+/* Define if you have the <sys/socket.h> header file. */
+/* #define HAVE_SYS_SOCKET_H 1 */
+
+/* Define if you have the <sys/sockio.h> header file. */
+/* #define HAVE_SYS_SOCKIO_H 1 */
+
+/* Define if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define if you have the <sys/time.h> header file. */
+/* #define HAVE_SYS_TIME_H 1 */
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have the <sys/utime.h> header file. */
+#ifndef __BORLANDC__
+#define HAVE_SYS_UTIME_H 1
+#endif
+
+/* Define if you have the <termio.h> header file. */
+/* #define HAVE_TERMIO_H 1 */
+
+/* Define if you have the <termios.h> header file. */
+/* #define HAVE_TERMIOS_H 1 */
+
+/* Define if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__) || \
+    defined(__POCC__)
+#define HAVE_UNISTD_H 1
+#endif
+
+/* Define if you have the <windows.h> header file. */
+#define HAVE_WINDOWS_H 1
+
+/* Define if you have the <winsock.h> header file. */
+#define HAVE_WINSOCK_H 1
+
+#ifndef __SALFORDC__
+/* Define if you have the <winsock2.h> header file. */
+#define HAVE_WINSOCK2_H 1
+
+/* Define if you have the <ws2tcpip.h> header file. */
+#define HAVE_WS2TCPIP_H 1
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                        OTHER HEADER INFO                         */
+/* ---------------------------------------------------------------- */
+
+/* Define if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+/* #define TIME_WITH_SYS_TIME 1 */
+
+/* ---------------------------------------------------------------- */
+/*                             FUNCTIONS                            */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have the closesocket function. */
+#define HAVE_CLOSESOCKET 1
+
+/* Define if you don't have vprintf but do have _doprnt. */
+/* #define HAVE_DOPRNT 1 */
+
+/* Define if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define if you have the getpass function. */
+/* #define HAVE_GETPASS 1 */
+
+/* Define if you have the getservbyname function. */
+#define HAVE_GETSERVBYNAME 1
+
+/* Define if you have the getprotobyname function. */
+#define HAVE_GETPROTOBYNAME
+
+/* Define if you have the gettimeofday function. */
+/* #define HAVE_GETTIMEOFDAY 1 */
+
+/* Define if you have the inet_addr function. */
+#define HAVE_INET_ADDR 1
+
+/* Define if you have the ioctlsocket function. */
+#define HAVE_IOCTLSOCKET 1
+
+/* Define if you have a working ioctlsocket FIONBIO function. */
+#define HAVE_IOCTLSOCKET_FIONBIO 1
+
+/* Define if you have the perror function. */
+#define HAVE_PERROR 1
+
+/* Define if you have the RAND_screen function when using SSL  */
+#define HAVE_RAND_SCREEN 1
+
+/* Define if you have the `RAND_status' function when using SSL. */
+#define HAVE_RAND_STATUS 1
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function.
+   This is present in OpenSSL versions after 0.9.6b */
+#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
+
+/* Define if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define if you have the setvbuf function. */
+#define HAVE_SETVBUF 1
+
+/* Define if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define if you have the strcasecmp function. */
+/* #define HAVE_STRCASECMP 1 */
+
+/* Define if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define if you have the strftime function. */
+#define HAVE_STRFTIME 1
+
+/* Define if you have the stricmp function. */
+#define HAVE_STRICMP 1
+
+/* Define if you have the strncasecmp function. */
+/* #define HAVE_STRNCASECMP 1 */
+
+/* Define if you have the strnicmp function. */
+#define HAVE_STRNICMP 1
+
+/* Define if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define if you have the strtoll function. */
+#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__POCC__)
+#define HAVE_STRTOLL 1
+#endif
+
+/* Define if you have the tcgetattr function. */
+/* #define HAVE_TCGETATTR 1 */
+
+/* Define if you have the tcsetattr function. */
+/* #define HAVE_TCSETATTR 1 */
+
+/* Define if you have the utime function */
+#ifndef __BORLANDC__
+#define HAVE_UTIME 1
+#endif
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 DWORD
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Define if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 SOCKET
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 SOCKET
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 char
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 int
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV int
+
+/* Define if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 SOCKET
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* ---------------------------------------------------------------- */
+/*                       TYPEDEF REPLACEMENTS                       */
+/* ---------------------------------------------------------------- */
+
+/* Define this if in_addr_t is not an available 'typedefed' type */
+#define in_addr_t unsigned long
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+#ifndef _SSIZE_T_DEFINED
+#if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || defined(__POCC__) || \
+    defined(__MINGW32__)
+#elif defined(_WIN64)
+#define ssize_t __int64
+#else
+#define ssize_t int
+#endif
+#define _SSIZE_T_DEFINED
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                            TYPE SIZES                            */
+/* ---------------------------------------------------------------- */
+
+/* Define to the size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* Define to the size of `long double', as computed by sizeof. */
+#define SIZEOF_LONG_DOUBLE 16
+
+/* Define to the size of `long long', as computed by sizeof. */
+/* #define SIZEOF_LONG_LONG 8 */
+
+/* Define to the size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to the size of `size_t', as computed by sizeof. */
+#if defined(_WIN64)
+#  define SIZEOF_SIZE_T 8
+#else
+#  define SIZEOF_SIZE_T 4
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                          STRUCT RELATED                          */
+/* ---------------------------------------------------------------- */
+
+/* Define this if you have struct sockaddr_storage */
+#ifndef __SALFORDC__
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+#endif
+
+/* Define this if you have struct timeval */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* ---------------------------------------------------------------- */
+/*                        Watt-32 tcp/ip SPECIFIC                   */
+/* ---------------------------------------------------------------- */
+
+#ifdef USE_WATT32
+  #include <tcp.h>
+  #undef byte
+  #undef word
+  #undef USE_WINSOCK
+  #undef HAVE_WINSOCK_H
+  #undef HAVE_WINSOCK2_H
+  #undef HAVE_WS2TCPIP_H
+  #define HAVE_GETADDRINFO
+  #define HAVE_GETNAMEINFO
+  #define HAVE_SYS_IOCTL_H
+  #define HAVE_SYS_SOCKET_H
+  #define HAVE_NETINET_IN_H
+  #define HAVE_NETDB_H
+  #define HAVE_ARPA_INET_H
+  #define HAVE_FREEADDRINFO
+  #define SOCKET int
+#endif
+
+
+/* ---------------------------------------------------------------- */
+/*                        COMPILER SPECIFIC                         */
+/* ---------------------------------------------------------------- */
+
+/* Undef keyword 'const' if it does not work. */
+/* #undef const */
+
+/* Windows should not have HAVE_GMTIME_R defined */
+/* #undef HAVE_GMTIME_R */
+
+/* Define if the compiler supports C99 variadic macro style. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define HAVE_VARIADIC_MACROS_C99 1
+#endif
+
+/* Define if the compiler supports the 'long long' data type. */
+#if defined(__MINGW32__) || defined(__WATCOMC__)
+#define HAVE_LONGLONG 1
+#endif
+
+/* Define to avoid VS2005 complaining about portable C functions */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define _CRT_SECURE_NO_DEPRECATE 1
+#define _CRT_NONSTDC_NO_DEPRECATE 1
+#endif
+
+/* VS2005 and later dafault size for time_t is 64-bit, unless */
+/* _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#  ifndef _USE_32BIT_TIME_T
+#    define SIZEOF_TIME_T 8
+#  else
+#    define SIZEOF_TIME_T 4
+#  endif
+#endif
+
+/* Officially, Microsoft's Windows SDK versions 6.X do not support Windows
+   2000 as a supported build target. VS2008 default installations provide an
+   embedded Windows SDK v6.0A along with the claim that Windows 2000 is a
+   valid build target for VS2008. Popular belief is that binaries built using
+   Windows SDK versions 6.X and Windows 2000 as a build target are functional */
+#if defined(_MSC_VER) && (_MSC_VER >= 1500)
+#  define VS2008_MIN_TARGET 0x0500
+#endif
+
+/* When no build target is specified VS2008 default build target is Windows
+   Vista, which leaves out even Winsows XP. If no build target has been given
+   for VS2008 we will target the minimum Officially supported build target,
+   which happens to be Windows XP. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1500)
+#  define VS2008_DEF_TARGET  0x0501
+#endif
+
+/* VS2008 default target settings and minimum build target check. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1500)
+#  ifndef _WIN32_WINNT
+#    define _WIN32_WINNT VS2008_DEF_TARGET
+#  endif
+#  ifndef WINVER
+#    define WINVER VS2008_DEF_TARGET
+#  endif
+#  if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET)
+#    error VS2008 does not support Windows build targets prior to Windows 2000
+#  endif
+#endif
+
+/* Availability of freeaddrinfo, getaddrinfo and getnameinfo functions is
+   quite convoluted, compiler dependant and in some cases even build target
+   dependant. */
+#if defined(HAVE_WS2TCPIP_H)
+#  if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
+#    define HAVE_FREEADDRINFO 1
+#    define HAVE_GETADDRINFO  1
+#    define HAVE_GETNAMEINFO  1
+#  elif defined(_MSC_VER) && (_MSC_VER >= 1200)
+#    define HAVE_FREEADDRINFO 1
+#    define HAVE_GETADDRINFO  1
+#    define HAVE_GETNAMEINFO  1
+#  endif
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                        LARGE FILE SUPPORT                        */
+/* ---------------------------------------------------------------- */
+
+#if defined(_MSC_VER) && !defined(_WIN32_WCE)
+#  if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+#    define USE_WIN32_LARGE_FILES
+#  else
+#    define USE_WIN32_SMALL_FILES
+#  endif
+#endif
+
+#if defined(__MINGW32__) && !defined(USE_WIN32_LARGE_FILES)
+#  define USE_WIN32_LARGE_FILES
+#endif
+
+#if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES)
+#  define USE_WIN32_SMALL_FILES
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                           LDAP SUPPORT                           */
+/* ---------------------------------------------------------------- */
+
+#if defined(CURL_HAS_NOVELL_LDAPSDK) || defined(CURL_HAS_MOZILLA_LDAPSDK)
+#undef CURL_LDAP_HYBRID
+#undef CURL_LDAP_WIN
+#define HAVE_LDAP_SSL_H 1
+#define HAVE_LDAP_URL_PARSE 1
+#elif defined(CURL_HAS_OPENLDAP_LDAPSDK)
+#undef CURL_LDAP_HYBRID
+#undef CURL_LDAP_WIN
+#define HAVE_LDAP_URL_PARSE 1
+#else
+#undef CURL_LDAP_HYBRID
+#undef HAVE_LDAP_URL_PARSE
+#define CURL_LDAP_WIN 1
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                       ADDITIONAL DEFINITIONS                     */
+/* ---------------------------------------------------------------- */
+
+/* Define cpu-machine-OS */
+#undef OS
+#if defined(_M_IX86) || defined(__i386__) /* x86 (MSVC or gcc) */
+#define OS "i386-pc-win32"
+#elif defined(_M_IA64) /* Itanium */
+#define OS "ia64-pc-win32"
+#elif defined(_M_X64) /* AMD64/EM64T - Not defined until MSVC 2005 */
+#define OS "amd64-pc-win32"
+#else
+#define OS "unknown-pc-win32"
+#endif
+
+/* Name of package */
+#define PACKAGE "curl"
+
+#define USE_OPENSSL
+#define USE_SSLEAY
+
+#endif /* HEADER_CURL_CONFIG_WIN32_H */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
Index: trunk/src/libs/curl-8.7.1/config.h.win.x86
===================================================================
--- trunk/src/libs/curl-8.7.1/config.h.win.x86	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/config.h.win.x86	(revision 104083)
@@ -0,0 +1,569 @@
+#ifndef HEADER_CURL_CONFIG_WIN32_H
+#define HEADER_CURL_CONFIG_WIN32_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/*               Hand crafted config file for Windows               */
+/* ================================================================ */
+
+/* ---------------------------------------------------------------- */
+/*                          HEADER FILES                            */
+/* ---------------------------------------------------------------- */
+
+/* Begin VBox specific */
+#define CURL_DISABLE_LDAP 1
+#define CURL_DISABLE_DICT 1
+#define CURL_DISABLE_TFTP 1
+
+/* to make a symbol visible */
+#define CURL_EXTERN_SYMBOL 1
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+/* End VBox specific */
+
+/* Define if you have the <arpa/inet.h> header file. */
+/* #define HAVE_ARPA_INET_H 1 */
+
+/* Define if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define if you have the <crypto.h> header file. */
+/* #define HAVE_CRYPTO_H 1 */
+
+/* Define if you have the <err.h> header file. */
+/* #define HAVE_ERR_H 1 */
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <getopt.h> header file. */
+/* #define HAVE_GETOPT_H 1 */
+
+/* Define if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* Define if you need the malloc.h header file even with stdlib.h */
+#ifndef __SALFORDC__
+#define NEED_MALLOC_H 1
+#endif
+
+/* Define if you have the <netdb.h> header file. */
+/* #define HAVE_NETDB_H 1 */
+
+/* Define if you have the <netinet/in.h> header file. */
+/* #define HAVE_NETINET_IN_H 1 */
+
+/* Define if you have the <process.h> header file. */
+#ifndef __SALFORDC__
+#define HAVE_PROCESS_H 1
+#endif
+
+/* Define if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define if you have the <sgtty.h> header file. */
+/* #define HAVE_SGTTY_H 1 */
+
+/* Define if you have the <ssl.h> header file. */
+/* #define HAVE_SSL_H 1 */
+
+/* Define if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <sys/param.h> header file. */
+/* #define HAVE_SYS_PARAM_H 1 */
+
+/* Define if you have the <sys/select.h> header file. */
+/* #define HAVE_SYS_SELECT_H 1 */
+
+/* Define if you have the <sys/socket.h> header file. */
+/* #define HAVE_SYS_SOCKET_H 1 */
+
+/* Define if you have the <sys/sockio.h> header file. */
+/* #define HAVE_SYS_SOCKIO_H 1 */
+
+/* Define if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define if you have the <sys/time.h> header file. */
+/* #define HAVE_SYS_TIME_H 1 */
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have the <sys/utime.h> header file. */
+#ifndef __BORLANDC__
+#define HAVE_SYS_UTIME_H 1
+#endif
+
+/* Define if you have the <termio.h> header file. */
+/* #define HAVE_TERMIO_H 1 */
+
+/* Define if you have the <termios.h> header file. */
+/* #define HAVE_TERMIOS_H 1 */
+
+/* Define if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__) || \
+    defined(__POCC__)
+#define HAVE_UNISTD_H 1
+#endif
+
+/* Define if you have the <windows.h> header file. */
+#define HAVE_WINDOWS_H 1
+
+/* Define if you have the <winsock.h> header file. */
+#define HAVE_WINSOCK_H 1
+
+#ifndef __SALFORDC__
+/* Define if you have the <winsock2.h> header file. */
+#define HAVE_WINSOCK2_H 1
+
+/* Define if you have the <ws2tcpip.h> header file. */
+#define HAVE_WS2TCPIP_H 1
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                        OTHER HEADER INFO                         */
+/* ---------------------------------------------------------------- */
+
+/* Define if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+/* #define TIME_WITH_SYS_TIME 1 */
+
+/* ---------------------------------------------------------------- */
+/*                             FUNCTIONS                            */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have the closesocket function. */
+#define HAVE_CLOSESOCKET 1
+
+/* Define if you don't have vprintf but do have _doprnt. */
+/* #define HAVE_DOPRNT 1 */
+
+/* Define if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define if you have the getpass function. */
+/* #define HAVE_GETPASS 1 */
+
+/* Define if you have the getservbyname function. */
+#define HAVE_GETSERVBYNAME 1
+
+/* Define if you have the getprotobyname function. */
+#define HAVE_GETPROTOBYNAME
+
+/* Define if you have the gettimeofday function. */
+/* #define HAVE_GETTIMEOFDAY 1 */
+
+/* Define if you have the inet_addr function. */
+#define HAVE_INET_ADDR 1
+
+/* Define if you have the ioctlsocket function. */
+#define HAVE_IOCTLSOCKET 1
+
+/* Define if you have a working ioctlsocket FIONBIO function. */
+#define HAVE_IOCTLSOCKET_FIONBIO 1
+
+/* Define if you have the perror function. */
+#define HAVE_PERROR 1
+
+/* Define if you have the RAND_screen function when using SSL  */
+#define HAVE_RAND_SCREEN 1
+
+/* Define if you have the `RAND_status' function when using SSL. */
+#define HAVE_RAND_STATUS 1
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function.
+   This is present in OpenSSL versions after 0.9.6b */
+#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
+
+/* Define if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define if you have the setvbuf function. */
+#define HAVE_SETVBUF 1
+
+/* Define if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define if you have the strcasecmp function. */
+/* #define HAVE_STRCASECMP 1 */
+
+/* Define if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define if you have the strftime function. */
+#define HAVE_STRFTIME 1
+
+/* Define if you have the stricmp function. */
+#define HAVE_STRICMP 1
+
+/* Define if you have the strncasecmp function. */
+/* #define HAVE_STRNCASECMP 1 */
+
+/* Define if you have the strnicmp function. */
+#define HAVE_STRNICMP 1
+
+/* Define if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define if you have the strtoll function. */
+#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__POCC__)
+#define HAVE_STRTOLL 1
+#endif
+
+/* Define if you have the tcgetattr function. */
+/* #define HAVE_TCGETATTR 1 */
+
+/* Define if you have the tcsetattr function. */
+/* #define HAVE_TCSETATTR 1 */
+
+/* Define if you have the utime function */
+#ifndef __BORLANDC__
+#define HAVE_UTIME 1
+#endif
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 DWORD
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Define if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 SOCKET
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 SOCKET
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 char
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 int
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV int
+
+/* Define if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 SOCKET
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* ---------------------------------------------------------------- */
+/*                       TYPEDEF REPLACEMENTS                       */
+/* ---------------------------------------------------------------- */
+
+/* Define this if in_addr_t is not an available 'typedefed' type */
+#define in_addr_t unsigned long
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+#ifndef _SSIZE_T_DEFINED
+#if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || defined(__POCC__) || \
+    defined(__MINGW32__)
+#elif defined(_WIN64)
+#define ssize_t __int64
+#else
+#define ssize_t int
+#endif
+#define _SSIZE_T_DEFINED
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                            TYPE SIZES                            */
+/* ---------------------------------------------------------------- */
+
+/* Define to the size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* Define to the size of `long double', as computed by sizeof. */
+#define SIZEOF_LONG_DOUBLE 16
+
+/* Define to the size of `long long', as computed by sizeof. */
+/* #define SIZEOF_LONG_LONG 8 */
+
+/* Define to the size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to the size of `size_t', as computed by sizeof. */
+#if defined(_WIN64)
+#  define SIZEOF_SIZE_T 8
+#else
+#  define SIZEOF_SIZE_T 4
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                          STRUCT RELATED                          */
+/* ---------------------------------------------------------------- */
+
+/* Define this if you have struct sockaddr_storage */
+#ifndef __SALFORDC__
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+#endif
+
+/* Define this if you have struct timeval */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* ---------------------------------------------------------------- */
+/*                        Watt-32 tcp/ip SPECIFIC                   */
+/* ---------------------------------------------------------------- */
+
+#ifdef USE_WATT32
+  #include <tcp.h>
+  #undef byte
+  #undef word
+  #undef USE_WINSOCK
+  #undef HAVE_WINSOCK_H
+  #undef HAVE_WINSOCK2_H
+  #undef HAVE_WS2TCPIP_H
+  #define HAVE_GETADDRINFO
+  #define HAVE_GETNAMEINFO
+  #define HAVE_SYS_IOCTL_H
+  #define HAVE_SYS_SOCKET_H
+  #define HAVE_NETINET_IN_H
+  #define HAVE_NETDB_H
+  #define HAVE_ARPA_INET_H
+  #define HAVE_FREEADDRINFO
+  #define SOCKET int
+#endif
+
+
+/* ---------------------------------------------------------------- */
+/*                        COMPILER SPECIFIC                         */
+/* ---------------------------------------------------------------- */
+
+/* Undef keyword 'const' if it does not work. */
+/* #undef const */
+
+/* Windows should not have HAVE_GMTIME_R defined */
+/* #undef HAVE_GMTIME_R */
+
+/* Define if the compiler supports C99 variadic macro style. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define HAVE_VARIADIC_MACROS_C99 1
+#endif
+
+/* Define if the compiler supports the 'long long' data type. */
+#if defined(__MINGW32__) || defined(__WATCOMC__)
+#define HAVE_LONGLONG 1
+#endif
+
+/* Define to avoid VS2005 complaining about portable C functions */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define _CRT_SECURE_NO_DEPRECATE 1
+#define _CRT_NONSTDC_NO_DEPRECATE 1
+#endif
+
+/* VS2005 and later dafault size for time_t is 64-bit, unless */
+/* _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#  ifndef _USE_32BIT_TIME_T
+#    define SIZEOF_TIME_T 8
+#  else
+#    define SIZEOF_TIME_T 4
+#  endif
+#endif
+
+/* Officially, Microsoft's Windows SDK versions 6.X do not support Windows
+   2000 as a supported build target. VS2008 default installations provide an
+   embedded Windows SDK v6.0A along with the claim that Windows 2000 is a
+   valid build target for VS2008. Popular belief is that binaries built using
+   Windows SDK versions 6.X and Windows 2000 as a build target are functional */
+#if defined(_MSC_VER) && (_MSC_VER >= 1500)
+#  define VS2008_MIN_TARGET 0x0500
+#endif
+
+/* When no build target is specified VS2008 default build target is Windows
+   Vista, which leaves out even Winsows XP. If no build target has been given
+   for VS2008 we will target the minimum Officially supported build target,
+   which happens to be Windows XP. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1500)
+#  define VS2008_DEF_TARGET  0x0501
+#endif
+
+/* VS2008 default target settings and minimum build target check. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1500)
+#  ifndef _WIN32_WINNT
+#    define _WIN32_WINNT VS2008_DEF_TARGET
+#  endif
+#  ifndef WINVER
+#    define WINVER VS2008_DEF_TARGET
+#  endif
+#  if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET)
+#    error VS2008 does not support Windows build targets prior to Windows 2000
+#  endif
+#endif
+
+/* Availability of freeaddrinfo, getaddrinfo and getnameinfo functions is
+   quite convoluted, compiler dependant and in some cases even build target
+   dependant. */
+#if defined(HAVE_WS2TCPIP_H)
+#  if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
+#    define HAVE_FREEADDRINFO 1
+#    define HAVE_GETADDRINFO  1
+#    define HAVE_GETNAMEINFO  1
+#  elif defined(_MSC_VER) && (_MSC_VER >= 1200)
+#    define HAVE_FREEADDRINFO 1
+#    define HAVE_GETADDRINFO  1
+#    define HAVE_GETNAMEINFO  1
+#  endif
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                        LARGE FILE SUPPORT                        */
+/* ---------------------------------------------------------------- */
+
+#if defined(_MSC_VER) && !defined(_WIN32_WCE)
+#  if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+#    define USE_WIN32_LARGE_FILES
+#  else
+#    define USE_WIN32_SMALL_FILES
+#  endif
+#endif
+
+#if defined(__MINGW32__) && !defined(USE_WIN32_LARGE_FILES)
+#  define USE_WIN32_LARGE_FILES
+#endif
+
+#if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES)
+#  define USE_WIN32_SMALL_FILES
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                           LDAP SUPPORT                           */
+/* ---------------------------------------------------------------- */
+
+#if defined(CURL_HAS_NOVELL_LDAPSDK) || defined(CURL_HAS_MOZILLA_LDAPSDK)
+#undef CURL_LDAP_HYBRID
+#undef CURL_LDAP_WIN
+#define HAVE_LDAP_SSL_H 1
+#define HAVE_LDAP_URL_PARSE 1
+#elif defined(CURL_HAS_OPENLDAP_LDAPSDK)
+#undef CURL_LDAP_HYBRID
+#undef CURL_LDAP_WIN
+#define HAVE_LDAP_URL_PARSE 1
+#else
+#undef CURL_LDAP_HYBRID
+#undef HAVE_LDAP_URL_PARSE
+#define CURL_LDAP_WIN 1
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                       ADDITIONAL DEFINITIONS                     */
+/* ---------------------------------------------------------------- */
+
+/* Define cpu-machine-OS */
+#undef OS
+#if defined(_M_IX86) || defined(__i386__) /* x86 (MSVC or gcc) */
+#define OS "i386-pc-win32"
+#elif defined(_M_IA64) /* Itanium */
+#define OS "ia64-pc-win32"
+#elif defined(_M_X64) /* AMD64/EM64T - Not defined until MSVC 2005 */
+#define OS "amd64-pc-win32"
+#else
+#define OS "unknown-pc-win32"
+#endif
+
+/* Name of package */
+#define PACKAGE "curl"
+
+#define USE_OPENSSL
+#define USE_SSLEAY
+
+#endif /* HEADER_CURL_CONFIG_WIN32_H */
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
Index: trunk/src/libs/curl-8.7.1/include/Makefile.am
===================================================================
--- trunk/src/libs/curl-8.7.1/include/Makefile.am	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/Makefile.am	(revision 104083)
@@ -0,0 +1,28 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+SUBDIRS = curl
+
+EXTRA_DIST = README.md
+
+AUTOMAKE_OPTIONS = foreign no-dependencies
Index: trunk/src/libs/curl-8.7.1/include/Makefile.in
===================================================================
--- trunk/src/libs/curl-8.7.1/include/Makefile.in	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/Makefile.in	(revision 104083)
@@ -0,0 +1,774 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \
+	$(top_srcdir)/m4/curl-bearssl.m4 \
+	$(top_srcdir)/m4/curl-compilers.m4 \
+	$(top_srcdir)/m4/curl-confopts.m4 \
+	$(top_srcdir)/m4/curl-functions.m4 \
+	$(top_srcdir)/m4/curl-gnutls.m4 \
+	$(top_srcdir)/m4/curl-mbedtls.m4 \
+	$(top_srcdir)/m4/curl-openssl.m4 \
+	$(top_srcdir)/m4/curl-override.m4 \
+	$(top_srcdir)/m4/curl-reentrant.m4 \
+	$(top_srcdir)/m4/curl-rustls.m4 \
+	$(top_srcdir)/m4/curl-schannel.m4 \
+	$(top_srcdir)/m4/curl-sectransp.m4 \
+	$(top_srcdir)/m4/curl-sysconfig.m4 \
+	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/xc-am-iface.m4 \
+	$(top_srcdir)/m4/xc-cc-check.m4 \
+	$(top_srcdir)/m4/xc-lt-iface.m4 \
+	$(top_srcdir)/m4/xc-translit.m4 \
+	$(top_srcdir)/m4/xc-val-flgs.m4 \
+	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
+	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
+	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/curl_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+depcomp =
+am__maybe_remake_depfiles =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in README.md
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APACHECTL = @APACHECTL@
+APXS = @APXS@
+AR = @AR@
+AR_FLAGS = @AR_FLAGS@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@
+CADDY = @CADDY@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@
+CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CURLVERSION = @CURLVERSION@
+CURL_CA_BUNDLE = @CURL_CA_BUNDLE@
+CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@
+CURL_DISABLE_DICT = @CURL_DISABLE_DICT@
+CURL_DISABLE_FILE = @CURL_DISABLE_FILE@
+CURL_DISABLE_FTP = @CURL_DISABLE_FTP@
+CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@
+CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@
+CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@
+CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@
+CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@
+CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@
+CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@
+CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@
+CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@
+CURL_DISABLE_SMB = @CURL_DISABLE_SMB@
+CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@
+CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@
+CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@
+CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@
+CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@
+CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@
+CURL_PLIST_VERSION = @CURL_PLIST_VERSION@
+CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_SHARED = @ENABLE_SHARED@
+ENABLE_STATIC = @ENABLE_STATIC@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@
+GCOV = @GCOV@
+GREP = @GREP@
+HAVE_BROTLI = @HAVE_BROTLI@
+HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@
+HAVE_LDAP_SSL = @HAVE_LDAP_SSL@
+HAVE_LIBZ = @HAVE_LIBZ@
+HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@
+HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@
+HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@
+HAVE_ZSTD = @HAVE_ZSTD@
+HTTPD = @HTTPD@
+HTTPD_NGHTTPX = @HTTPD_NGHTTPX@
+IDN_ENABLED = @IDN_ENABLED@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPV6_ENABLED = @IPV6_ENABLED@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCURL_LIBS = @LIBCURL_LIBS@
+LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKGADD_NAME = @PKGADD_NAME@
+PKGADD_PKG = @PKGADD_PKG@
+PKGADD_VENDOR = @PKGADD_VENDOR@
+PKGCONFIG = @PKGCONFIG@
+RANDOM_FILE = @RANDOM_FILE@
+RANLIB = @RANLIB@
+RC = @RC@
+REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSL_BACKENDS = @SSL_BACKENDS@
+SSL_ENABLED = @SSL_ENABLED@
+SSL_LIBS = @SSL_LIBS@
+STRIP = @STRIP@
+SUPPORT_FEATURES = @SUPPORT_FEATURES@
+SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@
+TEST_NGHTTPX = @TEST_NGHTTPX@
+USE_ARES = @USE_ARES@
+USE_BEARSSL = @USE_BEARSSL@
+USE_GNUTLS = @USE_GNUTLS@
+USE_HYPER = @USE_HYPER@
+USE_LIBPSL = @USE_LIBPSL@
+USE_LIBRTMP = @USE_LIBRTMP@
+USE_LIBSSH = @USE_LIBSSH@
+USE_LIBSSH2 = @USE_LIBSSH2@
+USE_MBEDTLS = @USE_MBEDTLS@
+USE_MSH3 = @USE_MSH3@
+USE_NGHTTP2 = @USE_NGHTTP2@
+USE_NGHTTP3 = @USE_NGHTTP3@
+USE_NGTCP2 = @USE_NGTCP2@
+USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@
+USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@
+USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@
+USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@
+USE_NGTCP2_H3 = @USE_NGTCP2_H3@
+USE_OPENLDAP = @USE_OPENLDAP@
+USE_OPENSSL_H3 = @USE_OPENSSL_H3@
+USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@
+USE_QUICHE = @USE_QUICHE@
+USE_RUSTLS = @USE_RUSTLS@
+USE_SCHANNEL = @USE_SCHANNEL@
+USE_SECTRANSP = @USE_SECTRANSP@
+USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@
+USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@
+USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@
+USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@
+USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@
+USE_WOLFSSH = @USE_WOLFSSH@
+USE_WOLFSSL = @USE_WOLFSSL@
+VERSION = @VERSION@
+VERSIONNUM = @VERSIONNUM@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libext = @libext@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+SUBDIRS = curl
+EXTRA_DIST = README.md
+AUTOMAKE_OPTIONS = foreign no-dependencies
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign include/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+	check-am clean clean-generic clean-libtool cscopelist-am ctags \
+	ctags-am distclean distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	installdirs-am maintainer-clean maintainer-clean-generic \
+	mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+	ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: trunk/src/libs/curl-8.7.1/include/README.md
===================================================================
--- trunk/src/libs/curl-8.7.1/include/README.md	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/README.md	(revision 104083)
@@ -0,0 +1,20 @@
+<!--
+Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+
+SPDX-License-Identifier: curl
+-->
+
+# include
+
+Public include files for libcurl, external users.
+
+They're all placed in the curl subdirectory here for better fit in any kind of
+environment. You must include files from here using...
+
+    #include <curl/curl.h>
+
+... style and point the compiler's include path to the directory holding the
+curl subdirectory. It makes it more likely to survive future modifications.
+
+The public curl include files can be shared freely between different platforms
+and different architectures.
Index: trunk/src/libs/curl-8.7.1/include/curl/Makefile.am
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/Makefile.am	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/Makefile.am	(revision 104083)
@@ -0,0 +1,41 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+pkginclude_HEADERS = \
+  curl.h curlver.h easy.h mprintf.h stdcheaders.h multi.h \
+  typecheck-gcc.h system.h urlapi.h options.h header.h websockets.h
+
+pkgincludedir= $(includedir)/curl
+
+CHECKSRC = $(CS_$(V))
+CS_0 = @echo "  RUN     " $@;
+CS_1 =
+CS_ = $(CS_0)
+
+checksrc:
+	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(top_srcdir)/include/curl $(pkginclude_HEADERS)
+
+if CURLDEBUG
+# for debug builds, we scan the sources on all regular make invokes
+all-local: checksrc
+endif
Index: trunk/src/libs/curl-8.7.1/include/curl/Makefile.in
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/Makefile.in	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/Makefile.in	(revision 104083)
@@ -0,0 +1,725 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include/curl
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \
+	$(top_srcdir)/m4/curl-bearssl.m4 \
+	$(top_srcdir)/m4/curl-compilers.m4 \
+	$(top_srcdir)/m4/curl-confopts.m4 \
+	$(top_srcdir)/m4/curl-functions.m4 \
+	$(top_srcdir)/m4/curl-gnutls.m4 \
+	$(top_srcdir)/m4/curl-mbedtls.m4 \
+	$(top_srcdir)/m4/curl-openssl.m4 \
+	$(top_srcdir)/m4/curl-override.m4 \
+	$(top_srcdir)/m4/curl-reentrant.m4 \
+	$(top_srcdir)/m4/curl-rustls.m4 \
+	$(top_srcdir)/m4/curl-schannel.m4 \
+	$(top_srcdir)/m4/curl-sectransp.m4 \
+	$(top_srcdir)/m4/curl-sysconfig.m4 \
+	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/xc-am-iface.m4 \
+	$(top_srcdir)/m4/xc-cc-check.m4 \
+	$(top_srcdir)/m4/xc-lt-iface.m4 \
+	$(top_srcdir)/m4/xc-translit.m4 \
+	$(top_srcdir)/m4/xc-val-flgs.m4 \
+	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
+	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
+	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(pkginclude_HEADERS) \
+	$(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/curl_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(pkgincludedir)"
+HEADERS = $(pkginclude_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgincludedir = $(includedir)/curl
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APACHECTL = @APACHECTL@
+APXS = @APXS@
+AR = @AR@
+AR_FLAGS = @AR_FLAGS@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@
+CADDY = @CADDY@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@
+CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CURLVERSION = @CURLVERSION@
+CURL_CA_BUNDLE = @CURL_CA_BUNDLE@
+CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@
+CURL_DISABLE_DICT = @CURL_DISABLE_DICT@
+CURL_DISABLE_FILE = @CURL_DISABLE_FILE@
+CURL_DISABLE_FTP = @CURL_DISABLE_FTP@
+CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@
+CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@
+CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@
+CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@
+CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@
+CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@
+CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@
+CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@
+CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@
+CURL_DISABLE_SMB = @CURL_DISABLE_SMB@
+CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@
+CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@
+CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@
+CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@
+CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@
+CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@
+CURL_PLIST_VERSION = @CURL_PLIST_VERSION@
+CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_SHARED = @ENABLE_SHARED@
+ENABLE_STATIC = @ENABLE_STATIC@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@
+GCOV = @GCOV@
+GREP = @GREP@
+HAVE_BROTLI = @HAVE_BROTLI@
+HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@
+HAVE_LDAP_SSL = @HAVE_LDAP_SSL@
+HAVE_LIBZ = @HAVE_LIBZ@
+HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@
+HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@
+HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@
+HAVE_ZSTD = @HAVE_ZSTD@
+HTTPD = @HTTPD@
+HTTPD_NGHTTPX = @HTTPD_NGHTTPX@
+IDN_ENABLED = @IDN_ENABLED@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPV6_ENABLED = @IPV6_ENABLED@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCURL_LIBS = @LIBCURL_LIBS@
+LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKGADD_NAME = @PKGADD_NAME@
+PKGADD_PKG = @PKGADD_PKG@
+PKGADD_VENDOR = @PKGADD_VENDOR@
+PKGCONFIG = @PKGCONFIG@
+RANDOM_FILE = @RANDOM_FILE@
+RANLIB = @RANLIB@
+RC = @RC@
+REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSL_BACKENDS = @SSL_BACKENDS@
+SSL_ENABLED = @SSL_ENABLED@
+SSL_LIBS = @SSL_LIBS@
+STRIP = @STRIP@
+SUPPORT_FEATURES = @SUPPORT_FEATURES@
+SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@
+TEST_NGHTTPX = @TEST_NGHTTPX@
+USE_ARES = @USE_ARES@
+USE_BEARSSL = @USE_BEARSSL@
+USE_GNUTLS = @USE_GNUTLS@
+USE_HYPER = @USE_HYPER@
+USE_LIBPSL = @USE_LIBPSL@
+USE_LIBRTMP = @USE_LIBRTMP@
+USE_LIBSSH = @USE_LIBSSH@
+USE_LIBSSH2 = @USE_LIBSSH2@
+USE_MBEDTLS = @USE_MBEDTLS@
+USE_MSH3 = @USE_MSH3@
+USE_NGHTTP2 = @USE_NGHTTP2@
+USE_NGHTTP3 = @USE_NGHTTP3@
+USE_NGTCP2 = @USE_NGTCP2@
+USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@
+USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@
+USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@
+USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@
+USE_NGTCP2_H3 = @USE_NGTCP2_H3@
+USE_OPENLDAP = @USE_OPENLDAP@
+USE_OPENSSL_H3 = @USE_OPENSSL_H3@
+USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@
+USE_QUICHE = @USE_QUICHE@
+USE_RUSTLS = @USE_RUSTLS@
+USE_SCHANNEL = @USE_SCHANNEL@
+USE_SECTRANSP = @USE_SECTRANSP@
+USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@
+USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@
+USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@
+USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@
+USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@
+USE_WOLFSSH = @USE_WOLFSSH@
+USE_WOLFSSL = @USE_WOLFSSL@
+VERSION = @VERSION@
+VERSIONNUM = @VERSIONNUM@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libext = @libext@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+pkginclude_HEADERS = \
+  curl.h curlver.h easy.h mprintf.h stdcheaders.h multi.h \
+  typecheck-gcc.h system.h urlapi.h options.h header.h websockets.h
+
+CHECKSRC = $(CS_$(V))
+CS_0 = @echo "  RUN     " $@;
+CS_1 = 
+CS_ = $(CS_0)
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/curl/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign include/curl/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+install-pkgincludeHEADERS: $(pkginclude_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \
+	done
+
+uninstall-pkgincludeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+@CURLDEBUG_FALSE@all-local:
+all-am: Makefile $(HEADERS) all-local
+installdirs:
+	for dir in "$(DESTDIR)$(pkgincludedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkgincludeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkgincludeHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \
+	clean-generic clean-libtool cscopelist-am ctags ctags-am \
+	distclean distclean-generic distclean-libtool distclean-tags \
+	distdir dvi dvi-am html html-am info info-am install \
+	install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkgincludeHEADERS \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+	uninstall-am uninstall-pkgincludeHEADERS
+
+.PRECIOUS: Makefile
+
+
+checksrc:
+	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(top_srcdir)/include/curl $(pkginclude_HEADERS)
+
+# for debug builds, we scan the sources on all regular make invokes
+@CURLDEBUG_TRUE@all-local: checksrc
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: trunk/src/libs/curl-8.7.1/include/curl/curl.h
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/curl.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/curl.h	(revision 104083)
@@ -0,0 +1,3245 @@
+#ifndef CURLINC_CURL_H
+#define CURLINC_CURL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * If you have libcurl problems, all docs and details are found here:
+ *   https://curl.se/libcurl/
+ */
+
+#ifdef CURL_NO_OLDIES
+#define CURL_STRICTER
+#endif
+
+/* Compile-time deprecation macros. */
+#if defined(__GNUC__) &&                                                \
+  ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) &&  \
+  !defined(__INTEL_COMPILER) &&                                         \
+  !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL)
+#define CURL_DEPRECATED(version, message)                       \
+  __attribute__((deprecated("since " # version ". " message)))
+#define CURL_IGNORE_DEPRECATION(statements) \
+      _Pragma("GCC diagnostic push") \
+      _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
+      statements \
+      _Pragma("GCC diagnostic pop")
+#else
+#define CURL_DEPRECATED(version, message)
+#define CURL_IGNORE_DEPRECATION(statements)     statements
+#endif
+
+#include "curlver.h"         /* libcurl version defines   */
+#include "system.h"          /* determine things run-time */
+
+#include <stdio.h>
+#include <limits.h>
+
+#if defined(__FreeBSD__) || defined(__MidnightBSD__)
+/* Needed for __FreeBSD_version or __MidnightBSD_version symbol definition */
+#include <sys/param.h>
+#endif
+
+/* The include stuff here below is mainly for time_t! */
+#include <sys/types.h>
+#include <time.h>
+
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__)
+#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \
+      defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H))
+/* The check above prevents the winsock2 inclusion if winsock.h already was
+   included, since they can't co-exist without problems */
+#  ifdef VBOX
+#   include <iprt/win/winsock2.h>
+#   include <iprt/win/ws2tcpip.h>
+#  else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#  endif
+#endif
+#endif
+
+/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
+   libc5-based Linux systems. Only include it on systems that are known to
+   require it! */
+#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
+    defined(__minix) || defined(__INTEGRITY) || \
+    defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
+    defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \
+   (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \
+   (defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000)) || \
+    defined(__sun__) || defined(__serenity__) || defined(__vxworks__)
+#include <sys/select.h>
+#endif
+
+#if !defined(_WIN32) && !defined(_WIN32_WCE)
+#include <sys/socket.h>
+#endif
+
+#if !defined(_WIN32)
+#include <sys/time.h>
+#endif
+
+/* Compatibility for non-Clang compilers */
+#ifndef __has_declspec_attribute
+#  define __has_declspec_attribute(x) 0
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER)
+typedef struct Curl_easy CURL;
+typedef struct Curl_share CURLSH;
+#else
+typedef void CURL;
+typedef void CURLSH;
+#endif
+
+/*
+ * libcurl external API function linkage decorations.
+ */
+
+#ifdef CURL_STATICLIB
+#  define CURL_EXTERN
+#elif defined(_WIN32) || \
+     (__has_declspec_attribute(dllexport) && \
+      __has_declspec_attribute(dllimport))
+#  if defined(BUILDING_LIBCURL)
+#    define CURL_EXTERN  __declspec(dllexport)
+#  else
+#    define CURL_EXTERN  __declspec(dllimport)
+#  endif
+#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS)
+#  define CURL_EXTERN CURL_EXTERN_SYMBOL
+#else
+#  define CURL_EXTERN
+#endif
+
+#ifndef curl_socket_typedef
+/* socket typedef */
+#if defined(_WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H)
+typedef SOCKET curl_socket_t;
+#define CURL_SOCKET_BAD INVALID_SOCKET
+#else
+typedef int curl_socket_t;
+#define CURL_SOCKET_BAD -1
+#endif
+#define curl_socket_typedef
+#endif /* curl_socket_typedef */
+
+/* enum for the different supported SSL backends */
+typedef enum {
+  CURLSSLBACKEND_NONE = 0,
+  CURLSSLBACKEND_OPENSSL = 1,
+  CURLSSLBACKEND_GNUTLS = 2,
+  CURLSSLBACKEND_NSS                    CURL_DEPRECATED(8.3.0, "") = 3,
+  CURLSSLBACKEND_OBSOLETE4 = 4,  /* Was QSOSSL. */
+  CURLSSLBACKEND_GSKIT                  CURL_DEPRECATED(8.3.0, "") = 5,
+  CURLSSLBACKEND_POLARSSL               CURL_DEPRECATED(7.69.0, "") = 6,
+  CURLSSLBACKEND_WOLFSSL = 7,
+  CURLSSLBACKEND_SCHANNEL = 8,
+  CURLSSLBACKEND_SECURETRANSPORT = 9,
+  CURLSSLBACKEND_AXTLS                  CURL_DEPRECATED(7.61.0, "") = 10,
+  CURLSSLBACKEND_MBEDTLS = 11,
+  CURLSSLBACKEND_MESALINK               CURL_DEPRECATED(7.82.0, "") = 12,
+  CURLSSLBACKEND_BEARSSL = 13,
+  CURLSSLBACKEND_RUSTLS = 14
+} curl_sslbackend;
+
+/* aliases for library clones and renames */
+#define CURLSSLBACKEND_AWSLC CURLSSLBACKEND_OPENSSL
+#define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL
+#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL
+
+/* deprecated names: */
+#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL
+#define CURLSSLBACKEND_DARWINSSL CURLSSLBACKEND_SECURETRANSPORT
+
+struct curl_httppost {
+  struct curl_httppost *next;       /* next entry in the list */
+  char *name;                       /* pointer to allocated name */
+  long namelength;                  /* length of name length */
+  char *contents;                   /* pointer to allocated data contents */
+  long contentslength;              /* length of contents field, see also
+                                       CURL_HTTPPOST_LARGE */
+  char *buffer;                     /* pointer to allocated buffer contents */
+  long bufferlength;                /* length of buffer field */
+  char *contenttype;                /* Content-Type */
+  struct curl_slist *contentheader; /* list of extra headers for this form */
+  struct curl_httppost *more;       /* if one field name has more than one
+                                       file, this link should link to following
+                                       files */
+  long flags;                       /* as defined below */
+
+/* specified content is a file name */
+#define CURL_HTTPPOST_FILENAME (1<<0)
+/* specified content is a file name */
+#define CURL_HTTPPOST_READFILE (1<<1)
+/* name is only stored pointer do not free in formfree */
+#define CURL_HTTPPOST_PTRNAME (1<<2)
+/* contents is only stored pointer do not free in formfree */
+#define CURL_HTTPPOST_PTRCONTENTS (1<<3)
+/* upload file from buffer */
+#define CURL_HTTPPOST_BUFFER (1<<4)
+/* upload file from pointer contents */
+#define CURL_HTTPPOST_PTRBUFFER (1<<5)
+/* upload file contents by using the regular read callback to get the data and
+   pass the given pointer as custom pointer */
+#define CURL_HTTPPOST_CALLBACK (1<<6)
+/* use size in 'contentlen', added in 7.46.0 */
+#define CURL_HTTPPOST_LARGE (1<<7)
+
+  char *showfilename;               /* The file name to show. If not set, the
+                                       actual file name will be used (if this
+                                       is a file part) */
+  void *userp;                      /* custom pointer used for
+                                       HTTPPOST_CALLBACK posts */
+  curl_off_t contentlen;            /* alternative length of contents
+                                       field. Used if CURL_HTTPPOST_LARGE is
+                                       set. Added in 7.46.0 */
+};
+
+
+/* This is a return code for the progress callback that, when returned, will
+   signal libcurl to continue executing the default progress function */
+#define CURL_PROGRESSFUNC_CONTINUE 0x10000001
+
+/* This is the CURLOPT_PROGRESSFUNCTION callback prototype. It is now
+   considered deprecated but was the only choice up until 7.31.0 */
+typedef int (*curl_progress_callback)(void *clientp,
+                                      double dltotal,
+                                      double dlnow,
+                                      double ultotal,
+                                      double ulnow);
+
+/* This is the CURLOPT_XFERINFOFUNCTION callback prototype. It was introduced
+   in 7.32.0, avoids the use of floating point numbers and provides more
+   detailed information. */
+typedef int (*curl_xferinfo_callback)(void *clientp,
+                                      curl_off_t dltotal,
+                                      curl_off_t dlnow,
+                                      curl_off_t ultotal,
+                                      curl_off_t ulnow);
+
+#ifndef CURL_MAX_READ_SIZE
+  /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */
+#define CURL_MAX_READ_SIZE (10*1024*1024)
+#endif
+
+#ifndef CURL_MAX_WRITE_SIZE
+  /* Tests have proven that 20K is a very bad buffer size for uploads on
+     Windows, while 16K for some odd reason performed a lot better.
+     We do the ifndef check to allow this value to easier be changed at build
+     time for those who feel adventurous. The practical minimum is about
+     400 bytes since libcurl uses a buffer of this size as a scratch area
+     (unrelated to network send operations). */
+#define CURL_MAX_WRITE_SIZE 16384
+#endif
+
+#ifndef CURL_MAX_HTTP_HEADER
+/* The only reason to have a max limit for this is to avoid the risk of a bad
+   server feeding libcurl with a never-ending header that will cause reallocs
+   infinitely */
+#define CURL_MAX_HTTP_HEADER (100*1024)
+#endif
+
+/* This is a magic return code for the write callback that, when returned,
+   will signal libcurl to pause receiving on the current transfer. */
+#define CURL_WRITEFUNC_PAUSE 0x10000001
+
+/* This is a magic return code for the write callback that, when returned,
+   will signal an error from the callback. */
+#define CURL_WRITEFUNC_ERROR 0xFFFFFFFF
+
+typedef size_t (*curl_write_callback)(char *buffer,
+                                      size_t size,
+                                      size_t nitems,
+                                      void *outstream);
+
+/* This callback will be called when a new resolver request is made */
+typedef int (*curl_resolver_start_callback)(void *resolver_state,
+                                            void *reserved, void *userdata);
+
+/* enumeration of file types */
+typedef enum {
+  CURLFILETYPE_FILE = 0,
+  CURLFILETYPE_DIRECTORY,
+  CURLFILETYPE_SYMLINK,
+  CURLFILETYPE_DEVICE_BLOCK,
+  CURLFILETYPE_DEVICE_CHAR,
+  CURLFILETYPE_NAMEDPIPE,
+  CURLFILETYPE_SOCKET,
+  CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */
+
+  CURLFILETYPE_UNKNOWN /* should never occur */
+} curlfiletype;
+
+#define CURLFINFOFLAG_KNOWN_FILENAME    (1<<0)
+#define CURLFINFOFLAG_KNOWN_FILETYPE    (1<<1)
+#define CURLFINFOFLAG_KNOWN_TIME        (1<<2)
+#define CURLFINFOFLAG_KNOWN_PERM        (1<<3)
+#define CURLFINFOFLAG_KNOWN_UID         (1<<4)
+#define CURLFINFOFLAG_KNOWN_GID         (1<<5)
+#define CURLFINFOFLAG_KNOWN_SIZE        (1<<6)
+#define CURLFINFOFLAG_KNOWN_HLINKCOUNT  (1<<7)
+
+/* Information about a single file, used when doing FTP wildcard matching */
+struct curl_fileinfo {
+  char *filename;
+  curlfiletype filetype;
+  time_t time; /* always zero! */
+  unsigned int perm;
+  int uid;
+  int gid;
+  curl_off_t size;
+  long int hardlinks;
+
+  struct {
+    /* If some of these fields is not NULL, it is a pointer to b_data. */
+    char *time;
+    char *perm;
+    char *user;
+    char *group;
+    char *target; /* pointer to the target filename of a symlink */
+  } strings;
+
+  unsigned int flags;
+
+  /* These are libcurl private struct fields. Previously used by libcurl, so
+     they must never be interfered with. */
+  char *b_data;
+  size_t b_size;
+  size_t b_used;
+};
+
+/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */
+#define CURL_CHUNK_BGN_FUNC_OK      0
+#define CURL_CHUNK_BGN_FUNC_FAIL    1 /* tell the lib to end the task */
+#define CURL_CHUNK_BGN_FUNC_SKIP    2 /* skip this chunk over */
+
+/* if splitting of data transfer is enabled, this callback is called before
+   download of an individual chunk started. Note that parameter "remains" works
+   only for FTP wildcard downloading (for now), otherwise is not used */
+typedef long (*curl_chunk_bgn_callback)(const void *transfer_info,
+                                        void *ptr,
+                                        int remains);
+
+/* return codes for CURLOPT_CHUNK_END_FUNCTION */
+#define CURL_CHUNK_END_FUNC_OK      0
+#define CURL_CHUNK_END_FUNC_FAIL    1 /* tell the lib to end the task */
+
+/* If splitting of data transfer is enabled this callback is called after
+   download of an individual chunk finished.
+   Note! After this callback was set then it have to be called FOR ALL chunks.
+   Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC.
+   This is the reason why we don't need "transfer_info" parameter in this
+   callback and we are not interested in "remains" parameter too. */
+typedef long (*curl_chunk_end_callback)(void *ptr);
+
+/* return codes for FNMATCHFUNCTION */
+#define CURL_FNMATCHFUNC_MATCH    0 /* string corresponds to the pattern */
+#define CURL_FNMATCHFUNC_NOMATCH  1 /* pattern doesn't match the string */
+#define CURL_FNMATCHFUNC_FAIL     2 /* an error occurred */
+
+/* callback type for wildcard downloading pattern matching. If the
+   string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */
+typedef int (*curl_fnmatch_callback)(void *ptr,
+                                     const char *pattern,
+                                     const char *string);
+
+/* These are the return codes for the seek callbacks */
+#define CURL_SEEKFUNC_OK       0
+#define CURL_SEEKFUNC_FAIL     1 /* fail the entire transfer */
+#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so
+                                    libcurl might try other means instead */
+typedef int (*curl_seek_callback)(void *instream,
+                                  curl_off_t offset,
+                                  int origin); /* 'whence' */
+
+/* This is a return code for the read callback that, when returned, will
+   signal libcurl to immediately abort the current transfer. */
+#define CURL_READFUNC_ABORT 0x10000000
+/* This is a return code for the read callback that, when returned, will
+   signal libcurl to pause sending data on the current transfer. */
+#define CURL_READFUNC_PAUSE 0x10000001
+
+/* Return code for when the trailing headers' callback has terminated
+   without any errors */
+#define CURL_TRAILERFUNC_OK 0
+/* Return code for when was an error in the trailing header's list and we
+  want to abort the request */
+#define CURL_TRAILERFUNC_ABORT 1
+
+typedef size_t (*curl_read_callback)(char *buffer,
+                                      size_t size,
+                                      size_t nitems,
+                                      void *instream);
+
+typedef int (*curl_trailer_callback)(struct curl_slist **list,
+                                      void *userdata);
+
+typedef enum {
+  CURLSOCKTYPE_IPCXN,  /* socket created for a specific IP connection */
+  CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
+  CURLSOCKTYPE_LAST    /* never use */
+} curlsocktype;
+
+/* The return code from the sockopt_callback can signal information back
+   to libcurl: */
+#define CURL_SOCKOPT_OK 0
+#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return
+                                CURLE_ABORTED_BY_CALLBACK */
+#define CURL_SOCKOPT_ALREADY_CONNECTED 2
+
+typedef int (*curl_sockopt_callback)(void *clientp,
+                                     curl_socket_t curlfd,
+                                     curlsocktype purpose);
+
+struct curl_sockaddr {
+  int family;
+  int socktype;
+  int protocol;
+  unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it
+                           turned really ugly and painful on the systems that
+                           lack this type */
+  struct sockaddr addr;
+};
+
+typedef curl_socket_t
+(*curl_opensocket_callback)(void *clientp,
+                            curlsocktype purpose,
+                            struct curl_sockaddr *address);
+
+typedef int
+(*curl_closesocket_callback)(void *clientp, curl_socket_t item);
+
+typedef enum {
+  CURLIOE_OK,            /* I/O operation successful */
+  CURLIOE_UNKNOWNCMD,    /* command was unknown to callback */
+  CURLIOE_FAILRESTART,   /* failed to restart the read */
+  CURLIOE_LAST           /* never use */
+} curlioerr;
+
+typedef enum {
+  CURLIOCMD_NOP,         /* no operation */
+  CURLIOCMD_RESTARTREAD, /* restart the read stream from start */
+  CURLIOCMD_LAST         /* never use */
+} curliocmd;
+
+typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
+                                         int cmd,
+                                         void *clientp);
+
+#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS
+/*
+ * The following typedef's are signatures of malloc, free, realloc, strdup and
+ * calloc respectively.  Function pointers of these types can be passed to the
+ * curl_global_init_mem() function to set user defined memory management
+ * callback routines.
+ */
+typedef void *(*curl_malloc_callback)(size_t size);
+typedef void (*curl_free_callback)(void *ptr);
+typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
+typedef char *(*curl_strdup_callback)(const char *str);
+typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
+
+#define CURL_DID_MEMORY_FUNC_TYPEDEFS
+#endif
+
+/* the kind of data that is passed to information_callback */
+typedef enum {
+  CURLINFO_TEXT = 0,
+  CURLINFO_HEADER_IN,    /* 1 */
+  CURLINFO_HEADER_OUT,   /* 2 */
+  CURLINFO_DATA_IN,      /* 3 */
+  CURLINFO_DATA_OUT,     /* 4 */
+  CURLINFO_SSL_DATA_IN,  /* 5 */
+  CURLINFO_SSL_DATA_OUT, /* 6 */
+  CURLINFO_END
+} curl_infotype;
+
+typedef int (*curl_debug_callback)
+       (CURL *handle,      /* the handle/transfer this concerns */
+        curl_infotype type, /* what kind of data */
+        char *data,        /* points to the data */
+        size_t size,       /* size of the data pointed to */
+        void *userptr);    /* whatever the user please */
+
+/* This is the CURLOPT_PREREQFUNCTION callback prototype. */
+typedef int (*curl_prereq_callback)(void *clientp,
+                                    char *conn_primary_ip,
+                                    char *conn_local_ip,
+                                    int conn_primary_port,
+                                    int conn_local_port);
+
+/* Return code for when the pre-request callback has terminated without
+   any errors */
+#define CURL_PREREQFUNC_OK 0
+/* Return code for when the pre-request callback wants to abort the
+   request */
+#define CURL_PREREQFUNC_ABORT 1
+
+/* All possible error codes from all sorts of curl functions. Future versions
+   may return other values, stay prepared.
+
+   Always add new return codes last. Never *EVER* remove any. The return
+   codes must remain the same!
+ */
+
+typedef enum {
+  CURLE_OK = 0,
+  CURLE_UNSUPPORTED_PROTOCOL,    /* 1 */
+  CURLE_FAILED_INIT,             /* 2 */
+  CURLE_URL_MALFORMAT,           /* 3 */
+  CURLE_NOT_BUILT_IN,            /* 4 - [was obsoleted in August 2007 for
+                                    7.17.0, reused in April 2011 for 7.21.5] */
+  CURLE_COULDNT_RESOLVE_PROXY,   /* 5 */
+  CURLE_COULDNT_RESOLVE_HOST,    /* 6 */
+  CURLE_COULDNT_CONNECT,         /* 7 */
+  CURLE_WEIRD_SERVER_REPLY,      /* 8 */
+  CURLE_REMOTE_ACCESS_DENIED,    /* 9 a service was denied by the server
+                                    due to lack of access - when login fails
+                                    this is not returned. */
+  CURLE_FTP_ACCEPT_FAILED,       /* 10 - [was obsoleted in April 2006 for
+                                    7.15.4, reused in Dec 2011 for 7.24.0]*/
+  CURLE_FTP_WEIRD_PASS_REPLY,    /* 11 */
+  CURLE_FTP_ACCEPT_TIMEOUT,      /* 12 - timeout occurred accepting server
+                                    [was obsoleted in August 2007 for 7.17.0,
+                                    reused in Dec 2011 for 7.24.0]*/
+  CURLE_FTP_WEIRD_PASV_REPLY,    /* 13 */
+  CURLE_FTP_WEIRD_227_FORMAT,    /* 14 */
+  CURLE_FTP_CANT_GET_HOST,       /* 15 */
+  CURLE_HTTP2,                   /* 16 - A problem in the http2 framing layer.
+                                    [was obsoleted in August 2007 for 7.17.0,
+                                    reused in July 2014 for 7.38.0] */
+  CURLE_FTP_COULDNT_SET_TYPE,    /* 17 */
+  CURLE_PARTIAL_FILE,            /* 18 */
+  CURLE_FTP_COULDNT_RETR_FILE,   /* 19 */
+  CURLE_OBSOLETE20,              /* 20 - NOT USED */
+  CURLE_QUOTE_ERROR,             /* 21 - quote command failure */
+  CURLE_HTTP_RETURNED_ERROR,     /* 22 */
+  CURLE_WRITE_ERROR,             /* 23 */
+  CURLE_OBSOLETE24,              /* 24 - NOT USED */
+  CURLE_UPLOAD_FAILED,           /* 25 - failed upload "command" */
+  CURLE_READ_ERROR,              /* 26 - couldn't open/read from file */
+  CURLE_OUT_OF_MEMORY,           /* 27 */
+  CURLE_OPERATION_TIMEDOUT,      /* 28 - the timeout time was reached */
+  CURLE_OBSOLETE29,              /* 29 - NOT USED */
+  CURLE_FTP_PORT_FAILED,         /* 30 - FTP PORT operation failed */
+  CURLE_FTP_COULDNT_USE_REST,    /* 31 - the REST command failed */
+  CURLE_OBSOLETE32,              /* 32 - NOT USED */
+  CURLE_RANGE_ERROR,             /* 33 - RANGE "command" didn't work */
+  CURLE_HTTP_POST_ERROR,         /* 34 */
+  CURLE_SSL_CONNECT_ERROR,       /* 35 - wrong when connecting with SSL */
+  CURLE_BAD_DOWNLOAD_RESUME,     /* 36 - couldn't resume download */
+  CURLE_FILE_COULDNT_READ_FILE,  /* 37 */
+  CURLE_LDAP_CANNOT_BIND,        /* 38 */
+  CURLE_LDAP_SEARCH_FAILED,      /* 39 */
+  CURLE_OBSOLETE40,              /* 40 - NOT USED */
+  CURLE_FUNCTION_NOT_FOUND,      /* 41 - NOT USED starting with 7.53.0 */
+  CURLE_ABORTED_BY_CALLBACK,     /* 42 */
+  CURLE_BAD_FUNCTION_ARGUMENT,   /* 43 */
+  CURLE_OBSOLETE44,              /* 44 - NOT USED */
+  CURLE_INTERFACE_FAILED,        /* 45 - CURLOPT_INTERFACE failed */
+  CURLE_OBSOLETE46,              /* 46 - NOT USED */
+  CURLE_TOO_MANY_REDIRECTS,      /* 47 - catch endless re-direct loops */
+  CURLE_UNKNOWN_OPTION,          /* 48 - User specified an unknown option */
+  CURLE_SETOPT_OPTION_SYNTAX,    /* 49 - Malformed setopt option */
+  CURLE_OBSOLETE50,              /* 50 - NOT USED */
+  CURLE_OBSOLETE51,              /* 51 - NOT USED */
+  CURLE_GOT_NOTHING,             /* 52 - when this is a specific error */
+  CURLE_SSL_ENGINE_NOTFOUND,     /* 53 - SSL crypto engine not found */
+  CURLE_SSL_ENGINE_SETFAILED,    /* 54 - can not set SSL crypto engine as
+                                    default */
+  CURLE_SEND_ERROR,              /* 55 - failed sending network data */
+  CURLE_RECV_ERROR,              /* 56 - failure in receiving network data */
+  CURLE_OBSOLETE57,              /* 57 - NOT IN USE */
+  CURLE_SSL_CERTPROBLEM,         /* 58 - problem with the local certificate */
+  CURLE_SSL_CIPHER,              /* 59 - couldn't use specified cipher */
+  CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint
+                                     wasn't verified fine */
+  CURLE_BAD_CONTENT_ENCODING,    /* 61 - Unrecognized/bad encoding */
+  CURLE_OBSOLETE62,              /* 62 - NOT IN USE since 7.82.0 */
+  CURLE_FILESIZE_EXCEEDED,       /* 63 - Maximum file size exceeded */
+  CURLE_USE_SSL_FAILED,          /* 64 - Requested FTP SSL level failed */
+  CURLE_SEND_FAIL_REWIND,        /* 65 - Sending the data requires a rewind
+                                    that failed */
+  CURLE_SSL_ENGINE_INITFAILED,   /* 66 - failed to initialise ENGINE */
+  CURLE_LOGIN_DENIED,            /* 67 - user, password or similar was not
+                                    accepted and we failed to login */
+  CURLE_TFTP_NOTFOUND,           /* 68 - file not found on server */
+  CURLE_TFTP_PERM,               /* 69 - permission problem on server */
+  CURLE_REMOTE_DISK_FULL,        /* 70 - out of disk space on server */
+  CURLE_TFTP_ILLEGAL,            /* 71 - Illegal TFTP operation */
+  CURLE_TFTP_UNKNOWNID,          /* 72 - Unknown transfer ID */
+  CURLE_REMOTE_FILE_EXISTS,      /* 73 - File already exists */
+  CURLE_TFTP_NOSUCHUSER,         /* 74 - No such user */
+  CURLE_OBSOLETE75,              /* 75 - NOT IN USE since 7.82.0 */
+  CURLE_OBSOLETE76,              /* 76 - NOT IN USE since 7.82.0 */
+  CURLE_SSL_CACERT_BADFILE,      /* 77 - could not load CACERT file, missing
+                                    or wrong format */
+  CURLE_REMOTE_FILE_NOT_FOUND,   /* 78 - remote file not found */
+  CURLE_SSH,                     /* 79 - error from the SSH layer, somewhat
+                                    generic so the error message will be of
+                                    interest when this has happened */
+
+  CURLE_SSL_SHUTDOWN_FAILED,     /* 80 - Failed to shut down the SSL
+                                    connection */
+  CURLE_AGAIN,                   /* 81 - socket is not ready for send/recv,
+                                    wait till it's ready and try again (Added
+                                    in 7.18.2) */
+  CURLE_SSL_CRL_BADFILE,         /* 82 - could not load CRL file, missing or
+                                    wrong format (Added in 7.19.0) */
+  CURLE_SSL_ISSUER_ERROR,        /* 83 - Issuer check failed.  (Added in
+                                    7.19.0) */
+  CURLE_FTP_PRET_FAILED,         /* 84 - a PRET command failed */
+  CURLE_RTSP_CSEQ_ERROR,         /* 85 - mismatch of RTSP CSeq numbers */
+  CURLE_RTSP_SESSION_ERROR,      /* 86 - mismatch of RTSP Session Ids */
+  CURLE_FTP_BAD_FILE_LIST,       /* 87 - unable to parse FTP file list */
+  CURLE_CHUNK_FAILED,            /* 88 - chunk callback reported error */
+  CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the
+                                    session will be queued */
+  CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not
+                                     match */
+  CURLE_SSL_INVALIDCERTSTATUS,   /* 91 - invalid certificate status */
+  CURLE_HTTP2_STREAM,            /* 92 - stream error in HTTP/2 framing layer
+                                    */
+  CURLE_RECURSIVE_API_CALL,      /* 93 - an api function was called from
+                                    inside a callback */
+  CURLE_AUTH_ERROR,              /* 94 - an authentication function returned an
+                                    error */
+  CURLE_HTTP3,                   /* 95 - An HTTP/3 layer problem */
+  CURLE_QUIC_CONNECT_ERROR,      /* 96 - QUIC connection error */
+  CURLE_PROXY,                   /* 97 - proxy handshake error */
+  CURLE_SSL_CLIENTCERT,          /* 98 - client-side certificate required */
+  CURLE_UNRECOVERABLE_POLL,      /* 99 - poll/select returned fatal error */
+  CURLE_TOO_LARGE,               /* 100 - a value/data met its maximum */
+  CURL_LAST /* never use! */
+} CURLcode;
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+                          the obsolete stuff removed! */
+
+/* Previously obsolete error code reused in 7.38.0 */
+#define CURLE_OBSOLETE16 CURLE_HTTP2
+
+/* Previously obsolete error codes reused in 7.24.0 */
+#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED
+#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT
+
+/*  compatibility with older names */
+#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING
+#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY
+
+/* The following were added in 7.62.0 */
+#define CURLE_SSL_CACERT CURLE_PEER_FAILED_VERIFICATION
+
+/* The following were added in 7.21.5, April 2011 */
+#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION
+
+/* Added for 7.78.0 */
+#define CURLE_TELNET_OPTION_SYNTAX CURLE_SETOPT_OPTION_SYNTAX
+
+/* The following were added in 7.17.1 */
+/* These are scheduled to disappear by 2009 */
+#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION
+
+/* The following were added in 7.17.0 */
+/* These are scheduled to disappear by 2009 */
+#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */
+#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46
+#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44
+#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10
+#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16
+#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32
+#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29
+#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12
+#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20
+#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40
+#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24
+#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57
+#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN
+
+#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED
+#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE
+#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR
+#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL
+#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS
+#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR
+#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED
+
+/* The following were added earlier */
+
+#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT
+#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
+#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED
+#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED
+#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE
+#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME
+#define CURLE_LDAP_INVALID_URL CURLE_OBSOLETE62
+#define CURLE_CONV_REQD CURLE_OBSOLETE76
+#define CURLE_CONV_FAILED CURLE_OBSOLETE75
+
+/* This was the error code 50 in 7.7.3 and a few earlier versions, this
+   is no longer used by libcurl but is instead #defined here only to not
+   make programs break */
+#define CURLE_ALREADY_COMPLETE 99999
+
+/* Provide defines for really old option names */
+#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */
+#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */
+#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA
+
+/* Since long deprecated options with no code in the lib that does anything
+   with them. */
+#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40
+#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72
+
+#endif /* !CURL_NO_OLDIES */
+
+/*
+ * Proxy error codes. Returned in CURLINFO_PROXY_ERROR if CURLE_PROXY was
+ * return for the transfers.
+ */
+typedef enum {
+  CURLPX_OK,
+  CURLPX_BAD_ADDRESS_TYPE,
+  CURLPX_BAD_VERSION,
+  CURLPX_CLOSED,
+  CURLPX_GSSAPI,
+  CURLPX_GSSAPI_PERMSG,
+  CURLPX_GSSAPI_PROTECTION,
+  CURLPX_IDENTD,
+  CURLPX_IDENTD_DIFFER,
+  CURLPX_LONG_HOSTNAME,
+  CURLPX_LONG_PASSWD,
+  CURLPX_LONG_USER,
+  CURLPX_NO_AUTH,
+  CURLPX_RECV_ADDRESS,
+  CURLPX_RECV_AUTH,
+  CURLPX_RECV_CONNECT,
+  CURLPX_RECV_REQACK,
+  CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED,
+  CURLPX_REPLY_COMMAND_NOT_SUPPORTED,
+  CURLPX_REPLY_CONNECTION_REFUSED,
+  CURLPX_REPLY_GENERAL_SERVER_FAILURE,
+  CURLPX_REPLY_HOST_UNREACHABLE,
+  CURLPX_REPLY_NETWORK_UNREACHABLE,
+  CURLPX_REPLY_NOT_ALLOWED,
+  CURLPX_REPLY_TTL_EXPIRED,
+  CURLPX_REPLY_UNASSIGNED,
+  CURLPX_REQUEST_FAILED,
+  CURLPX_RESOLVE_HOST,
+  CURLPX_SEND_AUTH,
+  CURLPX_SEND_CONNECT,
+  CURLPX_SEND_REQUEST,
+  CURLPX_UNKNOWN_FAIL,
+  CURLPX_UNKNOWN_MODE,
+  CURLPX_USER_REJECTED,
+  CURLPX_LAST /* never use */
+} CURLproxycode;
+
+/* This prototype applies to all conversion callbacks */
+typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);
+
+typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl,    /* easy handle */
+                                          void *ssl_ctx, /* actually an OpenSSL
+                                                            or WolfSSL SSL_CTX,
+                                                            or an mbedTLS
+                                                          mbedtls_ssl_config */
+                                          void *userptr);
+
+typedef enum {
+  CURLPROXY_HTTP = 0,   /* added in 7.10, new in 7.19.4 default is to use
+                           CONNECT HTTP/1.1 */
+  CURLPROXY_HTTP_1_0 = 1,   /* added in 7.19.4, force to use CONNECT
+                               HTTP/1.0  */
+  CURLPROXY_HTTPS = 2,  /* HTTPS but stick to HTTP/1 added in 7.52.0 */
+  CURLPROXY_HTTPS2 = 3, /* HTTPS and attempt HTTP/2 added in 8.2.0 */
+  CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already
+                           in 7.10 */
+  CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
+  CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */
+  CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the
+                                   host name rather than the IP address. added
+                                   in 7.18.0 */
+} curl_proxytype;  /* this enum was added in 7.10 */
+
+/*
+ * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options:
+ *
+ * CURLAUTH_NONE         - No HTTP authentication
+ * CURLAUTH_BASIC        - HTTP Basic authentication (default)
+ * CURLAUTH_DIGEST       - HTTP Digest authentication
+ * CURLAUTH_NEGOTIATE    - HTTP Negotiate (SPNEGO) authentication
+ * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated)
+ * CURLAUTH_NTLM         - HTTP NTLM authentication
+ * CURLAUTH_DIGEST_IE    - HTTP Digest authentication with IE flavour
+ * CURLAUTH_NTLM_WB      - HTTP NTLM authentication delegated to winbind helper
+ * CURLAUTH_BEARER       - HTTP Bearer token authentication
+ * CURLAUTH_ONLY         - Use together with a single other type to force no
+ *                         authentication or just that single type
+ * CURLAUTH_ANY          - All fine types set
+ * CURLAUTH_ANYSAFE      - All fine types except Basic
+ */
+
+#define CURLAUTH_NONE         ((unsigned long)0)
+#define CURLAUTH_BASIC        (((unsigned long)1)<<0)
+#define CURLAUTH_DIGEST       (((unsigned long)1)<<1)
+#define CURLAUTH_NEGOTIATE    (((unsigned long)1)<<2)
+/* Deprecated since the advent of CURLAUTH_NEGOTIATE */
+#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE
+/* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */
+#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE
+#define CURLAUTH_NTLM         (((unsigned long)1)<<3)
+#define CURLAUTH_DIGEST_IE    (((unsigned long)1)<<4)
+#define CURLAUTH_NTLM_WB      (((unsigned long)1)<<5)
+#define CURLAUTH_BEARER       (((unsigned long)1)<<6)
+#define CURLAUTH_AWS_SIGV4    (((unsigned long)1)<<7)
+#define CURLAUTH_ONLY         (((unsigned long)1)<<31)
+#define CURLAUTH_ANY          (~CURLAUTH_DIGEST_IE)
+#define CURLAUTH_ANYSAFE      (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE))
+
+#define CURLSSH_AUTH_ANY       ~0     /* all types supported by the server */
+#define CURLSSH_AUTH_NONE      0      /* none allowed, silly but complete */
+#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */
+#define CURLSSH_AUTH_PASSWORD  (1<<1) /* password */
+#define CURLSSH_AUTH_HOST      (1<<2) /* host key files */
+#define CURLSSH_AUTH_KEYBOARD  (1<<3) /* keyboard interactive */
+#define CURLSSH_AUTH_AGENT     (1<<4) /* agent (ssh-agent, pageant...) */
+#define CURLSSH_AUTH_GSSAPI    (1<<5) /* gssapi (kerberos, ...) */
+#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY
+
+#define CURLGSSAPI_DELEGATION_NONE        0      /* no delegation (default) */
+#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */
+#define CURLGSSAPI_DELEGATION_FLAG        (1<<1) /* delegate always */
+
+#define CURL_ERROR_SIZE 256
+
+enum curl_khtype {
+  CURLKHTYPE_UNKNOWN,
+  CURLKHTYPE_RSA1,
+  CURLKHTYPE_RSA,
+  CURLKHTYPE_DSS,
+  CURLKHTYPE_ECDSA,
+  CURLKHTYPE_ED25519
+};
+
+struct curl_khkey {
+  const char *key; /* points to a null-terminated string encoded with base64
+                      if len is zero, otherwise to the "raw" data */
+  size_t len;
+  enum curl_khtype keytype;
+};
+
+/* this is the set of return values expected from the curl_sshkeycallback
+   callback */
+enum curl_khstat {
+  CURLKHSTAT_FINE_ADD_TO_FILE,
+  CURLKHSTAT_FINE,
+  CURLKHSTAT_REJECT, /* reject the connection, return an error */
+  CURLKHSTAT_DEFER,  /* do not accept it, but we can't answer right now.
+                        Causes a CURLE_PEER_FAILED_VERIFICATION error but the
+                        connection will be left intact etc */
+  CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key */
+  CURLKHSTAT_LAST    /* not for use, only a marker for last-in-list */
+};
+
+/* this is the set of status codes pass in to the callback */
+enum curl_khmatch {
+  CURLKHMATCH_OK,       /* match */
+  CURLKHMATCH_MISMATCH, /* host found, key mismatch! */
+  CURLKHMATCH_MISSING,  /* no matching host/key found */
+  CURLKHMATCH_LAST      /* not for use, only a marker for last-in-list */
+};
+
+typedef int
+  (*curl_sshkeycallback) (CURL *easy,     /* easy handle */
+                          const struct curl_khkey *knownkey, /* known */
+                          const struct curl_khkey *foundkey, /* found */
+                          enum curl_khmatch, /* libcurl's view on the keys */
+                          void *clientp); /* custom pointer passed with */
+                                          /* CURLOPT_SSH_KEYDATA */
+
+typedef int
+  (*curl_sshhostkeycallback) (void *clientp,/* custom pointer passed */
+                                            /* with CURLOPT_SSH_HOSTKEYDATA */
+                          int keytype, /* CURLKHTYPE */
+                          const char *key, /* hostkey to check */
+                          size_t keylen); /* length of the key */
+                          /* return CURLE_OK to accept */
+                          /* or something else to refuse */
+
+
+/* parameter for the CURLOPT_USE_SSL option */
+typedef enum {
+  CURLUSESSL_NONE,    /* do not attempt to use SSL */
+  CURLUSESSL_TRY,     /* try using SSL, proceed anyway otherwise */
+  CURLUSESSL_CONTROL, /* SSL for the control connection or fail */
+  CURLUSESSL_ALL,     /* SSL for all communication or fail */
+  CURLUSESSL_LAST     /* not an option, never use */
+} curl_usessl;
+
+/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */
+
+/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the
+   name of improving interoperability with older servers. Some SSL libraries
+   have introduced work-arounds for this flaw but those work-arounds sometimes
+   make the SSL communication fail. To regain functionality with those broken
+   servers, a user can this way allow the vulnerability back. */
+#define CURLSSLOPT_ALLOW_BEAST (1<<0)
+
+/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those
+   SSL backends where such behavior is present. */
+#define CURLSSLOPT_NO_REVOKE (1<<1)
+
+/* - NO_PARTIALCHAIN tells libcurl to *NOT* accept a partial certificate chain
+   if possible. The OpenSSL backend has this ability. */
+#define CURLSSLOPT_NO_PARTIALCHAIN (1<<2)
+
+/* - REVOKE_BEST_EFFORT tells libcurl to ignore certificate revocation offline
+   checks and ignore missing revocation list for those SSL backends where such
+   behavior is present. */
+#define CURLSSLOPT_REVOKE_BEST_EFFORT (1<<3)
+
+/* - CURLSSLOPT_NATIVE_CA tells libcurl to use standard certificate store of
+   operating system. Currently implemented under MS-Windows. */
+#define CURLSSLOPT_NATIVE_CA (1<<4)
+
+/* - CURLSSLOPT_AUTO_CLIENT_CERT tells libcurl to automatically locate and use
+   a client certificate for authentication. (Schannel) */
+#define CURLSSLOPT_AUTO_CLIENT_CERT (1<<5)
+
+/* The default connection attempt delay in milliseconds for happy eyeballs.
+   CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document
+   this value, keep them in sync. */
+#define CURL_HET_DEFAULT 200L
+
+/* The default connection upkeep interval in milliseconds. */
+#define CURL_UPKEEP_INTERVAL_DEFAULT 60000L
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+                          the obsolete stuff removed! */
+
+/* Backwards compatibility with older names */
+/* These are scheduled to disappear by 2009 */
+
+#define CURLFTPSSL_NONE CURLUSESSL_NONE
+#define CURLFTPSSL_TRY CURLUSESSL_TRY
+#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL
+#define CURLFTPSSL_ALL CURLUSESSL_ALL
+#define CURLFTPSSL_LAST CURLUSESSL_LAST
+#define curl_ftpssl curl_usessl
+#endif /* !CURL_NO_OLDIES */
+
+/* parameter for the CURLOPT_FTP_SSL_CCC option */
+typedef enum {
+  CURLFTPSSL_CCC_NONE,    /* do not send CCC */
+  CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */
+  CURLFTPSSL_CCC_ACTIVE,  /* Initiate the shutdown */
+  CURLFTPSSL_CCC_LAST     /* not an option, never use */
+} curl_ftpccc;
+
+/* parameter for the CURLOPT_FTPSSLAUTH option */
+typedef enum {
+  CURLFTPAUTH_DEFAULT, /* let libcurl decide */
+  CURLFTPAUTH_SSL,     /* use "AUTH SSL" */
+  CURLFTPAUTH_TLS,     /* use "AUTH TLS" */
+  CURLFTPAUTH_LAST /* not an option, never use */
+} curl_ftpauth;
+
+/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */
+typedef enum {
+  CURLFTP_CREATE_DIR_NONE,  /* do NOT create missing dirs! */
+  CURLFTP_CREATE_DIR,       /* (FTP/SFTP) if CWD fails, try MKD and then CWD
+                               again if MKD succeeded, for SFTP this does
+                               similar magic */
+  CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD
+                               again even if MKD failed! */
+  CURLFTP_CREATE_DIR_LAST   /* not an option, never use */
+} curl_ftpcreatedir;
+
+/* parameter for the CURLOPT_FTP_FILEMETHOD option */
+typedef enum {
+  CURLFTPMETHOD_DEFAULT,   /* let libcurl pick */
+  CURLFTPMETHOD_MULTICWD,  /* single CWD operation for each path part */
+  CURLFTPMETHOD_NOCWD,     /* no CWD at all */
+  CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */
+  CURLFTPMETHOD_LAST       /* not an option, never use */
+} curl_ftpmethod;
+
+/* bitmask defines for CURLOPT_HEADEROPT */
+#define CURLHEADER_UNIFIED  0
+#define CURLHEADER_SEPARATE (1<<0)
+
+/* CURLALTSVC_* are bits for the CURLOPT_ALTSVC_CTRL option */
+#define CURLALTSVC_READONLYFILE (1<<2)
+#define CURLALTSVC_H1           (1<<3)
+#define CURLALTSVC_H2           (1<<4)
+#define CURLALTSVC_H3           (1<<5)
+
+
+struct curl_hstsentry {
+  char *name;
+  size_t namelen;
+  unsigned int includeSubDomains:1;
+  char expire[18]; /* YYYYMMDD HH:MM:SS [null-terminated] */
+};
+
+struct curl_index {
+  size_t index; /* the provided entry's "index" or count */
+  size_t total; /* total number of entries to save */
+};
+
+typedef enum {
+  CURLSTS_OK,
+  CURLSTS_DONE,
+  CURLSTS_FAIL
+} CURLSTScode;
+
+typedef CURLSTScode (*curl_hstsread_callback)(CURL *easy,
+                                              struct curl_hstsentry *e,
+                                              void *userp);
+typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy,
+                                               struct curl_hstsentry *e,
+                                               struct curl_index *i,
+                                               void *userp);
+
+/* CURLHSTS_* are bits for the CURLOPT_HSTS option */
+#define CURLHSTS_ENABLE       (long)(1<<0)
+#define CURLHSTS_READONLYFILE (long)(1<<1)
+
+/* The CURLPROTO_ defines below are for the **deprecated** CURLOPT_*PROTOCOLS
+   options. Do not use. */
+#define CURLPROTO_HTTP   (1<<0)
+#define CURLPROTO_HTTPS  (1<<1)
+#define CURLPROTO_FTP    (1<<2)
+#define CURLPROTO_FTPS   (1<<3)
+#define CURLPROTO_SCP    (1<<4)
+#define CURLPROTO_SFTP   (1<<5)
+#define CURLPROTO_TELNET (1<<6)
+#define CURLPROTO_LDAP   (1<<7)
+#define CURLPROTO_LDAPS  (1<<8)
+#define CURLPROTO_DICT   (1<<9)
+#define CURLPROTO_FILE   (1<<10)
+#define CURLPROTO_TFTP   (1<<11)
+#define CURLPROTO_IMAP   (1<<12)
+#define CURLPROTO_IMAPS  (1<<13)
+#define CURLPROTO_POP3   (1<<14)
+#define CURLPROTO_POP3S  (1<<15)
+#define CURLPROTO_SMTP   (1<<16)
+#define CURLPROTO_SMTPS  (1<<17)
+#define CURLPROTO_RTSP   (1<<18)
+#define CURLPROTO_RTMP   (1<<19)
+#define CURLPROTO_RTMPT  (1<<20)
+#define CURLPROTO_RTMPE  (1<<21)
+#define CURLPROTO_RTMPTE (1<<22)
+#define CURLPROTO_RTMPS  (1<<23)
+#define CURLPROTO_RTMPTS (1<<24)
+#define CURLPROTO_GOPHER (1<<25)
+#define CURLPROTO_SMB    (1<<26)
+#define CURLPROTO_SMBS   (1<<27)
+#define CURLPROTO_MQTT   (1<<28)
+#define CURLPROTO_GOPHERS (1<<29)
+#define CURLPROTO_ALL    (~0) /* enable everything */
+
+/* long may be 32 or 64 bits, but we should never depend on anything else
+   but 32 */
+#define CURLOPTTYPE_LONG          0
+#define CURLOPTTYPE_OBJECTPOINT   10000
+#define CURLOPTTYPE_FUNCTIONPOINT 20000
+#define CURLOPTTYPE_OFF_T         30000
+#define CURLOPTTYPE_BLOB          40000
+
+/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the
+   string options from the header file */
+
+
+#define CURLOPT(na,t,nu) na = t + nu
+#define CURLOPTDEPRECATED(na,t,nu,v,m) na CURL_DEPRECATED(v,m) = t + nu
+
+/* CURLOPT aliases that make no run-time difference */
+
+/* 'char *' argument to a string with a trailing zero */
+#define CURLOPTTYPE_STRINGPOINT CURLOPTTYPE_OBJECTPOINT
+
+/* 'struct curl_slist *' argument */
+#define CURLOPTTYPE_SLISTPOINT  CURLOPTTYPE_OBJECTPOINT
+
+/* 'void *' argument passed untouched to callback */
+#define CURLOPTTYPE_CBPOINT     CURLOPTTYPE_OBJECTPOINT
+
+/* 'long' argument with a set of values/bitmask */
+#define CURLOPTTYPE_VALUES      CURLOPTTYPE_LONG
+
+/*
+ * All CURLOPT_* values.
+ */
+
+typedef enum {
+  /* This is the FILE * or void * the regular output should be written to. */
+  CURLOPT(CURLOPT_WRITEDATA, CURLOPTTYPE_CBPOINT, 1),
+
+  /* The full URL to get/put */
+  CURLOPT(CURLOPT_URL, CURLOPTTYPE_STRINGPOINT, 2),
+
+  /* Port number to connect to, if other than default. */
+  CURLOPT(CURLOPT_PORT, CURLOPTTYPE_LONG, 3),
+
+  /* Name of proxy to use. */
+  CURLOPT(CURLOPT_PROXY, CURLOPTTYPE_STRINGPOINT, 4),
+
+  /* "user:password;options" to use when fetching. */
+  CURLOPT(CURLOPT_USERPWD, CURLOPTTYPE_STRINGPOINT, 5),
+
+  /* "user:password" to use with proxy. */
+  CURLOPT(CURLOPT_PROXYUSERPWD, CURLOPTTYPE_STRINGPOINT, 6),
+
+  /* Range to get, specified as an ASCII string. */
+  CURLOPT(CURLOPT_RANGE, CURLOPTTYPE_STRINGPOINT, 7),
+
+  /* not used */
+
+  /* Specified file stream to upload from (use as input): */
+  CURLOPT(CURLOPT_READDATA, CURLOPTTYPE_CBPOINT, 9),
+
+  /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE
+   * bytes big. */
+  CURLOPT(CURLOPT_ERRORBUFFER, CURLOPTTYPE_OBJECTPOINT, 10),
+
+  /* Function that will be called to store the output (instead of fwrite). The
+   * parameters will use fwrite() syntax, make sure to follow them. */
+  CURLOPT(CURLOPT_WRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 11),
+
+  /* Function that will be called to read the input (instead of fread). The
+   * parameters will use fread() syntax, make sure to follow them. */
+  CURLOPT(CURLOPT_READFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 12),
+
+  /* Time-out the read operation after this amount of seconds */
+  CURLOPT(CURLOPT_TIMEOUT, CURLOPTTYPE_LONG, 13),
+
+  /* If CURLOPT_READDATA is used, this can be used to inform libcurl about
+   * how large the file being sent really is. That allows better error
+   * checking and better verifies that the upload was successful. -1 means
+   * unknown size.
+   *
+   * For large file support, there is also a _LARGE version of the key
+   * which takes an off_t type, allowing platforms with larger off_t
+   * sizes to handle larger files.  See below for INFILESIZE_LARGE.
+   */
+  CURLOPT(CURLOPT_INFILESIZE, CURLOPTTYPE_LONG, 14),
+
+  /* POST static input fields. */
+  CURLOPT(CURLOPT_POSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 15),
+
+  /* Set the referrer page (needed by some CGIs) */
+  CURLOPT(CURLOPT_REFERER, CURLOPTTYPE_STRINGPOINT, 16),
+
+  /* Set the FTP PORT string (interface name, named or numerical IP address)
+     Use i.e '-' to use default address. */
+  CURLOPT(CURLOPT_FTPPORT, CURLOPTTYPE_STRINGPOINT, 17),
+
+  /* Set the User-Agent string (examined by some CGIs) */
+  CURLOPT(CURLOPT_USERAGENT, CURLOPTTYPE_STRINGPOINT, 18),
+
+  /* If the download receives less than "low speed limit" bytes/second
+   * during "low speed time" seconds, the operations is aborted.
+   * You could i.e if you have a pretty high speed connection, abort if
+   * it is less than 2000 bytes/sec during 20 seconds.
+   */
+
+  /* Set the "low speed limit" */
+  CURLOPT(CURLOPT_LOW_SPEED_LIMIT, CURLOPTTYPE_LONG, 19),
+
+  /* Set the "low speed time" */
+  CURLOPT(CURLOPT_LOW_SPEED_TIME, CURLOPTTYPE_LONG, 20),
+
+  /* Set the continuation offset.
+   *
+   * Note there is also a _LARGE version of this key which uses
+   * off_t types, allowing for large file offsets on platforms which
+   * use larger-than-32-bit off_t's.  Look below for RESUME_FROM_LARGE.
+   */
+  CURLOPT(CURLOPT_RESUME_FROM, CURLOPTTYPE_LONG, 21),
+
+  /* Set cookie in request: */
+  CURLOPT(CURLOPT_COOKIE, CURLOPTTYPE_STRINGPOINT, 22),
+
+  /* This points to a linked list of headers, struct curl_slist kind. This
+     list is also used for RTSP (in spite of its name) */
+  CURLOPT(CURLOPT_HTTPHEADER, CURLOPTTYPE_SLISTPOINT, 23),
+
+  /* This points to a linked list of post entries, struct curl_httppost */
+  CURLOPTDEPRECATED(CURLOPT_HTTPPOST, CURLOPTTYPE_OBJECTPOINT, 24,
+                    7.56.0, "Use CURLOPT_MIMEPOST"),
+
+  /* name of the file keeping your private SSL-certificate */
+  CURLOPT(CURLOPT_SSLCERT, CURLOPTTYPE_STRINGPOINT, 25),
+
+  /* password for the SSL or SSH private key */
+  CURLOPT(CURLOPT_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 26),
+
+  /* send TYPE parameter? */
+  CURLOPT(CURLOPT_CRLF, CURLOPTTYPE_LONG, 27),
+
+  /* send linked-list of QUOTE commands */
+  CURLOPT(CURLOPT_QUOTE, CURLOPTTYPE_SLISTPOINT, 28),
+
+  /* send FILE * or void * to store headers to, if you use a callback it
+     is simply passed to the callback unmodified */
+  CURLOPT(CURLOPT_HEADERDATA, CURLOPTTYPE_CBPOINT, 29),
+
+  /* point to a file to read the initial cookies from, also enables
+     "cookie awareness" */
+  CURLOPT(CURLOPT_COOKIEFILE, CURLOPTTYPE_STRINGPOINT, 31),
+
+  /* What version to specifically try to use.
+     See CURL_SSLVERSION defines below. */
+  CURLOPT(CURLOPT_SSLVERSION, CURLOPTTYPE_VALUES, 32),
+
+  /* What kind of HTTP time condition to use, see defines */
+  CURLOPT(CURLOPT_TIMECONDITION, CURLOPTTYPE_VALUES, 33),
+
+  /* Time to use with the above condition. Specified in number of seconds
+     since 1 Jan 1970 */
+  CURLOPT(CURLOPT_TIMEVALUE, CURLOPTTYPE_LONG, 34),
+
+  /* 35 = OBSOLETE */
+
+  /* Custom request, for customizing the get command like
+     HTTP: DELETE, TRACE and others
+     FTP: to use a different list command
+     */
+  CURLOPT(CURLOPT_CUSTOMREQUEST, CURLOPTTYPE_STRINGPOINT, 36),
+
+  /* FILE handle to use instead of stderr */
+  CURLOPT(CURLOPT_STDERR, CURLOPTTYPE_OBJECTPOINT, 37),
+
+  /* 38 is not used */
+
+  /* send linked-list of post-transfer QUOTE commands */
+  CURLOPT(CURLOPT_POSTQUOTE, CURLOPTTYPE_SLISTPOINT, 39),
+
+   /* OBSOLETE, do not use! */
+  CURLOPT(CURLOPT_OBSOLETE40, CURLOPTTYPE_OBJECTPOINT, 40),
+
+  /* talk a lot */
+  CURLOPT(CURLOPT_VERBOSE, CURLOPTTYPE_LONG, 41),
+
+  /* throw the header out too */
+  CURLOPT(CURLOPT_HEADER, CURLOPTTYPE_LONG, 42),
+
+  /* shut off the progress meter */
+  CURLOPT(CURLOPT_NOPROGRESS, CURLOPTTYPE_LONG, 43),
+
+  /* use HEAD to get http document */
+  CURLOPT(CURLOPT_NOBODY, CURLOPTTYPE_LONG, 44),
+
+  /* no output on http error codes >= 400 */
+  CURLOPT(CURLOPT_FAILONERROR, CURLOPTTYPE_LONG, 45),
+
+  /* this is an upload */
+  CURLOPT(CURLOPT_UPLOAD, CURLOPTTYPE_LONG, 46),
+
+  /* HTTP POST method */
+  CURLOPT(CURLOPT_POST, CURLOPTTYPE_LONG, 47),
+
+  /* bare names when listing directories */
+  CURLOPT(CURLOPT_DIRLISTONLY, CURLOPTTYPE_LONG, 48),
+
+  /* Append instead of overwrite on upload! */
+  CURLOPT(CURLOPT_APPEND, CURLOPTTYPE_LONG, 50),
+
+  /* Specify whether to read the user+password from the .netrc or the URL.
+   * This must be one of the CURL_NETRC_* enums below. */
+  CURLOPT(CURLOPT_NETRC, CURLOPTTYPE_VALUES, 51),
+
+  /* use Location: Luke! */
+  CURLOPT(CURLOPT_FOLLOWLOCATION, CURLOPTTYPE_LONG, 52),
+
+   /* transfer data in text/ASCII format */
+  CURLOPT(CURLOPT_TRANSFERTEXT, CURLOPTTYPE_LONG, 53),
+
+  /* HTTP PUT */
+  CURLOPTDEPRECATED(CURLOPT_PUT, CURLOPTTYPE_LONG, 54,
+                    7.12.1, "Use CURLOPT_UPLOAD"),
+
+  /* 55 = OBSOLETE */
+
+  /* DEPRECATED
+   * Function that will be called instead of the internal progress display
+   * function. This function should be defined as the curl_progress_callback
+   * prototype defines. */
+  CURLOPTDEPRECATED(CURLOPT_PROGRESSFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 56,
+                    7.32.0, "Use CURLOPT_XFERINFOFUNCTION"),
+
+  /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION
+     callbacks */
+  CURLOPT(CURLOPT_XFERINFODATA, CURLOPTTYPE_CBPOINT, 57),
+#define CURLOPT_PROGRESSDATA CURLOPT_XFERINFODATA
+
+  /* We want the referrer field set automatically when following locations */
+  CURLOPT(CURLOPT_AUTOREFERER, CURLOPTTYPE_LONG, 58),
+
+  /* Port of the proxy, can be set in the proxy string as well with:
+     "[host]:[port]" */
+  CURLOPT(CURLOPT_PROXYPORT, CURLOPTTYPE_LONG, 59),
+
+  /* size of the POST input data, if strlen() is not good to use */
+  CURLOPT(CURLOPT_POSTFIELDSIZE, CURLOPTTYPE_LONG, 60),
+
+  /* tunnel non-http operations through an HTTP proxy */
+  CURLOPT(CURLOPT_HTTPPROXYTUNNEL, CURLOPTTYPE_LONG, 61),
+
+  /* Set the interface string to use as outgoing network interface */
+  CURLOPT(CURLOPT_INTERFACE, CURLOPTTYPE_STRINGPOINT, 62),
+
+  /* Set the krb4/5 security level, this also enables krb4/5 awareness.  This
+   * is a string, 'clear', 'safe', 'confidential' or 'private'.  If the string
+   * is set but doesn't match one of these, 'private' will be used.  */
+  CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63),
+
+  /* Set if we should verify the peer in ssl handshake, set 1 to verify. */
+  CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64),
+
+  /* The CApath or CAfile used to validate the peer certificate
+     this option is used only if SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_CAINFO, CURLOPTTYPE_STRINGPOINT, 65),
+
+  /* 66 = OBSOLETE */
+  /* 67 = OBSOLETE */
+
+  /* Maximum number of http redirects to follow */
+  CURLOPT(CURLOPT_MAXREDIRS, CURLOPTTYPE_LONG, 68),
+
+  /* Pass a long set to 1 to get the date of the requested document (if
+     possible)! Pass a zero to shut it off. */
+  CURLOPT(CURLOPT_FILETIME, CURLOPTTYPE_LONG, 69),
+
+  /* This points to a linked list of telnet options */
+  CURLOPT(CURLOPT_TELNETOPTIONS, CURLOPTTYPE_SLISTPOINT, 70),
+
+  /* Max amount of cached alive connections */
+  CURLOPT(CURLOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 71),
+
+  /* OBSOLETE, do not use! */
+  CURLOPT(CURLOPT_OBSOLETE72, CURLOPTTYPE_LONG, 72),
+
+  /* 73 = OBSOLETE */
+
+  /* Set to explicitly use a new connection for the upcoming transfer.
+     Do not use this unless you're absolutely sure of this, as it makes the
+     operation slower and is less friendly for the network. */
+  CURLOPT(CURLOPT_FRESH_CONNECT, CURLOPTTYPE_LONG, 74),
+
+  /* Set to explicitly forbid the upcoming transfer's connection to be reused
+     when done. Do not use this unless you're absolutely sure of this, as it
+     makes the operation slower and is less friendly for the network. */
+  CURLOPT(CURLOPT_FORBID_REUSE, CURLOPTTYPE_LONG, 75),
+
+  /* Set to a file name that contains random data for libcurl to use to
+     seed the random engine when doing SSL connects. */
+  CURLOPTDEPRECATED(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76,
+                    7.84.0, "Serves no purpose anymore"),
+
+  /* Set to the Entropy Gathering Daemon socket pathname */
+  CURLOPTDEPRECATED(CURLOPT_EGDSOCKET, CURLOPTTYPE_STRINGPOINT, 77,
+                    7.84.0, "Serves no purpose anymore"),
+
+  /* Time-out connect operations after this amount of seconds, if connects are
+     OK within this time, then fine... This only aborts the connect phase. */
+  CURLOPT(CURLOPT_CONNECTTIMEOUT, CURLOPTTYPE_LONG, 78),
+
+  /* Function that will be called to store headers (instead of fwrite). The
+   * parameters will use fwrite() syntax, make sure to follow them. */
+  CURLOPT(CURLOPT_HEADERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 79),
+
+  /* Set this to force the HTTP request to get back to GET. Only really usable
+     if POST, PUT or a custom request have been used first.
+   */
+  CURLOPT(CURLOPT_HTTPGET, CURLOPTTYPE_LONG, 80),
+
+  /* Set if we should verify the Common name from the peer certificate in ssl
+   * handshake, set 1 to check existence, 2 to ensure that it matches the
+   * provided hostname. */
+  CURLOPT(CURLOPT_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 81),
+
+  /* Specify which file name to write all known cookies in after completed
+     operation. Set file name to "-" (dash) to make it go to stdout. */
+  CURLOPT(CURLOPT_COOKIEJAR, CURLOPTTYPE_STRINGPOINT, 82),
+
+  /* Specify which SSL ciphers to use */
+  CURLOPT(CURLOPT_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 83),
+
+  /* Specify which HTTP version to use! This must be set to one of the
+     CURL_HTTP_VERSION* enums set below. */
+  CURLOPT(CURLOPT_HTTP_VERSION, CURLOPTTYPE_VALUES, 84),
+
+  /* Specifically switch on or off the FTP engine's use of the EPSV command. By
+     default, that one will always be attempted before the more traditional
+     PASV command. */
+  CURLOPT(CURLOPT_FTP_USE_EPSV, CURLOPTTYPE_LONG, 85),
+
+  /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */
+  CURLOPT(CURLOPT_SSLCERTTYPE, CURLOPTTYPE_STRINGPOINT, 86),
+
+  /* name of the file keeping your private SSL-key */
+  CURLOPT(CURLOPT_SSLKEY, CURLOPTTYPE_STRINGPOINT, 87),
+
+  /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */
+  CURLOPT(CURLOPT_SSLKEYTYPE, CURLOPTTYPE_STRINGPOINT, 88),
+
+  /* crypto engine for the SSL-sub system */
+  CURLOPT(CURLOPT_SSLENGINE, CURLOPTTYPE_STRINGPOINT, 89),
+
+  /* set the crypto engine for the SSL-sub system as default
+     the param has no meaning...
+   */
+  CURLOPT(CURLOPT_SSLENGINE_DEFAULT, CURLOPTTYPE_LONG, 90),
+
+  /* Non-zero value means to use the global dns cache */
+  /* DEPRECATED, do not use! */
+  CURLOPTDEPRECATED(CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOPTTYPE_LONG, 91,
+                    7.11.1, "Use CURLOPT_SHARE"),
+
+  /* DNS cache timeout */
+  CURLOPT(CURLOPT_DNS_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 92),
+
+  /* send linked-list of pre-transfer QUOTE commands */
+  CURLOPT(CURLOPT_PREQUOTE, CURLOPTTYPE_SLISTPOINT, 93),
+
+  /* set the debug function */
+  CURLOPT(CURLOPT_DEBUGFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 94),
+
+  /* set the data for the debug function */
+  CURLOPT(CURLOPT_DEBUGDATA, CURLOPTTYPE_CBPOINT, 95),
+
+  /* mark this as start of a cookie session */
+  CURLOPT(CURLOPT_COOKIESESSION, CURLOPTTYPE_LONG, 96),
+
+  /* The CApath directory used to validate the peer certificate
+     this option is used only if SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_CAPATH, CURLOPTTYPE_STRINGPOINT, 97),
+
+  /* Instruct libcurl to use a smaller receive buffer */
+  CURLOPT(CURLOPT_BUFFERSIZE, CURLOPTTYPE_LONG, 98),
+
+  /* Instruct libcurl to not use any signal/alarm handlers, even when using
+     timeouts. This option is useful for multi-threaded applications.
+     See libcurl-the-guide for more background information. */
+  CURLOPT(CURLOPT_NOSIGNAL, CURLOPTTYPE_LONG, 99),
+
+  /* Provide a CURLShare for mutexing non-ts data */
+  CURLOPT(CURLOPT_SHARE, CURLOPTTYPE_OBJECTPOINT, 100),
+
+  /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default),
+     CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and
+     CURLPROXY_SOCKS5. */
+  CURLOPT(CURLOPT_PROXYTYPE, CURLOPTTYPE_VALUES, 101),
+
+  /* Set the Accept-Encoding string. Use this to tell a server you would like
+     the response to be compressed. Before 7.21.6, this was known as
+     CURLOPT_ENCODING */
+  CURLOPT(CURLOPT_ACCEPT_ENCODING, CURLOPTTYPE_STRINGPOINT, 102),
+
+  /* Set pointer to private data */
+  CURLOPT(CURLOPT_PRIVATE, CURLOPTTYPE_OBJECTPOINT, 103),
+
+  /* Set aliases for HTTP 200 in the HTTP Response header */
+  CURLOPT(CURLOPT_HTTP200ALIASES, CURLOPTTYPE_SLISTPOINT, 104),
+
+  /* Continue to send authentication (user+password) when following locations,
+     even when hostname changed. This can potentially send off the name
+     and password to whatever host the server decides. */
+  CURLOPT(CURLOPT_UNRESTRICTED_AUTH, CURLOPTTYPE_LONG, 105),
+
+  /* Specifically switch on or off the FTP engine's use of the EPRT command (
+     it also disables the LPRT attempt). By default, those ones will always be
+     attempted before the good old traditional PORT command. */
+  CURLOPT(CURLOPT_FTP_USE_EPRT, CURLOPTTYPE_LONG, 106),
+
+  /* Set this to a bitmask value to enable the particular authentications
+     methods you like. Use this in combination with CURLOPT_USERPWD.
+     Note that setting multiple bits may cause extra network round-trips. */
+  CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_VALUES, 107),
+
+  /* Set the ssl context callback function, currently only for OpenSSL or
+     WolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument.
+     The function must match the curl_ssl_ctx_callback prototype. */
+  CURLOPT(CURLOPT_SSL_CTX_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 108),
+
+  /* Set the userdata for the ssl context callback function's third
+     argument */
+  CURLOPT(CURLOPT_SSL_CTX_DATA, CURLOPTTYPE_CBPOINT, 109),
+
+  /* FTP Option that causes missing dirs to be created on the remote server.
+     In 7.19.4 we introduced the convenience enums for this option using the
+     CURLFTP_CREATE_DIR prefix.
+  */
+  CURLOPT(CURLOPT_FTP_CREATE_MISSING_DIRS, CURLOPTTYPE_LONG, 110),
+
+  /* Set this to a bitmask value to enable the particular authentications
+     methods you like. Use this in combination with CURLOPT_PROXYUSERPWD.
+     Note that setting multiple bits may cause extra network round-trips. */
+  CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_VALUES, 111),
+
+  /* Option that changes the timeout, in seconds, associated with getting a
+     response.  This is different from transfer timeout time and essentially
+     places a demand on the server to acknowledge commands in a timely
+     manner. For FTP, SMTP, IMAP and POP3. */
+  CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT, CURLOPTTYPE_LONG, 112),
+
+  /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
+     tell libcurl to use those IP versions only. This only has effect on
+     systems with support for more than one, i.e IPv4 _and_ IPv6. */
+  CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_VALUES, 113),
+
+  /* Set this option to limit the size of a file that will be downloaded from
+     an HTTP or FTP server.
+
+     Note there is also _LARGE version which adds large file support for
+     platforms which have larger off_t sizes.  See MAXFILESIZE_LARGE below. */
+  CURLOPT(CURLOPT_MAXFILESIZE, CURLOPTTYPE_LONG, 114),
+
+  /* See the comment for INFILESIZE above, but in short, specifies
+   * the size of the file being uploaded.  -1 means unknown.
+   */
+  CURLOPT(CURLOPT_INFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 115),
+
+  /* Sets the continuation offset.  There is also a CURLOPTTYPE_LONG version
+   * of this; look above for RESUME_FROM.
+   */
+  CURLOPT(CURLOPT_RESUME_FROM_LARGE, CURLOPTTYPE_OFF_T, 116),
+
+  /* Sets the maximum size of data that will be downloaded from
+   * an HTTP or FTP server.  See MAXFILESIZE above for the LONG version.
+   */
+  CURLOPT(CURLOPT_MAXFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 117),
+
+  /* Set this option to the file name of your .netrc file you want libcurl
+     to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
+     a poor attempt to find the user's home directory and check for a .netrc
+     file in there. */
+  CURLOPT(CURLOPT_NETRC_FILE, CURLOPTTYPE_STRINGPOINT, 118),
+
+  /* Enable SSL/TLS for FTP, pick one of:
+     CURLUSESSL_TRY     - try using SSL, proceed anyway otherwise
+     CURLUSESSL_CONTROL - SSL for the control connection or fail
+     CURLUSESSL_ALL     - SSL for all communication or fail
+  */
+  CURLOPT(CURLOPT_USE_SSL, CURLOPTTYPE_VALUES, 119),
+
+  /* The _LARGE version of the standard POSTFIELDSIZE option */
+  CURLOPT(CURLOPT_POSTFIELDSIZE_LARGE, CURLOPTTYPE_OFF_T, 120),
+
+  /* Enable/disable the TCP Nagle algorithm */
+  CURLOPT(CURLOPT_TCP_NODELAY, CURLOPTTYPE_LONG, 121),
+
+  /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+  /* 123 OBSOLETE. Gone in 7.16.0 */
+  /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+  /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+  /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+  /* 127 OBSOLETE. Gone in 7.16.0 */
+  /* 128 OBSOLETE. Gone in 7.16.0 */
+
+  /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option
+     can be used to change libcurl's default action which is to first try
+     "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK
+     response has been received.
+
+     Available parameters are:
+     CURLFTPAUTH_DEFAULT - let libcurl decide
+     CURLFTPAUTH_SSL     - try "AUTH SSL" first, then TLS
+     CURLFTPAUTH_TLS     - try "AUTH TLS" first, then SSL
+  */
+  CURLOPT(CURLOPT_FTPSSLAUTH, CURLOPTTYPE_VALUES, 129),
+
+  CURLOPTDEPRECATED(CURLOPT_IOCTLFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 130,
+                    7.18.0, "Use CURLOPT_SEEKFUNCTION"),
+  CURLOPTDEPRECATED(CURLOPT_IOCTLDATA, CURLOPTTYPE_CBPOINT, 131,
+                    7.18.0, "Use CURLOPT_SEEKDATA"),
+
+  /* 132 OBSOLETE. Gone in 7.16.0 */
+  /* 133 OBSOLETE. Gone in 7.16.0 */
+
+  /* null-terminated string for pass on to the FTP server when asked for
+     "account" info */
+  CURLOPT(CURLOPT_FTP_ACCOUNT, CURLOPTTYPE_STRINGPOINT, 134),
+
+  /* feed cookie into cookie engine */
+  CURLOPT(CURLOPT_COOKIELIST, CURLOPTTYPE_STRINGPOINT, 135),
+
+  /* ignore Content-Length */
+  CURLOPT(CURLOPT_IGNORE_CONTENT_LENGTH, CURLOPTTYPE_LONG, 136),
+
+  /* Set to non-zero to skip the IP address received in a 227 PASV FTP server
+     response. Typically used for FTP-SSL purposes but is not restricted to
+     that. libcurl will then instead use the same IP address it used for the
+     control connection. */
+  CURLOPT(CURLOPT_FTP_SKIP_PASV_IP, CURLOPTTYPE_LONG, 137),
+
+  /* Select "file method" to use when doing FTP, see the curl_ftpmethod
+     above. */
+  CURLOPT(CURLOPT_FTP_FILEMETHOD, CURLOPTTYPE_VALUES, 138),
+
+  /* Local port number to bind the socket to */
+  CURLOPT(CURLOPT_LOCALPORT, CURLOPTTYPE_LONG, 139),
+
+  /* Number of ports to try, including the first one set with LOCALPORT.
+     Thus, setting it to 1 will make no additional attempts but the first.
+  */
+  CURLOPT(CURLOPT_LOCALPORTRANGE, CURLOPTTYPE_LONG, 140),
+
+  /* no transfer, set up connection and let application use the socket by
+     extracting it with CURLINFO_LASTSOCKET */
+  CURLOPT(CURLOPT_CONNECT_ONLY, CURLOPTTYPE_LONG, 141),
+
+  /* Function that will be called to convert from the
+     network encoding (instead of using the iconv calls in libcurl) */
+  CURLOPTDEPRECATED(CURLOPT_CONV_FROM_NETWORK_FUNCTION,
+                    CURLOPTTYPE_FUNCTIONPOINT, 142,
+                    7.82.0, "Serves no purpose anymore"),
+
+  /* Function that will be called to convert to the
+     network encoding (instead of using the iconv calls in libcurl) */
+  CURLOPTDEPRECATED(CURLOPT_CONV_TO_NETWORK_FUNCTION,
+                    CURLOPTTYPE_FUNCTIONPOINT, 143,
+                    7.82.0, "Serves no purpose anymore"),
+
+  /* Function that will be called to convert from UTF8
+     (instead of using the iconv calls in libcurl)
+     Note that this is used only for SSL certificate processing */
+  CURLOPTDEPRECATED(CURLOPT_CONV_FROM_UTF8_FUNCTION,
+                    CURLOPTTYPE_FUNCTIONPOINT, 144,
+                    7.82.0, "Serves no purpose anymore"),
+
+  /* if the connection proceeds too quickly then need to slow it down */
+  /* limit-rate: maximum number of bytes per second to send or receive */
+  CURLOPT(CURLOPT_MAX_SEND_SPEED_LARGE, CURLOPTTYPE_OFF_T, 145),
+  CURLOPT(CURLOPT_MAX_RECV_SPEED_LARGE, CURLOPTTYPE_OFF_T, 146),
+
+  /* Pointer to command string to send if USER/PASS fails. */
+  CURLOPT(CURLOPT_FTP_ALTERNATIVE_TO_USER, CURLOPTTYPE_STRINGPOINT, 147),
+
+  /* callback function for setting socket options */
+  CURLOPT(CURLOPT_SOCKOPTFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 148),
+  CURLOPT(CURLOPT_SOCKOPTDATA, CURLOPTTYPE_CBPOINT, 149),
+
+  /* set to 0 to disable session ID reuse for this transfer, default is
+     enabled (== 1) */
+  CURLOPT(CURLOPT_SSL_SESSIONID_CACHE, CURLOPTTYPE_LONG, 150),
+
+  /* allowed SSH authentication methods */
+  CURLOPT(CURLOPT_SSH_AUTH_TYPES, CURLOPTTYPE_VALUES, 151),
+
+  /* Used by scp/sftp to do public/private key authentication */
+  CURLOPT(CURLOPT_SSH_PUBLIC_KEYFILE, CURLOPTTYPE_STRINGPOINT, 152),
+  CURLOPT(CURLOPT_SSH_PRIVATE_KEYFILE, CURLOPTTYPE_STRINGPOINT, 153),
+
+  /* Send CCC (Clear Command Channel) after authentication */
+  CURLOPT(CURLOPT_FTP_SSL_CCC, CURLOPTTYPE_LONG, 154),
+
+  /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */
+  CURLOPT(CURLOPT_TIMEOUT_MS, CURLOPTTYPE_LONG, 155),
+  CURLOPT(CURLOPT_CONNECTTIMEOUT_MS, CURLOPTTYPE_LONG, 156),
+
+  /* set to zero to disable the libcurl's decoding and thus pass the raw body
+     data to the application even when it is encoded/compressed */
+  CURLOPT(CURLOPT_HTTP_TRANSFER_DECODING, CURLOPTTYPE_LONG, 157),
+  CURLOPT(CURLOPT_HTTP_CONTENT_DECODING, CURLOPTTYPE_LONG, 158),
+
+  /* Permission used when creating new files and directories on the remote
+     server for protocols that support it, SFTP/SCP/FILE */
+  CURLOPT(CURLOPT_NEW_FILE_PERMS, CURLOPTTYPE_LONG, 159),
+  CURLOPT(CURLOPT_NEW_DIRECTORY_PERMS, CURLOPTTYPE_LONG, 160),
+
+  /* Set the behavior of POST when redirecting. Values must be set to one
+     of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */
+  CURLOPT(CURLOPT_POSTREDIR, CURLOPTTYPE_VALUES, 161),
+
+  /* used by scp/sftp to verify the host's public key */
+  CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, CURLOPTTYPE_STRINGPOINT, 162),
+
+  /* Callback function for opening socket (instead of socket(2)). Optionally,
+     callback is able change the address or refuse to connect returning
+     CURL_SOCKET_BAD.  The callback should have type
+     curl_opensocket_callback */
+  CURLOPT(CURLOPT_OPENSOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 163),
+  CURLOPT(CURLOPT_OPENSOCKETDATA, CURLOPTTYPE_CBPOINT, 164),
+
+  /* POST volatile input fields. */
+  CURLOPT(CURLOPT_COPYPOSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 165),
+
+  /* set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy */
+  CURLOPT(CURLOPT_PROXY_TRANSFER_MODE, CURLOPTTYPE_LONG, 166),
+
+  /* Callback function for seeking in the input stream */
+  CURLOPT(CURLOPT_SEEKFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 167),
+  CURLOPT(CURLOPT_SEEKDATA, CURLOPTTYPE_CBPOINT, 168),
+
+  /* CRL file */
+  CURLOPT(CURLOPT_CRLFILE, CURLOPTTYPE_STRINGPOINT, 169),
+
+  /* Issuer certificate */
+  CURLOPT(CURLOPT_ISSUERCERT, CURLOPTTYPE_STRINGPOINT, 170),
+
+  /* (IPv6) Address scope */
+  CURLOPT(CURLOPT_ADDRESS_SCOPE, CURLOPTTYPE_LONG, 171),
+
+  /* Collect certificate chain info and allow it to get retrievable with
+     CURLINFO_CERTINFO after the transfer is complete. */
+  CURLOPT(CURLOPT_CERTINFO, CURLOPTTYPE_LONG, 172),
+
+  /* "name" and "pwd" to use when fetching. */
+  CURLOPT(CURLOPT_USERNAME, CURLOPTTYPE_STRINGPOINT, 173),
+  CURLOPT(CURLOPT_PASSWORD, CURLOPTTYPE_STRINGPOINT, 174),
+
+    /* "name" and "pwd" to use with Proxy when fetching. */
+  CURLOPT(CURLOPT_PROXYUSERNAME, CURLOPTTYPE_STRINGPOINT, 175),
+  CURLOPT(CURLOPT_PROXYPASSWORD, CURLOPTTYPE_STRINGPOINT, 176),
+
+  /* Comma separated list of hostnames defining no-proxy zones. These should
+     match both hostnames directly, and hostnames within a domain. For
+     example, local.com will match local.com and www.local.com, but NOT
+     notlocal.com or www.notlocal.com. For compatibility with other
+     implementations of this, .local.com will be considered to be the same as
+     local.com. A single * is the only valid wildcard, and effectively
+     disables the use of proxy. */
+  CURLOPT(CURLOPT_NOPROXY, CURLOPTTYPE_STRINGPOINT, 177),
+
+  /* block size for TFTP transfers */
+  CURLOPT(CURLOPT_TFTP_BLKSIZE, CURLOPTTYPE_LONG, 178),
+
+  /* Socks Service */
+  /* DEPRECATED, do not use! */
+  CURLOPTDEPRECATED(CURLOPT_SOCKS5_GSSAPI_SERVICE,
+                    CURLOPTTYPE_STRINGPOINT, 179,
+                    7.49.0, "Use CURLOPT_PROXY_SERVICE_NAME"),
+
+  /* Socks Service */
+  CURLOPT(CURLOPT_SOCKS5_GSSAPI_NEC, CURLOPTTYPE_LONG, 180),
+
+  /* set the bitmask for the protocols that are allowed to be used for the
+     transfer, which thus helps the app which takes URLs from users or other
+     external inputs and want to restrict what protocol(s) to deal
+     with. Defaults to CURLPROTO_ALL. */
+  CURLOPTDEPRECATED(CURLOPT_PROTOCOLS, CURLOPTTYPE_LONG, 181,
+                    7.85.0, "Use CURLOPT_PROTOCOLS_STR"),
+
+  /* set the bitmask for the protocols that libcurl is allowed to follow to,
+     as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+     to be set in both bitmasks to be allowed to get redirected to. */
+  CURLOPTDEPRECATED(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182,
+                    7.85.0, "Use CURLOPT_REDIR_PROTOCOLS_STR"),
+
+  /* set the SSH knownhost file name to use */
+  CURLOPT(CURLOPT_SSH_KNOWNHOSTS, CURLOPTTYPE_STRINGPOINT, 183),
+
+  /* set the SSH host key callback, must point to a curl_sshkeycallback
+     function */
+  CURLOPT(CURLOPT_SSH_KEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 184),
+
+  /* set the SSH host key callback custom pointer */
+  CURLOPT(CURLOPT_SSH_KEYDATA, CURLOPTTYPE_CBPOINT, 185),
+
+  /* set the SMTP mail originator */
+  CURLOPT(CURLOPT_MAIL_FROM, CURLOPTTYPE_STRINGPOINT, 186),
+
+  /* set the list of SMTP mail receiver(s) */
+  CURLOPT(CURLOPT_MAIL_RCPT, CURLOPTTYPE_SLISTPOINT, 187),
+
+  /* FTP: send PRET before PASV */
+  CURLOPT(CURLOPT_FTP_USE_PRET, CURLOPTTYPE_LONG, 188),
+
+  /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */
+  CURLOPT(CURLOPT_RTSP_REQUEST, CURLOPTTYPE_VALUES, 189),
+
+  /* The RTSP session identifier */
+  CURLOPT(CURLOPT_RTSP_SESSION_ID, CURLOPTTYPE_STRINGPOINT, 190),
+
+  /* The RTSP stream URI */
+  CURLOPT(CURLOPT_RTSP_STREAM_URI, CURLOPTTYPE_STRINGPOINT, 191),
+
+  /* The Transport: header to use in RTSP requests */
+  CURLOPT(CURLOPT_RTSP_TRANSPORT, CURLOPTTYPE_STRINGPOINT, 192),
+
+  /* Manually initialize the client RTSP CSeq for this handle */
+  CURLOPT(CURLOPT_RTSP_CLIENT_CSEQ, CURLOPTTYPE_LONG, 193),
+
+  /* Manually initialize the server RTSP CSeq for this handle */
+  CURLOPT(CURLOPT_RTSP_SERVER_CSEQ, CURLOPTTYPE_LONG, 194),
+
+  /* The stream to pass to INTERLEAVEFUNCTION. */
+  CURLOPT(CURLOPT_INTERLEAVEDATA, CURLOPTTYPE_CBPOINT, 195),
+
+  /* Let the application define a custom write method for RTP data */
+  CURLOPT(CURLOPT_INTERLEAVEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 196),
+
+  /* Turn on wildcard matching */
+  CURLOPT(CURLOPT_WILDCARDMATCH, CURLOPTTYPE_LONG, 197),
+
+  /* Directory matching callback called before downloading of an
+     individual file (chunk) started */
+  CURLOPT(CURLOPT_CHUNK_BGN_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 198),
+
+  /* Directory matching callback called after the file (chunk)
+     was downloaded, or skipped */
+  CURLOPT(CURLOPT_CHUNK_END_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 199),
+
+  /* Change match (fnmatch-like) callback for wildcard matching */
+  CURLOPT(CURLOPT_FNMATCH_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 200),
+
+  /* Let the application define custom chunk data pointer */
+  CURLOPT(CURLOPT_CHUNK_DATA, CURLOPTTYPE_CBPOINT, 201),
+
+  /* FNMATCH_FUNCTION user pointer */
+  CURLOPT(CURLOPT_FNMATCH_DATA, CURLOPTTYPE_CBPOINT, 202),
+
+  /* send linked-list of name:port:address sets */
+  CURLOPT(CURLOPT_RESOLVE, CURLOPTTYPE_SLISTPOINT, 203),
+
+  /* Set a username for authenticated TLS */
+  CURLOPT(CURLOPT_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 204),
+
+  /* Set a password for authenticated TLS */
+  CURLOPT(CURLOPT_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 205),
+
+  /* Set authentication type for authenticated TLS */
+  CURLOPT(CURLOPT_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 206),
+
+  /* Set to 1 to enable the "TE:" header in HTTP requests to ask for
+     compressed transfer-encoded responses. Set to 0 to disable the use of TE:
+     in outgoing requests. The current default is 0, but it might change in a
+     future libcurl release.
+
+     libcurl will ask for the compressed methods it knows of, and if that
+     isn't any, it will not ask for transfer-encoding at all even if this
+     option is set to 1.
+
+  */
+  CURLOPT(CURLOPT_TRANSFER_ENCODING, CURLOPTTYPE_LONG, 207),
+
+  /* Callback function for closing socket (instead of close(2)). The callback
+     should have type curl_closesocket_callback */
+  CURLOPT(CURLOPT_CLOSESOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 208),
+  CURLOPT(CURLOPT_CLOSESOCKETDATA, CURLOPTTYPE_CBPOINT, 209),
+
+  /* allow GSSAPI credential delegation */
+  CURLOPT(CURLOPT_GSSAPI_DELEGATION, CURLOPTTYPE_VALUES, 210),
+
+  /* Set the name servers to use for DNS resolution.
+   * Only supported by the c-ares DNS backend */
+  CURLOPT(CURLOPT_DNS_SERVERS, CURLOPTTYPE_STRINGPOINT, 211),
+
+  /* Time-out accept operations (currently for FTP only) after this amount
+     of milliseconds. */
+  CURLOPT(CURLOPT_ACCEPTTIMEOUT_MS, CURLOPTTYPE_LONG, 212),
+
+  /* Set TCP keepalive */
+  CURLOPT(CURLOPT_TCP_KEEPALIVE, CURLOPTTYPE_LONG, 213),
+
+  /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */
+  CURLOPT(CURLOPT_TCP_KEEPIDLE, CURLOPTTYPE_LONG, 214),
+  CURLOPT(CURLOPT_TCP_KEEPINTVL, CURLOPTTYPE_LONG, 215),
+
+  /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */
+  CURLOPT(CURLOPT_SSL_OPTIONS, CURLOPTTYPE_VALUES, 216),
+
+  /* Set the SMTP auth originator */
+  CURLOPT(CURLOPT_MAIL_AUTH, CURLOPTTYPE_STRINGPOINT, 217),
+
+  /* Enable/disable SASL initial response */
+  CURLOPT(CURLOPT_SASL_IR, CURLOPTTYPE_LONG, 218),
+
+  /* Function that will be called instead of the internal progress display
+   * function. This function should be defined as the curl_xferinfo_callback
+   * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */
+  CURLOPT(CURLOPT_XFERINFOFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 219),
+
+  /* The XOAUTH2 bearer token */
+  CURLOPT(CURLOPT_XOAUTH2_BEARER, CURLOPTTYPE_STRINGPOINT, 220),
+
+  /* Set the interface string to use as outgoing network
+   * interface for DNS requests.
+   * Only supported by the c-ares DNS backend */
+  CURLOPT(CURLOPT_DNS_INTERFACE, CURLOPTTYPE_STRINGPOINT, 221),
+
+  /* Set the local IPv4 address to use for outgoing DNS requests.
+   * Only supported by the c-ares DNS backend */
+  CURLOPT(CURLOPT_DNS_LOCAL_IP4, CURLOPTTYPE_STRINGPOINT, 222),
+
+  /* Set the local IPv6 address to use for outgoing DNS requests.
+   * Only supported by the c-ares DNS backend */
+  CURLOPT(CURLOPT_DNS_LOCAL_IP6, CURLOPTTYPE_STRINGPOINT, 223),
+
+  /* Set authentication options directly */
+  CURLOPT(CURLOPT_LOGIN_OPTIONS, CURLOPTTYPE_STRINGPOINT, 224),
+
+  /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */
+  CURLOPTDEPRECATED(CURLOPT_SSL_ENABLE_NPN, CURLOPTTYPE_LONG, 225,
+                    7.86.0, "Has no function"),
+
+  /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */
+  CURLOPT(CURLOPT_SSL_ENABLE_ALPN, CURLOPTTYPE_LONG, 226),
+
+  /* Time to wait for a response to an HTTP request containing an
+   * Expect: 100-continue header before sending the data anyway. */
+  CURLOPT(CURLOPT_EXPECT_100_TIMEOUT_MS, CURLOPTTYPE_LONG, 227),
+
+  /* This points to a linked list of headers used for proxy requests only,
+     struct curl_slist kind */
+  CURLOPT(CURLOPT_PROXYHEADER, CURLOPTTYPE_SLISTPOINT, 228),
+
+  /* Pass in a bitmask of "header options" */
+  CURLOPT(CURLOPT_HEADEROPT, CURLOPTTYPE_VALUES, 229),
+
+  /* The public key in DER form used to validate the peer public key
+     this option is used only if SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 230),
+
+  /* Path to Unix domain socket */
+  CURLOPT(CURLOPT_UNIX_SOCKET_PATH, CURLOPTTYPE_STRINGPOINT, 231),
+
+  /* Set if we should verify the certificate status. */
+  CURLOPT(CURLOPT_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 232),
+
+  /* Set if we should enable TLS false start. */
+  CURLOPT(CURLOPT_SSL_FALSESTART, CURLOPTTYPE_LONG, 233),
+
+  /* Do not squash dot-dot sequences */
+  CURLOPT(CURLOPT_PATH_AS_IS, CURLOPTTYPE_LONG, 234),
+
+  /* Proxy Service Name */
+  CURLOPT(CURLOPT_PROXY_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 235),
+
+  /* Service Name */
+  CURLOPT(CURLOPT_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 236),
+
+  /* Wait/don't wait for pipe/mutex to clarify */
+  CURLOPT(CURLOPT_PIPEWAIT, CURLOPTTYPE_LONG, 237),
+
+  /* Set the protocol used when curl is given a URL without a protocol */
+  CURLOPT(CURLOPT_DEFAULT_PROTOCOL, CURLOPTTYPE_STRINGPOINT, 238),
+
+  /* Set stream weight, 1 - 256 (default is 16) */
+  CURLOPT(CURLOPT_STREAM_WEIGHT, CURLOPTTYPE_LONG, 239),
+
+  /* Set stream dependency on another CURL handle */
+  CURLOPT(CURLOPT_STREAM_DEPENDS, CURLOPTTYPE_OBJECTPOINT, 240),
+
+  /* Set E-xclusive stream dependency on another CURL handle */
+  CURLOPT(CURLOPT_STREAM_DEPENDS_E, CURLOPTTYPE_OBJECTPOINT, 241),
+
+  /* Do not send any tftp option requests to the server */
+  CURLOPT(CURLOPT_TFTP_NO_OPTIONS, CURLOPTTYPE_LONG, 242),
+
+  /* Linked-list of host:port:connect-to-host:connect-to-port,
+     overrides the URL's host:port (only for the network layer) */
+  CURLOPT(CURLOPT_CONNECT_TO, CURLOPTTYPE_SLISTPOINT, 243),
+
+  /* Set TCP Fast Open */
+  CURLOPT(CURLOPT_TCP_FASTOPEN, CURLOPTTYPE_LONG, 244),
+
+  /* Continue to send data if the server responds early with an
+   * HTTP status code >= 300 */
+  CURLOPT(CURLOPT_KEEP_SENDING_ON_ERROR, CURLOPTTYPE_LONG, 245),
+
+  /* The CApath or CAfile used to validate the proxy certificate
+     this option is used only if PROXY_SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_PROXY_CAINFO, CURLOPTTYPE_STRINGPOINT, 246),
+
+  /* The CApath directory used to validate the proxy certificate
+     this option is used only if PROXY_SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_PROXY_CAPATH, CURLOPTTYPE_STRINGPOINT, 247),
+
+  /* Set if we should verify the proxy in ssl handshake,
+     set 1 to verify. */
+  CURLOPT(CURLOPT_PROXY_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 248),
+
+  /* Set if we should verify the Common name from the proxy certificate in ssl
+   * handshake, set 1 to check existence, 2 to ensure that it matches
+   * the provided hostname. */
+  CURLOPT(CURLOPT_PROXY_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 249),
+
+  /* What version to specifically try to use for proxy.
+     See CURL_SSLVERSION defines below. */
+  CURLOPT(CURLOPT_PROXY_SSLVERSION, CURLOPTTYPE_VALUES, 250),
+
+  /* Set a username for authenticated TLS for proxy */
+  CURLOPT(CURLOPT_PROXY_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 251),
+
+  /* Set a password for authenticated TLS for proxy */
+  CURLOPT(CURLOPT_PROXY_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 252),
+
+  /* Set authentication type for authenticated TLS for proxy */
+  CURLOPT(CURLOPT_PROXY_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 253),
+
+  /* name of the file keeping your private SSL-certificate for proxy */
+  CURLOPT(CURLOPT_PROXY_SSLCERT, CURLOPTTYPE_STRINGPOINT, 254),
+
+  /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for
+     proxy */
+  CURLOPT(CURLOPT_PROXY_SSLCERTTYPE, CURLOPTTYPE_STRINGPOINT, 255),
+
+  /* name of the file keeping your private SSL-key for proxy */
+  CURLOPT(CURLOPT_PROXY_SSLKEY, CURLOPTTYPE_STRINGPOINT, 256),
+
+  /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for
+     proxy */
+  CURLOPT(CURLOPT_PROXY_SSLKEYTYPE, CURLOPTTYPE_STRINGPOINT, 257),
+
+  /* password for the SSL private key for proxy */
+  CURLOPT(CURLOPT_PROXY_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 258),
+
+  /* Specify which SSL ciphers to use for proxy */
+  CURLOPT(CURLOPT_PROXY_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 259),
+
+  /* CRL file for proxy */
+  CURLOPT(CURLOPT_PROXY_CRLFILE, CURLOPTTYPE_STRINGPOINT, 260),
+
+  /* Enable/disable specific SSL features with a bitmask for proxy, see
+     CURLSSLOPT_* */
+  CURLOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLOPTTYPE_LONG, 261),
+
+  /* Name of pre proxy to use. */
+  CURLOPT(CURLOPT_PRE_PROXY, CURLOPTTYPE_STRINGPOINT, 262),
+
+  /* The public key in DER form used to validate the proxy public key
+     this option is used only if PROXY_SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_PROXY_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 263),
+
+  /* Path to an abstract Unix domain socket */
+  CURLOPT(CURLOPT_ABSTRACT_UNIX_SOCKET, CURLOPTTYPE_STRINGPOINT, 264),
+
+  /* Suppress proxy CONNECT response headers from user callbacks */
+  CURLOPT(CURLOPT_SUPPRESS_CONNECT_HEADERS, CURLOPTTYPE_LONG, 265),
+
+  /* The request target, instead of extracted from the URL */
+  CURLOPT(CURLOPT_REQUEST_TARGET, CURLOPTTYPE_STRINGPOINT, 266),
+
+  /* bitmask of allowed auth methods for connections to SOCKS5 proxies */
+  CURLOPT(CURLOPT_SOCKS5_AUTH, CURLOPTTYPE_LONG, 267),
+
+  /* Enable/disable SSH compression */
+  CURLOPT(CURLOPT_SSH_COMPRESSION, CURLOPTTYPE_LONG, 268),
+
+  /* Post MIME data. */
+  CURLOPT(CURLOPT_MIMEPOST, CURLOPTTYPE_OBJECTPOINT, 269),
+
+  /* Time to use with the CURLOPT_TIMECONDITION. Specified in number of
+     seconds since 1 Jan 1970. */
+  CURLOPT(CURLOPT_TIMEVALUE_LARGE, CURLOPTTYPE_OFF_T, 270),
+
+  /* Head start in milliseconds to give happy eyeballs. */
+  CURLOPT(CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, CURLOPTTYPE_LONG, 271),
+
+  /* Function that will be called before a resolver request is made */
+  CURLOPT(CURLOPT_RESOLVER_START_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 272),
+
+  /* User data to pass to the resolver start callback. */
+  CURLOPT(CURLOPT_RESOLVER_START_DATA, CURLOPTTYPE_CBPOINT, 273),
+
+  /* send HAProxy PROXY protocol header? */
+  CURLOPT(CURLOPT_HAPROXYPROTOCOL, CURLOPTTYPE_LONG, 274),
+
+  /* shuffle addresses before use when DNS returns multiple */
+  CURLOPT(CURLOPT_DNS_SHUFFLE_ADDRESSES, CURLOPTTYPE_LONG, 275),
+
+  /* Specify which TLS 1.3 ciphers suites to use */
+  CURLOPT(CURLOPT_TLS13_CIPHERS, CURLOPTTYPE_STRINGPOINT, 276),
+  CURLOPT(CURLOPT_PROXY_TLS13_CIPHERS, CURLOPTTYPE_STRINGPOINT, 277),
+
+  /* Disallow specifying username/login in URL. */
+  CURLOPT(CURLOPT_DISALLOW_USERNAME_IN_URL, CURLOPTTYPE_LONG, 278),
+
+  /* DNS-over-HTTPS URL */
+  CURLOPT(CURLOPT_DOH_URL, CURLOPTTYPE_STRINGPOINT, 279),
+
+  /* Preferred buffer size to use for uploads */
+  CURLOPT(CURLOPT_UPLOAD_BUFFERSIZE, CURLOPTTYPE_LONG, 280),
+
+  /* Time in ms between connection upkeep calls for long-lived connections. */
+  CURLOPT(CURLOPT_UPKEEP_INTERVAL_MS, CURLOPTTYPE_LONG, 281),
+
+  /* Specify URL using CURL URL API. */
+  CURLOPT(CURLOPT_CURLU, CURLOPTTYPE_OBJECTPOINT, 282),
+
+  /* add trailing data just after no more data is available */
+  CURLOPT(CURLOPT_TRAILERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 283),
+
+  /* pointer to be passed to HTTP_TRAILER_FUNCTION */
+  CURLOPT(CURLOPT_TRAILERDATA, CURLOPTTYPE_CBPOINT, 284),
+
+  /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */
+  CURLOPT(CURLOPT_HTTP09_ALLOWED, CURLOPTTYPE_LONG, 285),
+
+  /* alt-svc control bitmask */
+  CURLOPT(CURLOPT_ALTSVC_CTRL, CURLOPTTYPE_LONG, 286),
+
+  /* alt-svc cache file name to possibly read from/write to */
+  CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287),
+
+  /* maximum age (idle time) of a connection to consider it for reuse
+   * (in seconds) */
+  CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288),
+
+  /* SASL authorization identity */
+  CURLOPT(CURLOPT_SASL_AUTHZID, CURLOPTTYPE_STRINGPOINT, 289),
+
+  /* allow RCPT TO command to fail for some recipients */
+  CURLOPT(CURLOPT_MAIL_RCPT_ALLOWFAILS, CURLOPTTYPE_LONG, 290),
+
+  /* the private SSL-certificate as a "blob" */
+  CURLOPT(CURLOPT_SSLCERT_BLOB, CURLOPTTYPE_BLOB, 291),
+  CURLOPT(CURLOPT_SSLKEY_BLOB, CURLOPTTYPE_BLOB, 292),
+  CURLOPT(CURLOPT_PROXY_SSLCERT_BLOB, CURLOPTTYPE_BLOB, 293),
+  CURLOPT(CURLOPT_PROXY_SSLKEY_BLOB, CURLOPTTYPE_BLOB, 294),
+  CURLOPT(CURLOPT_ISSUERCERT_BLOB, CURLOPTTYPE_BLOB, 295),
+
+  /* Issuer certificate for proxy */
+  CURLOPT(CURLOPT_PROXY_ISSUERCERT, CURLOPTTYPE_STRINGPOINT, 296),
+  CURLOPT(CURLOPT_PROXY_ISSUERCERT_BLOB, CURLOPTTYPE_BLOB, 297),
+
+  /* the EC curves requested by the TLS client (RFC 8422, 5.1);
+   * OpenSSL support via 'set_groups'/'set_curves':
+   * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html
+   */
+  CURLOPT(CURLOPT_SSL_EC_CURVES, CURLOPTTYPE_STRINGPOINT, 298),
+
+  /* HSTS bitmask */
+  CURLOPT(CURLOPT_HSTS_CTRL, CURLOPTTYPE_LONG, 299),
+  /* HSTS file name */
+  CURLOPT(CURLOPT_HSTS, CURLOPTTYPE_STRINGPOINT, 300),
+
+  /* HSTS read callback */
+  CURLOPT(CURLOPT_HSTSREADFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 301),
+  CURLOPT(CURLOPT_HSTSREADDATA, CURLOPTTYPE_CBPOINT, 302),
+
+  /* HSTS write callback */
+  CURLOPT(CURLOPT_HSTSWRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 303),
+  CURLOPT(CURLOPT_HSTSWRITEDATA, CURLOPTTYPE_CBPOINT, 304),
+
+  /* Parameters for V4 signature */
+  CURLOPT(CURLOPT_AWS_SIGV4, CURLOPTTYPE_STRINGPOINT, 305),
+
+  /* Same as CURLOPT_SSL_VERIFYPEER but for DoH (DNS-over-HTTPS) servers. */
+  CURLOPT(CURLOPT_DOH_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 306),
+
+  /* Same as CURLOPT_SSL_VERIFYHOST but for DoH (DNS-over-HTTPS) servers. */
+  CURLOPT(CURLOPT_DOH_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 307),
+
+  /* Same as CURLOPT_SSL_VERIFYSTATUS but for DoH (DNS-over-HTTPS) servers. */
+  CURLOPT(CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 308),
+
+  /* The CA certificates as "blob" used to validate the peer certificate
+     this option is used only if SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_CAINFO_BLOB, CURLOPTTYPE_BLOB, 309),
+
+  /* The CA certificates as "blob" used to validate the proxy certificate
+     this option is used only if PROXY_SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310),
+
+  /* used by scp/sftp to verify the host's public key */
+  CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, CURLOPTTYPE_STRINGPOINT, 311),
+
+  /* Function that will be called immediately before the initial request
+     is made on a connection (after any protocol negotiation step).  */
+  CURLOPT(CURLOPT_PREREQFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 312),
+
+  /* Data passed to the CURLOPT_PREREQFUNCTION callback */
+  CURLOPT(CURLOPT_PREREQDATA, CURLOPTTYPE_CBPOINT, 313),
+
+  /* maximum age (since creation) of a connection to consider it for reuse
+   * (in seconds) */
+  CURLOPT(CURLOPT_MAXLIFETIME_CONN, CURLOPTTYPE_LONG, 314),
+
+  /* Set MIME option flags. */
+  CURLOPT(CURLOPT_MIME_OPTIONS, CURLOPTTYPE_LONG, 315),
+
+  /* set the SSH host key callback, must point to a curl_sshkeycallback
+     function */
+  CURLOPT(CURLOPT_SSH_HOSTKEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 316),
+
+  /* set the SSH host key callback custom pointer */
+  CURLOPT(CURLOPT_SSH_HOSTKEYDATA, CURLOPTTYPE_CBPOINT, 317),
+
+  /* specify which protocols that are allowed to be used for the transfer,
+     which thus helps the app which takes URLs from users or other external
+     inputs and want to restrict what protocol(s) to deal with. Defaults to
+     all built-in protocols. */
+  CURLOPT(CURLOPT_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 318),
+
+  /* specify which protocols that libcurl is allowed to follow directs to */
+  CURLOPT(CURLOPT_REDIR_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 319),
+
+  /* websockets options */
+  CURLOPT(CURLOPT_WS_OPTIONS, CURLOPTTYPE_LONG, 320),
+
+  /* CA cache timeout */
+  CURLOPT(CURLOPT_CA_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 321),
+
+  /* Can leak things, gonna exit() soon */
+  CURLOPT(CURLOPT_QUICK_EXIT, CURLOPTTYPE_LONG, 322),
+
+  /* set a specific client IP for HAProxy PROXY protocol header? */
+  CURLOPT(CURLOPT_HAPROXY_CLIENT_IP, CURLOPTTYPE_STRINGPOINT, 323),
+
+  /* millisecond version */
+  CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324),
+
+  CURLOPT_LASTENTRY /* the last unused */
+} CURLoption;
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+                          the obsolete stuff removed! */
+
+/* Backwards compatibility with older names */
+/* These are scheduled to disappear by 2011 */
+
+/* This was added in version 7.19.1 */
+#define CURLOPT_POST301 CURLOPT_POSTREDIR
+
+/* These are scheduled to disappear by 2009 */
+
+/* The following were added in 7.17.0 */
+#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD
+#define CURLOPT_FTPAPPEND CURLOPT_APPEND
+#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY
+#define CURLOPT_FTP_SSL CURLOPT_USE_SSL
+
+/* The following were added earlier */
+
+#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD
+#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL
+
+/* */
+#define CURLOPT_FTP_RESPONSE_TIMEOUT CURLOPT_SERVER_RESPONSE_TIMEOUT
+
+/* Added in 8.2.0 */
+#define CURLOPT_MAIL_RCPT_ALLLOWFAILS CURLOPT_MAIL_RCPT_ALLOWFAILS
+
+#else
+/* This is set if CURL_NO_OLDIES is defined at compile-time */
+#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
+#endif
+
+
+  /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
+     name resolves addresses using more than one IP protocol version, this
+     option might be handy to force libcurl to use a specific IP version. */
+#define CURL_IPRESOLVE_WHATEVER 0 /* default, uses addresses to all IP
+                                     versions that your system allows */
+#define CURL_IPRESOLVE_V4       1 /* uses only IPv4 addresses/connections */
+#define CURL_IPRESOLVE_V6       2 /* uses only IPv6 addresses/connections */
+
+  /* Convenient "aliases" */
+#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
+
+  /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
+enum {
+  CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd
+                             like the library to choose the best possible
+                             for us! */
+  CURL_HTTP_VERSION_1_0,  /* please use HTTP 1.0 in the request */
+  CURL_HTTP_VERSION_1_1,  /* please use HTTP 1.1 in the request */
+  CURL_HTTP_VERSION_2_0,  /* please use HTTP 2 in the request */
+  CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */
+  CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE,  /* please use HTTP 2 without HTTP/1.1
+                                           Upgrade */
+  CURL_HTTP_VERSION_3 = 30, /* Use HTTP/3, fallback to HTTP/2 or HTTP/1 if
+                               needed. For HTTPS only. For HTTP, this option
+                               makes libcurl return error. */
+  CURL_HTTP_VERSION_3ONLY = 31, /* Use HTTP/3 without fallback. For HTTPS
+                                   only. For HTTP, this makes libcurl
+                                   return error. */
+
+  CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
+};
+
+/* Convenience definition simple because the name of the version is HTTP/2 and
+   not 2.0. The 2_0 version of the enum name was set while the version was
+   still planned to be 2.0 and we stick to it for compatibility. */
+#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0
+
+/*
+ * Public API enums for RTSP requests
+ */
+enum {
+    CURL_RTSPREQ_NONE, /* first in list */
+    CURL_RTSPREQ_OPTIONS,
+    CURL_RTSPREQ_DESCRIBE,
+    CURL_RTSPREQ_ANNOUNCE,
+    CURL_RTSPREQ_SETUP,
+    CURL_RTSPREQ_PLAY,
+    CURL_RTSPREQ_PAUSE,
+    CURL_RTSPREQ_TEARDOWN,
+    CURL_RTSPREQ_GET_PARAMETER,
+    CURL_RTSPREQ_SET_PARAMETER,
+    CURL_RTSPREQ_RECORD,
+    CURL_RTSPREQ_RECEIVE,
+    CURL_RTSPREQ_LAST /* last in list */
+};
+
+  /* These enums are for use with the CURLOPT_NETRC option. */
+enum CURL_NETRC_OPTION {
+  CURL_NETRC_IGNORED,     /* The .netrc will never be read.
+                           * This is the default. */
+  CURL_NETRC_OPTIONAL,    /* A user:password in the URL will be preferred
+                           * to one in the .netrc. */
+  CURL_NETRC_REQUIRED,    /* A user:password in the URL will be ignored.
+                           * Unless one is set programmatically, the .netrc
+                           * will be queried. */
+  CURL_NETRC_LAST
+};
+
+enum {
+  CURL_SSLVERSION_DEFAULT,
+  CURL_SSLVERSION_TLSv1, /* TLS 1.x */
+  CURL_SSLVERSION_SSLv2,
+  CURL_SSLVERSION_SSLv3,
+  CURL_SSLVERSION_TLSv1_0,
+  CURL_SSLVERSION_TLSv1_1,
+  CURL_SSLVERSION_TLSv1_2,
+  CURL_SSLVERSION_TLSv1_3,
+
+  CURL_SSLVERSION_LAST /* never use, keep last */
+};
+
+enum {
+  CURL_SSLVERSION_MAX_NONE =     0,
+  CURL_SSLVERSION_MAX_DEFAULT =  (CURL_SSLVERSION_TLSv1   << 16),
+  CURL_SSLVERSION_MAX_TLSv1_0 =  (CURL_SSLVERSION_TLSv1_0 << 16),
+  CURL_SSLVERSION_MAX_TLSv1_1 =  (CURL_SSLVERSION_TLSv1_1 << 16),
+  CURL_SSLVERSION_MAX_TLSv1_2 =  (CURL_SSLVERSION_TLSv1_2 << 16),
+  CURL_SSLVERSION_MAX_TLSv1_3 =  (CURL_SSLVERSION_TLSv1_3 << 16),
+
+  /* never use, keep last */
+  CURL_SSLVERSION_MAX_LAST =     (CURL_SSLVERSION_LAST    << 16)
+};
+
+enum CURL_TLSAUTH {
+  CURL_TLSAUTH_NONE,
+  CURL_TLSAUTH_SRP,
+  CURL_TLSAUTH_LAST /* never use, keep last */
+};
+
+/* symbols to use with CURLOPT_POSTREDIR.
+   CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303
+   can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302
+   | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */
+
+#define CURL_REDIR_GET_ALL  0
+#define CURL_REDIR_POST_301 1
+#define CURL_REDIR_POST_302 2
+#define CURL_REDIR_POST_303 4
+#define CURL_REDIR_POST_ALL \
+    (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303)
+
+typedef enum {
+  CURL_TIMECOND_NONE,
+
+  CURL_TIMECOND_IFMODSINCE,
+  CURL_TIMECOND_IFUNMODSINCE,
+  CURL_TIMECOND_LASTMOD,
+
+  CURL_TIMECOND_LAST
+} curl_TimeCond;
+
+/* Special size_t value signaling a null-terminated string. */
+#define CURL_ZERO_TERMINATED ((size_t) -1)
+
+/* curl_strequal() and curl_strnequal() are subject for removal in a future
+   release */
+CURL_EXTERN int curl_strequal(const char *s1, const char *s2);
+CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n);
+
+/* Mime/form handling support. */
+typedef struct curl_mime      curl_mime;      /* Mime context. */
+typedef struct curl_mimepart  curl_mimepart;  /* Mime part context. */
+
+/* CURLMIMEOPT_ defines are for the CURLOPT_MIME_OPTIONS option. */
+#define CURLMIMEOPT_FORMESCAPE  (1<<0) /* Use backslash-escaping for forms. */
+
+/*
+ * NAME curl_mime_init()
+ *
+ * DESCRIPTION
+ *
+ * Create a mime context and return its handle. The easy parameter is the
+ * target handle.
+ */
+CURL_EXTERN curl_mime *curl_mime_init(CURL *easy);
+
+/*
+ * NAME curl_mime_free()
+ *
+ * DESCRIPTION
+ *
+ * release a mime handle and its substructures.
+ */
+CURL_EXTERN void curl_mime_free(curl_mime *mime);
+
+/*
+ * NAME curl_mime_addpart()
+ *
+ * DESCRIPTION
+ *
+ * Append a new empty part to the given mime context and return a handle to
+ * the created part.
+ */
+CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime);
+
+/*
+ * NAME curl_mime_name()
+ *
+ * DESCRIPTION
+ *
+ * Set mime/form part name.
+ */
+CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name);
+
+/*
+ * NAME curl_mime_filename()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part remote file name.
+ */
+CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part,
+                                        const char *filename);
+
+/*
+ * NAME curl_mime_type()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part type.
+ */
+CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype);
+
+/*
+ * NAME curl_mime_encoder()
+ *
+ * DESCRIPTION
+ *
+ * Set mime data transfer encoder.
+ */
+CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part,
+                                       const char *encoding);
+
+/*
+ * NAME curl_mime_data()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part data source from memory data,
+ */
+CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part,
+                                    const char *data, size_t datasize);
+
+/*
+ * NAME curl_mime_filedata()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part data source from named file.
+ */
+CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part,
+                                        const char *filename);
+
+/*
+ * NAME curl_mime_data_cb()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part data source from callback function.
+ */
+CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part,
+                                       curl_off_t datasize,
+                                       curl_read_callback readfunc,
+                                       curl_seek_callback seekfunc,
+                                       curl_free_callback freefunc,
+                                       void *arg);
+
+/*
+ * NAME curl_mime_subparts()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part data source from subparts.
+ */
+CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part,
+                                        curl_mime *subparts);
+/*
+ * NAME curl_mime_headers()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part headers.
+ */
+CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part,
+                                       struct curl_slist *headers,
+                                       int take_ownership);
+
+typedef enum {
+  /********* the first one is unused ************/
+  CURLFORM_NOTHING         CURL_DEPRECATED(7.56.0, ""),
+  CURLFORM_COPYNAME        CURL_DEPRECATED(7.56.0, "Use curl_mime_name()"),
+  CURLFORM_PTRNAME         CURL_DEPRECATED(7.56.0, "Use curl_mime_name()"),
+  CURLFORM_NAMELENGTH      CURL_DEPRECATED(7.56.0, ""),
+  CURLFORM_COPYCONTENTS    CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+  CURLFORM_PTRCONTENTS     CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+  CURLFORM_CONTENTSLENGTH  CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+  CURLFORM_FILECONTENT     CURL_DEPRECATED(7.56.0, "Use curl_mime_data_cb()"),
+  CURLFORM_ARRAY           CURL_DEPRECATED(7.56.0, ""),
+  CURLFORM_OBSOLETE,
+  CURLFORM_FILE            CURL_DEPRECATED(7.56.0, "Use curl_mime_filedata()"),
+
+  CURLFORM_BUFFER          CURL_DEPRECATED(7.56.0, "Use curl_mime_filename()"),
+  CURLFORM_BUFFERPTR       CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+  CURLFORM_BUFFERLENGTH    CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+
+  CURLFORM_CONTENTTYPE     CURL_DEPRECATED(7.56.0, "Use curl_mime_type()"),
+  CURLFORM_CONTENTHEADER   CURL_DEPRECATED(7.56.0, "Use curl_mime_headers()"),
+  CURLFORM_FILENAME        CURL_DEPRECATED(7.56.0, "Use curl_mime_filename()"),
+  CURLFORM_END,
+  CURLFORM_OBSOLETE2,
+
+  CURLFORM_STREAM          CURL_DEPRECATED(7.56.0, "Use curl_mime_data_cb()"),
+  CURLFORM_CONTENTLEN  /* added in 7.46.0, provide a curl_off_t length */
+                           CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+
+  CURLFORM_LASTENTRY /* the last unused */
+} CURLformoption;
+
+/* structure to be used as parameter for CURLFORM_ARRAY */
+struct curl_forms {
+  CURLformoption option;
+  const char     *value;
+};
+
+/* use this for multipart formpost building */
+/* Returns code for curl_formadd()
+ *
+ * Returns:
+ * CURL_FORMADD_OK             on success
+ * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
+ * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
+ * CURL_FORMADD_NULL           if a null pointer was given for a char
+ * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
+ * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
+ * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
+ * CURL_FORMADD_MEMORY         if a curl_httppost struct cannot be allocated
+ * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
+ * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
+ *
+ ***************************************************************************/
+typedef enum {
+  CURL_FORMADD_OK             CURL_DEPRECATED(7.56.0, ""), /* 1st, no error */
+
+  CURL_FORMADD_MEMORY         CURL_DEPRECATED(7.56.0, ""),
+  CURL_FORMADD_OPTION_TWICE   CURL_DEPRECATED(7.56.0, ""),
+  CURL_FORMADD_NULL           CURL_DEPRECATED(7.56.0, ""),
+  CURL_FORMADD_UNKNOWN_OPTION CURL_DEPRECATED(7.56.0, ""),
+  CURL_FORMADD_INCOMPLETE     CURL_DEPRECATED(7.56.0, ""),
+  CURL_FORMADD_ILLEGAL_ARRAY  CURL_DEPRECATED(7.56.0, ""),
+  /* libcurl was built with form api disabled */
+  CURL_FORMADD_DISABLED       CURL_DEPRECATED(7.56.0, ""),
+
+  CURL_FORMADD_LAST /* last */
+} CURLFORMcode;
+
+/*
+ * NAME curl_formadd()
+ *
+ * DESCRIPTION
+ *
+ * Pretty advanced function for building multi-part formposts. Each invoke
+ * adds one part that together construct a full post. Then use
+ * CURLOPT_HTTPPOST to send it off to libcurl.
+ */
+CURL_EXTERN CURLFORMcode CURL_DEPRECATED(7.56.0, "Use curl_mime_init()")
+curl_formadd(struct curl_httppost **httppost,
+             struct curl_httppost **last_post,
+             ...);
+
+/*
+ * callback function for curl_formget()
+ * The void *arg pointer will be the one passed as second argument to
+ *   curl_formget().
+ * The character buffer passed to it must not be freed.
+ * Should return the buffer length passed to it as the argument "len" on
+ *   success.
+ */
+typedef size_t (*curl_formget_callback)(void *arg, const char *buf,
+                                        size_t len);
+
+/*
+ * NAME curl_formget()
+ *
+ * DESCRIPTION
+ *
+ * Serialize a curl_httppost struct built with curl_formadd().
+ * Accepts a void pointer as second argument which will be passed to
+ * the curl_formget_callback function.
+ * Returns 0 on success.
+ */
+CURL_EXTERN int CURL_DEPRECATED(7.56.0, "")
+curl_formget(struct curl_httppost *form, void *arg,
+             curl_formget_callback append);
+/*
+ * NAME curl_formfree()
+ *
+ * DESCRIPTION
+ *
+ * Free a multipart formpost previously built with curl_formadd().
+ */
+CURL_EXTERN void CURL_DEPRECATED(7.56.0, "Use curl_mime_free()")
+curl_formfree(struct curl_httppost *form);
+
+/*
+ * NAME curl_getenv()
+ *
+ * DESCRIPTION
+ *
+ * Returns a malloc()'ed string that MUST be curl_free()ed after usage is
+ * complete. DEPRECATED - see lib/README.curlx
+ */
+CURL_EXTERN char *curl_getenv(const char *variable);
+
+/*
+ * NAME curl_version()
+ *
+ * DESCRIPTION
+ *
+ * Returns a static ascii string of the libcurl version.
+ */
+CURL_EXTERN char *curl_version(void);
+
+/*
+ * NAME curl_easy_escape()
+ *
+ * DESCRIPTION
+ *
+ * Escapes URL strings (converts all letters consider illegal in URLs to their
+ * %XX versions). This function returns a new allocated string or NULL if an
+ * error occurred.
+ */
+CURL_EXTERN char *curl_easy_escape(CURL *handle,
+                                   const char *string,
+                                   int length);
+
+/* the previous version: */
+CURL_EXTERN char *curl_escape(const char *string,
+                              int length);
+
+
+/*
+ * NAME curl_easy_unescape()
+ *
+ * DESCRIPTION
+ *
+ * Unescapes URL encoding in strings (converts all %XX codes to their 8bit
+ * versions). This function returns a new allocated string or NULL if an error
+ * occurred.
+ * Conversion Note: On non-ASCII platforms the ASCII %XX codes are
+ * converted into the host encoding.
+ */
+CURL_EXTERN char *curl_easy_unescape(CURL *handle,
+                                     const char *string,
+                                     int length,
+                                     int *outlength);
+
+/* the previous version */
+CURL_EXTERN char *curl_unescape(const char *string,
+                                int length);
+
+/*
+ * NAME curl_free()
+ *
+ * DESCRIPTION
+ *
+ * Provided for de-allocation in the same translation unit that did the
+ * allocation. Added in libcurl 7.10
+ */
+CURL_EXTERN void curl_free(void *p);
+
+/*
+ * NAME curl_global_init()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() should be invoked exactly once for each application that
+ * uses libcurl and before any call of other libcurl functions.
+
+ * This function is thread-safe if CURL_VERSION_THREADSAFE is set in the
+ * curl_version_info_data.features flag (fetch by curl_version_info()).
+
+ */
+CURL_EXTERN CURLcode curl_global_init(long flags);
+
+/*
+ * NAME curl_global_init_mem()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() or curl_global_init_mem() should be invoked exactly once
+ * for each application that uses libcurl.  This function can be used to
+ * initialize libcurl and set user defined memory management callback
+ * functions.  Users can implement memory management routines to check for
+ * memory leaks, check for mis-use of the curl library etc.  User registered
+ * callback routines will be invoked by this library instead of the system
+ * memory management routines like malloc, free etc.
+ */
+CURL_EXTERN CURLcode curl_global_init_mem(long flags,
+                                          curl_malloc_callback m,
+                                          curl_free_callback f,
+                                          curl_realloc_callback r,
+                                          curl_strdup_callback s,
+                                          curl_calloc_callback c);
+
+/*
+ * NAME curl_global_cleanup()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_cleanup() should be invoked exactly once for each application
+ * that uses libcurl
+ */
+CURL_EXTERN void curl_global_cleanup(void);
+
+/*
+ * NAME curl_global_trace()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_trace() can be invoked at application start to
+ * configure which components in curl should participate in tracing.
+
+ * This function is thread-safe if CURL_VERSION_THREADSAFE is set in the
+ * curl_version_info_data.features flag (fetch by curl_version_info()).
+
+ */
+CURL_EXTERN CURLcode curl_global_trace(const char *config);
+
+/* linked-list structure for the CURLOPT_QUOTE option (and other) */
+struct curl_slist {
+  char *data;
+  struct curl_slist *next;
+};
+
+/*
+ * NAME curl_global_sslset()
+ *
+ * DESCRIPTION
+ *
+ * When built with multiple SSL backends, curl_global_sslset() allows to
+ * choose one. This function can only be called once, and it must be called
+ * *before* curl_global_init().
+ *
+ * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The
+ * backend can also be specified via the name parameter (passing -1 as id).
+ * If both id and name are specified, the name will be ignored. If neither id
+ * nor name are specified, the function will fail with
+ * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the
+ * NULL-terminated list of available backends.
+ *
+ * Upon success, the function returns CURLSSLSET_OK.
+ *
+ * If the specified SSL backend is not available, the function returns
+ * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated
+ * list of available SSL backends.
+ *
+ * The SSL backend can be set only once. If it has already been set, a
+ * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE.
+ */
+
+struct curl_ssl_backend {
+  curl_sslbackend id;
+  const char *name;
+};
+typedef struct curl_ssl_backend curl_ssl_backend;
+
+typedef enum {
+  CURLSSLSET_OK = 0,
+  CURLSSLSET_UNKNOWN_BACKEND,
+  CURLSSLSET_TOO_LATE,
+  CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */
+} CURLsslset;
+
+CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
+                                          const curl_ssl_backend ***avail);
+
+/*
+ * NAME curl_slist_append()
+ *
+ * DESCRIPTION
+ *
+ * Appends a string to a linked list. If no list exists, it will be created
+ * first. Returns the new list, after appending.
+ */
+CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *list,
+                                                 const char *data);
+
+/*
+ * NAME curl_slist_free_all()
+ *
+ * DESCRIPTION
+ *
+ * free a previously built curl_slist.
+ */
+CURL_EXTERN void curl_slist_free_all(struct curl_slist *list);
+
+/*
+ * NAME curl_getdate()
+ *
+ * DESCRIPTION
+ *
+ * Returns the time, in seconds since 1 Jan 1970 of the time string given in
+ * the first argument. The time argument in the second parameter is unused
+ * and should be set to NULL.
+ */
+CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
+
+/* info about the certificate chain, for SSL backends that support it. Asked
+   for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+struct curl_certinfo {
+  int num_of_certs;             /* number of certificates with information */
+  struct curl_slist **certinfo; /* for each index in this array, there's a
+                                   linked list with textual information for a
+                                   certificate in the format "name:content".
+                                   eg "Subject:foo", "Issuer:bar", etc. */
+};
+
+/* Information about the SSL library used and the respective internal SSL
+   handle, which can be used to obtain further information regarding the
+   connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */
+struct curl_tlssessioninfo {
+  curl_sslbackend backend;
+  void *internals;
+};
+
+#define CURLINFO_STRING   0x100000
+#define CURLINFO_LONG     0x200000
+#define CURLINFO_DOUBLE   0x300000
+#define CURLINFO_SLIST    0x400000
+#define CURLINFO_PTR      0x400000 /* same as SLIST */
+#define CURLINFO_SOCKET   0x500000
+#define CURLINFO_OFF_T    0x600000
+#define CURLINFO_MASK     0x0fffff
+#define CURLINFO_TYPEMASK 0xf00000
+
+typedef enum {
+  CURLINFO_NONE, /* first, never use this */
+  CURLINFO_EFFECTIVE_URL    = CURLINFO_STRING + 1,
+  CURLINFO_RESPONSE_CODE    = CURLINFO_LONG   + 2,
+  CURLINFO_TOTAL_TIME       = CURLINFO_DOUBLE + 3,
+  CURLINFO_NAMELOOKUP_TIME  = CURLINFO_DOUBLE + 4,
+  CURLINFO_CONNECT_TIME     = CURLINFO_DOUBLE + 5,
+  CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
+  CURLINFO_SIZE_UPLOAD CURL_DEPRECATED(7.55.0, "Use CURLINFO_SIZE_UPLOAD_T")
+                            = CURLINFO_DOUBLE + 7,
+  CURLINFO_SIZE_UPLOAD_T    = CURLINFO_OFF_T  + 7,
+  CURLINFO_SIZE_DOWNLOAD
+                       CURL_DEPRECATED(7.55.0, "Use CURLINFO_SIZE_DOWNLOAD_T")
+                            = CURLINFO_DOUBLE + 8,
+  CURLINFO_SIZE_DOWNLOAD_T  = CURLINFO_OFF_T  + 8,
+  CURLINFO_SPEED_DOWNLOAD
+                       CURL_DEPRECATED(7.55.0, "Use CURLINFO_SPEED_DOWNLOAD_T")
+                            = CURLINFO_DOUBLE + 9,
+  CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T  + 9,
+  CURLINFO_SPEED_UPLOAD
+                       CURL_DEPRECATED(7.55.0, "Use CURLINFO_SPEED_UPLOAD_T")
+                            = CURLINFO_DOUBLE + 10,
+  CURLINFO_SPEED_UPLOAD_T   = CURLINFO_OFF_T  + 10,
+  CURLINFO_HEADER_SIZE      = CURLINFO_LONG   + 11,
+  CURLINFO_REQUEST_SIZE     = CURLINFO_LONG   + 12,
+  CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG   + 13,
+  CURLINFO_FILETIME         = CURLINFO_LONG   + 14,
+  CURLINFO_FILETIME_T       = CURLINFO_OFF_T  + 14,
+  CURLINFO_CONTENT_LENGTH_DOWNLOAD
+                       CURL_DEPRECATED(7.55.0,
+                                      "Use CURLINFO_CONTENT_LENGTH_DOWNLOAD_T")
+                            = CURLINFO_DOUBLE + 15,
+  CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T  + 15,
+  CURLINFO_CONTENT_LENGTH_UPLOAD
+                       CURL_DEPRECATED(7.55.0,
+                                       "Use CURLINFO_CONTENT_LENGTH_UPLOAD_T")
+                            = CURLINFO_DOUBLE + 16,
+  CURLINFO_CONTENT_LENGTH_UPLOAD_T   = CURLINFO_OFF_T  + 16,
+  CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
+  CURLINFO_CONTENT_TYPE     = CURLINFO_STRING + 18,
+  CURLINFO_REDIRECT_TIME    = CURLINFO_DOUBLE + 19,
+  CURLINFO_REDIRECT_COUNT   = CURLINFO_LONG   + 20,
+  CURLINFO_PRIVATE          = CURLINFO_STRING + 21,
+  CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG   + 22,
+  CURLINFO_HTTPAUTH_AVAIL   = CURLINFO_LONG   + 23,
+  CURLINFO_PROXYAUTH_AVAIL  = CURLINFO_LONG   + 24,
+  CURLINFO_OS_ERRNO         = CURLINFO_LONG   + 25,
+  CURLINFO_NUM_CONNECTS     = CURLINFO_LONG   + 26,
+  CURLINFO_SSL_ENGINES      = CURLINFO_SLIST  + 27,
+  CURLINFO_COOKIELIST       = CURLINFO_SLIST  + 28,
+  CURLINFO_LASTSOCKET  CURL_DEPRECATED(7.45.0, "Use CURLINFO_ACTIVESOCKET")
+                            = CURLINFO_LONG   + 29,
+  CURLINFO_FTP_ENTRY_PATH   = CURLINFO_STRING + 30,
+  CURLINFO_REDIRECT_URL     = CURLINFO_STRING + 31,
+  CURLINFO_PRIMARY_IP       = CURLINFO_STRING + 32,
+  CURLINFO_APPCONNECT_TIME  = CURLINFO_DOUBLE + 33,
+  CURLINFO_CERTINFO         = CURLINFO_PTR    + 34,
+  CURLINFO_CONDITION_UNMET  = CURLINFO_LONG   + 35,
+  CURLINFO_RTSP_SESSION_ID  = CURLINFO_STRING + 36,
+  CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG   + 37,
+  CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG   + 38,
+  CURLINFO_RTSP_CSEQ_RECV   = CURLINFO_LONG   + 39,
+  CURLINFO_PRIMARY_PORT     = CURLINFO_LONG   + 40,
+  CURLINFO_LOCAL_IP         = CURLINFO_STRING + 41,
+  CURLINFO_LOCAL_PORT       = CURLINFO_LONG   + 42,
+  CURLINFO_TLS_SESSION CURL_DEPRECATED(7.48.0, "Use CURLINFO_TLS_SSL_PTR")
+                            = CURLINFO_PTR    + 43,
+  CURLINFO_ACTIVESOCKET     = CURLINFO_SOCKET + 44,
+  CURLINFO_TLS_SSL_PTR      = CURLINFO_PTR    + 45,
+  CURLINFO_HTTP_VERSION     = CURLINFO_LONG   + 46,
+  CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47,
+  CURLINFO_PROTOCOL    CURL_DEPRECATED(7.85.0, "Use CURLINFO_SCHEME")
+                            = CURLINFO_LONG   + 48,
+  CURLINFO_SCHEME           = CURLINFO_STRING + 49,
+  CURLINFO_TOTAL_TIME_T     = CURLINFO_OFF_T + 50,
+  CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51,
+  CURLINFO_CONNECT_TIME_T   = CURLINFO_OFF_T + 52,
+  CURLINFO_PRETRANSFER_TIME_T = CURLINFO_OFF_T + 53,
+  CURLINFO_STARTTRANSFER_TIME_T = CURLINFO_OFF_T + 54,
+  CURLINFO_REDIRECT_TIME_T  = CURLINFO_OFF_T + 55,
+  CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56,
+  CURLINFO_RETRY_AFTER      = CURLINFO_OFF_T + 57,
+  CURLINFO_EFFECTIVE_METHOD = CURLINFO_STRING + 58,
+  CURLINFO_PROXY_ERROR      = CURLINFO_LONG + 59,
+  CURLINFO_REFERER          = CURLINFO_STRING + 60,
+  CURLINFO_CAINFO           = CURLINFO_STRING + 61,
+  CURLINFO_CAPATH           = CURLINFO_STRING + 62,
+  CURLINFO_XFER_ID          = CURLINFO_OFF_T + 63,
+  CURLINFO_CONN_ID          = CURLINFO_OFF_T + 64,
+  CURLINFO_QUEUE_TIME_T     = CURLINFO_OFF_T + 65,
+  CURLINFO_USED_PROXY       = CURLINFO_LONG + 66,
+  CURLINFO_LASTONE          = 66
+} CURLINFO;
+
+/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
+   CURLINFO_HTTP_CODE */
+#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE
+
+typedef enum {
+  CURLCLOSEPOLICY_NONE, /* first, never use this */
+
+  CURLCLOSEPOLICY_OLDEST,
+  CURLCLOSEPOLICY_LEAST_RECENTLY_USED,
+  CURLCLOSEPOLICY_LEAST_TRAFFIC,
+  CURLCLOSEPOLICY_SLOWEST,
+  CURLCLOSEPOLICY_CALLBACK,
+
+  CURLCLOSEPOLICY_LAST /* last, never use this */
+} curl_closepolicy;
+
+#define CURL_GLOBAL_SSL (1<<0) /* no purpose since 7.57.0 */
+#define CURL_GLOBAL_WIN32 (1<<1)
+#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
+#define CURL_GLOBAL_NOTHING 0
+#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL
+#define CURL_GLOBAL_ACK_EINTR (1<<2)
+
+
+/*****************************************************************************
+ * Setup defines, protos etc for the sharing stuff.
+ */
+
+/* Different data locks for a single share */
+typedef enum {
+  CURL_LOCK_DATA_NONE = 0,
+  /*  CURL_LOCK_DATA_SHARE is used internally to say that
+   *  the locking is just made to change the internal state of the share
+   *  itself.
+   */
+  CURL_LOCK_DATA_SHARE,
+  CURL_LOCK_DATA_COOKIE,
+  CURL_LOCK_DATA_DNS,
+  CURL_LOCK_DATA_SSL_SESSION,
+  CURL_LOCK_DATA_CONNECT,
+  CURL_LOCK_DATA_PSL,
+  CURL_LOCK_DATA_HSTS,
+  CURL_LOCK_DATA_LAST
+} curl_lock_data;
+
+/* Different lock access types */
+typedef enum {
+  CURL_LOCK_ACCESS_NONE = 0,   /* unspecified action */
+  CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */
+  CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */
+  CURL_LOCK_ACCESS_LAST        /* never use */
+} curl_lock_access;
+
+typedef void (*curl_lock_function)(CURL *handle,
+                                   curl_lock_data data,
+                                   curl_lock_access locktype,
+                                   void *userptr);
+typedef void (*curl_unlock_function)(CURL *handle,
+                                     curl_lock_data data,
+                                     void *userptr);
+
+
+typedef enum {
+  CURLSHE_OK,  /* all is fine */
+  CURLSHE_BAD_OPTION, /* 1 */
+  CURLSHE_IN_USE,     /* 2 */
+  CURLSHE_INVALID,    /* 3 */
+  CURLSHE_NOMEM,      /* 4 out of memory */
+  CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */
+  CURLSHE_LAST        /* never use */
+} CURLSHcode;
+
+typedef enum {
+  CURLSHOPT_NONE,  /* don't use */
+  CURLSHOPT_SHARE,   /* specify a data type to share */
+  CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */
+  CURLSHOPT_LOCKFUNC,   /* pass in a 'curl_lock_function' pointer */
+  CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */
+  CURLSHOPT_USERDATA,   /* pass in a user data pointer used in the lock/unlock
+                           callback functions */
+  CURLSHOPT_LAST  /* never use */
+} CURLSHoption;
+
+CURL_EXTERN CURLSH *curl_share_init(void);
+CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *share, CURLSHoption option,
+                                         ...);
+CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *share);
+
+/****************************************************************************
+ * Structures for querying information about the curl library at runtime.
+ */
+
+typedef enum {
+  CURLVERSION_FIRST,
+  CURLVERSION_SECOND,
+  CURLVERSION_THIRD,
+  CURLVERSION_FOURTH,
+  CURLVERSION_FIFTH,
+  CURLVERSION_SIXTH,
+  CURLVERSION_SEVENTH,
+  CURLVERSION_EIGHTH,
+  CURLVERSION_NINTH,
+  CURLVERSION_TENTH,
+  CURLVERSION_ELEVENTH,
+  CURLVERSION_LAST /* never actually use this */
+} CURLversion;
+
+/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by
+   basically all programs ever that want to get version information. It is
+   meant to be a built-in version number for what kind of struct the caller
+   expects. If the struct ever changes, we redefine the NOW to another enum
+   from above. */
+#define CURLVERSION_NOW CURLVERSION_ELEVENTH
+
+struct curl_version_info_data {
+  CURLversion age;          /* age of the returned struct */
+  const char *version;      /* LIBCURL_VERSION */
+  unsigned int version_num; /* LIBCURL_VERSION_NUM */
+  const char *host;         /* OS/host/cpu/machine when configured */
+  int features;             /* bitmask, see defines below */
+  const char *ssl_version;  /* human readable string */
+  long ssl_version_num;     /* not used anymore, always 0 */
+  const char *libz_version; /* human readable string */
+  /* protocols is terminated by an entry with a NULL protoname */
+  const char * const *protocols;
+
+  /* The fields below this were added in CURLVERSION_SECOND */
+  const char *ares;
+  int ares_num;
+
+  /* This field was added in CURLVERSION_THIRD */
+  const char *libidn;
+
+  /* These field were added in CURLVERSION_FOURTH */
+
+  /* Same as '_libiconv_version' if built with HAVE_ICONV */
+  int iconv_ver_num;
+
+  const char *libssh_version; /* human readable string */
+
+  /* These fields were added in CURLVERSION_FIFTH */
+  unsigned int brotli_ver_num; /* Numeric Brotli version
+                                  (MAJOR << 24) | (MINOR << 12) | PATCH */
+  const char *brotli_version; /* human readable string. */
+
+  /* These fields were added in CURLVERSION_SIXTH */
+  unsigned int nghttp2_ver_num; /* Numeric nghttp2 version
+                                   (MAJOR << 16) | (MINOR << 8) | PATCH */
+  const char *nghttp2_version; /* human readable string. */
+  const char *quic_version;    /* human readable quic (+ HTTP/3) library +
+                                  version or NULL */
+
+  /* These fields were added in CURLVERSION_SEVENTH */
+  const char *cainfo;          /* the built-in default CURLOPT_CAINFO, might
+                                  be NULL */
+  const char *capath;          /* the built-in default CURLOPT_CAPATH, might
+                                  be NULL */
+
+  /* These fields were added in CURLVERSION_EIGHTH */
+  unsigned int zstd_ver_num; /* Numeric Zstd version
+                                  (MAJOR << 24) | (MINOR << 12) | PATCH */
+  const char *zstd_version; /* human readable string. */
+
+  /* These fields were added in CURLVERSION_NINTH */
+  const char *hyper_version; /* human readable string. */
+
+  /* These fields were added in CURLVERSION_TENTH */
+  const char *gsasl_version; /* human readable string. */
+
+  /* These fields were added in CURLVERSION_ELEVENTH */
+  /* feature_names is terminated by an entry with a NULL feature name */
+  const char * const *feature_names;
+};
+typedef struct curl_version_info_data curl_version_info_data;
+
+#define CURL_VERSION_IPV6         (1<<0)  /* IPv6-enabled */
+#define CURL_VERSION_KERBEROS4    (1<<1)  /* Kerberos V4 auth is supported
+                                             (deprecated) */
+#define CURL_VERSION_SSL          (1<<2)  /* SSL options are present */
+#define CURL_VERSION_LIBZ         (1<<3)  /* libz features are present */
+#define CURL_VERSION_NTLM         (1<<4)  /* NTLM auth is supported */
+#define CURL_VERSION_GSSNEGOTIATE (1<<5)  /* Negotiate auth is supported
+                                             (deprecated) */
+#define CURL_VERSION_DEBUG        (1<<6)  /* Built with debug capabilities */
+#define CURL_VERSION_ASYNCHDNS    (1<<7)  /* Asynchronous DNS resolves */
+#define CURL_VERSION_SPNEGO       (1<<8)  /* SPNEGO auth is supported */
+#define CURL_VERSION_LARGEFILE    (1<<9)  /* Supports files larger than 2GB */
+#define CURL_VERSION_IDN          (1<<10) /* Internationized Domain Names are
+                                             supported */
+#define CURL_VERSION_SSPI         (1<<11) /* Built against Windows SSPI */
+#define CURL_VERSION_CONV         (1<<12) /* Character conversions supported */
+#define CURL_VERSION_CURLDEBUG    (1<<13) /* Debug memory tracking supported */
+#define CURL_VERSION_TLSAUTH_SRP  (1<<14) /* TLS-SRP auth is supported */
+#define CURL_VERSION_NTLM_WB      (1<<15) /* NTLM delegation to winbind helper
+                                             is supported */
+#define CURL_VERSION_HTTP2        (1<<16) /* HTTP2 support built-in */
+#define CURL_VERSION_GSSAPI       (1<<17) /* Built against a GSS-API library */
+#define CURL_VERSION_KERBEROS5    (1<<18) /* Kerberos V5 auth is supported */
+#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */
+#define CURL_VERSION_PSL          (1<<20) /* Mozilla's Public Suffix List, used
+                                             for cookie domain verification */
+#define CURL_VERSION_HTTPS_PROXY  (1<<21) /* HTTPS-proxy support built-in */
+#define CURL_VERSION_MULTI_SSL    (1<<22) /* Multiple SSL backends available */
+#define CURL_VERSION_BROTLI       (1<<23) /* Brotli features are present. */
+#define CURL_VERSION_ALTSVC       (1<<24) /* Alt-Svc handling built-in */
+#define CURL_VERSION_HTTP3        (1<<25) /* HTTP3 support built-in */
+#define CURL_VERSION_ZSTD         (1<<26) /* zstd features are present */
+#define CURL_VERSION_UNICODE      (1<<27) /* Unicode support on Windows */
+#define CURL_VERSION_HSTS         (1<<28) /* HSTS is supported */
+#define CURL_VERSION_GSASL        (1<<29) /* libgsasl is supported */
+#define CURL_VERSION_THREADSAFE   (1<<30) /* libcurl API is thread-safe */
+
+ /*
+ * NAME curl_version_info()
+ *
+ * DESCRIPTION
+ *
+ * This function returns a pointer to a static copy of the version info
+ * struct. See above.
+ */
+CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion);
+
+/*
+ * NAME curl_easy_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_strerror function may be used to turn a CURLcode value
+ * into the equivalent human readable error string.  This is useful
+ * for printing meaningful error messages.
+ */
+CURL_EXTERN const char *curl_easy_strerror(CURLcode);
+
+/*
+ * NAME curl_share_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_share_strerror function may be used to turn a CURLSHcode value
+ * into the equivalent human readable error string.  This is useful
+ * for printing meaningful error messages.
+ */
+CURL_EXTERN const char *curl_share_strerror(CURLSHcode);
+
+/*
+ * NAME curl_easy_pause()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_pause function pauses or unpauses transfers. Select the new
+ * state by setting the bitmask, use the convenience defines below.
+ *
+ */
+CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
+
+#define CURLPAUSE_RECV      (1<<0)
+#define CURLPAUSE_RECV_CONT (0)
+
+#define CURLPAUSE_SEND      (1<<2)
+#define CURLPAUSE_SEND_CONT (0)
+
+#define CURLPAUSE_ALL       (CURLPAUSE_RECV|CURLPAUSE_SEND)
+#define CURLPAUSE_CONT      (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT)
+
+#ifdef  __cplusplus
+} /* end of extern "C" */
+#endif
+
+/* unfortunately, the easy.h and multi.h include files need options and info
+  stuff before they can be included! */
+#include "easy.h" /* nothing in curl is fun without the easy stuff */
+#include "multi.h"
+#include "urlapi.h"
+#include "options.h"
+#include "header.h"
+#include "websockets.h"
+#include "mprintf.h"
+
+/* the typechecker doesn't work in C++ (yet) */
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
+    ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \
+    !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK)
+#include "typecheck-gcc.h"
+#else
+#if defined(__STDC__) && (__STDC__ >= 1)
+/* This preprocessor magic that replaces a call with the exact same call is
+   only done to make sure application authors pass exactly three arguments
+   to these functions. */
+#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param)
+#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg)
+#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
+#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
+#endif /* __STDC__ >= 1 */
+#endif /* gcc >= 4.3 && !__cplusplus && !CURL_DISABLE_TYPECHECK */
+
+#endif /* CURLINC_CURL_H */
Index: trunk/src/libs/curl-8.7.1/include/curl/curlver.h
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/curlver.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/curlver.h	(revision 104083)
@@ -0,0 +1,79 @@
+#ifndef CURLINC_CURLVER_H
+#define CURLINC_CURLVER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* This header file contains nothing but libcurl version info, generated by
+   a script at release-time. This was made its own header file in 7.11.2 */
+
+/* This is the global package copyright */
+#define LIBCURL_COPYRIGHT "Daniel Stenberg, <daniel@haxx.se>."
+
+/* This is the version number of the libcurl package from which this header
+   file origins: */
+#define LIBCURL_VERSION "8.7.1"
+
+/* The numeric version number is also available "in parts" by using these
+   defines: */
+#define LIBCURL_VERSION_MAJOR 8
+#define LIBCURL_VERSION_MINOR 7
+#define LIBCURL_VERSION_PATCH 1
+
+/* This is the numeric version of the libcurl version number, meant for easier
+   parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
+   always follow this syntax:
+
+         0xXXYYZZ
+
+   Where XX, YY and ZZ are the main version, release and patch numbers in
+   hexadecimal (using 8 bits each). All three numbers are always represented
+   using two digits.  1.2 would appear as "0x010200" while version 9.11.7
+   appears as "0x090b07".
+
+   This 6-digit (24 bits) hexadecimal number does not show pre-release number,
+   and it is always a greater number in a more recent release. It makes
+   comparisons with greater than and less than work.
+
+   Note: This define is the full hex number and _does not_ use the
+   CURL_VERSION_BITS() macro since curl's own configure script greps for it
+   and needs it to contain the full number.
+*/
+#define LIBCURL_VERSION_NUM 0x080701
+
+/*
+ * This is the date and time when the full source package was created. The
+ * timestamp is not stored in git, as the timestamp is properly set in the
+ * tarballs by the maketgz script.
+ *
+ * The format of the date follows this template:
+ *
+ * "2007-11-23"
+ */
+#define LIBCURL_TIMESTAMP "2024-03-27"
+
+#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z))
+#define CURL_AT_LEAST_VERSION(x,y,z) \
+  (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
+
+#endif /* CURLINC_CURLVER_H */
Index: trunk/src/libs/curl-8.7.1/include/curl/easy.h
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/easy.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/easy.h	(revision 104083)
@@ -0,0 +1,125 @@
+#ifndef CURLINC_EASY_H
+#define CURLINC_EASY_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Flag bits in the curl_blob struct: */
+#define CURL_BLOB_COPY   1 /* tell libcurl to copy the data */
+#define CURL_BLOB_NOCOPY 0 /* tell libcurl to NOT copy the data */
+
+struct curl_blob {
+  void *data;
+  size_t len;
+  unsigned int flags; /* bit 0 is defined, the rest are reserved and should be
+                         left zeroes */
+};
+
+CURL_EXTERN CURL *curl_easy_init(void);
+CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
+CURL_EXTERN CURLcode curl_easy_perform(CURL *curl);
+CURL_EXTERN void curl_easy_cleanup(CURL *curl);
+
+/*
+ * NAME curl_easy_getinfo()
+ *
+ * DESCRIPTION
+ *
+ * Request internal information from the curl session with this function.
+ * The third argument MUST be pointing to the specific type of the used option
+ * which is documented in each man page of the option. The data pointed to
+ * will be filled in accordingly and can be relied upon only if the function
+ * returns CURLE_OK. This function is intended to get used *AFTER* a performed
+ * transfer, all results from this function are undefined until the transfer
+ * is completed.
+ */
+CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
+
+
+/*
+ * NAME curl_easy_duphandle()
+ *
+ * DESCRIPTION
+ *
+ * Creates a new curl session handle with the same options set for the handle
+ * passed in. Duplicating a handle could only be a matter of cloning data and
+ * options, internal state info and things like persistent connections cannot
+ * be transferred. It is useful in multithreaded applications when you can run
+ * curl_easy_duphandle() for each new thread to avoid a series of identical
+ * curl_easy_setopt() invokes in every thread.
+ */
+CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl);
+
+/*
+ * NAME curl_easy_reset()
+ *
+ * DESCRIPTION
+ *
+ * Re-initializes a CURL handle to the default values. This puts back the
+ * handle to the same state as it was in when it was just created.
+ *
+ * It does keep: live connections, the Session ID cache, the DNS cache and the
+ * cookies.
+ */
+CURL_EXTERN void curl_easy_reset(CURL *curl);
+
+/*
+ * NAME curl_easy_recv()
+ *
+ * DESCRIPTION
+ *
+ * Receives data from the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen,
+                                    size_t *n);
+
+/*
+ * NAME curl_easy_send()
+ *
+ * DESCRIPTION
+ *
+ * Sends data over the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer,
+                                    size_t buflen, size_t *n);
+
+
+/*
+ * NAME curl_easy_upkeep()
+ *
+ * DESCRIPTION
+ *
+ * Performs connection upkeep for the given session handle.
+ */
+CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl);
+
+#ifdef  __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif
Index: trunk/src/libs/curl-8.7.1/include/curl/header.h
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/header.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/header.h	(revision 104083)
@@ -0,0 +1,74 @@
+#ifndef CURLINC_HEADER_H
+#define CURLINC_HEADER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct curl_header {
+  char *name;    /* this might not use the same case */
+  char *value;
+  size_t amount; /* number of headers using this name  */
+  size_t index;  /* ... of this instance, 0 or higher */
+  unsigned int origin; /* see bits below */
+  void *anchor; /* handle privately used by libcurl */
+};
+
+/* 'origin' bits */
+#define CURLH_HEADER    (1<<0) /* plain server header */
+#define CURLH_TRAILER   (1<<1) /* trailers */
+#define CURLH_CONNECT   (1<<2) /* CONNECT headers */
+#define CURLH_1XX       (1<<3) /* 1xx headers */
+#define CURLH_PSEUDO    (1<<4) /* pseudo headers */
+
+typedef enum {
+  CURLHE_OK,
+  CURLHE_BADINDEX,      /* header exists but not with this index */
+  CURLHE_MISSING,       /* no such header exists */
+  CURLHE_NOHEADERS,     /* no headers at all exist (yet) */
+  CURLHE_NOREQUEST,     /* no request with this number was used */
+  CURLHE_OUT_OF_MEMORY, /* out of memory while processing */
+  CURLHE_BAD_ARGUMENT,  /* a function argument was not okay */
+  CURLHE_NOT_BUILT_IN   /* if API was disabled in the build */
+} CURLHcode;
+
+CURL_EXTERN CURLHcode curl_easy_header(CURL *easy,
+                                       const char *name,
+                                       size_t index,
+                                       unsigned int origin,
+                                       int request,
+                                       struct curl_header **hout);
+
+CURL_EXTERN struct curl_header *curl_easy_nextheader(CURL *easy,
+                                                     unsigned int origin,
+                                                     int request,
+                                                     struct curl_header *prev);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif /* CURLINC_HEADER_H */
Index: trunk/src/libs/curl-8.7.1/include/curl/mprintf.h
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/mprintf.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/mprintf.h	(revision 104083)
@@ -0,0 +1,78 @@
+#ifndef CURLINC_MPRINTF_H
+#define CURLINC_MPRINTF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <stdarg.h>
+#include <stdio.h> /* needed for FILE */
+#include "curl.h"  /* for CURL_EXTERN */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#if (defined(__GNUC__) || defined(__clang__)) &&                        \
+  defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) &&         \
+  !defined(CURL_NO_FMT_CHECKS)
+#if defined(__MINGW32__) && !defined(__clang__)
+#define CURL_TEMP_PRINTF(fmt, arg) \
+  __attribute__((format(gnu_printf, fmt, arg)))
+#else
+#define CURL_TEMP_PRINTF(fmt, arg) \
+  __attribute__((format(printf, fmt, arg)))
+#endif
+#else
+#define CURL_TEMP_PRINTF(fmt, arg)
+#endif
+
+CURL_EXTERN int curl_mprintf(const char *format, ...)
+  CURL_TEMP_PRINTF(1, 2);
+CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...)
+  CURL_TEMP_PRINTF(2, 3);
+CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...)
+  CURL_TEMP_PRINTF(2, 3);
+CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength,
+                               const char *format, ...)
+  CURL_TEMP_PRINTF(3, 4);
+CURL_EXTERN int curl_mvprintf(const char *format, va_list args)
+  CURL_TEMP_PRINTF(1, 0);
+CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args)
+  CURL_TEMP_PRINTF(2, 0);
+CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args)
+  CURL_TEMP_PRINTF(2, 0);
+CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength,
+                                const char *format, va_list args)
+  CURL_TEMP_PRINTF(3, 0);
+CURL_EXTERN char *curl_maprintf(const char *format, ...)
+  CURL_TEMP_PRINTF(1, 2);
+CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args)
+  CURL_TEMP_PRINTF(1, 0);
+
+#undef CURL_TEMP_PRINTF
+
+#ifdef  __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif /* CURLINC_MPRINTF_H */
Index: trunk/src/libs/curl-8.7.1/include/curl/multi.h
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/multi.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/multi.h	(revision 104083)
@@ -0,0 +1,471 @@
+#ifndef CURLINC_MULTI_H
+#define CURLINC_MULTI_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+/*
+  This is an "external" header file. Don't give away any internals here!
+
+  GOALS
+
+  o Enable a "pull" interface. The application that uses libcurl decides where
+    and when to ask libcurl to get/send data.
+
+  o Enable multiple simultaneous transfers in the same thread without making it
+    complicated for the application.
+
+  o Enable the application to select() on its own file descriptors and curl's
+    file descriptors simultaneous easily.
+
+*/
+
+/*
+ * This header file should not really need to include "curl.h" since curl.h
+ * itself includes this file and we expect user applications to do #include
+ * <curl/curl.h> without the need for especially including multi.h.
+ *
+ * For some reason we added this include here at one point, and rather than to
+ * break existing (wrongly written) libcurl applications, we leave it as-is
+ * but with this warning attached.
+ */
+#include "curl.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER)
+typedef struct Curl_multi CURLM;
+#else
+typedef void CURLM;
+#endif
+
+typedef enum {
+  CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
+                                    curl_multi_socket*() soon */
+  CURLM_OK,
+  CURLM_BAD_HANDLE,      /* the passed-in handle is not a valid CURLM handle */
+  CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
+  CURLM_OUT_OF_MEMORY,   /* if you ever get this, you're in deep sh*t */
+  CURLM_INTERNAL_ERROR,  /* this is a libcurl bug */
+  CURLM_BAD_SOCKET,      /* the passed in socket argument did not match */
+  CURLM_UNKNOWN_OPTION,  /* curl_multi_setopt() with unsupported option */
+  CURLM_ADDED_ALREADY,   /* an easy handle already added to a multi handle was
+                            attempted to get added - again */
+  CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
+                               callback */
+  CURLM_WAKEUP_FAILURE,  /* wakeup is unavailable or failed */
+  CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */
+  CURLM_ABORTED_BY_CALLBACK,
+  CURLM_UNRECOVERABLE_POLL,
+  CURLM_LAST
+} CURLMcode;
+
+/* just to make code nicer when using curl_multi_socket() you can now check
+   for CURLM_CALL_MULTI_SOCKET too in the same style it works for
+   curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
+#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM
+
+/* bitmask bits for CURLMOPT_PIPELINING */
+#define CURLPIPE_NOTHING   0L
+#define CURLPIPE_HTTP1     1L
+#define CURLPIPE_MULTIPLEX 2L
+
+typedef enum {
+  CURLMSG_NONE, /* first, not used */
+  CURLMSG_DONE, /* This easy handle has completed. 'result' contains
+                   the CURLcode of the transfer */
+  CURLMSG_LAST /* last, not used */
+} CURLMSG;
+
+struct CURLMsg {
+  CURLMSG msg;       /* what this message means */
+  CURL *easy_handle; /* the handle it concerns */
+  union {
+    void *whatever;    /* message-specific data */
+    CURLcode result;   /* return code for transfer */
+  } data;
+};
+typedef struct CURLMsg CURLMsg;
+
+/* Based on poll(2) structure and values.
+ * We don't use pollfd and POLL* constants explicitly
+ * to cover platforms without poll(). */
+#define CURL_WAIT_POLLIN    0x0001
+#define CURL_WAIT_POLLPRI   0x0002
+#define CURL_WAIT_POLLOUT   0x0004
+
+struct curl_waitfd {
+  curl_socket_t fd;
+  short events;
+  short revents;
+};
+
+/*
+ * Name:    curl_multi_init()
+ *
+ * Desc:    initialize multi-style curl usage
+ *
+ * Returns: a new CURLM handle to use in all 'curl_multi' functions.
+ */
+CURL_EXTERN CURLM *curl_multi_init(void);
+
+/*
+ * Name:    curl_multi_add_handle()
+ *
+ * Desc:    add a standard curl handle to the multi stack
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle,
+                                            CURL *curl_handle);
+
+ /*
+  * Name:    curl_multi_remove_handle()
+  *
+  * Desc:    removes a curl handle from the multi stack again
+  *
+  * Returns: CURLMcode type, general multi error code.
+  */
+CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
+                                               CURL *curl_handle);
+
+ /*
+  * Name:    curl_multi_fdset()
+  *
+  * Desc:    Ask curl for its fd_set sets. The app can use these to select() or
+  *          poll() on. We want curl_multi_perform() called as soon as one of
+  *          them are ready.
+  *
+  * Returns: CURLMcode type, general multi error code.
+  */
+CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle,
+                                       fd_set *read_fd_set,
+                                       fd_set *write_fd_set,
+                                       fd_set *exc_fd_set,
+                                       int *max_fd);
+
+/*
+ * Name:     curl_multi_wait()
+ *
+ * Desc:     Poll on all fds within a CURLM set as well as any
+ *           additional fds passed to the function.
+ *
+ * Returns:  CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle,
+                                      struct curl_waitfd extra_fds[],
+                                      unsigned int extra_nfds,
+                                      int timeout_ms,
+                                      int *ret);
+
+/*
+ * Name:     curl_multi_poll()
+ *
+ * Desc:     Poll on all fds within a CURLM set as well as any
+ *           additional fds passed to the function.
+ *
+ * Returns:  CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_poll(CURLM *multi_handle,
+                                      struct curl_waitfd extra_fds[],
+                                      unsigned int extra_nfds,
+                                      int timeout_ms,
+                                      int *ret);
+
+/*
+ * Name:     curl_multi_wakeup()
+ *
+ * Desc:     wakes up a sleeping curl_multi_poll call.
+ *
+ * Returns:  CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle);
+
+ /*
+  * Name:    curl_multi_perform()
+  *
+  * Desc:    When the app thinks there's data available for curl it calls this
+  *          function to read/write whatever there is right now. This returns
+  *          as soon as the reads and writes are done. This function does not
+  *          require that there actually is data available for reading or that
+  *          data can be written, it can be called just in case. It returns
+  *          the number of handles that still transfer data in the second
+  *          argument's integer-pointer.
+  *
+  * Returns: CURLMcode type, general multi error code. *NOTE* that this only
+  *          returns errors etc regarding the whole multi stack. There might
+  *          still have occurred problems on individual transfers even when
+  *          this returns OK.
+  */
+CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle,
+                                         int *running_handles);
+
+ /*
+  * Name:    curl_multi_cleanup()
+  *
+  * Desc:    Cleans up and removes a whole multi stack. It does not free or
+  *          touch any individual easy handles in any way. We need to define
+  *          in what state those handles will be if this function is called
+  *          in the middle of a transfer.
+  *
+  * Returns: CURLMcode type, general multi error code.
+  */
+CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
+
+/*
+ * Name:    curl_multi_info_read()
+ *
+ * Desc:    Ask the multi handle if there's any messages/informationals from
+ *          the individual transfers. Messages include informationals such as
+ *          error code from the transfer or just the fact that a transfer is
+ *          completed. More details on these should be written down as well.
+ *
+ *          Repeated calls to this function will return a new struct each
+ *          time, until a special "end of msgs" struct is returned as a signal
+ *          that there is no more to get at this point.
+ *
+ *          The data the returned pointer points to will not survive calling
+ *          curl_multi_cleanup().
+ *
+ *          The 'CURLMsg' struct is meant to be very simple and only contain
+ *          very basic information. If more involved information is wanted,
+ *          we will provide the particular "transfer handle" in that struct
+ *          and that should/could/would be used in subsequent
+ *          curl_easy_getinfo() calls (or similar). The point being that we
+ *          must never expose complex structs to applications, as then we'll
+ *          undoubtably get backwards compatibility problems in the future.
+ *
+ * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
+ *          of structs. It also writes the number of messages left in the
+ *          queue (after this read) in the integer the second argument points
+ *          to.
+ */
+CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
+                                          int *msgs_in_queue);
+
+/*
+ * Name:    curl_multi_strerror()
+ *
+ * Desc:    The curl_multi_strerror function may be used to turn a CURLMcode
+ *          value into the equivalent human readable error string.  This is
+ *          useful for printing meaningful error messages.
+ *
+ * Returns: A pointer to a null-terminated error message.
+ */
+CURL_EXTERN const char *curl_multi_strerror(CURLMcode);
+
+/*
+ * Name:    curl_multi_socket() and
+ *          curl_multi_socket_all()
+ *
+ * Desc:    An alternative version of curl_multi_perform() that allows the
+ *          application to pass in one of the file descriptors that have been
+ *          detected to have "action" on them and let libcurl perform.
+ *          See man page for details.
+ */
+#define CURL_POLL_NONE   0
+#define CURL_POLL_IN     1
+#define CURL_POLL_OUT    2
+#define CURL_POLL_INOUT  3
+#define CURL_POLL_REMOVE 4
+
+#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD
+
+#define CURL_CSELECT_IN   0x01
+#define CURL_CSELECT_OUT  0x02
+#define CURL_CSELECT_ERR  0x04
+
+typedef int (*curl_socket_callback)(CURL *easy,      /* easy handle */
+                                    curl_socket_t s, /* socket */
+                                    int what,        /* see above */
+                                    void *userp,     /* private callback
+                                                        pointer */
+                                    void *socketp);  /* private socket
+                                                        pointer */
+/*
+ * Name:    curl_multi_timer_callback
+ *
+ * Desc:    Called by libcurl whenever the library detects a change in the
+ *          maximum number of milliseconds the app is allowed to wait before
+ *          curl_multi_socket() or curl_multi_perform() must be called
+ *          (to allow libcurl's timed events to take place).
+ *
+ * Returns: The callback should return zero.
+ */
+typedef int (*curl_multi_timer_callback)(CURLM *multi,    /* multi handle */
+                                         long timeout_ms, /* see above */
+                                         void *userp);    /* private callback
+                                                             pointer */
+
+CURL_EXTERN CURLMcode CURL_DEPRECATED(7.19.5, "Use curl_multi_socket_action()")
+curl_multi_socket(CURLM *multi_handle, curl_socket_t s, int *running_handles);
+
+CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle,
+                                               curl_socket_t s,
+                                               int ev_bitmask,
+                                               int *running_handles);
+
+CURL_EXTERN CURLMcode CURL_DEPRECATED(7.19.5, "Use curl_multi_socket_action()")
+curl_multi_socket_all(CURLM *multi_handle, int *running_handles);
+
+#ifndef CURL_ALLOW_OLD_MULTI_SOCKET
+/* This macro below was added in 7.16.3 to push users who recompile to use
+   the new curl_multi_socket_action() instead of the old curl_multi_socket()
+*/
+#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z)
+#endif
+
+/*
+ * Name:    curl_multi_timeout()
+ *
+ * Desc:    Returns the maximum number of milliseconds the app is allowed to
+ *          wait before curl_multi_socket() or curl_multi_perform() must be
+ *          called (to allow libcurl's timed events to take place).
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle,
+                                         long *milliseconds);
+
+typedef enum {
+  /* This is the socket callback function pointer */
+  CURLOPT(CURLMOPT_SOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 1),
+
+  /* This is the argument passed to the socket callback */
+  CURLOPT(CURLMOPT_SOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 2),
+
+    /* set to 1 to enable pipelining for this multi handle */
+  CURLOPT(CURLMOPT_PIPELINING, CURLOPTTYPE_LONG, 3),
+
+   /* This is the timer callback function pointer */
+  CURLOPT(CURLMOPT_TIMERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 4),
+
+  /* This is the argument passed to the timer callback */
+  CURLOPT(CURLMOPT_TIMERDATA, CURLOPTTYPE_OBJECTPOINT, 5),
+
+  /* maximum number of entries in the connection cache */
+  CURLOPT(CURLMOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 6),
+
+  /* maximum number of (pipelining) connections to one host */
+  CURLOPT(CURLMOPT_MAX_HOST_CONNECTIONS, CURLOPTTYPE_LONG, 7),
+
+  /* maximum number of requests in a pipeline */
+  CURLOPT(CURLMOPT_MAX_PIPELINE_LENGTH, CURLOPTTYPE_LONG, 8),
+
+  /* a connection with a content-length longer than this
+     will not be considered for pipelining */
+  CURLOPT(CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 9),
+
+  /* a connection with a chunk length longer than this
+     will not be considered for pipelining */
+  CURLOPT(CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 10),
+
+  /* a list of site names(+port) that are blocked from pipelining */
+  CURLOPT(CURLMOPT_PIPELINING_SITE_BL, CURLOPTTYPE_OBJECTPOINT, 11),
+
+  /* a list of server types that are blocked from pipelining */
+  CURLOPT(CURLMOPT_PIPELINING_SERVER_BL, CURLOPTTYPE_OBJECTPOINT, 12),
+
+  /* maximum number of open connections in total */
+  CURLOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, CURLOPTTYPE_LONG, 13),
+
+   /* This is the server push callback function pointer */
+  CURLOPT(CURLMOPT_PUSHFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 14),
+
+  /* This is the argument passed to the server push callback */
+  CURLOPT(CURLMOPT_PUSHDATA, CURLOPTTYPE_OBJECTPOINT, 15),
+
+  /* maximum number of concurrent streams to support on a connection */
+  CURLOPT(CURLMOPT_MAX_CONCURRENT_STREAMS, CURLOPTTYPE_LONG, 16),
+
+  CURLMOPT_LASTENTRY /* the last unused */
+} CURLMoption;
+
+
+/*
+ * Name:    curl_multi_setopt()
+ *
+ * Desc:    Sets options for the multi handle.
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
+                                        CURLMoption option, ...);
+
+
+/*
+ * Name:    curl_multi_assign()
+ *
+ * Desc:    This function sets an association in the multi handle between the
+ *          given socket and a private pointer of the application. This is
+ *          (only) useful for curl_multi_socket uses.
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
+                                        curl_socket_t sockfd, void *sockp);
+
+/*
+ * Name:    curl_multi_get_handles()
+ *
+ * Desc:    Returns an allocated array holding all handles currently added to
+ *          the multi handle. Marks the final entry with a NULL pointer. If
+ *          there is no easy handle added to the multi handle, this function
+ *          returns an array with the first entry as a NULL pointer.
+ *
+ * Returns: NULL on failure, otherwise a CURL **array pointer
+ */
+CURL_EXTERN CURL **curl_multi_get_handles(CURLM *multi_handle);
+
+/*
+ * Name: curl_push_callback
+ *
+ * Desc: This callback gets called when a new stream is being pushed by the
+ *       server. It approves or denies the new stream. It can also decide
+ *       to completely fail the connection.
+ *
+ * Returns: CURL_PUSH_OK, CURL_PUSH_DENY or CURL_PUSH_ERROROUT
+ */
+#define CURL_PUSH_OK       0
+#define CURL_PUSH_DENY     1
+#define CURL_PUSH_ERROROUT 2 /* added in 7.72.0 */
+
+struct curl_pushheaders;  /* forward declaration only */
+
+CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h,
+                                        size_t num);
+CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h,
+                                         const char *name);
+
+typedef int (*curl_push_callback)(CURL *parent,
+                                  CURL *easy,
+                                  size_t num_headers,
+                                  struct curl_pushheaders *headers,
+                                  void *userp);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif
Index: trunk/src/libs/curl-8.7.1/include/curl/options.h
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/options.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/options.h	(revision 104083)
@@ -0,0 +1,70 @@
+#ifndef CURLINC_OPTIONS_H
+#define CURLINC_OPTIONS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+  CURLOT_LONG,    /* long (a range of values) */
+  CURLOT_VALUES,  /*      (a defined set or bitmask) */
+  CURLOT_OFF_T,   /* curl_off_t (a range of values) */
+  CURLOT_OBJECT,  /* pointer (void *) */
+  CURLOT_STRING,  /*         (char * to null-terminated buffer) */
+  CURLOT_SLIST,   /*         (struct curl_slist *) */
+  CURLOT_CBPTR,   /*         (void * passed as-is to a callback) */
+  CURLOT_BLOB,    /* blob (struct curl_blob *) */
+  CURLOT_FUNCTION /* function pointer */
+} curl_easytype;
+
+/* Flag bits */
+
+/* "alias" means it is provided for old programs to remain functional,
+   we prefer another name */
+#define CURLOT_FLAG_ALIAS (1<<0)
+
+/* The CURLOPTTYPE_* id ranges can still be used to figure out what type/size
+   to use for curl_easy_setopt() for the given id */
+struct curl_easyoption {
+  const char *name;
+  CURLoption id;
+  curl_easytype type;
+  unsigned int flags;
+};
+
+CURL_EXTERN const struct curl_easyoption *
+curl_easy_option_by_name(const char *name);
+
+CURL_EXTERN const struct curl_easyoption *
+curl_easy_option_by_id(CURLoption id);
+
+CURL_EXTERN const struct curl_easyoption *
+curl_easy_option_next(const struct curl_easyoption *prev);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+#endif /* CURLINC_OPTIONS_H */
Index: trunk/src/libs/curl-8.7.1/include/curl/stdcheaders.h
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/stdcheaders.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/stdcheaders.h	(revision 104083)
@@ -0,0 +1,35 @@
+#ifndef CURLINC_STDCHEADERS_H
+#define CURLINC_STDCHEADERS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <sys/types.h>
+
+size_t fread(void *, size_t, size_t, FILE *);
+size_t fwrite(const void *, size_t, size_t, FILE *);
+
+int strcasecmp(const char *, const char *);
+int strncasecmp(const char *, const char *, size_t);
+
+#endif /* CURLINC_STDCHEADERS_H */
Index: trunk/src/libs/curl-8.7.1/include/curl/system.h
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/system.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/system.h	(revision 104083)
@@ -0,0 +1,515 @@
+#ifndef CURLINC_SYSTEM_H
+#define CURLINC_SYSTEM_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Try to keep one section per platform, compiler and architecture, otherwise,
+ * if an existing section is reused for a different one and later on the
+ * original is adjusted, probably the piggybacking one can be adversely
+ * changed.
+ *
+ * In order to differentiate between platforms/compilers/architectures use
+ * only compiler built in predefined preprocessor symbols.
+ *
+ * curl_off_t
+ * ----------
+ *
+ * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit
+ * wide signed integral data type. The width of this data type must remain
+ * constant and independent of any possible large file support settings.
+ *
+ * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit
+ * wide signed integral data type if there is no 64-bit type.
+ *
+ * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall
+ * only be violated if off_t is the only 64-bit data type available and the
+ * size of off_t is independent of large file support settings. Keep your
+ * build on the safe side avoiding an off_t gating.  If you have a 64-bit
+ * off_t then take for sure that another 64-bit data type exists, dig deeper
+ * and you will find it.
+ *
+ */
+
+#if defined(__DJGPP__) || defined(__GO32__)
+#  if defined(__DJGPP__) && (__DJGPP__ > 1)
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__SALFORDC__)
+#  define CURL_TYPEOF_CURL_OFF_T     long
+#  define CURL_FORMAT_CURL_OFF_T     "ld"
+#  define CURL_FORMAT_CURL_OFF_TU    "lu"
+#  define CURL_SUFFIX_CURL_OFF_T     L
+#  define CURL_SUFFIX_CURL_OFF_TU    UL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__BORLANDC__)
+#  if (__BORLANDC__ < 0x520)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "I64d"
+#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__TURBOC__)
+#  define CURL_TYPEOF_CURL_OFF_T     long
+#  define CURL_FORMAT_CURL_OFF_T     "ld"
+#  define CURL_FORMAT_CURL_OFF_TU    "lu"
+#  define CURL_SUFFIX_CURL_OFF_T     L
+#  define CURL_SUFFIX_CURL_OFF_TU    UL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__POCC__)
+#  if (__POCC__ < 280)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  elif defined(_MSC_VER)
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "I64d"
+#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__LCC__)
+#  if defined(__MCST__) /* MCST eLbrus Compiler Collection */
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#    define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#    define CURL_PULL_SYS_TYPES_H      1
+#    define CURL_PULL_SYS_SOCKET_H     1
+#  else                /* Local (or Little) C Compiler */
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#    define CURL_TYPEOF_CURL_SOCKLEN_T int
+#  endif
+
+#elif defined(macintosh)
+#  include <ConditionalMacros.h>
+#  if TYPE_LONGLONG
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
+
+#elif defined(__TANDEM)
+# if ! defined(__LP64)
+   /* Required for 32-bit NonStop builds only. */
+#  define CURL_TYPEOF_CURL_OFF_T     long long
+#  define CURL_FORMAT_CURL_OFF_T     "lld"
+#  define CURL_FORMAT_CURL_OFF_TU    "llu"
+#  define CURL_SUFFIX_CURL_OFF_T     LL
+#  define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+# endif
+
+#elif defined(_WIN32_WCE)
+#  define CURL_TYPEOF_CURL_OFF_T     __int64
+#  define CURL_FORMAT_CURL_OFF_T     "I64d"
+#  define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#  define CURL_SUFFIX_CURL_OFF_T     i64
+#  define CURL_SUFFIX_CURL_OFF_TU    ui64
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__MINGW32__)
+#  include <inttypes.h>
+#  define CURL_TYPEOF_CURL_OFF_T     long long
+#  define CURL_FORMAT_CURL_OFF_T     PRId64
+#  define CURL_FORMAT_CURL_OFF_TU    PRIu64
+#  define CURL_SUFFIX_CURL_OFF_T     LL
+#  define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+#  define CURL_PULL_SYS_TYPES_H      1
+
+#elif defined(__VMS)
+#  if defined(__VAX)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
+
+#elif defined(__OS400__)
+#  define CURL_TYPEOF_CURL_OFF_T     long long
+#  define CURL_FORMAT_CURL_OFF_T     "lld"
+#  define CURL_FORMAT_CURL_OFF_TU    "llu"
+#  define CURL_SUFFIX_CURL_OFF_T     LL
+#  define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
+#elif defined(__MVS__)
+#  if defined(_LONG_LONG)
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  elif defined(_LP64)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
+#elif defined(__370__)
+#  if defined(__IBMC__) || defined(__IBMCPP__)
+#    if defined(_ILP32)
+#    elif defined(_LP64)
+#    endif
+#    if defined(_LONG_LONG)
+#      define CURL_TYPEOF_CURL_OFF_T     long long
+#      define CURL_FORMAT_CURL_OFF_T     "lld"
+#      define CURL_FORMAT_CURL_OFF_TU    "llu"
+#      define CURL_SUFFIX_CURL_OFF_T     LL
+#      define CURL_SUFFIX_CURL_OFF_TU    ULL
+#    elif defined(_LP64)
+#      define CURL_TYPEOF_CURL_OFF_T     long
+#      define CURL_FORMAT_CURL_OFF_T     "ld"
+#      define CURL_FORMAT_CURL_OFF_TU    "lu"
+#      define CURL_SUFFIX_CURL_OFF_T     L
+#      define CURL_SUFFIX_CURL_OFF_TU    UL
+#    else
+#      define CURL_TYPEOF_CURL_OFF_T     long
+#      define CURL_FORMAT_CURL_OFF_T     "ld"
+#      define CURL_FORMAT_CURL_OFF_TU    "lu"
+#      define CURL_SUFFIX_CURL_OFF_T     L
+#      define CURL_SUFFIX_CURL_OFF_TU    UL
+#    endif
+#    define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#    define CURL_PULL_SYS_TYPES_H      1
+#    define CURL_PULL_SYS_SOCKET_H     1
+#  endif
+
+#elif defined(TPF)
+#  define CURL_TYPEOF_CURL_OFF_T     long
+#  define CURL_FORMAT_CURL_OFF_T     "ld"
+#  define CURL_FORMAT_CURL_OFF_TU    "lu"
+#  define CURL_SUFFIX_CURL_OFF_T     L
+#  define CURL_SUFFIX_CURL_OFF_TU    UL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__TINYC__) /* also known as tcc */
+#  define CURL_TYPEOF_CURL_OFF_T     long long
+#  define CURL_FORMAT_CURL_OFF_T     "lld"
+#  define CURL_FORMAT_CURL_OFF_TU    "llu"
+#  define CURL_SUFFIX_CURL_OFF_T     LL
+#  define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
+#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Oracle Solaris Studio */
+#  if !defined(__LP64) && (defined(__ILP32) ||                          \
+                           defined(__i386) ||                           \
+                           defined(__sparcv8) ||                        \
+                           defined(__sparcv8plus))
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  elif defined(__LP64) || \
+        defined(__amd64) || defined(__sparcv9)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
+#elif defined(__xlc__) /* IBM xlc compiler */
+#  if !defined(_LP64)
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
+#elif defined(__hpux) /* HP aCC compiler */
+#  if !defined(_LP64)
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
+/* ===================================== */
+/*    KEEP MSVC THE PENULTIMATE ENTRY    */
+/* ===================================== */
+
+#elif defined(_MSC_VER)
+#  if (_MSC_VER >= 1800)
+#    include <inttypes.h>
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     PRId64
+#    define CURL_FORMAT_CURL_OFF_TU    PRIu64
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
+#  elif (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "I64d"
+#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+/* ===================================== */
+/*    KEEP GENERIC GCC THE LAST ENTRY    */
+/* ===================================== */
+
+#elif defined(__GNUC__) && !defined(_SCO_DS)
+#  if !defined(__LP64__) &&                                             \
+  (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) ||      \
+   defined(__ppc__) || defined(__powerpc__) || defined(__arm__) ||      \
+   defined(__sparc__) || defined(__mips__) || defined(__sh__) ||        \
+   defined(__XTENSA__) ||                                               \
+   (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4)  ||               \
+   (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L))
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  elif defined(__LP64__) || \
+        defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \
+        defined(__e2k__) || \
+        (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \
+        (defined(__LONG_MAX__) && __LONG_MAX__ == 9223372036854775807L)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  ifdef RT_OS_OS2                                  /* VBOX */
+#   define CURL_TYPEOF_CURL_SOCKLEN_T int           /* VBOX */
+#  else                                             /* VBOX */
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  endif                                            /* VBOX */
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
+#else
+/* generic "safe guess" on old 32 bit style */
+# define CURL_TYPEOF_CURL_OFF_T     long
+# define CURL_FORMAT_CURL_OFF_T     "ld"
+# define CURL_FORMAT_CURL_OFF_TU    "lu"
+# define CURL_SUFFIX_CURL_OFF_T     L
+# define CURL_SUFFIX_CURL_OFF_TU    UL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+#endif
+
+#ifdef _AIX
+/* AIX needs <sys/poll.h> */
+#define CURL_PULL_SYS_POLL_H
+#endif
+
+
+/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file  */
+/* ws2tcpip.h is required here to properly make type definitions below. */
+#ifdef CURL_PULL_WS2TCPIP_H
+# ifdef VBOX
+#  include <iprt/win/winsock2.h>
+#  include <iprt/win/windows.h>
+#  include <iprt/win/ws2tcpip.h>
+# else
+#  include <winsock2.h>
+#  include <windows.h>
+#  include <ws2tcpip.h>
+# endif
+#endif
+
+/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file  */
+/* sys/types.h is required here to properly make type definitions below. */
+#ifdef CURL_PULL_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+
+/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file  */
+/* sys/socket.h is required here to properly make type definitions below. */
+#ifdef CURL_PULL_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+
+/* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file    */
+/* sys/poll.h is required here to properly make type definitions below.   */
+#ifdef CURL_PULL_SYS_POLL_H
+#  include <sys/poll.h>
+#endif
+
+/* Data type definition of curl_socklen_t. */
+#ifdef CURL_TYPEOF_CURL_SOCKLEN_T
+  typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t;
+#endif
+
+/* Data type definition of curl_off_t. */
+
+#ifdef CURL_TYPEOF_CURL_OFF_T
+  typedef CURL_TYPEOF_CURL_OFF_T curl_off_t;
+#endif
+
+/*
+ * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow
+ * these to be visible and exported by the external libcurl interface API,
+ * while also making them visible to the library internals, simply including
+ * curl_setup.h, without actually needing to include curl.h internally.
+ * If some day this section would grow big enough, all this should be moved
+ * to its own header file.
+ */
+
+/*
+ * Figure out if we can use the ## preprocessor operator, which is supported
+ * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__
+ * or  __cplusplus so we need to carefully check for them too.
+ */
+
+#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
+  defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
+  defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \
+  defined(__ILEC400__)
+  /* This compiler is believed to have an ISO compatible preprocessor */
+#define CURL_ISOCPP
+#else
+  /* This compiler is believed NOT to have an ISO compatible preprocessor */
+#undef CURL_ISOCPP
+#endif
+
+/*
+ * Macros for minimum-width signed and unsigned curl_off_t integer constants.
+ */
+
+#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551)
+#  define CURLINC_OFF_T_C_HLPR2(x) x
+#  define CURLINC_OFF_T_C_HLPR1(x) CURLINC_OFF_T_C_HLPR2(x)
+#  define CURL_OFF_T_C(Val)  CURLINC_OFF_T_C_HLPR1(Val) ## \
+                             CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T)
+#  define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \
+                             CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU)
+#else
+#  ifdef CURL_ISOCPP
+#    define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix
+#  else
+#    define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix
+#  endif
+#  define CURLINC_OFF_T_C_HLPR1(Val,Suffix) CURLINC_OFF_T_C_HLPR2(Val,Suffix)
+#  define CURL_OFF_T_C(Val)  CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T)
+#  define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU)
+#endif
+
+#endif /* CURLINC_SYSTEM_H */
Index: trunk/src/libs/curl-8.7.1/include/curl/typecheck-gcc.h
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/typecheck-gcc.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/typecheck-gcc.h	(revision 104083)
@@ -0,0 +1,717 @@
+#ifndef CURLINC_TYPECHECK_GCC_H
+#define CURLINC_TYPECHECK_GCC_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* wraps curl_easy_setopt() with typechecking */
+
+/* To add a new kind of warning, add an
+ *   if(curlcheck_sometype_option(_curl_opt))
+ *     if(!curlcheck_sometype(value))
+ *       _curl_easy_setopt_err_sometype();
+ * block and define curlcheck_sometype_option, curlcheck_sometype and
+ * _curl_easy_setopt_err_sometype below
+ *
+ * NOTE: We use two nested 'if' statements here instead of the && operator, in
+ *       order to work around gcc bug #32061.  It affects only gcc 4.3.x/4.4.x
+ *       when compiling with -Wlogical-op.
+ *
+ * To add an option that uses the same type as an existing option, you'll just
+ * need to extend the appropriate _curl_*_option macro
+ */
+#define curl_easy_setopt(handle, option, value)                         \
+  __extension__({                                                       \
+      CURLoption _curl_opt = (option);                                  \
+      if(__builtin_constant_p(_curl_opt)) {                             \
+        CURL_IGNORE_DEPRECATION(                                        \
+          if(curlcheck_long_option(_curl_opt))                          \
+            if(!curlcheck_long(value))                                  \
+              _curl_easy_setopt_err_long();                             \
+          if(curlcheck_off_t_option(_curl_opt))                         \
+            if(!curlcheck_off_t(value))                                 \
+              _curl_easy_setopt_err_curl_off_t();                       \
+          if(curlcheck_string_option(_curl_opt))                        \
+            if(!curlcheck_string(value))                                \
+              _curl_easy_setopt_err_string();                           \
+          if(curlcheck_write_cb_option(_curl_opt))                      \
+            if(!curlcheck_write_cb(value))                              \
+              _curl_easy_setopt_err_write_callback();                   \
+          if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION)            \
+            if(!curlcheck_resolver_start_callback(value))               \
+              _curl_easy_setopt_err_resolver_start_callback();          \
+          if((_curl_opt) == CURLOPT_READFUNCTION)                       \
+            if(!curlcheck_read_cb(value))                               \
+              _curl_easy_setopt_err_read_cb();                          \
+          if((_curl_opt) == CURLOPT_IOCTLFUNCTION)                      \
+            if(!curlcheck_ioctl_cb(value))                              \
+              _curl_easy_setopt_err_ioctl_cb();                         \
+          if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION)                    \
+            if(!curlcheck_sockopt_cb(value))                            \
+              _curl_easy_setopt_err_sockopt_cb();                       \
+          if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION)                 \
+            if(!curlcheck_opensocket_cb(value))                         \
+              _curl_easy_setopt_err_opensocket_cb();                    \
+          if((_curl_opt) == CURLOPT_PROGRESSFUNCTION)                   \
+            if(!curlcheck_progress_cb(value))                           \
+              _curl_easy_setopt_err_progress_cb();                      \
+          if((_curl_opt) == CURLOPT_DEBUGFUNCTION)                      \
+            if(!curlcheck_debug_cb(value))                              \
+              _curl_easy_setopt_err_debug_cb();                         \
+          if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION)                   \
+            if(!curlcheck_ssl_ctx_cb(value))                            \
+              _curl_easy_setopt_err_ssl_ctx_cb();                       \
+          if(curlcheck_conv_cb_option(_curl_opt))                       \
+            if(!curlcheck_conv_cb(value))                               \
+              _curl_easy_setopt_err_conv_cb();                          \
+          if((_curl_opt) == CURLOPT_SEEKFUNCTION)                       \
+            if(!curlcheck_seek_cb(value))                               \
+              _curl_easy_setopt_err_seek_cb();                          \
+          if(curlcheck_cb_data_option(_curl_opt))                       \
+            if(!curlcheck_cb_data(value))                               \
+              _curl_easy_setopt_err_cb_data();                          \
+          if((_curl_opt) == CURLOPT_ERRORBUFFER)                        \
+            if(!curlcheck_error_buffer(value))                          \
+              _curl_easy_setopt_err_error_buffer();                     \
+          if((_curl_opt) == CURLOPT_STDERR)                             \
+            if(!curlcheck_FILE(value))                                  \
+              _curl_easy_setopt_err_FILE();                             \
+          if(curlcheck_postfields_option(_curl_opt))                    \
+            if(!curlcheck_postfields(value))                            \
+              _curl_easy_setopt_err_postfields();                       \
+          if((_curl_opt) == CURLOPT_HTTPPOST)                           \
+            if(!curlcheck_arr((value), struct curl_httppost))           \
+              _curl_easy_setopt_err_curl_httpost();                     \
+          if((_curl_opt) == CURLOPT_MIMEPOST)                           \
+            if(!curlcheck_ptr((value), curl_mime))                      \
+              _curl_easy_setopt_err_curl_mimepost();                    \
+          if(curlcheck_slist_option(_curl_opt))                         \
+            if(!curlcheck_arr((value), struct curl_slist))              \
+              _curl_easy_setopt_err_curl_slist();                       \
+          if((_curl_opt) == CURLOPT_SHARE)                              \
+            if(!curlcheck_ptr((value), CURLSH))                         \
+              _curl_easy_setopt_err_CURLSH();                           \
+        )                                                               \
+      }                                                                 \
+      curl_easy_setopt(handle, _curl_opt, value);                       \
+    })
+
+/* wraps curl_easy_getinfo() with typechecking */
+#define curl_easy_getinfo(handle, info, arg)                            \
+  __extension__({                                                       \
+      CURLINFO _curl_info = (info);                                     \
+      if(__builtin_constant_p(_curl_info)) {                            \
+        CURL_IGNORE_DEPRECATION(                                        \
+          if(curlcheck_string_info(_curl_info))                         \
+            if(!curlcheck_arr((arg), char *))                           \
+              _curl_easy_getinfo_err_string();                          \
+          if(curlcheck_long_info(_curl_info))                           \
+            if(!curlcheck_arr((arg), long))                             \
+              _curl_easy_getinfo_err_long();                            \
+          if(curlcheck_double_info(_curl_info))                         \
+            if(!curlcheck_arr((arg), double))                           \
+              _curl_easy_getinfo_err_double();                          \
+          if(curlcheck_slist_info(_curl_info))                          \
+            if(!curlcheck_arr((arg), struct curl_slist *))              \
+              _curl_easy_getinfo_err_curl_slist();                      \
+          if(curlcheck_tlssessioninfo_info(_curl_info))                 \
+            if(!curlcheck_arr((arg), struct curl_tlssessioninfo *))     \
+              _curl_easy_getinfo_err_curl_tlssesssioninfo();            \
+          if(curlcheck_certinfo_info(_curl_info))                       \
+            if(!curlcheck_arr((arg), struct curl_certinfo *))           \
+              _curl_easy_getinfo_err_curl_certinfo();                   \
+          if(curlcheck_socket_info(_curl_info))                         \
+            if(!curlcheck_arr((arg), curl_socket_t))                    \
+              _curl_easy_getinfo_err_curl_socket();                     \
+          if(curlcheck_off_t_info(_curl_info))                          \
+            if(!curlcheck_arr((arg), curl_off_t))                       \
+              _curl_easy_getinfo_err_curl_off_t();                      \
+        )                                                               \
+      }                                                                 \
+      curl_easy_getinfo(handle, _curl_info, arg);                       \
+    })
+
+/*
+ * For now, just make sure that the functions are called with three arguments
+ */
+#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
+#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
+
+
+/* the actual warnings, triggered by calling the _curl_easy_setopt_err*
+ * functions */
+
+/* To define a new warning, use _CURL_WARNING(identifier, "message") */
+#define CURLWARNING(id, message)                                        \
+  static void __attribute__((__warning__(message)))                     \
+  __attribute__((__unused__)) __attribute__((__noinline__))             \
+  id(void) { __asm__(""); }
+
+CURLWARNING(_curl_easy_setopt_err_long,
+  "curl_easy_setopt expects a long argument for this option")
+CURLWARNING(_curl_easy_setopt_err_curl_off_t,
+  "curl_easy_setopt expects a curl_off_t argument for this option")
+CURLWARNING(_curl_easy_setopt_err_string,
+              "curl_easy_setopt expects a "
+              "string ('char *' or char[]) argument for this option"
+  )
+CURLWARNING(_curl_easy_setopt_err_write_callback,
+  "curl_easy_setopt expects a curl_write_callback argument for this option")
+CURLWARNING(_curl_easy_setopt_err_resolver_start_callback,
+              "curl_easy_setopt expects a "
+              "curl_resolver_start_callback argument for this option"
+  )
+CURLWARNING(_curl_easy_setopt_err_read_cb,
+  "curl_easy_setopt expects a curl_read_callback argument for this option")
+CURLWARNING(_curl_easy_setopt_err_ioctl_cb,
+  "curl_easy_setopt expects a curl_ioctl_callback argument for this option")
+CURLWARNING(_curl_easy_setopt_err_sockopt_cb,
+  "curl_easy_setopt expects a curl_sockopt_callback argument for this option")
+CURLWARNING(_curl_easy_setopt_err_opensocket_cb,
+              "curl_easy_setopt expects a "
+              "curl_opensocket_callback argument for this option"
+  )
+CURLWARNING(_curl_easy_setopt_err_progress_cb,
+  "curl_easy_setopt expects a curl_progress_callback argument for this option")
+CURLWARNING(_curl_easy_setopt_err_debug_cb,
+  "curl_easy_setopt expects a curl_debug_callback argument for this option")
+CURLWARNING(_curl_easy_setopt_err_ssl_ctx_cb,
+  "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option")
+CURLWARNING(_curl_easy_setopt_err_conv_cb,
+  "curl_easy_setopt expects a curl_conv_callback argument for this option")
+CURLWARNING(_curl_easy_setopt_err_seek_cb,
+  "curl_easy_setopt expects a curl_seek_callback argument for this option")
+CURLWARNING(_curl_easy_setopt_err_cb_data,
+              "curl_easy_setopt expects a "
+              "private data pointer as argument for this option")
+CURLWARNING(_curl_easy_setopt_err_error_buffer,
+              "curl_easy_setopt expects a "
+              "char buffer of CURL_ERROR_SIZE as argument for this option")
+CURLWARNING(_curl_easy_setopt_err_FILE,
+  "curl_easy_setopt expects a 'FILE *' argument for this option")
+CURLWARNING(_curl_easy_setopt_err_postfields,
+  "curl_easy_setopt expects a 'void *' or 'char *' argument for this option")
+CURLWARNING(_curl_easy_setopt_err_curl_httpost,
+              "curl_easy_setopt expects a 'struct curl_httppost *' "
+              "argument for this option")
+CURLWARNING(_curl_easy_setopt_err_curl_mimepost,
+              "curl_easy_setopt expects a 'curl_mime *' "
+              "argument for this option")
+CURLWARNING(_curl_easy_setopt_err_curl_slist,
+  "curl_easy_setopt expects a 'struct curl_slist *' argument for this option")
+CURLWARNING(_curl_easy_setopt_err_CURLSH,
+  "curl_easy_setopt expects a CURLSH* argument for this option")
+
+CURLWARNING(_curl_easy_getinfo_err_string,
+  "curl_easy_getinfo expects a pointer to 'char *' for this info")
+CURLWARNING(_curl_easy_getinfo_err_long,
+  "curl_easy_getinfo expects a pointer to long for this info")
+CURLWARNING(_curl_easy_getinfo_err_double,
+  "curl_easy_getinfo expects a pointer to double for this info")
+CURLWARNING(_curl_easy_getinfo_err_curl_slist,
+  "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info")
+CURLWARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo,
+              "curl_easy_getinfo expects a pointer to "
+              "'struct curl_tlssessioninfo *' for this info")
+CURLWARNING(_curl_easy_getinfo_err_curl_certinfo,
+              "curl_easy_getinfo expects a pointer to "
+              "'struct curl_certinfo *' for this info")
+CURLWARNING(_curl_easy_getinfo_err_curl_socket,
+  "curl_easy_getinfo expects a pointer to curl_socket_t for this info")
+CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
+  "curl_easy_getinfo expects a pointer to curl_off_t for this info")
+
+/* groups of curl_easy_setops options that take the same type of argument */
+
+/* To add a new option to one of the groups, just add
+ *   (option) == CURLOPT_SOMETHING
+ * to the or-expression. If the option takes a long or curl_off_t, you don't
+ * have to do anything
+ */
+
+/* evaluates to true if option takes a long argument */
+#define curlcheck_long_option(option)                   \
+  (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT)
+
+#define curlcheck_off_t_option(option)          \
+  (((option) > CURLOPTTYPE_OFF_T) && ((option) < CURLOPTTYPE_BLOB))
+
+/* evaluates to true if option takes a char* argument */
+#define curlcheck_string_option(option)                                       \
+  ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET ||                                \
+   (option) == CURLOPT_ACCEPT_ENCODING ||                                     \
+   (option) == CURLOPT_ALTSVC ||                                              \
+   (option) == CURLOPT_CAINFO ||                                              \
+   (option) == CURLOPT_CAPATH ||                                              \
+   (option) == CURLOPT_COOKIE ||                                              \
+   (option) == CURLOPT_COOKIEFILE ||                                          \
+   (option) == CURLOPT_COOKIEJAR ||                                           \
+   (option) == CURLOPT_COOKIELIST ||                                          \
+   (option) == CURLOPT_CRLFILE ||                                             \
+   (option) == CURLOPT_CUSTOMREQUEST ||                                       \
+   (option) == CURLOPT_DEFAULT_PROTOCOL ||                                    \
+   (option) == CURLOPT_DNS_INTERFACE ||                                       \
+   (option) == CURLOPT_DNS_LOCAL_IP4 ||                                       \
+   (option) == CURLOPT_DNS_LOCAL_IP6 ||                                       \
+   (option) == CURLOPT_DNS_SERVERS ||                                         \
+   (option) == CURLOPT_DOH_URL ||                                             \
+   (option) == CURLOPT_EGDSOCKET ||                                           \
+   (option) == CURLOPT_FTP_ACCOUNT ||                                         \
+   (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER ||                             \
+   (option) == CURLOPT_FTPPORT ||                                             \
+   (option) == CURLOPT_HSTS ||                                                \
+   (option) == CURLOPT_HAPROXY_CLIENT_IP ||                                   \
+   (option) == CURLOPT_INTERFACE ||                                           \
+   (option) == CURLOPT_ISSUERCERT ||                                          \
+   (option) == CURLOPT_KEYPASSWD ||                                           \
+   (option) == CURLOPT_KRBLEVEL ||                                            \
+   (option) == CURLOPT_LOGIN_OPTIONS ||                                       \
+   (option) == CURLOPT_MAIL_AUTH ||                                           \
+   (option) == CURLOPT_MAIL_FROM ||                                           \
+   (option) == CURLOPT_NETRC_FILE ||                                          \
+   (option) == CURLOPT_NOPROXY ||                                             \
+   (option) == CURLOPT_PASSWORD ||                                            \
+   (option) == CURLOPT_PINNEDPUBLICKEY ||                                     \
+   (option) == CURLOPT_PRE_PROXY ||                                           \
+   (option) == CURLOPT_PROTOCOLS_STR ||                                       \
+   (option) == CURLOPT_PROXY ||                                               \
+   (option) == CURLOPT_PROXY_CAINFO ||                                        \
+   (option) == CURLOPT_PROXY_CAPATH ||                                        \
+   (option) == CURLOPT_PROXY_CRLFILE ||                                       \
+   (option) == CURLOPT_PROXY_ISSUERCERT ||                                    \
+   (option) == CURLOPT_PROXY_KEYPASSWD ||                                     \
+   (option) == CURLOPT_PROXY_PINNEDPUBLICKEY ||                               \
+   (option) == CURLOPT_PROXY_SERVICE_NAME ||                                  \
+   (option) == CURLOPT_PROXY_SSL_CIPHER_LIST ||                               \
+   (option) == CURLOPT_PROXY_SSLCERT ||                                       \
+   (option) == CURLOPT_PROXY_SSLCERTTYPE ||                                   \
+   (option) == CURLOPT_PROXY_SSLKEY ||                                        \
+   (option) == CURLOPT_PROXY_SSLKEYTYPE ||                                    \
+   (option) == CURLOPT_PROXY_TLS13_CIPHERS ||                                 \
+   (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD ||                              \
+   (option) == CURLOPT_PROXY_TLSAUTH_TYPE ||                                  \
+   (option) == CURLOPT_PROXY_TLSAUTH_USERNAME ||                              \
+   (option) == CURLOPT_PROXYPASSWORD ||                                       \
+   (option) == CURLOPT_PROXYUSERNAME ||                                       \
+   (option) == CURLOPT_PROXYUSERPWD ||                                        \
+   (option) == CURLOPT_RANDOM_FILE ||                                         \
+   (option) == CURLOPT_RANGE ||                                               \
+   (option) == CURLOPT_REDIR_PROTOCOLS_STR ||                                 \
+   (option) == CURLOPT_REFERER ||                                             \
+   (option) == CURLOPT_REQUEST_TARGET ||                                      \
+   (option) == CURLOPT_RTSP_SESSION_ID ||                                     \
+   (option) == CURLOPT_RTSP_STREAM_URI ||                                     \
+   (option) == CURLOPT_RTSP_TRANSPORT ||                                      \
+   (option) == CURLOPT_SASL_AUTHZID ||                                        \
+   (option) == CURLOPT_SERVICE_NAME ||                                        \
+   (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE ||                               \
+   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 ||                             \
+   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 ||                          \
+   (option) == CURLOPT_SSH_KNOWNHOSTS ||                                      \
+   (option) == CURLOPT_SSH_PRIVATE_KEYFILE ||                                 \
+   (option) == CURLOPT_SSH_PUBLIC_KEYFILE ||                                  \
+   (option) == CURLOPT_SSLCERT ||                                             \
+   (option) == CURLOPT_SSLCERTTYPE ||                                         \
+   (option) == CURLOPT_SSLENGINE ||                                           \
+   (option) == CURLOPT_SSLKEY ||                                              \
+   (option) == CURLOPT_SSLKEYTYPE ||                                          \
+   (option) == CURLOPT_SSL_CIPHER_LIST ||                                     \
+   (option) == CURLOPT_TLS13_CIPHERS ||                                       \
+   (option) == CURLOPT_TLSAUTH_PASSWORD ||                                    \
+   (option) == CURLOPT_TLSAUTH_TYPE ||                                        \
+   (option) == CURLOPT_TLSAUTH_USERNAME ||                                    \
+   (option) == CURLOPT_UNIX_SOCKET_PATH ||                                    \
+   (option) == CURLOPT_URL ||                                                 \
+   (option) == CURLOPT_USERAGENT ||                                           \
+   (option) == CURLOPT_USERNAME ||                                            \
+   (option) == CURLOPT_AWS_SIGV4 ||                                           \
+   (option) == CURLOPT_USERPWD ||                                             \
+   (option) == CURLOPT_XOAUTH2_BEARER ||                                      \
+   (option) == CURLOPT_SSL_EC_CURVES ||                                       \
+   0)
+
+/* evaluates to true if option takes a curl_write_callback argument */
+#define curlcheck_write_cb_option(option)                               \
+  ((option) == CURLOPT_HEADERFUNCTION ||                                \
+   (option) == CURLOPT_WRITEFUNCTION)
+
+/* evaluates to true if option takes a curl_conv_callback argument */
+#define curlcheck_conv_cb_option(option)                                \
+  ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION ||                      \
+   (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION ||                    \
+   (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION)
+
+/* evaluates to true if option takes a data argument to pass to a callback */
+#define curlcheck_cb_data_option(option)                                      \
+  ((option) == CURLOPT_CHUNK_DATA ||                                          \
+   (option) == CURLOPT_CLOSESOCKETDATA ||                                     \
+   (option) == CURLOPT_DEBUGDATA ||                                           \
+   (option) == CURLOPT_FNMATCH_DATA ||                                        \
+   (option) == CURLOPT_HEADERDATA ||                                          \
+   (option) == CURLOPT_HSTSREADDATA ||                                        \
+   (option) == CURLOPT_HSTSWRITEDATA ||                                       \
+   (option) == CURLOPT_INTERLEAVEDATA ||                                      \
+   (option) == CURLOPT_IOCTLDATA ||                                           \
+   (option) == CURLOPT_OPENSOCKETDATA ||                                      \
+   (option) == CURLOPT_PREREQDATA ||                                          \
+   (option) == CURLOPT_PROGRESSDATA ||                                        \
+   (option) == CURLOPT_READDATA ||                                            \
+   (option) == CURLOPT_SEEKDATA ||                                            \
+   (option) == CURLOPT_SOCKOPTDATA ||                                         \
+   (option) == CURLOPT_SSH_KEYDATA ||                                         \
+   (option) == CURLOPT_SSL_CTX_DATA ||                                        \
+   (option) == CURLOPT_WRITEDATA ||                                           \
+   (option) == CURLOPT_RESOLVER_START_DATA ||                                 \
+   (option) == CURLOPT_TRAILERDATA ||                                         \
+   (option) == CURLOPT_SSH_HOSTKEYDATA ||                                     \
+   0)
+
+/* evaluates to true if option takes a POST data argument (void* or char*) */
+#define curlcheck_postfields_option(option)                                   \
+  ((option) == CURLOPT_POSTFIELDS ||                                          \
+   (option) == CURLOPT_COPYPOSTFIELDS ||                                      \
+   0)
+
+/* evaluates to true if option takes a struct curl_slist * argument */
+#define curlcheck_slist_option(option)                                        \
+  ((option) == CURLOPT_HTTP200ALIASES ||                                      \
+   (option) == CURLOPT_HTTPHEADER ||                                          \
+   (option) == CURLOPT_MAIL_RCPT ||                                           \
+   (option) == CURLOPT_POSTQUOTE ||                                           \
+   (option) == CURLOPT_PREQUOTE ||                                            \
+   (option) == CURLOPT_PROXYHEADER ||                                         \
+   (option) == CURLOPT_QUOTE ||                                               \
+   (option) == CURLOPT_RESOLVE ||                                             \
+   (option) == CURLOPT_TELNETOPTIONS ||                                       \
+   (option) == CURLOPT_CONNECT_TO ||                                          \
+   0)
+
+/* groups of curl_easy_getinfo infos that take the same type of argument */
+
+/* evaluates to true if info expects a pointer to char * argument */
+#define curlcheck_string_info(info)                             \
+  (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG &&        \
+   (info) != CURLINFO_PRIVATE)
+
+/* evaluates to true if info expects a pointer to long argument */
+#define curlcheck_long_info(info)                       \
+  (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE)
+
+/* evaluates to true if info expects a pointer to double argument */
+#define curlcheck_double_info(info)                     \
+  (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST)
+
+/* true if info expects a pointer to struct curl_slist * argument */
+#define curlcheck_slist_info(info)                                      \
+  (((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST))
+
+/* true if info expects a pointer to struct curl_tlssessioninfo * argument */
+#define curlcheck_tlssessioninfo_info(info)                              \
+  (((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION))
+
+/* true if info expects a pointer to struct curl_certinfo * argument */
+#define curlcheck_certinfo_info(info) ((info) == CURLINFO_CERTINFO)
+
+/* true if info expects a pointer to struct curl_socket_t argument */
+#define curlcheck_socket_info(info)                     \
+  (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T)
+
+/* true if info expects a pointer to curl_off_t argument */
+#define curlcheck_off_t_info(info)              \
+  (CURLINFO_OFF_T < (info))
+
+
+/* typecheck helpers -- check whether given expression has requested type */
+
+/* For pointers, you can use the curlcheck_ptr/curlcheck_arr macros,
+ * otherwise define a new macro. Search for __builtin_types_compatible_p
+ * in the GCC manual.
+ * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is
+ * the actual expression passed to the curl_easy_setopt macro. This
+ * means that you can only apply the sizeof and __typeof__ operators, no
+ * == or whatsoever.
+ */
+
+/* XXX: should evaluate to true if expr is a pointer */
+#define curlcheck_any_ptr(expr)                 \
+  (sizeof(expr) == sizeof(void *))
+
+/* evaluates to true if expr is NULL */
+/* XXX: must not evaluate expr, so this check is not accurate */
+#define curlcheck_NULL(expr)                                            \
+  (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL)))
+
+/* evaluates to true if expr is type*, const type* or NULL */
+#define curlcheck_ptr(expr, type)                                       \
+  (curlcheck_NULL(expr) ||                                              \
+   __builtin_types_compatible_p(__typeof__(expr), type *) ||            \
+   __builtin_types_compatible_p(__typeof__(expr), const type *))
+
+/* evaluates to true if expr is one of type[], type*, NULL or const type* */
+#define curlcheck_arr(expr, type)                                       \
+  (curlcheck_ptr((expr), type) ||                                       \
+   __builtin_types_compatible_p(__typeof__(expr), type []))
+
+/* evaluates to true if expr is a string */
+#define curlcheck_string(expr)                                          \
+  (curlcheck_arr((expr), char) ||                                       \
+   curlcheck_arr((expr), signed char) ||                                \
+   curlcheck_arr((expr), unsigned char))
+
+/* evaluates to true if expr is a long (no matter the signedness)
+ * XXX: for now, int is also accepted (and therefore short and char, which
+ * are promoted to int when passed to a variadic function) */
+#define curlcheck_long(expr)                                                  \
+  (__builtin_types_compatible_p(__typeof__(expr), long) ||                    \
+   __builtin_types_compatible_p(__typeof__(expr), signed long) ||             \
+   __builtin_types_compatible_p(__typeof__(expr), unsigned long) ||           \
+   __builtin_types_compatible_p(__typeof__(expr), int) ||                     \
+   __builtin_types_compatible_p(__typeof__(expr), signed int) ||              \
+   __builtin_types_compatible_p(__typeof__(expr), unsigned int) ||            \
+   __builtin_types_compatible_p(__typeof__(expr), short) ||                   \
+   __builtin_types_compatible_p(__typeof__(expr), signed short) ||            \
+   __builtin_types_compatible_p(__typeof__(expr), unsigned short) ||          \
+   __builtin_types_compatible_p(__typeof__(expr), char) ||                    \
+   __builtin_types_compatible_p(__typeof__(expr), signed char) ||             \
+   __builtin_types_compatible_p(__typeof__(expr), unsigned char))
+
+/* evaluates to true if expr is of type curl_off_t */
+#define curlcheck_off_t(expr)                                   \
+  (__builtin_types_compatible_p(__typeof__(expr), curl_off_t))
+
+/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */
+/* XXX: also check size of an char[] array? */
+#define curlcheck_error_buffer(expr)                                    \
+  (curlcheck_NULL(expr) ||                                              \
+   __builtin_types_compatible_p(__typeof__(expr), char *) ||            \
+   __builtin_types_compatible_p(__typeof__(expr), char[]))
+
+/* evaluates to true if expr is of type (const) void* or (const) FILE* */
+#if 0
+#define curlcheck_cb_data(expr)                                         \
+  (curlcheck_ptr((expr), void) ||                                       \
+   curlcheck_ptr((expr), FILE))
+#else /* be less strict */
+#define curlcheck_cb_data(expr)                 \
+  curlcheck_any_ptr(expr)
+#endif
+
+/* evaluates to true if expr is of type FILE* */
+#define curlcheck_FILE(expr)                                            \
+  (curlcheck_NULL(expr) ||                                              \
+   (__builtin_types_compatible_p(__typeof__(expr), FILE *)))
+
+/* evaluates to true if expr can be passed as POST data (void* or char*) */
+#define curlcheck_postfields(expr)                                      \
+  (curlcheck_ptr((expr), void) ||                                       \
+   curlcheck_arr((expr), char) ||                                       \
+   curlcheck_arr((expr), unsigned char))
+
+/* helper: __builtin_types_compatible_p distinguishes between functions and
+ * function pointers, hide it */
+#define curlcheck_cb_compatible(func, type)                             \
+  (__builtin_types_compatible_p(__typeof__(func), type) ||              \
+   __builtin_types_compatible_p(__typeof__(func) *, type))
+
+/* evaluates to true if expr is of type curl_resolver_start_callback */
+#define curlcheck_resolver_start_callback(expr)       \
+  (curlcheck_NULL(expr) || \
+   curlcheck_cb_compatible((expr), curl_resolver_start_callback))
+
+/* evaluates to true if expr is of type curl_read_callback or "similar" */
+#define curlcheck_read_cb(expr)                                         \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), __typeof__(fread) *) ||              \
+   curlcheck_cb_compatible((expr), curl_read_callback) ||               \
+   curlcheck_cb_compatible((expr), _curl_read_callback1) ||             \
+   curlcheck_cb_compatible((expr), _curl_read_callback2) ||             \
+   curlcheck_cb_compatible((expr), _curl_read_callback3) ||             \
+   curlcheck_cb_compatible((expr), _curl_read_callback4) ||             \
+   curlcheck_cb_compatible((expr), _curl_read_callback5) ||             \
+   curlcheck_cb_compatible((expr), _curl_read_callback6))
+typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *);
+typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *);
+typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *);
+typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *);
+typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *);
+typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *);
+
+/* evaluates to true if expr is of type curl_write_callback or "similar" */
+#define curlcheck_write_cb(expr)                                        \
+  (curlcheck_read_cb(expr) ||                                           \
+   curlcheck_cb_compatible((expr), __typeof__(fwrite) *) ||             \
+   curlcheck_cb_compatible((expr), curl_write_callback) ||              \
+   curlcheck_cb_compatible((expr), _curl_write_callback1) ||            \
+   curlcheck_cb_compatible((expr), _curl_write_callback2) ||            \
+   curlcheck_cb_compatible((expr), _curl_write_callback3) ||            \
+   curlcheck_cb_compatible((expr), _curl_write_callback4) ||            \
+   curlcheck_cb_compatible((expr), _curl_write_callback5) ||            \
+   curlcheck_cb_compatible((expr), _curl_write_callback6))
+typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *);
+typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t,
+                                       const void *);
+typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *);
+typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *);
+typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t,
+                                       const void *);
+typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *);
+
+/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */
+#define curlcheck_ioctl_cb(expr)                                        \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_ioctl_callback) ||              \
+   curlcheck_cb_compatible((expr), _curl_ioctl_callback1) ||            \
+   curlcheck_cb_compatible((expr), _curl_ioctl_callback2) ||            \
+   curlcheck_cb_compatible((expr), _curl_ioctl_callback3) ||            \
+   curlcheck_cb_compatible((expr), _curl_ioctl_callback4))
+typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *);
+typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *);
+typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *);
+typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *);
+
+/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */
+#define curlcheck_sockopt_cb(expr)                                      \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_sockopt_callback) ||            \
+   curlcheck_cb_compatible((expr), _curl_sockopt_callback1) ||          \
+   curlcheck_cb_compatible((expr), _curl_sockopt_callback2))
+typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype);
+typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t,
+                                      curlsocktype);
+
+/* evaluates to true if expr is of type curl_opensocket_callback or
+   "similar" */
+#define curlcheck_opensocket_cb(expr)                                   \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_opensocket_callback) ||         \
+   curlcheck_cb_compatible((expr), _curl_opensocket_callback1) ||       \
+   curlcheck_cb_compatible((expr), _curl_opensocket_callback2) ||       \
+   curlcheck_cb_compatible((expr), _curl_opensocket_callback3) ||       \
+   curlcheck_cb_compatible((expr), _curl_opensocket_callback4))
+typedef curl_socket_t (*_curl_opensocket_callback1)
+  (void *, curlsocktype, struct curl_sockaddr *);
+typedef curl_socket_t (*_curl_opensocket_callback2)
+  (void *, curlsocktype, const struct curl_sockaddr *);
+typedef curl_socket_t (*_curl_opensocket_callback3)
+  (const void *, curlsocktype, struct curl_sockaddr *);
+typedef curl_socket_t (*_curl_opensocket_callback4)
+  (const void *, curlsocktype, const struct curl_sockaddr *);
+
+/* evaluates to true if expr is of type curl_progress_callback or "similar" */
+#define curlcheck_progress_cb(expr)                                     \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_progress_callback) ||           \
+   curlcheck_cb_compatible((expr), _curl_progress_callback1) ||         \
+   curlcheck_cb_compatible((expr), _curl_progress_callback2))
+typedef int (*_curl_progress_callback1)(void *,
+    double, double, double, double);
+typedef int (*_curl_progress_callback2)(const void *,
+    double, double, double, double);
+
+/* evaluates to true if expr is of type curl_debug_callback or "similar" */
+#define curlcheck_debug_cb(expr)                                        \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_debug_callback) ||              \
+   curlcheck_cb_compatible((expr), _curl_debug_callback1) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback2) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback3) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback4) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback5) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback6) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback7) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback8))
+typedef int (*_curl_debug_callback1) (CURL *,
+    curl_infotype, char *, size_t, void *);
+typedef int (*_curl_debug_callback2) (CURL *,
+    curl_infotype, char *, size_t, const void *);
+typedef int (*_curl_debug_callback3) (CURL *,
+    curl_infotype, const char *, size_t, void *);
+typedef int (*_curl_debug_callback4) (CURL *,
+    curl_infotype, const char *, size_t, const void *);
+typedef int (*_curl_debug_callback5) (CURL *,
+    curl_infotype, unsigned char *, size_t, void *);
+typedef int (*_curl_debug_callback6) (CURL *,
+    curl_infotype, unsigned char *, size_t, const void *);
+typedef int (*_curl_debug_callback7) (CURL *,
+    curl_infotype, const unsigned char *, size_t, void *);
+typedef int (*_curl_debug_callback8) (CURL *,
+    curl_infotype, const unsigned char *, size_t, const void *);
+
+/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */
+/* this is getting even messier... */
+#define curlcheck_ssl_ctx_cb(expr)                                      \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_ssl_ctx_callback) ||            \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback1) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback2) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback3) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback4) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback5) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback6) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback7) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback8))
+typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *);
+typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *,
+                                            const void *);
+#ifdef HEADER_SSL_H
+/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
+ * this will of course break if we're included before OpenSSL headers...
+ */
+typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *);
+typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX *, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX *,
+                                            const void *);
+#else
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8;
+#endif
+
+/* evaluates to true if expr is of type curl_conv_callback or "similar" */
+#define curlcheck_conv_cb(expr)                                         \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_conv_callback) ||               \
+   curlcheck_cb_compatible((expr), _curl_conv_callback1) ||             \
+   curlcheck_cb_compatible((expr), _curl_conv_callback2) ||             \
+   curlcheck_cb_compatible((expr), _curl_conv_callback3) ||             \
+   curlcheck_cb_compatible((expr), _curl_conv_callback4))
+typedef CURLcode (*_curl_conv_callback1)(char *, size_t length);
+typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length);
+typedef CURLcode (*_curl_conv_callback3)(void *, size_t length);
+typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length);
+
+/* evaluates to true if expr is of type curl_seek_callback or "similar" */
+#define curlcheck_seek_cb(expr)                                         \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_seek_callback) ||               \
+   curlcheck_cb_compatible((expr), _curl_seek_callback1) ||             \
+   curlcheck_cb_compatible((expr), _curl_seek_callback2))
+typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int);
+typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int);
+
+
+#endif /* CURLINC_TYPECHECK_GCC_H */
Index: trunk/src/libs/curl-8.7.1/include/curl/urlapi.h
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/urlapi.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/urlapi.h	(revision 104083)
@@ -0,0 +1,151 @@
+#ifndef CURLINC_URLAPI_H
+#define CURLINC_URLAPI_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* the error codes for the URL API */
+typedef enum {
+  CURLUE_OK,
+  CURLUE_BAD_HANDLE,          /* 1 */
+  CURLUE_BAD_PARTPOINTER,     /* 2 */
+  CURLUE_MALFORMED_INPUT,     /* 3 */
+  CURLUE_BAD_PORT_NUMBER,     /* 4 */
+  CURLUE_UNSUPPORTED_SCHEME,  /* 5 */
+  CURLUE_URLDECODE,           /* 6 */
+  CURLUE_OUT_OF_MEMORY,       /* 7 */
+  CURLUE_USER_NOT_ALLOWED,    /* 8 */
+  CURLUE_UNKNOWN_PART,        /* 9 */
+  CURLUE_NO_SCHEME,           /* 10 */
+  CURLUE_NO_USER,             /* 11 */
+  CURLUE_NO_PASSWORD,         /* 12 */
+  CURLUE_NO_OPTIONS,          /* 13 */
+  CURLUE_NO_HOST,             /* 14 */
+  CURLUE_NO_PORT,             /* 15 */
+  CURLUE_NO_QUERY,            /* 16 */
+  CURLUE_NO_FRAGMENT,         /* 17 */
+  CURLUE_NO_ZONEID,           /* 18 */
+  CURLUE_BAD_FILE_URL,        /* 19 */
+  CURLUE_BAD_FRAGMENT,        /* 20 */
+  CURLUE_BAD_HOSTNAME,        /* 21 */
+  CURLUE_BAD_IPV6,            /* 22 */
+  CURLUE_BAD_LOGIN,           /* 23 */
+  CURLUE_BAD_PASSWORD,        /* 24 */
+  CURLUE_BAD_PATH,            /* 25 */
+  CURLUE_BAD_QUERY,           /* 26 */
+  CURLUE_BAD_SCHEME,          /* 27 */
+  CURLUE_BAD_SLASHES,         /* 28 */
+  CURLUE_BAD_USER,            /* 29 */
+  CURLUE_LACKS_IDN,           /* 30 */
+  CURLUE_TOO_LARGE,           /* 31 */
+  CURLUE_LAST
+} CURLUcode;
+
+typedef enum {
+  CURLUPART_URL,
+  CURLUPART_SCHEME,
+  CURLUPART_USER,
+  CURLUPART_PASSWORD,
+  CURLUPART_OPTIONS,
+  CURLUPART_HOST,
+  CURLUPART_PORT,
+  CURLUPART_PATH,
+  CURLUPART_QUERY,
+  CURLUPART_FRAGMENT,
+  CURLUPART_ZONEID /* added in 7.65.0 */
+} CURLUPart;
+
+#define CURLU_DEFAULT_PORT (1<<0)       /* return default port number */
+#define CURLU_NO_DEFAULT_PORT (1<<1)    /* act as if no port number was set,
+                                           if the port number matches the
+                                           default for the scheme */
+#define CURLU_DEFAULT_SCHEME (1<<2)     /* return default scheme if
+                                           missing */
+#define CURLU_NON_SUPPORT_SCHEME (1<<3) /* allow non-supported scheme */
+#define CURLU_PATH_AS_IS (1<<4)         /* leave dot sequences */
+#define CURLU_DISALLOW_USER (1<<5)      /* no user+password allowed */
+#define CURLU_URLDECODE (1<<6)          /* URL decode on get */
+#define CURLU_URLENCODE (1<<7)          /* URL encode on set */
+#define CURLU_APPENDQUERY (1<<8)        /* append a form style part */
+#define CURLU_GUESS_SCHEME (1<<9)       /* legacy curl-style guessing */
+#define CURLU_NO_AUTHORITY (1<<10)      /* Allow empty authority when the
+                                           scheme is unknown. */
+#define CURLU_ALLOW_SPACE (1<<11)       /* Allow spaces in the URL */
+#define CURLU_PUNYCODE (1<<12)          /* get the host name in punycode */
+#define CURLU_PUNY2IDN (1<<13)          /* punycode => IDN conversion */
+
+typedef struct Curl_URL CURLU;
+
+/*
+ * curl_url() creates a new CURLU handle and returns a pointer to it.
+ * Must be freed with curl_url_cleanup().
+ */
+CURL_EXTERN CURLU *curl_url(void);
+
+/*
+ * curl_url_cleanup() frees the CURLU handle and related resources used for
+ * the URL parsing. It will not free strings previously returned with the URL
+ * API.
+ */
+CURL_EXTERN void curl_url_cleanup(CURLU *handle);
+
+/*
+ * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new
+ * handle must also be freed with curl_url_cleanup().
+ */
+CURL_EXTERN CURLU *curl_url_dup(const CURLU *in);
+
+/*
+ * curl_url_get() extracts a specific part of the URL from a CURLU
+ * handle. Returns error code. The returned pointer MUST be freed with
+ * curl_free() afterwards.
+ */
+CURL_EXTERN CURLUcode curl_url_get(const CURLU *handle, CURLUPart what,
+                                   char **part, unsigned int flags);
+
+/*
+ * curl_url_set() sets a specific part of the URL in a CURLU handle. Returns
+ * error code. The passed in string will be copied. Passing a NULL instead of
+ * a part string, clears that part.
+ */
+CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
+                                   const char *part, unsigned int flags);
+
+/*
+ * curl_url_strerror() turns a CURLUcode value into the equivalent human
+ * readable error string.  This is useful for printing meaningful error
+ * messages.
+ */
+CURL_EXTERN const char *curl_url_strerror(CURLUcode);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif /* CURLINC_URLAPI_H */
Index: trunk/src/libs/curl-8.7.1/include/curl/websockets.h
===================================================================
--- trunk/src/libs/curl-8.7.1/include/curl/websockets.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/include/curl/websockets.h	(revision 104083)
@@ -0,0 +1,84 @@
+#ifndef CURLINC_WEBSOCKETS_H
+#define CURLINC_WEBSOCKETS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct curl_ws_frame {
+  int age;              /* zero */
+  int flags;            /* See the CURLWS_* defines */
+  curl_off_t offset;    /* the offset of this data into the frame */
+  curl_off_t bytesleft; /* number of pending bytes left of the payload */
+  size_t len;           /* size of the current data chunk */
+};
+
+/* flag bits */
+#define CURLWS_TEXT       (1<<0)
+#define CURLWS_BINARY     (1<<1)
+#define CURLWS_CONT       (1<<2)
+#define CURLWS_CLOSE      (1<<3)
+#define CURLWS_PING       (1<<4)
+#define CURLWS_OFFSET     (1<<5)
+
+/*
+ * NAME curl_ws_recv()
+ *
+ * DESCRIPTION
+ *
+ * Receives data from the websocket connection. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
+                                  size_t *recv,
+                                  const struct curl_ws_frame **metap);
+
+/* flags for curl_ws_send() */
+#define CURLWS_PONG       (1<<6)
+
+/*
+ * NAME curl_ws_send()
+ *
+ * DESCRIPTION
+ *
+ * Sends data over the websocket connection. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer,
+                                  size_t buflen, size_t *sent,
+                                  curl_off_t fragsize,
+                                  unsigned int flags);
+
+/* bits for the CURLOPT_WS_OPTIONS bitmask: */
+#define CURLWS_RAW_MODE (1<<0)
+
+CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *curl);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* CURLINC_WEBSOCKETS_H */
Index: trunk/src/libs/curl-8.7.1/lib/.checksrc
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/.checksrc	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/.checksrc	(revision 104083)
@@ -0,0 +1,1 @@
+enable STRERROR
Index: trunk/src/libs/curl-8.7.1/lib/CMakeLists.txt
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/CMakeLists.txt	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/CMakeLists.txt	(revision 104083)
@@ -0,0 +1,240 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+set(LIB_NAME libcurl)
+set(LIBCURL_OUTPUT_NAME libcurl CACHE STRING "Basename of the curl library")
+add_definitions(-DBUILDING_LIBCURL)
+
+configure_file(curl_config.h.cmake
+  ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
+
+transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
+include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)
+
+list(APPEND HHEADERS
+  ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h
+  )
+
+# The rest of the build
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../include)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include)
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/..)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+if(USE_ARES)
+  include_directories(${CARES_INCLUDE_DIR})
+endif()
+
+if(BUILD_TESTING)
+  add_library(
+    curlu # special libcurlu library just for unittests
+    STATIC
+    EXCLUDE_FROM_ALL
+    ${HHEADERS} ${CSOURCES}
+  )
+  target_compile_definitions(curlu PUBLIC UNITTESTS CURL_STATICLIB)
+endif()
+
+if(ENABLE_CURLDEBUG)
+  # We must compile these sources separately to avoid memdebug.h redefinitions
+  # applying to them.
+  set_source_files_properties(memdebug.c curl_multibyte.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
+endif()
+
+if(BUILD_TESTING)
+  target_link_libraries(curlu PRIVATE ${CURL_LIBS})
+endif()
+
+transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
+include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake)
+
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
+  CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+  CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR
+  CMAKE_SYSTEM_NAME STREQUAL "SunOS" OR
+  CMAKE_SYSTEM_NAME STREQUAL "GNU/kFreeBSD" OR
+
+  # FreeBSD comes with the a.out and elf flavours
+  # but a.out was supported up to version 3.x and
+  # elf from 3.x. I cannot imagine someone running
+  # CMake on those ancient systems
+  CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
+
+  CMAKE_SYSTEM_NAME STREQUAL "Haiku")
+
+  math(EXPR CMAKESONAME "${VERSIONCHANGE} - ${VERSIONDEL}")
+  set(CMAKEVERSION "${CMAKESONAME}.${VERSIONDEL}.${VERSIONADD}")
+else()
+  unset(CMAKESONAME)
+endif()
+
+## Library definition
+
+# Add "_imp" as a suffix before the extension to avoid conflicting with
+# the statically linked "libcurl.lib" (typically with MSVC)
+if(WIN32 AND
+   NOT IMPORT_LIB_SUFFIX AND
+   CMAKE_STATIC_LIBRARY_SUFFIX STREQUAL CMAKE_IMPORT_LIBRARY_SUFFIX)
+  set(IMPORT_LIB_SUFFIX "_imp")
+endif()
+
+# Whether to do a single compilation pass for libcurl sources and reuse these
+# objects to generate both static and shared target.
+if(NOT DEFINED SHARE_LIB_OBJECT)
+  # Enable it by default on platforms where PIC is the default for both shared
+  # and static and there is a way to tell the linker which libcurl symbols it
+  # should export (vs. marking these symbols exportable at compile-time).
+  if(WIN32)
+    set(SHARE_LIB_OBJECT ON)
+  else()
+    # On other platforms, make it an option disabled by default
+    set(SHARE_LIB_OBJECT OFF)
+  endif()
+endif()
+
+if(WIN32)
+  # Define CURL_STATICLIB always, to disable __declspec(dllexport) for exported
+  # libcurl symbols. We handle exports via libcurl.def instead. Except with
+  # symbol hiding disabled or debug mode enabled, when we export _all_ symbols
+  # from libcurl DLL, without using libcurl.def.
+  add_definitions("-DCURL_STATICLIB")
+endif()
+
+if(SHARE_LIB_OBJECT)
+  set(LIB_OBJECT "libcurl_object")
+  add_library(${LIB_OBJECT} OBJECT ${HHEADERS} ${CSOURCES})
+  target_link_libraries(${LIB_OBJECT} PRIVATE ${CURL_LIBS})
+  set_target_properties(${LIB_OBJECT} PROPERTIES
+    POSITION_INDEPENDENT_CODE ON)
+  if(HIDES_CURL_PRIVATE_SYMBOLS)
+    set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
+    set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
+  endif()
+  if(CURL_HAS_LTO)
+    set_target_properties(${LIB_OBJECT} PROPERTIES
+      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
+      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+  endif()
+
+  target_include_directories(${LIB_OBJECT} INTERFACE
+    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+
+  set(LIB_SOURCE $<TARGET_OBJECTS:${LIB_OBJECT}>)
+else()
+  set(LIB_SOURCE ${HHEADERS} ${CSOURCES})
+endif()
+
+# we want it to be called libcurl on all platforms
+if(BUILD_STATIC_LIBS)
+  list(APPEND libcurl_export ${LIB_STATIC})
+  add_library(${LIB_STATIC} STATIC ${LIB_SOURCE})
+  add_library(${PROJECT_NAME}::${LIB_STATIC} ALIAS ${LIB_STATIC})
+  target_link_libraries(${LIB_STATIC} PRIVATE ${CURL_LIBS})
+  # Remove the "lib" prefix since the library is already named "libcurl".
+  set_target_properties(${LIB_STATIC} PROPERTIES
+    PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
+    SUFFIX "${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}"
+    INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB")
+  if(HIDES_CURL_PRIVATE_SYMBOLS)
+    set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
+    set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
+  endif()
+  if(CURL_HAS_LTO)
+    set_target_properties(${LIB_STATIC} PROPERTIES
+      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
+      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+  endif()
+  if(CMAKEVERSION AND CMAKESONAME)
+    set_target_properties(${LIB_STATIC} PROPERTIES
+      VERSION ${CMAKEVERSION} SOVERSION ${CMAKESONAME})
+  endif()
+
+  target_include_directories(${LIB_STATIC} INTERFACE
+    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+endif()
+
+if(BUILD_SHARED_LIBS)
+  list(APPEND libcurl_export ${LIB_SHARED})
+  add_library(${LIB_SHARED} SHARED ${LIB_SOURCE})
+  add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
+  if(WIN32)
+    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)
+    if(HIDES_CURL_PRIVATE_SYMBOLS)
+      set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${CURL_SOURCE_DIR}/libcurl.def")
+    endif()
+  endif()
+  target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_LIBS})
+  # Remove the "lib" prefix since the library is already named "libcurl".
+  set_target_properties(${LIB_SHARED} PROPERTIES
+    PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
+    IMPORT_PREFIX "" IMPORT_SUFFIX "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}"
+    POSITION_INDEPENDENT_CODE ON)
+  if(HIDES_CURL_PRIVATE_SYMBOLS)
+    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
+    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
+  endif()
+  if(CURL_HAS_LTO)
+    set_target_properties(${LIB_SHARED} PROPERTIES
+      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
+      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+  endif()
+  if(CMAKEVERSION AND CMAKESONAME)
+    set_target_properties(${LIB_SHARED} PROPERTIES
+      VERSION ${CMAKEVERSION} SOVERSION ${CMAKESONAME})
+  endif()
+
+  target_include_directories(${LIB_SHARED} INTERFACE
+    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+endif()
+
+add_library(${LIB_NAME} ALIAS ${LIB_SELECTED})
+add_library(${PROJECT_NAME}::${LIB_NAME} ALIAS ${LIB_SELECTED})
+
+if(CURL_ENABLE_EXPORT_TARGET)
+  if(BUILD_STATIC_LIBS)
+    install(TARGETS ${LIB_STATIC}
+      EXPORT ${TARGETS_EXPORT_NAME}
+      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    )
+  endif()
+  if(BUILD_SHARED_LIBS)
+    install(TARGETS ${LIB_SHARED}
+      EXPORT ${TARGETS_EXPORT_NAME}
+      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    )
+  endif()
+
+  export(TARGETS ${libcurl_export}
+         FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake
+         NAMESPACE ${PROJECT_NAME}::
+  )
+endif()
Index: trunk/src/libs/curl-8.7.1/lib/Makefile.am
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/Makefile.am	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/Makefile.am	(revision 104083)
@@ -0,0 +1,149 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+AUTOMAKE_OPTIONS = foreign nostdinc
+
+CMAKE_DIST = CMakeLists.txt curl_config.h.cmake
+
+EXTRA_DIST = Makefile.mk config-win32.h config-win32ce.h config-plan9.h    \
+ config-riscos.h config-mac.h curl_config.h.in config-dos.h                \
+ libcurl.plist libcurl.rc config-amigaos.h config-win32ce.h                \
+ config-os400.h setup-os400.h $(CMAKE_DIST) setup-win32.h .checksrc \
+ Makefile.soname
+
+lib_LTLIBRARIES = libcurl.la
+
+if BUILD_UNITTESTS
+noinst_LTLIBRARIES = libcurlu.la
+else
+noinst_LTLIBRARIES =
+endif
+
+# This might hold -Werror
+CFLAGS += @CURL_CFLAG_EXTRAS@
+
+# Specify our include paths here, and do it relative to $(top_srcdir) and
+# $(top_builddir), to ensure that these paths which belong to the library
+# being currently built and tested are searched before the library which
+# might possibly already be installed in the system.
+#
+# $(top_srcdir)/include is for libcurl's external include files
+# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file
+# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "private" files
+
+AM_CPPFLAGS = -I$(top_srcdir)/include        \
+              -I$(top_builddir)/lib          \
+              -I$(top_srcdir)/lib
+
+# Prevent LIBS from being used for all link targets
+LIBS = $(BLANK_AT_MAKETIME)
+
+include Makefile.soname
+
+AM_CPPFLAGS += -DBUILDING_LIBCURL
+AM_LDFLAGS =
+AM_CFLAGS =
+
+# Makefile.inc provides the CSOURCES and HHEADERS defines
+include Makefile.inc
+
+libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS)
+libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS)
+
+libcurl_la_CPPFLAGS_EXTRA =
+libcurl_la_LDFLAGS_EXTRA =
+libcurl_la_CFLAGS_EXTRA =
+
+if CURL_LT_SHLIB_USE_VERSION_INFO
+libcurl_la_LDFLAGS_EXTRA += $(VERSIONINFO)
+endif
+
+if CURL_LT_SHLIB_USE_NO_UNDEFINED
+libcurl_la_LDFLAGS_EXTRA += -no-undefined
+endif
+
+if CURL_LT_SHLIB_USE_MIMPURE_TEXT
+libcurl_la_LDFLAGS_EXTRA += -mimpure-text
+endif
+
+if CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS
+libcurl_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers
+else
+# if symbol-hiding is enabled, hide them!
+if DOING_CURL_SYMBOL_HIDING
+libcurl_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*'
+endif
+endif
+
+if USE_CPPFLAG_CURL_STATICLIB
+libcurl_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB
+else
+if HAVE_WINDRES
+libcurl_la_SOURCES += $(LIB_RCFILES)
+$(LIB_RCFILES): $(top_srcdir)/include/curl/curlver.h
+endif
+endif
+
+if DOING_CURL_SYMBOL_HIDING
+libcurl_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS
+libcurl_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING)
+endif
+
+libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA)
+libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(CURL_LDFLAGS_LIB) $(LIBCURL_LIBS)
+libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA)
+
+libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS
+libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS)
+libcurlu_la_CFLAGS = $(AM_CFLAGS)
+
+CHECKSRC = $(CS_$(V))
+CS_0 = @echo "  RUN     " $@;
+CS_1 =
+CS_ = $(CS_0)
+
+checksrc:
+	$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir)    \
+	-W$(srcdir)/curl_config.h $(srcdir)/*.[ch] $(srcdir)/vauth/*.[ch]   \
+	$(srcdir)/vtls/*.[ch] $(srcdir)/vquic/*.[ch] $(srcdir)/vssh/*.[ch])
+
+if CURLDEBUG
+# for debug builds, we scan the sources on all regular make invokes
+all-local: checksrc
+endif
+
+# disable the tests that are mostly causing false positives
+TIDYFLAGS=-checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference -quiet
+
+TIDY:=clang-tidy
+
+tidy:
+	$(TIDY) $(CSOURCES) $(TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H
+
+optiontable:
+	perl optiontable.pl < $(top_srcdir)/include/curl/curl.h > easyoptions.c
+
+if HAVE_WINDRES
+.rc.lo:
+	$(LIBTOOL) --tag=RC --mode=compile $(RC) -I$(top_srcdir)/include $(RCFLAGS) -i $< -o $@
+endif
Index: trunk/src/libs/curl-8.7.1/lib/Makefile.in
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/Makefile.in	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/Makefile.in	(revision 104083)
@@ -0,0 +1,5497 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@CURL_LT_SHLIB_USE_VERSION_INFO_TRUE@am__append_1 = $(VERSIONINFO)
+@CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE@am__append_2 = -no-undefined
+@CURL_LT_SHLIB_USE_MIMPURE_TEXT_TRUE@am__append_3 = -mimpure-text
+@CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_TRUE@am__append_4 = -Wl,--version-script=libcurl.vers
+# if symbol-hiding is enabled, hide them!
+@CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_FALSE@@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_5 = -export-symbols-regex '^curl_.*'
+@USE_CPPFLAG_CURL_STATICLIB_TRUE@am__append_6 = -DCURL_STATICLIB
+@HAVE_WINDRES_TRUE@@USE_CPPFLAG_CURL_STATICLIB_FALSE@am__append_7 = $(LIB_RCFILES)
+@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_8 = -DCURL_HIDDEN_SYMBOLS
+@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_9 = $(CFLAG_CURL_SYMBOL_HIDING)
+subdir = lib
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \
+	$(top_srcdir)/m4/curl-bearssl.m4 \
+	$(top_srcdir)/m4/curl-compilers.m4 \
+	$(top_srcdir)/m4/curl-confopts.m4 \
+	$(top_srcdir)/m4/curl-functions.m4 \
+	$(top_srcdir)/m4/curl-gnutls.m4 \
+	$(top_srcdir)/m4/curl-mbedtls.m4 \
+	$(top_srcdir)/m4/curl-openssl.m4 \
+	$(top_srcdir)/m4/curl-override.m4 \
+	$(top_srcdir)/m4/curl-reentrant.m4 \
+	$(top_srcdir)/m4/curl-rustls.m4 \
+	$(top_srcdir)/m4/curl-schannel.m4 \
+	$(top_srcdir)/m4/curl-sectransp.m4 \
+	$(top_srcdir)/m4/curl-sysconfig.m4 \
+	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/m4/xc-am-iface.m4 \
+	$(top_srcdir)/m4/xc-cc-check.m4 \
+	$(top_srcdir)/m4/xc-lt-iface.m4 \
+	$(top_srcdir)/m4/xc-translit.m4 \
+	$(top_srcdir)/m4/xc-val-flgs.m4 \
+	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
+	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
+	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = curl_config.h
+CONFIG_CLEAN_FILES = libcurl.vers libcurl.plist
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(libdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
+libcurl_la_LIBADD =
+am__libcurl_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \
+	asyn-thread.c base64.c bufq.c bufref.c c-hyper.c cf-h1-proxy.c \
+	cf-h2-proxy.c cf-haproxy.c cf-https-connect.c cf-socket.c \
+	cfilters.c conncache.c connect.c content_encoding.c cookie.c \
+	curl_addrinfo.c curl_des.c curl_endian.c curl_fnmatch.c \
+	curl_get_line.c curl_gethostname.c curl_gssapi.c \
+	curl_memrchr.c curl_multibyte.c curl_ntlm_core.c \
+	curl_ntlm_wb.c curl_path.c curl_range.c curl_rtmp.c \
+	curl_sasl.c curl_sha512_256.c curl_sspi.c curl_threads.c \
+	curl_trc.c cw-out.c dict.c doh.c dynbuf.c dynhds.c easy.c \
+	easygetopt.c easyoptions.c escape.c file.c fileinfo.c fopen.c \
+	formdata.c ftp.c ftplistparser.c getenv.c getinfo.c gopher.c \
+	hash.c headers.c hmac.c hostasyn.c hostip.c hostip4.c \
+	hostip6.c hostsyn.c hsts.c http.c http1.c http2.c \
+	http_aws_sigv4.c http_chunks.c http_digest.c http_negotiate.c \
+	http_ntlm.c http_proxy.c idn.c if2ip.c imap.c inet_ntop.c \
+	inet_pton.c krb5.c ldap.c llist.c macos.c md4.c md5.c \
+	memdebug.c mime.c mprintf.c mqtt.c multi.c netrc.c nonblock.c \
+	noproxy.c openldap.c parsedate.c pingpong.c pop3.c progress.c \
+	psl.c rand.c rename.c request.c rtsp.c select.c sendf.c \
+	setopt.c sha256.c share.c slist.c smb.c smtp.c socketpair.c \
+	socks.c socks_gssapi.c socks_sspi.c speedcheck.c splay.c \
+	strcase.c strdup.c strerror.c strtok.c strtoofft.c \
+	system_win32.c telnet.c tftp.c timediff.c timeval.c transfer.c \
+	url.c urlapi.c version.c version_win32.c warnless.c ws.c \
+	vauth/cleartext.c vauth/cram.c vauth/digest.c \
+	vauth/digest_sspi.c vauth/gsasl.c vauth/krb5_gssapi.c \
+	vauth/krb5_sspi.c vauth/ntlm.c vauth/ntlm_sspi.c \
+	vauth/oauth2.c vauth/spnego_gssapi.c vauth/spnego_sspi.c \
+	vauth/vauth.c vtls/bearssl.c vtls/gtls.c vtls/hostcheck.c \
+	vtls/keylog.c vtls/mbedtls.c vtls/mbedtls_threadlock.c \
+	vtls/openssl.c vtls/rustls.c vtls/schannel.c \
+	vtls/schannel_verify.c vtls/sectransp.c vtls/vtls.c \
+	vtls/wolfssl.c vtls/x509asn1.c vquic/curl_msh3.c \
+	vquic/curl_ngtcp2.c vquic/curl_osslq.c vquic/curl_quiche.c \
+	vquic/vquic.c vquic/vquic-tls.c vssh/libssh.c vssh/libssh2.c \
+	vssh/wolfssh.c altsvc.h amigaos.h arpa_telnet.h asyn.h bufq.h \
+	bufref.h c-hyper.h cf-h1-proxy.h cf-h2-proxy.h cf-haproxy.h \
+	cf-https-connect.h cf-socket.h cfilters.h conncache.h \
+	connect.h content_encoding.h cookie.h curl_addrinfo.h \
+	curl_base64.h curl_ctype.h curl_des.h curl_endian.h \
+	curl_fnmatch.h curl_get_line.h curl_gethostname.h \
+	curl_gssapi.h curl_hmac.h curl_krb5.h curl_ldap.h curl_md4.h \
+	curl_md5.h curl_memory.h curl_memrchr.h curl_multibyte.h \
+	curl_ntlm_core.h curl_ntlm_wb.h curl_path.h curl_printf.h \
+	curl_range.h curl_rtmp.h curl_sasl.h curl_setup.h \
+	curl_setup_once.h curl_sha256.h curl_sha512_256.h curl_sspi.h \
+	curl_threads.h curl_trc.h curlx.h cw-out.h dict.h doh.h \
+	dynbuf.h dynhds.h easy_lock.h easyif.h easyoptions.h escape.h \
+	file.h fileinfo.h fopen.h formdata.h ftp.h ftplistparser.h \
+	functypes.h getinfo.h gopher.h hash.h headers.h hostip.h \
+	hsts.h http.h http1.h http2.h http_aws_sigv4.h http_chunks.h \
+	http_digest.h http_negotiate.h http_ntlm.h http_proxy.h idn.h \
+	if2ip.h imap.h inet_ntop.h inet_pton.h llist.h macos.h \
+	memdebug.h mime.h mqtt.h multihandle.h multiif.h netrc.h \
+	nonblock.h noproxy.h parsedate.h pingpong.h pop3.h progress.h \
+	psl.h rand.h rename.h request.h rtsp.h select.h sendf.h \
+	setopt.h setup-vms.h share.h sigpipe.h slist.h smb.h smtp.h \
+	sockaddr.h socketpair.h socks.h speedcheck.h splay.h strcase.h \
+	strdup.h strerror.h strtok.h strtoofft.h system_win32.h \
+	telnet.h tftp.h timediff.h timeval.h transfer.h url.h \
+	urlapi-int.h urldata.h version_win32.h warnless.h ws.h \
+	vauth/digest.h vauth/ntlm.h vauth/vauth.h vtls/bearssl.h \
+	vtls/gtls.h vtls/hostcheck.h vtls/keylog.h vtls/mbedtls.h \
+	vtls/mbedtls_threadlock.h vtls/openssl.h vtls/rustls.h \
+	vtls/schannel.h vtls/schannel_int.h vtls/sectransp.h \
+	vtls/vtls.h vtls/vtls_int.h vtls/wolfssl.h vtls/x509asn1.h \
+	vquic/curl_msh3.h vquic/curl_ngtcp2.h vquic/curl_osslq.h \
+	vquic/curl_quiche.h vquic/vquic.h vquic/vquic_int.h \
+	vquic/vquic-tls.h vssh/ssh.h libcurl.rc
+am__objects_1 = libcurl_la-altsvc.lo libcurl_la-amigaos.lo \
+	libcurl_la-asyn-ares.lo libcurl_la-asyn-thread.lo \
+	libcurl_la-base64.lo libcurl_la-bufq.lo libcurl_la-bufref.lo \
+	libcurl_la-c-hyper.lo libcurl_la-cf-h1-proxy.lo \
+	libcurl_la-cf-h2-proxy.lo libcurl_la-cf-haproxy.lo \
+	libcurl_la-cf-https-connect.lo libcurl_la-cf-socket.lo \
+	libcurl_la-cfilters.lo libcurl_la-conncache.lo \
+	libcurl_la-connect.lo libcurl_la-content_encoding.lo \
+	libcurl_la-cookie.lo libcurl_la-curl_addrinfo.lo \
+	libcurl_la-curl_des.lo libcurl_la-curl_endian.lo \
+	libcurl_la-curl_fnmatch.lo libcurl_la-curl_get_line.lo \
+	libcurl_la-curl_gethostname.lo libcurl_la-curl_gssapi.lo \
+	libcurl_la-curl_memrchr.lo libcurl_la-curl_multibyte.lo \
+	libcurl_la-curl_ntlm_core.lo libcurl_la-curl_ntlm_wb.lo \
+	libcurl_la-curl_path.lo libcurl_la-curl_range.lo \
+	libcurl_la-curl_rtmp.lo libcurl_la-curl_sasl.lo \
+	libcurl_la-curl_sha512_256.lo libcurl_la-curl_sspi.lo \
+	libcurl_la-curl_threads.lo libcurl_la-curl_trc.lo \
+	libcurl_la-cw-out.lo libcurl_la-dict.lo libcurl_la-doh.lo \
+	libcurl_la-dynbuf.lo libcurl_la-dynhds.lo libcurl_la-easy.lo \
+	libcurl_la-easygetopt.lo libcurl_la-easyoptions.lo \
+	libcurl_la-escape.lo libcurl_la-file.lo libcurl_la-fileinfo.lo \
+	libcurl_la-fopen.lo libcurl_la-formdata.lo libcurl_la-ftp.lo \
+	libcurl_la-ftplistparser.lo libcurl_la-getenv.lo \
+	libcurl_la-getinfo.lo libcurl_la-gopher.lo libcurl_la-hash.lo \
+	libcurl_la-headers.lo libcurl_la-hmac.lo \
+	libcurl_la-hostasyn.lo libcurl_la-hostip.lo \
+	libcurl_la-hostip4.lo libcurl_la-hostip6.lo \
+	libcurl_la-hostsyn.lo libcurl_la-hsts.lo libcurl_la-http.lo \
+	libcurl_la-http1.lo libcurl_la-http2.lo \
+	libcurl_la-http_aws_sigv4.lo libcurl_la-http_chunks.lo \
+	libcurl_la-http_digest.lo libcurl_la-http_negotiate.lo \
+	libcurl_la-http_ntlm.lo libcurl_la-http_proxy.lo \
+	libcurl_la-idn.lo libcurl_la-if2ip.lo libcurl_la-imap.lo \
+	libcurl_la-inet_ntop.lo libcurl_la-inet_pton.lo \
+	libcurl_la-krb5.lo libcurl_la-ldap.lo libcurl_la-llist.lo \
+	libcurl_la-macos.lo libcurl_la-md4.lo libcurl_la-md5.lo \
+	libcurl_la-memdebug.lo libcurl_la-mime.lo \
+	libcurl_la-mprintf.lo libcurl_la-mqtt.lo libcurl_la-multi.lo \
+	libcurl_la-netrc.lo libcurl_la-nonblock.lo \
+	libcurl_la-noproxy.lo libcurl_la-openldap.lo \
+	libcurl_la-parsedate.lo libcurl_la-pingpong.lo \
+	libcurl_la-pop3.lo libcurl_la-progress.lo libcurl_la-psl.lo \
+	libcurl_la-rand.lo libcurl_la-rename.lo libcurl_la-request.lo \
+	libcurl_la-rtsp.lo libcurl_la-select.lo libcurl_la-sendf.lo \
+	libcurl_la-setopt.lo libcurl_la-sha256.lo libcurl_la-share.lo \
+	libcurl_la-slist.lo libcurl_la-smb.lo libcurl_la-smtp.lo \
+	libcurl_la-socketpair.lo libcurl_la-socks.lo \
+	libcurl_la-socks_gssapi.lo libcurl_la-socks_sspi.lo \
+	libcurl_la-speedcheck.lo libcurl_la-splay.lo \
+	libcurl_la-strcase.lo libcurl_la-strdup.lo \
+	libcurl_la-strerror.lo libcurl_la-strtok.lo \
+	libcurl_la-strtoofft.lo libcurl_la-system_win32.lo \
+	libcurl_la-telnet.lo libcurl_la-tftp.lo libcurl_la-timediff.lo \
+	libcurl_la-timeval.lo libcurl_la-transfer.lo libcurl_la-url.lo \
+	libcurl_la-urlapi.lo libcurl_la-version.lo \
+	libcurl_la-version_win32.lo libcurl_la-warnless.lo \
+	libcurl_la-ws.lo
+am__dirstamp = $(am__leading_dot)dirstamp
+am__objects_2 = vauth/libcurl_la-cleartext.lo vauth/libcurl_la-cram.lo \
+	vauth/libcurl_la-digest.lo vauth/libcurl_la-digest_sspi.lo \
+	vauth/libcurl_la-gsasl.lo vauth/libcurl_la-krb5_gssapi.lo \
+	vauth/libcurl_la-krb5_sspi.lo vauth/libcurl_la-ntlm.lo \
+	vauth/libcurl_la-ntlm_sspi.lo vauth/libcurl_la-oauth2.lo \
+	vauth/libcurl_la-spnego_gssapi.lo \
+	vauth/libcurl_la-spnego_sspi.lo vauth/libcurl_la-vauth.lo
+am__objects_3 = vtls/libcurl_la-bearssl.lo vtls/libcurl_la-gtls.lo \
+	vtls/libcurl_la-hostcheck.lo vtls/libcurl_la-keylog.lo \
+	vtls/libcurl_la-mbedtls.lo \
+	vtls/libcurl_la-mbedtls_threadlock.lo \
+	vtls/libcurl_la-openssl.lo vtls/libcurl_la-rustls.lo \
+	vtls/libcurl_la-schannel.lo vtls/libcurl_la-schannel_verify.lo \
+	vtls/libcurl_la-sectransp.lo vtls/libcurl_la-vtls.lo \
+	vtls/libcurl_la-wolfssl.lo vtls/libcurl_la-x509asn1.lo
+am__objects_4 = vquic/libcurl_la-curl_msh3.lo \
+	vquic/libcurl_la-curl_ngtcp2.lo vquic/libcurl_la-curl_osslq.lo \
+	vquic/libcurl_la-curl_quiche.lo vquic/libcurl_la-vquic.lo \
+	vquic/libcurl_la-vquic-tls.lo
+am__objects_5 = vssh/libcurl_la-libssh.lo vssh/libcurl_la-libssh2.lo \
+	vssh/libcurl_la-wolfssh.lo
+am__objects_6 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \
+	$(am__objects_4) $(am__objects_5)
+am__objects_7 =
+am__objects_8 = $(am__objects_7) $(am__objects_7) $(am__objects_7) \
+	$(am__objects_7) $(am__objects_7)
+am__objects_9 = libcurl.lo
+@HAVE_WINDRES_TRUE@@USE_CPPFLAG_CURL_STATICLIB_FALSE@am__objects_10 = $(am__objects_9)
+am_libcurl_la_OBJECTS = $(am__objects_6) $(am__objects_8) \
+	$(am__objects_10)
+libcurl_la_OBJECTS = $(am_libcurl_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libcurl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libcurl_la_CFLAGS) \
+	$(CFLAGS) $(libcurl_la_LDFLAGS) $(LDFLAGS) -o $@
+libcurlu_la_LIBADD =
+am__objects_11 = libcurlu_la-altsvc.lo libcurlu_la-amigaos.lo \
+	libcurlu_la-asyn-ares.lo libcurlu_la-asyn-thread.lo \
+	libcurlu_la-base64.lo libcurlu_la-bufq.lo \
+	libcurlu_la-bufref.lo libcurlu_la-c-hyper.lo \
+	libcurlu_la-cf-h1-proxy.lo libcurlu_la-cf-h2-proxy.lo \
+	libcurlu_la-cf-haproxy.lo libcurlu_la-cf-https-connect.lo \
+	libcurlu_la-cf-socket.lo libcurlu_la-cfilters.lo \
+	libcurlu_la-conncache.lo libcurlu_la-connect.lo \
+	libcurlu_la-content_encoding.lo libcurlu_la-cookie.lo \
+	libcurlu_la-curl_addrinfo.lo libcurlu_la-curl_des.lo \
+	libcurlu_la-curl_endian.lo libcurlu_la-curl_fnmatch.lo \
+	libcurlu_la-curl_get_line.lo libcurlu_la-curl_gethostname.lo \
+	libcurlu_la-curl_gssapi.lo libcurlu_la-curl_memrchr.lo \
+	libcurlu_la-curl_multibyte.lo libcurlu_la-curl_ntlm_core.lo \
+	libcurlu_la-curl_ntlm_wb.lo libcurlu_la-curl_path.lo \
+	libcurlu_la-curl_range.lo libcurlu_la-curl_rtmp.lo \
+	libcurlu_la-curl_sasl.lo libcurlu_la-curl_sha512_256.lo \
+	libcurlu_la-curl_sspi.lo libcurlu_la-curl_threads.lo \
+	libcurlu_la-curl_trc.lo libcurlu_la-cw-out.lo \
+	libcurlu_la-dict.lo libcurlu_la-doh.lo libcurlu_la-dynbuf.lo \
+	libcurlu_la-dynhds.lo libcurlu_la-easy.lo \
+	libcurlu_la-easygetopt.lo libcurlu_la-easyoptions.lo \
+	libcurlu_la-escape.lo libcurlu_la-file.lo \
+	libcurlu_la-fileinfo.lo libcurlu_la-fopen.lo \
+	libcurlu_la-formdata.lo libcurlu_la-ftp.lo \
+	libcurlu_la-ftplistparser.lo libcurlu_la-getenv.lo \
+	libcurlu_la-getinfo.lo libcurlu_la-gopher.lo \
+	libcurlu_la-hash.lo libcurlu_la-headers.lo libcurlu_la-hmac.lo \
+	libcurlu_la-hostasyn.lo libcurlu_la-hostip.lo \
+	libcurlu_la-hostip4.lo libcurlu_la-hostip6.lo \
+	libcurlu_la-hostsyn.lo libcurlu_la-hsts.lo libcurlu_la-http.lo \
+	libcurlu_la-http1.lo libcurlu_la-http2.lo \
+	libcurlu_la-http_aws_sigv4.lo libcurlu_la-http_chunks.lo \
+	libcurlu_la-http_digest.lo libcurlu_la-http_negotiate.lo \
+	libcurlu_la-http_ntlm.lo libcurlu_la-http_proxy.lo \
+	libcurlu_la-idn.lo libcurlu_la-if2ip.lo libcurlu_la-imap.lo \
+	libcurlu_la-inet_ntop.lo libcurlu_la-inet_pton.lo \
+	libcurlu_la-krb5.lo libcurlu_la-ldap.lo libcurlu_la-llist.lo \
+	libcurlu_la-macos.lo libcurlu_la-md4.lo libcurlu_la-md5.lo \
+	libcurlu_la-memdebug.lo libcurlu_la-mime.lo \
+	libcurlu_la-mprintf.lo libcurlu_la-mqtt.lo \
+	libcurlu_la-multi.lo libcurlu_la-netrc.lo \
+	libcurlu_la-nonblock.lo libcurlu_la-noproxy.lo \
+	libcurlu_la-openldap.lo libcurlu_la-parsedate.lo \
+	libcurlu_la-pingpong.lo libcurlu_la-pop3.lo \
+	libcurlu_la-progress.lo libcurlu_la-psl.lo libcurlu_la-rand.lo \
+	libcurlu_la-rename.lo libcurlu_la-request.lo \
+	libcurlu_la-rtsp.lo libcurlu_la-select.lo libcurlu_la-sendf.lo \
+	libcurlu_la-setopt.lo libcurlu_la-sha256.lo \
+	libcurlu_la-share.lo libcurlu_la-slist.lo libcurlu_la-smb.lo \
+	libcurlu_la-smtp.lo libcurlu_la-socketpair.lo \
+	libcurlu_la-socks.lo libcurlu_la-socks_gssapi.lo \
+	libcurlu_la-socks_sspi.lo libcurlu_la-speedcheck.lo \
+	libcurlu_la-splay.lo libcurlu_la-strcase.lo \
+	libcurlu_la-strdup.lo libcurlu_la-strerror.lo \
+	libcurlu_la-strtok.lo libcurlu_la-strtoofft.lo \
+	libcurlu_la-system_win32.lo libcurlu_la-telnet.lo \
+	libcurlu_la-tftp.lo libcurlu_la-timediff.lo \
+	libcurlu_la-timeval.lo libcurlu_la-transfer.lo \
+	libcurlu_la-url.lo libcurlu_la-urlapi.lo \
+	libcurlu_la-version.lo libcurlu_la-version_win32.lo \
+	libcurlu_la-warnless.lo libcurlu_la-ws.lo
+am__objects_12 = vauth/libcurlu_la-cleartext.lo \
+	vauth/libcurlu_la-cram.lo vauth/libcurlu_la-digest.lo \
+	vauth/libcurlu_la-digest_sspi.lo vauth/libcurlu_la-gsasl.lo \
+	vauth/libcurlu_la-krb5_gssapi.lo \
+	vauth/libcurlu_la-krb5_sspi.lo vauth/libcurlu_la-ntlm.lo \
+	vauth/libcurlu_la-ntlm_sspi.lo vauth/libcurlu_la-oauth2.lo \
+	vauth/libcurlu_la-spnego_gssapi.lo \
+	vauth/libcurlu_la-spnego_sspi.lo vauth/libcurlu_la-vauth.lo
+am__objects_13 = vtls/libcurlu_la-bearssl.lo vtls/libcurlu_la-gtls.lo \
+	vtls/libcurlu_la-hostcheck.lo vtls/libcurlu_la-keylog.lo \
+	vtls/libcurlu_la-mbedtls.lo \
+	vtls/libcurlu_la-mbedtls_threadlock.lo \
+	vtls/libcurlu_la-openssl.lo vtls/libcurlu_la-rustls.lo \
+	vtls/libcurlu_la-schannel.lo \
+	vtls/libcurlu_la-schannel_verify.lo \
+	vtls/libcurlu_la-sectransp.lo vtls/libcurlu_la-vtls.lo \
+	vtls/libcurlu_la-wolfssl.lo vtls/libcurlu_la-x509asn1.lo
+am__objects_14 = vquic/libcurlu_la-curl_msh3.lo \
+	vquic/libcurlu_la-curl_ngtcp2.lo \
+	vquic/libcurlu_la-curl_osslq.lo \
+	vquic/libcurlu_la-curl_quiche.lo vquic/libcurlu_la-vquic.lo \
+	vquic/libcurlu_la-vquic-tls.lo
+am__objects_15 = vssh/libcurlu_la-libssh.lo \
+	vssh/libcurlu_la-libssh2.lo vssh/libcurlu_la-wolfssh.lo
+am__objects_16 = $(am__objects_11) $(am__objects_12) $(am__objects_13) \
+	$(am__objects_14) $(am__objects_15)
+am_libcurlu_la_OBJECTS = $(am__objects_16) $(am__objects_8)
+libcurlu_la_OBJECTS = $(am_libcurlu_la_OBJECTS)
+libcurlu_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libcurlu_la_CFLAGS) \
+	$(CFLAGS) $(libcurlu_la_LDFLAGS) $(LDFLAGS) -o $@
+@BUILD_UNITTESTS_TRUE@am_libcurlu_la_rpath =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = 
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
+	./$(DEPDIR)/libcurl_la-amigaos.Plo \
+	./$(DEPDIR)/libcurl_la-asyn-ares.Plo \
+	./$(DEPDIR)/libcurl_la-asyn-thread.Plo \
+	./$(DEPDIR)/libcurl_la-base64.Plo \
+	./$(DEPDIR)/libcurl_la-bufq.Plo \
+	./$(DEPDIR)/libcurl_la-bufref.Plo \
+	./$(DEPDIR)/libcurl_la-c-hyper.Plo \
+	./$(DEPDIR)/libcurl_la-cf-h1-proxy.Plo \
+	./$(DEPDIR)/libcurl_la-cf-h2-proxy.Plo \
+	./$(DEPDIR)/libcurl_la-cf-haproxy.Plo \
+	./$(DEPDIR)/libcurl_la-cf-https-connect.Plo \
+	./$(DEPDIR)/libcurl_la-cf-socket.Plo \
+	./$(DEPDIR)/libcurl_la-cfilters.Plo \
+	./$(DEPDIR)/libcurl_la-conncache.Plo \
+	./$(DEPDIR)/libcurl_la-connect.Plo \
+	./$(DEPDIR)/libcurl_la-content_encoding.Plo \
+	./$(DEPDIR)/libcurl_la-cookie.Plo \
+	./$(DEPDIR)/libcurl_la-curl_addrinfo.Plo \
+	./$(DEPDIR)/libcurl_la-curl_des.Plo \
+	./$(DEPDIR)/libcurl_la-curl_endian.Plo \
+	./$(DEPDIR)/libcurl_la-curl_fnmatch.Plo \
+	./$(DEPDIR)/libcurl_la-curl_get_line.Plo \
+	./$(DEPDIR)/libcurl_la-curl_gethostname.Plo \
+	./$(DEPDIR)/libcurl_la-curl_gssapi.Plo \
+	./$(DEPDIR)/libcurl_la-curl_memrchr.Plo \
+	./$(DEPDIR)/libcurl_la-curl_multibyte.Plo \
+	./$(DEPDIR)/libcurl_la-curl_ntlm_core.Plo \
+	./$(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo \
+	./$(DEPDIR)/libcurl_la-curl_path.Plo \
+	./$(DEPDIR)/libcurl_la-curl_range.Plo \
+	./$(DEPDIR)/libcurl_la-curl_rtmp.Plo \
+	./$(DEPDIR)/libcurl_la-curl_sasl.Plo \
+	./$(DEPDIR)/libcurl_la-curl_sha512_256.Plo \
+	./$(DEPDIR)/libcurl_la-curl_sspi.Plo \
+	./$(DEPDIR)/libcurl_la-curl_threads.Plo \
+	./$(DEPDIR)/libcurl_la-curl_trc.Plo \
+	./$(DEPDIR)/libcurl_la-cw-out.Plo \
+	./$(DEPDIR)/libcurl_la-dict.Plo ./$(DEPDIR)/libcurl_la-doh.Plo \
+	./$(DEPDIR)/libcurl_la-dynbuf.Plo \
+	./$(DEPDIR)/libcurl_la-dynhds.Plo \
+	./$(DEPDIR)/libcurl_la-easy.Plo \
+	./$(DEPDIR)/libcurl_la-easygetopt.Plo \
+	./$(DEPDIR)/libcurl_la-easyoptions.Plo \
+	./$(DEPDIR)/libcurl_la-escape.Plo \
+	./$(DEPDIR)/libcurl_la-file.Plo \
+	./$(DEPDIR)/libcurl_la-fileinfo.Plo \
+	./$(DEPDIR)/libcurl_la-fopen.Plo \
+	./$(DEPDIR)/libcurl_la-formdata.Plo \
+	./$(DEPDIR)/libcurl_la-ftp.Plo \
+	./$(DEPDIR)/libcurl_la-ftplistparser.Plo \
+	./$(DEPDIR)/libcurl_la-getenv.Plo \
+	./$(DEPDIR)/libcurl_la-getinfo.Plo \
+	./$(DEPDIR)/libcurl_la-gopher.Plo \
+	./$(DEPDIR)/libcurl_la-hash.Plo \
+	./$(DEPDIR)/libcurl_la-headers.Plo \
+	./$(DEPDIR)/libcurl_la-hmac.Plo \
+	./$(DEPDIR)/libcurl_la-hostasyn.Plo \
+	./$(DEPDIR)/libcurl_la-hostip.Plo \
+	./$(DEPDIR)/libcurl_la-hostip4.Plo \
+	./$(DEPDIR)/libcurl_la-hostip6.Plo \
+	./$(DEPDIR)/libcurl_la-hostsyn.Plo \
+	./$(DEPDIR)/libcurl_la-hsts.Plo \
+	./$(DEPDIR)/libcurl_la-http.Plo \
+	./$(DEPDIR)/libcurl_la-http1.Plo \
+	./$(DEPDIR)/libcurl_la-http2.Plo \
+	./$(DEPDIR)/libcurl_la-http_aws_sigv4.Plo \
+	./$(DEPDIR)/libcurl_la-http_chunks.Plo \
+	./$(DEPDIR)/libcurl_la-http_digest.Plo \
+	./$(DEPDIR)/libcurl_la-http_negotiate.Plo \
+	./$(DEPDIR)/libcurl_la-http_ntlm.Plo \
+	./$(DEPDIR)/libcurl_la-http_proxy.Plo \
+	./$(DEPDIR)/libcurl_la-idn.Plo \
+	./$(DEPDIR)/libcurl_la-if2ip.Plo \
+	./$(DEPDIR)/libcurl_la-imap.Plo \
+	./$(DEPDIR)/libcurl_la-inet_ntop.Plo \
+	./$(DEPDIR)/libcurl_la-inet_pton.Plo \
+	./$(DEPDIR)/libcurl_la-krb5.Plo \
+	./$(DEPDIR)/libcurl_la-ldap.Plo \
+	./$(DEPDIR)/libcurl_la-llist.Plo \
+	./$(DEPDIR)/libcurl_la-macos.Plo \
+	./$(DEPDIR)/libcurl_la-md4.Plo ./$(DEPDIR)/libcurl_la-md5.Plo \
+	./$(DEPDIR)/libcurl_la-memdebug.Plo \
+	./$(DEPDIR)/libcurl_la-mime.Plo \
+	./$(DEPDIR)/libcurl_la-mprintf.Plo \
+	./$(DEPDIR)/libcurl_la-mqtt.Plo \
+	./$(DEPDIR)/libcurl_la-multi.Plo \
+	./$(DEPDIR)/libcurl_la-netrc.Plo \
+	./$(DEPDIR)/libcurl_la-nonblock.Plo \
+	./$(DEPDIR)/libcurl_la-noproxy.Plo \
+	./$(DEPDIR)/libcurl_la-openldap.Plo \
+	./$(DEPDIR)/libcurl_la-parsedate.Plo \
+	./$(DEPDIR)/libcurl_la-pingpong.Plo \
+	./$(DEPDIR)/libcurl_la-pop3.Plo \
+	./$(DEPDIR)/libcurl_la-progress.Plo \
+	./$(DEPDIR)/libcurl_la-psl.Plo ./$(DEPDIR)/libcurl_la-rand.Plo \
+	./$(DEPDIR)/libcurl_la-rename.Plo \
+	./$(DEPDIR)/libcurl_la-request.Plo \
+	./$(DEPDIR)/libcurl_la-rtsp.Plo \
+	./$(DEPDIR)/libcurl_la-select.Plo \
+	./$(DEPDIR)/libcurl_la-sendf.Plo \
+	./$(DEPDIR)/libcurl_la-setopt.Plo \
+	./$(DEPDIR)/libcurl_la-sha256.Plo \
+	./$(DEPDIR)/libcurl_la-share.Plo \
+	./$(DEPDIR)/libcurl_la-slist.Plo \
+	./$(DEPDIR)/libcurl_la-smb.Plo ./$(DEPDIR)/libcurl_la-smtp.Plo \
+	./$(DEPDIR)/libcurl_la-socketpair.Plo \
+	./$(DEPDIR)/libcurl_la-socks.Plo \
+	./$(DEPDIR)/libcurl_la-socks_gssapi.Plo \
+	./$(DEPDIR)/libcurl_la-socks_sspi.Plo \
+	./$(DEPDIR)/libcurl_la-speedcheck.Plo \
+	./$(DEPDIR)/libcurl_la-splay.Plo \
+	./$(DEPDIR)/libcurl_la-strcase.Plo \
+	./$(DEPDIR)/libcurl_la-strdup.Plo \
+	./$(DEPDIR)/libcurl_la-strerror.Plo \
+	./$(DEPDIR)/libcurl_la-strtok.Plo \
+	./$(DEPDIR)/libcurl_la-strtoofft.Plo \
+	./$(DEPDIR)/libcurl_la-system_win32.Plo \
+	./$(DEPDIR)/libcurl_la-telnet.Plo \
+	./$(DEPDIR)/libcurl_la-tftp.Plo \
+	./$(DEPDIR)/libcurl_la-timediff.Plo \
+	./$(DEPDIR)/libcurl_la-timeval.Plo \
+	./$(DEPDIR)/libcurl_la-transfer.Plo \
+	./$(DEPDIR)/libcurl_la-url.Plo \
+	./$(DEPDIR)/libcurl_la-urlapi.Plo \
+	./$(DEPDIR)/libcurl_la-version.Plo \
+	./$(DEPDIR)/libcurl_la-version_win32.Plo \
+	./$(DEPDIR)/libcurl_la-warnless.Plo \
+	./$(DEPDIR)/libcurl_la-ws.Plo \
+	./$(DEPDIR)/libcurlu_la-altsvc.Plo \
+	./$(DEPDIR)/libcurlu_la-amigaos.Plo \
+	./$(DEPDIR)/libcurlu_la-asyn-ares.Plo \
+	./$(DEPDIR)/libcurlu_la-asyn-thread.Plo \
+	./$(DEPDIR)/libcurlu_la-base64.Plo \
+	./$(DEPDIR)/libcurlu_la-bufq.Plo \
+	./$(DEPDIR)/libcurlu_la-bufref.Plo \
+	./$(DEPDIR)/libcurlu_la-c-hyper.Plo \
+	./$(DEPDIR)/libcurlu_la-cf-h1-proxy.Plo \
+	./$(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo \
+	./$(DEPDIR)/libcurlu_la-cf-haproxy.Plo \
+	./$(DEPDIR)/libcurlu_la-cf-https-connect.Plo \
+	./$(DEPDIR)/libcurlu_la-cf-socket.Plo \
+	./$(DEPDIR)/libcurlu_la-cfilters.Plo \
+	./$(DEPDIR)/libcurlu_la-conncache.Plo \
+	./$(DEPDIR)/libcurlu_la-connect.Plo \
+	./$(DEPDIR)/libcurlu_la-content_encoding.Plo \
+	./$(DEPDIR)/libcurlu_la-cookie.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_addrinfo.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_des.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_endian.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_fnmatch.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_get_line.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_gethostname.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_gssapi.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_memrchr.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_multibyte.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_path.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_range.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_rtmp.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_sasl.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_sha512_256.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_sspi.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_threads.Plo \
+	./$(DEPDIR)/libcurlu_la-curl_trc.Plo \
+	./$(DEPDIR)/libcurlu_la-cw-out.Plo \
+	./$(DEPDIR)/libcurlu_la-dict.Plo \
+	./$(DEPDIR)/libcurlu_la-doh.Plo \
+	./$(DEPDIR)/libcurlu_la-dynbuf.Plo \
+	./$(DEPDIR)/libcurlu_la-dynhds.Plo \
+	./$(DEPDIR)/libcurlu_la-easy.Plo \
+	./$(DEPDIR)/libcurlu_la-easygetopt.Plo \
+	./$(DEPDIR)/libcurlu_la-easyoptions.Plo \
+	./$(DEPDIR)/libcurlu_la-escape.Plo \
+	./$(DEPDIR)/libcurlu_la-file.Plo \
+	./$(DEPDIR)/libcurlu_la-fileinfo.Plo \
+	./$(DEPDIR)/libcurlu_la-fopen.Plo \
+	./$(DEPDIR)/libcurlu_la-formdata.Plo \
+	./$(DEPDIR)/libcurlu_la-ftp.Plo \
+	./$(DEPDIR)/libcurlu_la-ftplistparser.Plo \
+	./$(DEPDIR)/libcurlu_la-getenv.Plo \
+	./$(DEPDIR)/libcurlu_la-getinfo.Plo \
+	./$(DEPDIR)/libcurlu_la-gopher.Plo \
+	./$(DEPDIR)/libcurlu_la-hash.Plo \
+	./$(DEPDIR)/libcurlu_la-headers.Plo \
+	./$(DEPDIR)/libcurlu_la-hmac.Plo \
+	./$(DEPDIR)/libcurlu_la-hostasyn.Plo \
+	./$(DEPDIR)/libcurlu_la-hostip.Plo \
+	./$(DEPDIR)/libcurlu_la-hostip4.Plo \
+	./$(DEPDIR)/libcurlu_la-hostip6.Plo \
+	./$(DEPDIR)/libcurlu_la-hostsyn.Plo \
+	./$(DEPDIR)/libcurlu_la-hsts.Plo \
+	./$(DEPDIR)/libcurlu_la-http.Plo \
+	./$(DEPDIR)/libcurlu_la-http1.Plo \
+	./$(DEPDIR)/libcurlu_la-http2.Plo \
+	./$(DEPDIR)/libcurlu_la-http_aws_sigv4.Plo \
+	./$(DEPDIR)/libcurlu_la-http_chunks.Plo \
+	./$(DEPDIR)/libcurlu_la-http_digest.Plo \
+	./$(DEPDIR)/libcurlu_la-http_negotiate.Plo \
+	./$(DEPDIR)/libcurlu_la-http_ntlm.Plo \
+	./$(DEPDIR)/libcurlu_la-http_proxy.Plo \
+	./$(DEPDIR)/libcurlu_la-idn.Plo \
+	./$(DEPDIR)/libcurlu_la-if2ip.Plo \
+	./$(DEPDIR)/libcurlu_la-imap.Plo \
+	./$(DEPDIR)/libcurlu_la-inet_ntop.Plo \
+	./$(DEPDIR)/libcurlu_la-inet_pton.Plo \
+	./$(DEPDIR)/libcurlu_la-krb5.Plo \
+	./$(DEPDIR)/libcurlu_la-ldap.Plo \
+	./$(DEPDIR)/libcurlu_la-llist.Plo \
+	./$(DEPDIR)/libcurlu_la-macos.Plo \
+	./$(DEPDIR)/libcurlu_la-md4.Plo \
+	./$(DEPDIR)/libcurlu_la-md5.Plo \
+	./$(DEPDIR)/libcurlu_la-memdebug.Plo \
+	./$(DEPDIR)/libcurlu_la-mime.Plo \
+	./$(DEPDIR)/libcurlu_la-mprintf.Plo \
+	./$(DEPDIR)/libcurlu_la-mqtt.Plo \
+	./$(DEPDIR)/libcurlu_la-multi.Plo \
+	./$(DEPDIR)/libcurlu_la-netrc.Plo \
+	./$(DEPDIR)/libcurlu_la-nonblock.Plo \
+	./$(DEPDIR)/libcurlu_la-noproxy.Plo \
+	./$(DEPDIR)/libcurlu_la-openldap.Plo \
+	./$(DEPDIR)/libcurlu_la-parsedate.Plo \
+	./$(DEPDIR)/libcurlu_la-pingpong.Plo \
+	./$(DEPDIR)/libcurlu_la-pop3.Plo \
+	./$(DEPDIR)/libcurlu_la-progress.Plo \
+	./$(DEPDIR)/libcurlu_la-psl.Plo \
+	./$(DEPDIR)/libcurlu_la-rand.Plo \
+	./$(DEPDIR)/libcurlu_la-rename.Plo \
+	./$(DEPDIR)/libcurlu_la-request.Plo \
+	./$(DEPDIR)/libcurlu_la-rtsp.Plo \
+	./$(DEPDIR)/libcurlu_la-select.Plo \
+	./$(DEPDIR)/libcurlu_la-sendf.Plo \
+	./$(DEPDIR)/libcurlu_la-setopt.Plo \
+	./$(DEPDIR)/libcurlu_la-sha256.Plo \
+	./$(DEPDIR)/libcurlu_la-share.Plo \
+	./$(DEPDIR)/libcurlu_la-slist.Plo \
+	./$(DEPDIR)/libcurlu_la-smb.Plo \
+	./$(DEPDIR)/libcurlu_la-smtp.Plo \
+	./$(DEPDIR)/libcurlu_la-socketpair.Plo \
+	./$(DEPDIR)/libcurlu_la-socks.Plo \
+	./$(DEPDIR)/libcurlu_la-socks_gssapi.Plo \
+	./$(DEPDIR)/libcurlu_la-socks_sspi.Plo \
+	./$(DEPDIR)/libcurlu_la-speedcheck.Plo \
+	./$(DEPDIR)/libcurlu_la-splay.Plo \
+	./$(DEPDIR)/libcurlu_la-strcase.Plo \
+	./$(DEPDIR)/libcurlu_la-strdup.Plo \
+	./$(DEPDIR)/libcurlu_la-strerror.Plo \
+	./$(DEPDIR)/libcurlu_la-strtok.Plo \
+	./$(DEPDIR)/libcurlu_la-strtoofft.Plo \
+	./$(DEPDIR)/libcurlu_la-system_win32.Plo \
+	./$(DEPDIR)/libcurlu_la-telnet.Plo \
+	./$(DEPDIR)/libcurlu_la-tftp.Plo \
+	./$(DEPDIR)/libcurlu_la-timediff.Plo \
+	./$(DEPDIR)/libcurlu_la-timeval.Plo \
+	./$(DEPDIR)/libcurlu_la-transfer.Plo \
+	./$(DEPDIR)/libcurlu_la-url.Plo \
+	./$(DEPDIR)/libcurlu_la-urlapi.Plo \
+	./$(DEPDIR)/libcurlu_la-version.Plo \
+	./$(DEPDIR)/libcurlu_la-version_win32.Plo \
+	./$(DEPDIR)/libcurlu_la-warnless.Plo \
+	./$(DEPDIR)/libcurlu_la-ws.Plo \
+	vauth/$(DEPDIR)/libcurl_la-cleartext.Plo \
+	vauth/$(DEPDIR)/libcurl_la-cram.Plo \
+	vauth/$(DEPDIR)/libcurl_la-digest.Plo \
+	vauth/$(DEPDIR)/libcurl_la-digest_sspi.Plo \
+	vauth/$(DEPDIR)/libcurl_la-gsasl.Plo \
+	vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Plo \
+	vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Plo \
+	vauth/$(DEPDIR)/libcurl_la-ntlm.Plo \
+	vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Plo \
+	vauth/$(DEPDIR)/libcurl_la-oauth2.Plo \
+	vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Plo \
+	vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Plo \
+	vauth/$(DEPDIR)/libcurl_la-vauth.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-cleartext.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-cram.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-digest.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-gsasl.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-ntlm.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-oauth2.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo \
+	vauth/$(DEPDIR)/libcurlu_la-vauth.Plo \
+	vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo \
+	vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo \
+	vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo \
+	vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo \
+	vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo \
+	vquic/$(DEPDIR)/libcurl_la-vquic.Plo \
+	vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo \
+	vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo \
+	vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo \
+	vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo \
+	vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo \
+	vquic/$(DEPDIR)/libcurlu_la-vquic.Plo \
+	vssh/$(DEPDIR)/libcurl_la-libssh.Plo \
+	vssh/$(DEPDIR)/libcurl_la-libssh2.Plo \
+	vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo \
+	vssh/$(DEPDIR)/libcurlu_la-libssh.Plo \
+	vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo \
+	vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo \
+	vtls/$(DEPDIR)/libcurl_la-bearssl.Plo \
+	vtls/$(DEPDIR)/libcurl_la-gtls.Plo \
+	vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo \
+	vtls/$(DEPDIR)/libcurl_la-keylog.Plo \
+	vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo \
+	vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo \
+	vtls/$(DEPDIR)/libcurl_la-openssl.Plo \
+	vtls/$(DEPDIR)/libcurl_la-rustls.Plo \
+	vtls/$(DEPDIR)/libcurl_la-schannel.Plo \
+	vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo \
+	vtls/$(DEPDIR)/libcurl_la-sectransp.Plo \
+	vtls/$(DEPDIR)/libcurl_la-vtls.Plo \
+	vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo \
+	vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-gtls.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-keylog.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-openssl.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-rustls.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-schannel.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-vtls.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-wolfssl.Plo \
+	vtls/$(DEPDIR)/libcurlu_la-x509asn1.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libcurl_la_SOURCES) $(libcurlu_la_SOURCES)
+DIST_SOURCES = $(am__libcurl_la_SOURCES_DIST) $(libcurlu_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \
+	curl_config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.inc \
+	$(srcdir)/Makefile.soname $(srcdir)/curl_config.h.in \
+	$(srcdir)/libcurl.plist.in $(srcdir)/libcurl.vers.in \
+	$(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APACHECTL = @APACHECTL@
+APXS = @APXS@
+AR = @AR@
+AR_FLAGS = @AR_FLAGS@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@
+CADDY = @CADDY@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+
+# This might hold -Werror
+CFLAGS = @CFLAGS@ @CURL_CFLAG_EXTRAS@
+CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@
+CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CURLVERSION = @CURLVERSION@
+CURL_CA_BUNDLE = @CURL_CA_BUNDLE@
+CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@
+CURL_DISABLE_DICT = @CURL_DISABLE_DICT@
+CURL_DISABLE_FILE = @CURL_DISABLE_FILE@
+CURL_DISABLE_FTP = @CURL_DISABLE_FTP@
+CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@
+CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@
+CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@
+CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@
+CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@
+CURL_DISABLE_MQTT = @CURL_DISABLE_MQTT@
+CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@
+CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@
+CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@
+CURL_DISABLE_SMB = @CURL_DISABLE_SMB@
+CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@
+CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@
+CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@
+CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@
+CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@
+CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@
+CURL_PLIST_VERSION = @CURL_PLIST_VERSION@
+CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_SHARED = @ENABLE_SHARED@
+ENABLE_STATIC = @ENABLE_STATIC@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@
+GCOV = @GCOV@
+GREP = @GREP@
+HAVE_BROTLI = @HAVE_BROTLI@
+HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@
+HAVE_LDAP_SSL = @HAVE_LDAP_SSL@
+HAVE_LIBZ = @HAVE_LIBZ@
+HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@
+HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@
+HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@
+HAVE_ZSTD = @HAVE_ZSTD@
+HTTPD = @HTTPD@
+HTTPD_NGHTTPX = @HTTPD_NGHTTPX@
+IDN_ENABLED = @IDN_ENABLED@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPV6_ENABLED = @IPV6_ENABLED@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCURL_LIBS = @LIBCURL_LIBS@
+LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
+LIBOBJS = @LIBOBJS@
+
+# Prevent LIBS from being used for all link targets
+LIBS = $(BLANK_AT_MAKETIME)
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKGADD_NAME = @PKGADD_NAME@
+PKGADD_PKG = @PKGADD_PKG@
+PKGADD_VENDOR = @PKGADD_VENDOR@
+PKGCONFIG = @PKGCONFIG@
+RANDOM_FILE = @RANDOM_FILE@
+RANLIB = @RANLIB@
+RC = @RC@
+REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSL_BACKENDS = @SSL_BACKENDS@
+SSL_ENABLED = @SSL_ENABLED@
+SSL_LIBS = @SSL_LIBS@
+STRIP = @STRIP@
+SUPPORT_FEATURES = @SUPPORT_FEATURES@
+SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@
+TEST_NGHTTPX = @TEST_NGHTTPX@
+USE_ARES = @USE_ARES@
+USE_BEARSSL = @USE_BEARSSL@
+USE_GNUTLS = @USE_GNUTLS@
+USE_HYPER = @USE_HYPER@
+USE_LIBPSL = @USE_LIBPSL@
+USE_LIBRTMP = @USE_LIBRTMP@
+USE_LIBSSH = @USE_LIBSSH@
+USE_LIBSSH2 = @USE_LIBSSH2@
+USE_MBEDTLS = @USE_MBEDTLS@
+USE_MSH3 = @USE_MSH3@
+USE_NGHTTP2 = @USE_NGHTTP2@
+USE_NGHTTP3 = @USE_NGHTTP3@
+USE_NGTCP2 = @USE_NGTCP2@
+USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@
+USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@
+USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@
+USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@
+USE_NGTCP2_H3 = @USE_NGTCP2_H3@
+USE_OPENLDAP = @USE_OPENLDAP@
+USE_OPENSSL_H3 = @USE_OPENSSL_H3@
+USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@
+USE_QUICHE = @USE_QUICHE@
+USE_RUSTLS = @USE_RUSTLS@
+USE_SCHANNEL = @USE_SCHANNEL@
+USE_SECTRANSP = @USE_SECTRANSP@
+USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@
+USE_WIN32_CRYPTO = @USE_WIN32_CRYPTO@
+USE_WIN32_LARGE_FILES = @USE_WIN32_LARGE_FILES@
+USE_WIN32_SMALL_FILES = @USE_WIN32_SMALL_FILES@
+USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@
+USE_WOLFSSH = @USE_WOLFSSH@
+USE_WOLFSSL = @USE_WOLFSSL@
+VERSION = @VERSION@
+VERSIONNUM = @VERSIONNUM@
+ZLIB_LIBS = @ZLIB_LIBS@
+ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libext = @libext@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+AUTOMAKE_OPTIONS = foreign nostdinc
+CMAKE_DIST = CMakeLists.txt curl_config.h.cmake
+EXTRA_DIST = Makefile.mk config-win32.h config-win32ce.h config-plan9.h    \
+ config-riscos.h config-mac.h curl_config.h.in config-dos.h                \
+ libcurl.plist libcurl.rc config-amigaos.h config-win32ce.h                \
+ config-os400.h setup-os400.h $(CMAKE_DIST) setup-win32.h .checksrc \
+ Makefile.soname
+
+lib_LTLIBRARIES = libcurl.la
+@BUILD_UNITTESTS_FALSE@noinst_LTLIBRARIES = 
+@BUILD_UNITTESTS_TRUE@noinst_LTLIBRARIES = libcurlu.la
+
+# Specify our include paths here, and do it relative to $(top_srcdir) and
+# $(top_builddir), to ensure that these paths which belong to the library
+# being currently built and tested are searched before the library which
+# might possibly already be installed in the system.
+#
+# $(top_srcdir)/include is for libcurl's external include files
+# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file
+# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "private" files
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/lib \
+	-I$(top_srcdir)/lib -DBUILDING_LIBCURL
+VERSIONCHANGE = 12
+VERSIONADD = 0
+VERSIONDEL = 8
+
+# libtool version:
+VERSIONINFO = -version-info $(VERSIONCHANGE):$(VERSIONADD):$(VERSIONDEL)
+AM_LDFLAGS = 
+AM_CFLAGS = 
+LIB_VAUTH_CFILES = \
+  vauth/cleartext.c     \
+  vauth/cram.c          \
+  vauth/digest.c        \
+  vauth/digest_sspi.c   \
+  vauth/gsasl.c         \
+  vauth/krb5_gssapi.c   \
+  vauth/krb5_sspi.c     \
+  vauth/ntlm.c          \
+  vauth/ntlm_sspi.c     \
+  vauth/oauth2.c        \
+  vauth/spnego_gssapi.c \
+  vauth/spnego_sspi.c   \
+  vauth/vauth.c
+
+LIB_VAUTH_HFILES = \
+  vauth/digest.h        \
+  vauth/ntlm.h          \
+  vauth/vauth.h
+
+LIB_VTLS_CFILES = \
+  vtls/bearssl.c            \
+  vtls/gtls.c               \
+  vtls/hostcheck.c          \
+  vtls/keylog.c             \
+  vtls/mbedtls.c            \
+  vtls/mbedtls_threadlock.c \
+  vtls/openssl.c            \
+  vtls/rustls.c             \
+  vtls/schannel.c           \
+  vtls/schannel_verify.c    \
+  vtls/sectransp.c          \
+  vtls/vtls.c               \
+  vtls/wolfssl.c            \
+  vtls/x509asn1.c
+
+LIB_VTLS_HFILES = \
+  vtls/bearssl.h            \
+  vtls/gtls.h               \
+  vtls/hostcheck.h          \
+  vtls/keylog.h             \
+  vtls/mbedtls.h            \
+  vtls/mbedtls_threadlock.h \
+  vtls/openssl.h            \
+  vtls/rustls.h             \
+  vtls/schannel.h           \
+  vtls/schannel_int.h       \
+  vtls/sectransp.h          \
+  vtls/vtls.h               \
+  vtls/vtls_int.h           \
+  vtls/wolfssl.h            \
+  vtls/x509asn1.h
+
+LIB_VQUIC_CFILES = \
+  vquic/curl_msh3.c   \
+  vquic/curl_ngtcp2.c   \
+  vquic/curl_osslq.c   \
+  vquic/curl_quiche.c   \
+  vquic/vquic.c \
+  vquic/vquic-tls.c
+
+LIB_VQUIC_HFILES = \
+  vquic/curl_msh3.h   \
+  vquic/curl_ngtcp2.h   \
+  vquic/curl_osslq.h   \
+  vquic/curl_quiche.h   \
+  vquic/vquic.h    \
+  vquic/vquic_int.h \
+  vquic/vquic-tls.h
+
+LIB_VSSH_CFILES = \
+  vssh/libssh.c    \
+  vssh/libssh2.c   \
+  vssh/wolfssh.c
+
+LIB_VSSH_HFILES = \
+  vssh/ssh.h
+
+LIB_CFILES = \
+  altsvc.c           \
+  amigaos.c          \
+  asyn-ares.c        \
+  asyn-thread.c      \
+  base64.c           \
+  bufq.c             \
+  bufref.c           \
+  c-hyper.c          \
+  cf-h1-proxy.c      \
+  cf-h2-proxy.c      \
+  cf-haproxy.c       \
+  cf-https-connect.c \
+  cf-socket.c        \
+  cfilters.c         \
+  conncache.c        \
+  connect.c          \
+  content_encoding.c \
+  cookie.c           \
+  curl_addrinfo.c    \
+  curl_des.c         \
+  curl_endian.c      \
+  curl_fnmatch.c     \
+  curl_get_line.c    \
+  curl_gethostname.c \
+  curl_gssapi.c      \
+  curl_memrchr.c     \
+  curl_multibyte.c   \
+  curl_ntlm_core.c   \
+  curl_ntlm_wb.c     \
+  curl_path.c        \
+  curl_range.c       \
+  curl_rtmp.c        \
+  curl_sasl.c        \
+  curl_sha512_256.c  \
+  curl_sspi.c        \
+  curl_threads.c     \
+  curl_trc.c         \
+  cw-out.c           \
+  dict.c             \
+  doh.c              \
+  dynbuf.c           \
+  dynhds.c           \
+  easy.c             \
+  easygetopt.c       \
+  easyoptions.c      \
+  escape.c           \
+  file.c             \
+  fileinfo.c         \
+  fopen.c            \
+  formdata.c         \
+  ftp.c              \
+  ftplistparser.c    \
+  getenv.c           \
+  getinfo.c          \
+  gopher.c           \
+  hash.c             \
+  headers.c          \
+  hmac.c             \
+  hostasyn.c         \
+  hostip.c           \
+  hostip4.c          \
+  hostip6.c          \
+  hostsyn.c          \
+  hsts.c             \
+  http.c             \
+  http1.c            \
+  http2.c            \
+  http_aws_sigv4.c   \
+  http_chunks.c      \
+  http_digest.c      \
+  http_negotiate.c   \
+  http_ntlm.c        \
+  http_proxy.c       \
+  idn.c              \
+  if2ip.c            \
+  imap.c             \
+  inet_ntop.c        \
+  inet_pton.c        \
+  krb5.c             \
+  ldap.c             \
+  llist.c            \
+  macos.c            \
+  md4.c              \
+  md5.c              \
+  memdebug.c         \
+  mime.c             \
+  mprintf.c          \
+  mqtt.c             \
+  multi.c            \
+  netrc.c            \
+  nonblock.c         \
+  noproxy.c          \
+  openldap.c         \
+  parsedate.c        \
+  pingpong.c         \
+  pop3.c             \
+  progress.c         \
+  psl.c              \
+  rand.c             \
+  rename.c           \
+  request.c          \
+  rtsp.c             \
+  select.c           \
+  sendf.c            \
+  setopt.c           \
+  sha256.c           \
+  share.c            \
+  slist.c            \
+  smb.c              \
+  smtp.c             \
+  socketpair.c       \
+  socks.c            \
+  socks_gssapi.c     \
+  socks_sspi.c       \
+  speedcheck.c       \
+  splay.c            \
+  strcase.c          \
+  strdup.c           \
+  strerror.c         \
+  strtok.c           \
+  strtoofft.c        \
+  system_win32.c     \
+  telnet.c           \
+  tftp.c             \
+  timediff.c         \
+  timeval.c          \
+  transfer.c         \
+  url.c              \
+  urlapi.c           \
+  version.c          \
+  version_win32.c    \
+  warnless.c         \
+  ws.c
+
+LIB_HFILES = \
+  altsvc.h           \
+  amigaos.h          \
+  arpa_telnet.h      \
+  asyn.h             \
+  bufq.h             \
+  bufref.h           \
+  c-hyper.h          \
+  cf-h1-proxy.h      \
+  cf-h2-proxy.h      \
+  cf-haproxy.h       \
+  cf-https-connect.h \
+  cf-socket.h        \
+  cfilters.h         \
+  conncache.h        \
+  connect.h          \
+  content_encoding.h \
+  cookie.h           \
+  curl_addrinfo.h    \
+  curl_base64.h      \
+  curl_ctype.h       \
+  curl_des.h         \
+  curl_endian.h      \
+  curl_fnmatch.h     \
+  curl_get_line.h    \
+  curl_gethostname.h \
+  curl_gssapi.h      \
+  curl_hmac.h        \
+  curl_krb5.h        \
+  curl_ldap.h        \
+  curl_md4.h         \
+  curl_md5.h         \
+  curl_memory.h      \
+  curl_memrchr.h     \
+  curl_multibyte.h   \
+  curl_ntlm_core.h   \
+  curl_ntlm_wb.h     \
+  curl_path.h        \
+  curl_printf.h      \
+  curl_range.h       \
+  curl_rtmp.h        \
+  curl_sasl.h        \
+  curl_setup.h       \
+  curl_setup_once.h  \
+  curl_sha256.h      \
+  curl_sha512_256.h  \
+  curl_sspi.h        \
+  curl_threads.h     \
+  curl_trc.h         \
+  curlx.h            \
+  cw-out.h           \
+  dict.h             \
+  doh.h              \
+  dynbuf.h           \
+  dynhds.h           \
+  easy_lock.h        \
+  easyif.h           \
+  easyoptions.h      \
+  escape.h           \
+  file.h             \
+  fileinfo.h         \
+  fopen.h            \
+  formdata.h         \
+  ftp.h              \
+  ftplistparser.h    \
+  functypes.h        \
+  getinfo.h          \
+  gopher.h           \
+  hash.h             \
+  headers.h          \
+  hostip.h           \
+  hsts.h             \
+  http.h             \
+  http1.h            \
+  http2.h            \
+  http_aws_sigv4.h   \
+  http_chunks.h      \
+  http_digest.h      \
+  http_negotiate.h   \
+  http_ntlm.h        \
+  http_proxy.h       \
+  idn.h              \
+  if2ip.h            \
+  imap.h             \
+  inet_ntop.h        \
+  inet_pton.h        \
+  llist.h            \
+  macos.h            \
+  memdebug.h         \
+  mime.h             \
+  mqtt.h             \
+  multihandle.h      \
+  multiif.h          \
+  netrc.h            \
+  nonblock.h         \
+  noproxy.h          \
+  parsedate.h        \
+  pingpong.h         \
+  pop3.h             \
+  progress.h         \
+  psl.h              \
+  rand.h             \
+  rename.h           \
+  request.h          \
+  rtsp.h             \
+  select.h           \
+  sendf.h            \
+  setopt.h           \
+  setup-vms.h        \
+  share.h            \
+  sigpipe.h          \
+  slist.h            \
+  smb.h              \
+  smtp.h             \
+  sockaddr.h         \
+  socketpair.h       \
+  socks.h            \
+  speedcheck.h       \
+  splay.h            \
+  strcase.h          \
+  strdup.h           \
+  strerror.h         \
+  strtok.h           \
+  strtoofft.h        \
+  system_win32.h     \
+  telnet.h           \
+  tftp.h             \
+  timediff.h         \
+  timeval.h          \
+  transfer.h         \
+  url.h              \
+  urlapi-int.h       \
+  urldata.h          \
+  version_win32.h    \
+  warnless.h         \
+  ws.h
+
+LIB_RCFILES = libcurl.rc
+CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \
+  $(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES)
+
+HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) \
+  $(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES)
+
+
+# Makefile.inc provides the CSOURCES and HHEADERS defines
+libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) $(am__append_7)
+libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS)
+libcurl_la_CPPFLAGS_EXTRA = $(am__append_6) $(am__append_8)
+libcurl_la_LDFLAGS_EXTRA = $(am__append_1) $(am__append_2) \
+	$(am__append_3) $(am__append_4) $(am__append_5)
+libcurl_la_CFLAGS_EXTRA = $(am__append_9)
+libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA)
+libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(CURL_LDFLAGS_LIB) $(LIBCURL_LIBS)
+libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA)
+libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS
+libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS)
+libcurlu_la_CFLAGS = $(AM_CFLAGS)
+CHECKSRC = $(CS_$(V))
+CS_0 = @echo "  RUN     " $@;
+CS_1 = 
+CS_ = $(CS_0)
+
+# disable the tests that are mostly causing false positives
+TIDYFLAGS = -checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference -quiet
+TIDY := clang-tidy
+all: curl_config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj .rc
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.soname $(srcdir)/Makefile.inc $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign lib/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+	esac;
+$(srcdir)/Makefile.soname $(srcdir)/Makefile.inc $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+curl_config.h: stamp-h1
+	@test -f $@ || rm -f stamp-h1
+	@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/curl_config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status lib/curl_config.h
+$(srcdir)/curl_config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f curl_config.h stamp-h1
+libcurl.vers: $(top_builddir)/config.status $(srcdir)/libcurl.vers.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+libcurl.plist: $(top_builddir)/config.status $(srcdir)/libcurl.plist.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+vauth/$(am__dirstamp):
+	@$(MKDIR_P) vauth
+	@: > vauth/$(am__dirstamp)
+vauth/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) vauth/$(DEPDIR)
+	@: > vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-cleartext.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-cram.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-digest.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-digest_sspi.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-gsasl.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-krb5_gssapi.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-krb5_sspi.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-ntlm.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-ntlm_sspi.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-oauth2.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-spnego_gssapi.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-spnego_sspi.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurl_la-vauth.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vtls/$(am__dirstamp):
+	@$(MKDIR_P) vtls
+	@: > vtls/$(am__dirstamp)
+vtls/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) vtls/$(DEPDIR)
+	@: > vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-bearssl.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-gtls.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-hostcheck.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-keylog.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-mbedtls.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-mbedtls_threadlock.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-openssl.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-rustls.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-schannel.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-schannel_verify.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-sectransp.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-vtls.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-wolfssl.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-x509asn1.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vquic/$(am__dirstamp):
+	@$(MKDIR_P) vquic
+	@: > vquic/$(am__dirstamp)
+vquic/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) vquic/$(DEPDIR)
+	@: > vquic/$(DEPDIR)/$(am__dirstamp)
+vquic/libcurl_la-curl_msh3.lo: vquic/$(am__dirstamp) \
+	vquic/$(DEPDIR)/$(am__dirstamp)
+vquic/libcurl_la-curl_ngtcp2.lo: vquic/$(am__dirstamp) \
+	vquic/$(DEPDIR)/$(am__dirstamp)
+vquic/libcurl_la-curl_osslq.lo: vquic/$(am__dirstamp) \
+	vquic/$(DEPDIR)/$(am__dirstamp)
+vquic/libcurl_la-curl_quiche.lo: vquic/$(am__dirstamp) \
+	vquic/$(DEPDIR)/$(am__dirstamp)
+vquic/libcurl_la-vquic.lo: vquic/$(am__dirstamp) \
+	vquic/$(DEPDIR)/$(am__dirstamp)
+vquic/libcurl_la-vquic-tls.lo: vquic/$(am__dirstamp) \
+	vquic/$(DEPDIR)/$(am__dirstamp)
+vssh/$(am__dirstamp):
+	@$(MKDIR_P) vssh
+	@: > vssh/$(am__dirstamp)
+vssh/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) vssh/$(DEPDIR)
+	@: > vssh/$(DEPDIR)/$(am__dirstamp)
+vssh/libcurl_la-libssh.lo: vssh/$(am__dirstamp) \
+	vssh/$(DEPDIR)/$(am__dirstamp)
+vssh/libcurl_la-libssh2.lo: vssh/$(am__dirstamp) \
+	vssh/$(DEPDIR)/$(am__dirstamp)
+vssh/libcurl_la-wolfssh.lo: vssh/$(am__dirstamp) \
+	vssh/$(DEPDIR)/$(am__dirstamp)
+
+libcurl.la: $(libcurl_la_OBJECTS) $(libcurl_la_DEPENDENCIES) $(EXTRA_libcurl_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libcurl_la_LINK) -rpath $(libdir) $(libcurl_la_OBJECTS) $(libcurl_la_LIBADD) $(LIBS)
+vauth/libcurlu_la-cleartext.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurlu_la-cram.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurlu_la-digest.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurlu_la-digest_sspi.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurlu_la-gsasl.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurlu_la-krb5_gssapi.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurlu_la-krb5_sspi.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurlu_la-ntlm.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurlu_la-ntlm_sspi.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurlu_la-oauth2.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurlu_la-spnego_gssapi.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurlu_la-spnego_sspi.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vauth/libcurlu_la-vauth.lo: vauth/$(am__dirstamp) \
+	vauth/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-bearssl.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-gtls.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-hostcheck.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-keylog.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-mbedtls.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-mbedtls_threadlock.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-openssl.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-rustls.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-schannel.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-schannel_verify.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-sectransp.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-vtls.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-wolfssl.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-x509asn1.lo: vtls/$(am__dirstamp) \
+	vtls/$(DEPDIR)/$(am__dirstamp)
+vquic/libcurlu_la-curl_msh3.lo: vquic/$(am__dirstamp) \
+	vquic/$(DEPDIR)/$(am__dirstamp)
+vquic/libcurlu_la-curl_ngtcp2.lo: vquic/$(am__dirstamp) \
+	vquic/$(DEPDIR)/$(am__dirstamp)
+vquic/libcurlu_la-curl_osslq.lo: vquic/$(am__dirstamp) \
+	vquic/$(DEPDIR)/$(am__dirstamp)
+vquic/libcurlu_la-curl_quiche.lo: vquic/$(am__dirstamp) \
+	vquic/$(DEPDIR)/$(am__dirstamp)
+vquic/libcurlu_la-vquic.lo: vquic/$(am__dirstamp) \
+	vquic/$(DEPDIR)/$(am__dirstamp)
+vquic/libcurlu_la-vquic-tls.lo: vquic/$(am__dirstamp) \
+	vquic/$(DEPDIR)/$(am__dirstamp)
+vssh/libcurlu_la-libssh.lo: vssh/$(am__dirstamp) \
+	vssh/$(DEPDIR)/$(am__dirstamp)
+vssh/libcurlu_la-libssh2.lo: vssh/$(am__dirstamp) \
+	vssh/$(DEPDIR)/$(am__dirstamp)
+vssh/libcurlu_la-wolfssh.lo: vssh/$(am__dirstamp) \
+	vssh/$(DEPDIR)/$(am__dirstamp)
+
+libcurlu.la: $(libcurlu_la_OBJECTS) $(libcurlu_la_DEPENDENCIES) $(EXTRA_libcurlu_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libcurlu_la_LINK) $(am_libcurlu_la_rpath) $(libcurlu_la_OBJECTS) $(libcurlu_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+	-rm -f vauth/*.$(OBJEXT)
+	-rm -f vauth/*.lo
+	-rm -f vquic/*.$(OBJEXT)
+	-rm -f vquic/*.lo
+	-rm -f vssh/*.$(OBJEXT)
+	-rm -f vssh/*.lo
+	-rm -f vtls/*.$(OBJEXT)
+	-rm -f vtls/*.lo
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-altsvc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-amigaos.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-asyn-ares.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-asyn-thread.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-base64.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-bufq.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-bufref.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-c-hyper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-h1-proxy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-h2-proxy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-haproxy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-https-connect.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-socket.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cfilters.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-conncache.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-connect.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-content_encoding.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cookie.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_addrinfo.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_des.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_endian.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_fnmatch.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_get_line.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_gethostname.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_gssapi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_memrchr.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_multibyte.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_ntlm_core.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_path.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_range.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_rtmp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_sasl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_sha512_256.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_sspi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_threads.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_trc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cw-out.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-dict.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-doh.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-dynbuf.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-dynhds.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-easy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-easygetopt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-easyoptions.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-escape.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-file.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-fileinfo.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-fopen.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-formdata.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-ftp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-ftplistparser.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-getenv.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-getinfo.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-gopher.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hash.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-headers.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hmac.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hostasyn.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hostip.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hostip4.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hostip6.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hostsyn.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hsts.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http1.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http_aws_sigv4.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http_chunks.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http_digest.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http_negotiate.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http_ntlm.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-http_proxy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-idn.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-if2ip.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-imap.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-inet_ntop.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-inet_pton.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-krb5.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-ldap.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-llist.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-macos.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-md4.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-md5.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-memdebug.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-mime.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-mprintf.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-mqtt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-multi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-netrc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-nonblock.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-noproxy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-openldap.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-parsedate.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-pingpong.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-pop3.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-progress.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-psl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-rand.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-rename.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-request.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-rtsp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-select.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-sendf.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-setopt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-sha256.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-share.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-slist.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-smb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-smtp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-socketpair.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-socks.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-socks_gssapi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-socks_sspi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-speedcheck.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-splay.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strcase.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strdup.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strerror.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strtok.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strtoofft.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-system_win32.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-telnet.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-tftp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-timediff.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-timeval.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-transfer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-url.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-urlapi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-version.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-version_win32.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-warnless.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-ws.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-altsvc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-amigaos.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-asyn-ares.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-asyn-thread.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-base64.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-bufq.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-bufref.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-c-hyper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-h1-proxy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-haproxy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-https-connect.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-socket.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cfilters.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-conncache.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-connect.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-content_encoding.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cookie.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_addrinfo.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_des.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_endian.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_fnmatch.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_get_line.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_gethostname.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_gssapi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_memrchr.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_multibyte.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_path.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_range.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_rtmp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_sasl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_sha512_256.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_sspi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_threads.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_trc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cw-out.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-dict.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-doh.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-dynbuf.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-dynhds.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-easy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-easygetopt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-easyoptions.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-escape.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-file.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-fileinfo.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-fopen.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-formdata.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-ftp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-ftplistparser.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-getenv.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-getinfo.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-gopher.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hash.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-headers.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hmac.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hostasyn.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hostip.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hostip4.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hostip6.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hostsyn.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hsts.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http1.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http_aws_sigv4.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http_chunks.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http_digest.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http_negotiate.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http_ntlm.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-http_proxy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-idn.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-if2ip.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-imap.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-inet_ntop.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-inet_pton.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-krb5.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-ldap.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-llist.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-macos.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-md4.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-md5.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-memdebug.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-mime.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-mprintf.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-mqtt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-multi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-netrc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-nonblock.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-noproxy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-openldap.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-parsedate.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-pingpong.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-pop3.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-progress.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-psl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-rand.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-rename.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-request.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-rtsp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-select.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-sendf.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-setopt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-sha256.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-share.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-slist.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-smb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-smtp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-socketpair.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-socks.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-socks_gssapi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-socks_sspi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-speedcheck.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-splay.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strcase.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strdup.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strerror.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strtok.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strtoofft.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-system_win32.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-telnet.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-tftp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-timediff.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-timeval.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-transfer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-url.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-urlapi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-version.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-version_win32.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-warnless.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-ws.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-cleartext.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-cram.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-digest.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-digest_sspi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-gsasl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-ntlm.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-oauth2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurl_la-vauth.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-cleartext.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-cram.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-digest.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-gsasl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-ntlm.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-oauth2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-vauth.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-vquic.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-vquic.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurl_la-libssh.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurl_la-libssh2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurlu_la-libssh.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-bearssl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-gtls.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-keylog.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-openssl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-rustls.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-schannel.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-sectransp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-vtls.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-gtls.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-keylog.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-openssl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-rustls.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-schannel.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-vtls.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-wolfssl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-x509asn1.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+	@$(MKDIR_P) $(@D)
+	@echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libcurl_la-altsvc.lo: altsvc.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-altsvc.lo -MD -MP -MF $(DEPDIR)/libcurl_la-altsvc.Tpo -c -o libcurl_la-altsvc.lo `test -f 'altsvc.c' || echo '$(srcdir)/'`altsvc.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-altsvc.Tpo $(DEPDIR)/libcurl_la-altsvc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='altsvc.c' object='libcurl_la-altsvc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-altsvc.lo `test -f 'altsvc.c' || echo '$(srcdir)/'`altsvc.c
+
+libcurl_la-amigaos.lo: amigaos.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-amigaos.lo -MD -MP -MF $(DEPDIR)/libcurl_la-amigaos.Tpo -c -o libcurl_la-amigaos.lo `test -f 'amigaos.c' || echo '$(srcdir)/'`amigaos.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-amigaos.Tpo $(DEPDIR)/libcurl_la-amigaos.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='amigaos.c' object='libcurl_la-amigaos.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-amigaos.lo `test -f 'amigaos.c' || echo '$(srcdir)/'`amigaos.c
+
+libcurl_la-asyn-ares.lo: asyn-ares.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-asyn-ares.lo -MD -MP -MF $(DEPDIR)/libcurl_la-asyn-ares.Tpo -c -o libcurl_la-asyn-ares.lo `test -f 'asyn-ares.c' || echo '$(srcdir)/'`asyn-ares.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-asyn-ares.Tpo $(DEPDIR)/libcurl_la-asyn-ares.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='asyn-ares.c' object='libcurl_la-asyn-ares.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-asyn-ares.lo `test -f 'asyn-ares.c' || echo '$(srcdir)/'`asyn-ares.c
+
+libcurl_la-asyn-thread.lo: asyn-thread.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-asyn-thread.lo -MD -MP -MF $(DEPDIR)/libcurl_la-asyn-thread.Tpo -c -o libcurl_la-asyn-thread.lo `test -f 'asyn-thread.c' || echo '$(srcdir)/'`asyn-thread.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-asyn-thread.Tpo $(DEPDIR)/libcurl_la-asyn-thread.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='asyn-thread.c' object='libcurl_la-asyn-thread.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-asyn-thread.lo `test -f 'asyn-thread.c' || echo '$(srcdir)/'`asyn-thread.c
+
+libcurl_la-base64.lo: base64.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-base64.lo -MD -MP -MF $(DEPDIR)/libcurl_la-base64.Tpo -c -o libcurl_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-base64.Tpo $(DEPDIR)/libcurl_la-base64.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='base64.c' object='libcurl_la-base64.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c
+
+libcurl_la-bufq.lo: bufq.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-bufq.lo -MD -MP -MF $(DEPDIR)/libcurl_la-bufq.Tpo -c -o libcurl_la-bufq.lo `test -f 'bufq.c' || echo '$(srcdir)/'`bufq.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-bufq.Tpo $(DEPDIR)/libcurl_la-bufq.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='bufq.c' object='libcurl_la-bufq.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-bufq.lo `test -f 'bufq.c' || echo '$(srcdir)/'`bufq.c
+
+libcurl_la-bufref.lo: bufref.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-bufref.lo -MD -MP -MF $(DEPDIR)/libcurl_la-bufref.Tpo -c -o libcurl_la-bufref.lo `test -f 'bufref.c' || echo '$(srcdir)/'`bufref.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-bufref.Tpo $(DEPDIR)/libcurl_la-bufref.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='bufref.c' object='libcurl_la-bufref.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-bufref.lo `test -f 'bufref.c' || echo '$(srcdir)/'`bufref.c
+
+libcurl_la-c-hyper.lo: c-hyper.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-c-hyper.lo -MD -MP -MF $(DEPDIR)/libcurl_la-c-hyper.Tpo -c -o libcurl_la-c-hyper.lo `test -f 'c-hyper.c' || echo '$(srcdir)/'`c-hyper.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-c-hyper.Tpo $(DEPDIR)/libcurl_la-c-hyper.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='c-hyper.c' object='libcurl_la-c-hyper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-c-hyper.lo `test -f 'c-hyper.c' || echo '$(srcdir)/'`c-hyper.c
+
+libcurl_la-cf-h1-proxy.lo: cf-h1-proxy.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cf-h1-proxy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cf-h1-proxy.Tpo -c -o libcurl_la-cf-h1-proxy.lo `test -f 'cf-h1-proxy.c' || echo '$(srcdir)/'`cf-h1-proxy.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cf-h1-proxy.Tpo $(DEPDIR)/libcurl_la-cf-h1-proxy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cf-h1-proxy.c' object='libcurl_la-cf-h1-proxy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cf-h1-proxy.lo `test -f 'cf-h1-proxy.c' || echo '$(srcdir)/'`cf-h1-proxy.c
+
+libcurl_la-cf-h2-proxy.lo: cf-h2-proxy.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cf-h2-proxy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cf-h2-proxy.Tpo -c -o libcurl_la-cf-h2-proxy.lo `test -f 'cf-h2-proxy.c' || echo '$(srcdir)/'`cf-h2-proxy.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cf-h2-proxy.Tpo $(DEPDIR)/libcurl_la-cf-h2-proxy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cf-h2-proxy.c' object='libcurl_la-cf-h2-proxy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cf-h2-proxy.lo `test -f 'cf-h2-proxy.c' || echo '$(srcdir)/'`cf-h2-proxy.c
+
+libcurl_la-cf-haproxy.lo: cf-haproxy.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cf-haproxy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cf-haproxy.Tpo -c -o libcurl_la-cf-haproxy.lo `test -f 'cf-haproxy.c' || echo '$(srcdir)/'`cf-haproxy.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cf-haproxy.Tpo $(DEPDIR)/libcurl_la-cf-haproxy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cf-haproxy.c' object='libcurl_la-cf-haproxy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cf-haproxy.lo `test -f 'cf-haproxy.c' || echo '$(srcdir)/'`cf-haproxy.c
+
+libcurl_la-cf-https-connect.lo: cf-https-connect.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cf-https-connect.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cf-https-connect.Tpo -c -o libcurl_la-cf-https-connect.lo `test -f 'cf-https-connect.c' || echo '$(srcdir)/'`cf-https-connect.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cf-https-connect.Tpo $(DEPDIR)/libcurl_la-cf-https-connect.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cf-https-connect.c' object='libcurl_la-cf-https-connect.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cf-https-connect.lo `test -f 'cf-https-connect.c' || echo '$(srcdir)/'`cf-https-connect.c
+
+libcurl_la-cf-socket.lo: cf-socket.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cf-socket.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cf-socket.Tpo -c -o libcurl_la-cf-socket.lo `test -f 'cf-socket.c' || echo '$(srcdir)/'`cf-socket.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cf-socket.Tpo $(DEPDIR)/libcurl_la-cf-socket.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cf-socket.c' object='libcurl_la-cf-socket.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cf-socket.lo `test -f 'cf-socket.c' || echo '$(srcdir)/'`cf-socket.c
+
+libcurl_la-cfilters.lo: cfilters.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cfilters.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cfilters.Tpo -c -o libcurl_la-cfilters.lo `test -f 'cfilters.c' || echo '$(srcdir)/'`cfilters.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cfilters.Tpo $(DEPDIR)/libcurl_la-cfilters.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cfilters.c' object='libcurl_la-cfilters.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cfilters.lo `test -f 'cfilters.c' || echo '$(srcdir)/'`cfilters.c
+
+libcurl_la-conncache.lo: conncache.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-conncache.lo -MD -MP -MF $(DEPDIR)/libcurl_la-conncache.Tpo -c -o libcurl_la-conncache.lo `test -f 'conncache.c' || echo '$(srcdir)/'`conncache.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-conncache.Tpo $(DEPDIR)/libcurl_la-conncache.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='conncache.c' object='libcurl_la-conncache.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-conncache.lo `test -f 'conncache.c' || echo '$(srcdir)/'`conncache.c
+
+libcurl_la-connect.lo: connect.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-connect.lo -MD -MP -MF $(DEPDIR)/libcurl_la-connect.Tpo -c -o libcurl_la-connect.lo `test -f 'connect.c' || echo '$(srcdir)/'`connect.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-connect.Tpo $(DEPDIR)/libcurl_la-connect.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='connect.c' object='libcurl_la-connect.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-connect.lo `test -f 'connect.c' || echo '$(srcdir)/'`connect.c
+
+libcurl_la-content_encoding.lo: content_encoding.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-content_encoding.lo -MD -MP -MF $(DEPDIR)/libcurl_la-content_encoding.Tpo -c -o libcurl_la-content_encoding.lo `test -f 'content_encoding.c' || echo '$(srcdir)/'`content_encoding.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-content_encoding.Tpo $(DEPDIR)/libcurl_la-content_encoding.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='content_encoding.c' object='libcurl_la-content_encoding.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-content_encoding.lo `test -f 'content_encoding.c' || echo '$(srcdir)/'`content_encoding.c
+
+libcurl_la-cookie.lo: cookie.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cookie.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cookie.Tpo -c -o libcurl_la-cookie.lo `test -f 'cookie.c' || echo '$(srcdir)/'`cookie.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cookie.Tpo $(DEPDIR)/libcurl_la-cookie.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cookie.c' object='libcurl_la-cookie.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cookie.lo `test -f 'cookie.c' || echo '$(srcdir)/'`cookie.c
+
+libcurl_la-curl_addrinfo.lo: curl_addrinfo.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_addrinfo.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_addrinfo.Tpo -c -o libcurl_la-curl_addrinfo.lo `test -f 'curl_addrinfo.c' || echo '$(srcdir)/'`curl_addrinfo.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_addrinfo.Tpo $(DEPDIR)/libcurl_la-curl_addrinfo.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_addrinfo.c' object='libcurl_la-curl_addrinfo.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_addrinfo.lo `test -f 'curl_addrinfo.c' || echo '$(srcdir)/'`curl_addrinfo.c
+
+libcurl_la-curl_des.lo: curl_des.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_des.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_des.Tpo -c -o libcurl_la-curl_des.lo `test -f 'curl_des.c' || echo '$(srcdir)/'`curl_des.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_des.Tpo $(DEPDIR)/libcurl_la-curl_des.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_des.c' object='libcurl_la-curl_des.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_des.lo `test -f 'curl_des.c' || echo '$(srcdir)/'`curl_des.c
+
+libcurl_la-curl_endian.lo: curl_endian.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_endian.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_endian.Tpo -c -o libcurl_la-curl_endian.lo `test -f 'curl_endian.c' || echo '$(srcdir)/'`curl_endian.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_endian.Tpo $(DEPDIR)/libcurl_la-curl_endian.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_endian.c' object='libcurl_la-curl_endian.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_endian.lo `test -f 'curl_endian.c' || echo '$(srcdir)/'`curl_endian.c
+
+libcurl_la-curl_fnmatch.lo: curl_fnmatch.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_fnmatch.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_fnmatch.Tpo -c -o libcurl_la-curl_fnmatch.lo `test -f 'curl_fnmatch.c' || echo '$(srcdir)/'`curl_fnmatch.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_fnmatch.Tpo $(DEPDIR)/libcurl_la-curl_fnmatch.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_fnmatch.c' object='libcurl_la-curl_fnmatch.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_fnmatch.lo `test -f 'curl_fnmatch.c' || echo '$(srcdir)/'`curl_fnmatch.c
+
+libcurl_la-curl_get_line.lo: curl_get_line.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_get_line.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_get_line.Tpo -c -o libcurl_la-curl_get_line.lo `test -f 'curl_get_line.c' || echo '$(srcdir)/'`curl_get_line.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_get_line.Tpo $(DEPDIR)/libcurl_la-curl_get_line.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_get_line.c' object='libcurl_la-curl_get_line.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_get_line.lo `test -f 'curl_get_line.c' || echo '$(srcdir)/'`curl_get_line.c
+
+libcurl_la-curl_gethostname.lo: curl_gethostname.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_gethostname.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_gethostname.Tpo -c -o libcurl_la-curl_gethostname.lo `test -f 'curl_gethostname.c' || echo '$(srcdir)/'`curl_gethostname.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_gethostname.Tpo $(DEPDIR)/libcurl_la-curl_gethostname.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_gethostname.c' object='libcurl_la-curl_gethostname.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_gethostname.lo `test -f 'curl_gethostname.c' || echo '$(srcdir)/'`curl_gethostname.c
+
+libcurl_la-curl_gssapi.lo: curl_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_gssapi.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_gssapi.Tpo -c -o libcurl_la-curl_gssapi.lo `test -f 'curl_gssapi.c' || echo '$(srcdir)/'`curl_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_gssapi.Tpo $(DEPDIR)/libcurl_la-curl_gssapi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_gssapi.c' object='libcurl_la-curl_gssapi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_gssapi.lo `test -f 'curl_gssapi.c' || echo '$(srcdir)/'`curl_gssapi.c
+
+libcurl_la-curl_memrchr.lo: curl_memrchr.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_memrchr.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_memrchr.Tpo -c -o libcurl_la-curl_memrchr.lo `test -f 'curl_memrchr.c' || echo '$(srcdir)/'`curl_memrchr.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_memrchr.Tpo $(DEPDIR)/libcurl_la-curl_memrchr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_memrchr.c' object='libcurl_la-curl_memrchr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_memrchr.lo `test -f 'curl_memrchr.c' || echo '$(srcdir)/'`curl_memrchr.c
+
+libcurl_la-curl_multibyte.lo: curl_multibyte.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_multibyte.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_multibyte.Tpo -c -o libcurl_la-curl_multibyte.lo `test -f 'curl_multibyte.c' || echo '$(srcdir)/'`curl_multibyte.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_multibyte.Tpo $(DEPDIR)/libcurl_la-curl_multibyte.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_multibyte.c' object='libcurl_la-curl_multibyte.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_multibyte.lo `test -f 'curl_multibyte.c' || echo '$(srcdir)/'`curl_multibyte.c
+
+libcurl_la-curl_ntlm_core.lo: curl_ntlm_core.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_ntlm_core.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_ntlm_core.Tpo -c -o libcurl_la-curl_ntlm_core.lo `test -f 'curl_ntlm_core.c' || echo '$(srcdir)/'`curl_ntlm_core.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_ntlm_core.Tpo $(DEPDIR)/libcurl_la-curl_ntlm_core.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_ntlm_core.c' object='libcurl_la-curl_ntlm_core.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_ntlm_core.lo `test -f 'curl_ntlm_core.c' || echo '$(srcdir)/'`curl_ntlm_core.c
+
+libcurl_la-curl_ntlm_wb.lo: curl_ntlm_wb.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_ntlm_wb.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_ntlm_wb.Tpo -c -o libcurl_la-curl_ntlm_wb.lo `test -f 'curl_ntlm_wb.c' || echo '$(srcdir)/'`curl_ntlm_wb.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_ntlm_wb.Tpo $(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_ntlm_wb.c' object='libcurl_la-curl_ntlm_wb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_ntlm_wb.lo `test -f 'curl_ntlm_wb.c' || echo '$(srcdir)/'`curl_ntlm_wb.c
+
+libcurl_la-curl_path.lo: curl_path.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_path.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_path.Tpo -c -o libcurl_la-curl_path.lo `test -f 'curl_path.c' || echo '$(srcdir)/'`curl_path.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_path.Tpo $(DEPDIR)/libcurl_la-curl_path.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_path.c' object='libcurl_la-curl_path.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_path.lo `test -f 'curl_path.c' || echo '$(srcdir)/'`curl_path.c
+
+libcurl_la-curl_range.lo: curl_range.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_range.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_range.Tpo -c -o libcurl_la-curl_range.lo `test -f 'curl_range.c' || echo '$(srcdir)/'`curl_range.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_range.Tpo $(DEPDIR)/libcurl_la-curl_range.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_range.c' object='libcurl_la-curl_range.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_range.lo `test -f 'curl_range.c' || echo '$(srcdir)/'`curl_range.c
+
+libcurl_la-curl_rtmp.lo: curl_rtmp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_rtmp.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_rtmp.Tpo -c -o libcurl_la-curl_rtmp.lo `test -f 'curl_rtmp.c' || echo '$(srcdir)/'`curl_rtmp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_rtmp.Tpo $(DEPDIR)/libcurl_la-curl_rtmp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_rtmp.c' object='libcurl_la-curl_rtmp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_rtmp.lo `test -f 'curl_rtmp.c' || echo '$(srcdir)/'`curl_rtmp.c
+
+libcurl_la-curl_sasl.lo: curl_sasl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_sasl.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_sasl.Tpo -c -o libcurl_la-curl_sasl.lo `test -f 'curl_sasl.c' || echo '$(srcdir)/'`curl_sasl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_sasl.Tpo $(DEPDIR)/libcurl_la-curl_sasl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_sasl.c' object='libcurl_la-curl_sasl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_sasl.lo `test -f 'curl_sasl.c' || echo '$(srcdir)/'`curl_sasl.c
+
+libcurl_la-curl_sha512_256.lo: curl_sha512_256.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_sha512_256.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_sha512_256.Tpo -c -o libcurl_la-curl_sha512_256.lo `test -f 'curl_sha512_256.c' || echo '$(srcdir)/'`curl_sha512_256.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_sha512_256.Tpo $(DEPDIR)/libcurl_la-curl_sha512_256.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_sha512_256.c' object='libcurl_la-curl_sha512_256.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_sha512_256.lo `test -f 'curl_sha512_256.c' || echo '$(srcdir)/'`curl_sha512_256.c
+
+libcurl_la-curl_sspi.lo: curl_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_sspi.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_sspi.Tpo -c -o libcurl_la-curl_sspi.lo `test -f 'curl_sspi.c' || echo '$(srcdir)/'`curl_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_sspi.Tpo $(DEPDIR)/libcurl_la-curl_sspi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_sspi.c' object='libcurl_la-curl_sspi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_sspi.lo `test -f 'curl_sspi.c' || echo '$(srcdir)/'`curl_sspi.c
+
+libcurl_la-curl_threads.lo: curl_threads.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_threads.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_threads.Tpo -c -o libcurl_la-curl_threads.lo `test -f 'curl_threads.c' || echo '$(srcdir)/'`curl_threads.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_threads.Tpo $(DEPDIR)/libcurl_la-curl_threads.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_threads.c' object='libcurl_la-curl_threads.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_threads.lo `test -f 'curl_threads.c' || echo '$(srcdir)/'`curl_threads.c
+
+libcurl_la-curl_trc.lo: curl_trc.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_trc.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_trc.Tpo -c -o libcurl_la-curl_trc.lo `test -f 'curl_trc.c' || echo '$(srcdir)/'`curl_trc.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_trc.Tpo $(DEPDIR)/libcurl_la-curl_trc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_trc.c' object='libcurl_la-curl_trc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_trc.lo `test -f 'curl_trc.c' || echo '$(srcdir)/'`curl_trc.c
+
+libcurl_la-cw-out.lo: cw-out.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cw-out.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cw-out.Tpo -c -o libcurl_la-cw-out.lo `test -f 'cw-out.c' || echo '$(srcdir)/'`cw-out.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cw-out.Tpo $(DEPDIR)/libcurl_la-cw-out.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cw-out.c' object='libcurl_la-cw-out.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cw-out.lo `test -f 'cw-out.c' || echo '$(srcdir)/'`cw-out.c
+
+libcurl_la-dict.lo: dict.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-dict.lo -MD -MP -MF $(DEPDIR)/libcurl_la-dict.Tpo -c -o libcurl_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-dict.Tpo $(DEPDIR)/libcurl_la-dict.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='dict.c' object='libcurl_la-dict.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c
+
+libcurl_la-doh.lo: doh.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-doh.lo -MD -MP -MF $(DEPDIR)/libcurl_la-doh.Tpo -c -o libcurl_la-doh.lo `test -f 'doh.c' || echo '$(srcdir)/'`doh.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-doh.Tpo $(DEPDIR)/libcurl_la-doh.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='doh.c' object='libcurl_la-doh.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-doh.lo `test -f 'doh.c' || echo '$(srcdir)/'`doh.c
+
+libcurl_la-dynbuf.lo: dynbuf.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-dynbuf.lo -MD -MP -MF $(DEPDIR)/libcurl_la-dynbuf.Tpo -c -o libcurl_la-dynbuf.lo `test -f 'dynbuf.c' || echo '$(srcdir)/'`dynbuf.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-dynbuf.Tpo $(DEPDIR)/libcurl_la-dynbuf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='dynbuf.c' object='libcurl_la-dynbuf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-dynbuf.lo `test -f 'dynbuf.c' || echo '$(srcdir)/'`dynbuf.c
+
+libcurl_la-dynhds.lo: dynhds.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-dynhds.lo -MD -MP -MF $(DEPDIR)/libcurl_la-dynhds.Tpo -c -o libcurl_la-dynhds.lo `test -f 'dynhds.c' || echo '$(srcdir)/'`dynhds.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-dynhds.Tpo $(DEPDIR)/libcurl_la-dynhds.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='dynhds.c' object='libcurl_la-dynhds.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-dynhds.lo `test -f 'dynhds.c' || echo '$(srcdir)/'`dynhds.c
+
+libcurl_la-easy.lo: easy.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-easy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-easy.Tpo -c -o libcurl_la-easy.lo `test -f 'easy.c' || echo '$(srcdir)/'`easy.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-easy.Tpo $(DEPDIR)/libcurl_la-easy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='easy.c' object='libcurl_la-easy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-easy.lo `test -f 'easy.c' || echo '$(srcdir)/'`easy.c
+
+libcurl_la-easygetopt.lo: easygetopt.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-easygetopt.lo -MD -MP -MF $(DEPDIR)/libcurl_la-easygetopt.Tpo -c -o libcurl_la-easygetopt.lo `test -f 'easygetopt.c' || echo '$(srcdir)/'`easygetopt.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-easygetopt.Tpo $(DEPDIR)/libcurl_la-easygetopt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='easygetopt.c' object='libcurl_la-easygetopt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-easygetopt.lo `test -f 'easygetopt.c' || echo '$(srcdir)/'`easygetopt.c
+
+libcurl_la-easyoptions.lo: easyoptions.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-easyoptions.lo -MD -MP -MF $(DEPDIR)/libcurl_la-easyoptions.Tpo -c -o libcurl_la-easyoptions.lo `test -f 'easyoptions.c' || echo '$(srcdir)/'`easyoptions.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-easyoptions.Tpo $(DEPDIR)/libcurl_la-easyoptions.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='easyoptions.c' object='libcurl_la-easyoptions.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-easyoptions.lo `test -f 'easyoptions.c' || echo '$(srcdir)/'`easyoptions.c
+
+libcurl_la-escape.lo: escape.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-escape.lo -MD -MP -MF $(DEPDIR)/libcurl_la-escape.Tpo -c -o libcurl_la-escape.lo `test -f 'escape.c' || echo '$(srcdir)/'`escape.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-escape.Tpo $(DEPDIR)/libcurl_la-escape.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='escape.c' object='libcurl_la-escape.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-escape.lo `test -f 'escape.c' || echo '$(srcdir)/'`escape.c
+
+libcurl_la-file.lo: file.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-file.lo -MD -MP -MF $(DEPDIR)/libcurl_la-file.Tpo -c -o libcurl_la-file.lo `test -f 'file.c' || echo '$(srcdir)/'`file.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-file.Tpo $(DEPDIR)/libcurl_la-file.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='file.c' object='libcurl_la-file.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-file.lo `test -f 'file.c' || echo '$(srcdir)/'`file.c
+
+libcurl_la-fileinfo.lo: fileinfo.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-fileinfo.lo -MD -MP -MF $(DEPDIR)/libcurl_la-fileinfo.Tpo -c -o libcurl_la-fileinfo.lo `test -f 'fileinfo.c' || echo '$(srcdir)/'`fileinfo.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-fileinfo.Tpo $(DEPDIR)/libcurl_la-fileinfo.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='fileinfo.c' object='libcurl_la-fileinfo.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-fileinfo.lo `test -f 'fileinfo.c' || echo '$(srcdir)/'`fileinfo.c
+
+libcurl_la-fopen.lo: fopen.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-fopen.lo -MD -MP -MF $(DEPDIR)/libcurl_la-fopen.Tpo -c -o libcurl_la-fopen.lo `test -f 'fopen.c' || echo '$(srcdir)/'`fopen.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-fopen.Tpo $(DEPDIR)/libcurl_la-fopen.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='fopen.c' object='libcurl_la-fopen.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-fopen.lo `test -f 'fopen.c' || echo '$(srcdir)/'`fopen.c
+
+libcurl_la-formdata.lo: formdata.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-formdata.lo -MD -MP -MF $(DEPDIR)/libcurl_la-formdata.Tpo -c -o libcurl_la-formdata.lo `test -f 'formdata.c' || echo '$(srcdir)/'`formdata.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-formdata.Tpo $(DEPDIR)/libcurl_la-formdata.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='formdata.c' object='libcurl_la-formdata.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-formdata.lo `test -f 'formdata.c' || echo '$(srcdir)/'`formdata.c
+
+libcurl_la-ftp.lo: ftp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-ftp.lo -MD -MP -MF $(DEPDIR)/libcurl_la-ftp.Tpo -c -o libcurl_la-ftp.lo `test -f 'ftp.c' || echo '$(srcdir)/'`ftp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-ftp.Tpo $(DEPDIR)/libcurl_la-ftp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ftp.c' object='libcurl_la-ftp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-ftp.lo `test -f 'ftp.c' || echo '$(srcdir)/'`ftp.c
+
+libcurl_la-ftplistparser.lo: ftplistparser.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-ftplistparser.lo -MD -MP -MF $(DEPDIR)/libcurl_la-ftplistparser.Tpo -c -o libcurl_la-ftplistparser.lo `test -f 'ftplistparser.c' || echo '$(srcdir)/'`ftplistparser.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-ftplistparser.Tpo $(DEPDIR)/libcurl_la-ftplistparser.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ftplistparser.c' object='libcurl_la-ftplistparser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-ftplistparser.lo `test -f 'ftplistparser.c' || echo '$(srcdir)/'`ftplistparser.c
+
+libcurl_la-getenv.lo: getenv.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-getenv.lo -MD -MP -MF $(DEPDIR)/libcurl_la-getenv.Tpo -c -o libcurl_la-getenv.lo `test -f 'getenv.c' || echo '$(srcdir)/'`getenv.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-getenv.Tpo $(DEPDIR)/libcurl_la-getenv.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='getenv.c' object='libcurl_la-getenv.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-getenv.lo `test -f 'getenv.c' || echo '$(srcdir)/'`getenv.c
+
+libcurl_la-getinfo.lo: getinfo.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-getinfo.lo -MD -MP -MF $(DEPDIR)/libcurl_la-getinfo.Tpo -c -o libcurl_la-getinfo.lo `test -f 'getinfo.c' || echo '$(srcdir)/'`getinfo.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-getinfo.Tpo $(DEPDIR)/libcurl_la-getinfo.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='getinfo.c' object='libcurl_la-getinfo.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-getinfo.lo `test -f 'getinfo.c' || echo '$(srcdir)/'`getinfo.c
+
+libcurl_la-gopher.lo: gopher.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-gopher.lo -MD -MP -MF $(DEPDIR)/libcurl_la-gopher.Tpo -c -o libcurl_la-gopher.lo `test -f 'gopher.c' || echo '$(srcdir)/'`gopher.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-gopher.Tpo $(DEPDIR)/libcurl_la-gopher.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gopher.c' object='libcurl_la-gopher.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-gopher.lo `test -f 'gopher.c' || echo '$(srcdir)/'`gopher.c
+
+libcurl_la-hash.lo: hash.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hash.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hash.Tpo -c -o libcurl_la-hash.lo `test -f 'hash.c' || echo '$(srcdir)/'`hash.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hash.Tpo $(DEPDIR)/libcurl_la-hash.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hash.c' object='libcurl_la-hash.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hash.lo `test -f 'hash.c' || echo '$(srcdir)/'`hash.c
+
+libcurl_la-headers.lo: headers.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-headers.lo -MD -MP -MF $(DEPDIR)/libcurl_la-headers.Tpo -c -o libcurl_la-headers.lo `test -f 'headers.c' || echo '$(srcdir)/'`headers.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-headers.Tpo $(DEPDIR)/libcurl_la-headers.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='headers.c' object='libcurl_la-headers.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-headers.lo `test -f 'headers.c' || echo '$(srcdir)/'`headers.c
+
+libcurl_la-hmac.lo: hmac.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hmac.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hmac.Tpo -c -o libcurl_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hmac.Tpo $(DEPDIR)/libcurl_la-hmac.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hmac.c' object='libcurl_la-hmac.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c
+
+libcurl_la-hostasyn.lo: hostasyn.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hostasyn.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hostasyn.Tpo -c -o libcurl_la-hostasyn.lo `test -f 'hostasyn.c' || echo '$(srcdir)/'`hostasyn.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hostasyn.Tpo $(DEPDIR)/libcurl_la-hostasyn.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hostasyn.c' object='libcurl_la-hostasyn.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hostasyn.lo `test -f 'hostasyn.c' || echo '$(srcdir)/'`hostasyn.c
+
+libcurl_la-hostip.lo: hostip.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hostip.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hostip.Tpo -c -o libcurl_la-hostip.lo `test -f 'hostip.c' || echo '$(srcdir)/'`hostip.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hostip.Tpo $(DEPDIR)/libcurl_la-hostip.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hostip.c' object='libcurl_la-hostip.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hostip.lo `test -f 'hostip.c' || echo '$(srcdir)/'`hostip.c
+
+libcurl_la-hostip4.lo: hostip4.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hostip4.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hostip4.Tpo -c -o libcurl_la-hostip4.lo `test -f 'hostip4.c' || echo '$(srcdir)/'`hostip4.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hostip4.Tpo $(DEPDIR)/libcurl_la-hostip4.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hostip4.c' object='libcurl_la-hostip4.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hostip4.lo `test -f 'hostip4.c' || echo '$(srcdir)/'`hostip4.c
+
+libcurl_la-hostip6.lo: hostip6.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hostip6.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hostip6.Tpo -c -o libcurl_la-hostip6.lo `test -f 'hostip6.c' || echo '$(srcdir)/'`hostip6.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hostip6.Tpo $(DEPDIR)/libcurl_la-hostip6.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hostip6.c' object='libcurl_la-hostip6.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hostip6.lo `test -f 'hostip6.c' || echo '$(srcdir)/'`hostip6.c
+
+libcurl_la-hostsyn.lo: hostsyn.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hostsyn.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hostsyn.Tpo -c -o libcurl_la-hostsyn.lo `test -f 'hostsyn.c' || echo '$(srcdir)/'`hostsyn.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hostsyn.Tpo $(DEPDIR)/libcurl_la-hostsyn.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hostsyn.c' object='libcurl_la-hostsyn.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hostsyn.lo `test -f 'hostsyn.c' || echo '$(srcdir)/'`hostsyn.c
+
+libcurl_la-hsts.lo: hsts.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hsts.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hsts.Tpo -c -o libcurl_la-hsts.lo `test -f 'hsts.c' || echo '$(srcdir)/'`hsts.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hsts.Tpo $(DEPDIR)/libcurl_la-hsts.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hsts.c' object='libcurl_la-hsts.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hsts.lo `test -f 'hsts.c' || echo '$(srcdir)/'`hsts.c
+
+libcurl_la-http.lo: http.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http.Tpo -c -o libcurl_la-http.lo `test -f 'http.c' || echo '$(srcdir)/'`http.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http.Tpo $(DEPDIR)/libcurl_la-http.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http.c' object='libcurl_la-http.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http.lo `test -f 'http.c' || echo '$(srcdir)/'`http.c
+
+libcurl_la-http1.lo: http1.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http1.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http1.Tpo -c -o libcurl_la-http1.lo `test -f 'http1.c' || echo '$(srcdir)/'`http1.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http1.Tpo $(DEPDIR)/libcurl_la-http1.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http1.c' object='libcurl_la-http1.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http1.lo `test -f 'http1.c' || echo '$(srcdir)/'`http1.c
+
+libcurl_la-http2.lo: http2.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http2.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http2.Tpo -c -o libcurl_la-http2.lo `test -f 'http2.c' || echo '$(srcdir)/'`http2.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http2.Tpo $(DEPDIR)/libcurl_la-http2.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http2.c' object='libcurl_la-http2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http2.lo `test -f 'http2.c' || echo '$(srcdir)/'`http2.c
+
+libcurl_la-http_aws_sigv4.lo: http_aws_sigv4.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http_aws_sigv4.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http_aws_sigv4.Tpo -c -o libcurl_la-http_aws_sigv4.lo `test -f 'http_aws_sigv4.c' || echo '$(srcdir)/'`http_aws_sigv4.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http_aws_sigv4.Tpo $(DEPDIR)/libcurl_la-http_aws_sigv4.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http_aws_sigv4.c' object='libcurl_la-http_aws_sigv4.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http_aws_sigv4.lo `test -f 'http_aws_sigv4.c' || echo '$(srcdir)/'`http_aws_sigv4.c
+
+libcurl_la-http_chunks.lo: http_chunks.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http_chunks.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http_chunks.Tpo -c -o libcurl_la-http_chunks.lo `test -f 'http_chunks.c' || echo '$(srcdir)/'`http_chunks.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http_chunks.Tpo $(DEPDIR)/libcurl_la-http_chunks.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http_chunks.c' object='libcurl_la-http_chunks.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http_chunks.lo `test -f 'http_chunks.c' || echo '$(srcdir)/'`http_chunks.c
+
+libcurl_la-http_digest.lo: http_digest.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http_digest.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http_digest.Tpo -c -o libcurl_la-http_digest.lo `test -f 'http_digest.c' || echo '$(srcdir)/'`http_digest.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http_digest.Tpo $(DEPDIR)/libcurl_la-http_digest.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http_digest.c' object='libcurl_la-http_digest.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http_digest.lo `test -f 'http_digest.c' || echo '$(srcdir)/'`http_digest.c
+
+libcurl_la-http_negotiate.lo: http_negotiate.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http_negotiate.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http_negotiate.Tpo -c -o libcurl_la-http_negotiate.lo `test -f 'http_negotiate.c' || echo '$(srcdir)/'`http_negotiate.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http_negotiate.Tpo $(DEPDIR)/libcurl_la-http_negotiate.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http_negotiate.c' object='libcurl_la-http_negotiate.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http_negotiate.lo `test -f 'http_negotiate.c' || echo '$(srcdir)/'`http_negotiate.c
+
+libcurl_la-http_ntlm.lo: http_ntlm.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http_ntlm.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http_ntlm.Tpo -c -o libcurl_la-http_ntlm.lo `test -f 'http_ntlm.c' || echo '$(srcdir)/'`http_ntlm.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http_ntlm.Tpo $(DEPDIR)/libcurl_la-http_ntlm.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http_ntlm.c' object='libcurl_la-http_ntlm.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http_ntlm.lo `test -f 'http_ntlm.c' || echo '$(srcdir)/'`http_ntlm.c
+
+libcurl_la-http_proxy.lo: http_proxy.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-http_proxy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-http_proxy.Tpo -c -o libcurl_la-http_proxy.lo `test -f 'http_proxy.c' || echo '$(srcdir)/'`http_proxy.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-http_proxy.Tpo $(DEPDIR)/libcurl_la-http_proxy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http_proxy.c' object='libcurl_la-http_proxy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-http_proxy.lo `test -f 'http_proxy.c' || echo '$(srcdir)/'`http_proxy.c
+
+libcurl_la-idn.lo: idn.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-idn.lo -MD -MP -MF $(DEPDIR)/libcurl_la-idn.Tpo -c -o libcurl_la-idn.lo `test -f 'idn.c' || echo '$(srcdir)/'`idn.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-idn.Tpo $(DEPDIR)/libcurl_la-idn.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='idn.c' object='libcurl_la-idn.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-idn.lo `test -f 'idn.c' || echo '$(srcdir)/'`idn.c
+
+libcurl_la-if2ip.lo: if2ip.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-if2ip.lo -MD -MP -MF $(DEPDIR)/libcurl_la-if2ip.Tpo -c -o libcurl_la-if2ip.lo `test -f 'if2ip.c' || echo '$(srcdir)/'`if2ip.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-if2ip.Tpo $(DEPDIR)/libcurl_la-if2ip.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='if2ip.c' object='libcurl_la-if2ip.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-if2ip.lo `test -f 'if2ip.c' || echo '$(srcdir)/'`if2ip.c
+
+libcurl_la-imap.lo: imap.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-imap.lo -MD -MP -MF $(DEPDIR)/libcurl_la-imap.Tpo -c -o libcurl_la-imap.lo `test -f 'imap.c' || echo '$(srcdir)/'`imap.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-imap.Tpo $(DEPDIR)/libcurl_la-imap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='imap.c' object='libcurl_la-imap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-imap.lo `test -f 'imap.c' || echo '$(srcdir)/'`imap.c
+
+libcurl_la-inet_ntop.lo: inet_ntop.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-inet_ntop.lo -MD -MP -MF $(DEPDIR)/libcurl_la-inet_ntop.Tpo -c -o libcurl_la-inet_ntop.lo `test -f 'inet_ntop.c' || echo '$(srcdir)/'`inet_ntop.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-inet_ntop.Tpo $(DEPDIR)/libcurl_la-inet_ntop.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='inet_ntop.c' object='libcurl_la-inet_ntop.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-inet_ntop.lo `test -f 'inet_ntop.c' || echo '$(srcdir)/'`inet_ntop.c
+
+libcurl_la-inet_pton.lo: inet_pton.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-inet_pton.lo -MD -MP -MF $(DEPDIR)/libcurl_la-inet_pton.Tpo -c -o libcurl_la-inet_pton.lo `test -f 'inet_pton.c' || echo '$(srcdir)/'`inet_pton.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-inet_pton.Tpo $(DEPDIR)/libcurl_la-inet_pton.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='inet_pton.c' object='libcurl_la-inet_pton.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-inet_pton.lo `test -f 'inet_pton.c' || echo '$(srcdir)/'`inet_pton.c
+
+libcurl_la-krb5.lo: krb5.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-krb5.lo -MD -MP -MF $(DEPDIR)/libcurl_la-krb5.Tpo -c -o libcurl_la-krb5.lo `test -f 'krb5.c' || echo '$(srcdir)/'`krb5.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-krb5.Tpo $(DEPDIR)/libcurl_la-krb5.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='krb5.c' object='libcurl_la-krb5.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-krb5.lo `test -f 'krb5.c' || echo '$(srcdir)/'`krb5.c
+
+libcurl_la-ldap.lo: ldap.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-ldap.lo -MD -MP -MF $(DEPDIR)/libcurl_la-ldap.Tpo -c -o libcurl_la-ldap.lo `test -f 'ldap.c' || echo '$(srcdir)/'`ldap.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-ldap.Tpo $(DEPDIR)/libcurl_la-ldap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ldap.c' object='libcurl_la-ldap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-ldap.lo `test -f 'ldap.c' || echo '$(srcdir)/'`ldap.c
+
+libcurl_la-llist.lo: llist.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-llist.lo -MD -MP -MF $(DEPDIR)/libcurl_la-llist.Tpo -c -o libcurl_la-llist.lo `test -f 'llist.c' || echo '$(srcdir)/'`llist.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-llist.Tpo $(DEPDIR)/libcurl_la-llist.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='llist.c' object='libcurl_la-llist.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-llist.lo `test -f 'llist.c' || echo '$(srcdir)/'`llist.c
+
+libcurl_la-macos.lo: macos.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-macos.lo -MD -MP -MF $(DEPDIR)/libcurl_la-macos.Tpo -c -o libcurl_la-macos.lo `test -f 'macos.c' || echo '$(srcdir)/'`macos.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-macos.Tpo $(DEPDIR)/libcurl_la-macos.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='macos.c' object='libcurl_la-macos.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-macos.lo `test -f 'macos.c' || echo '$(srcdir)/'`macos.c
+
+libcurl_la-md4.lo: md4.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-md4.lo -MD -MP -MF $(DEPDIR)/libcurl_la-md4.Tpo -c -o libcurl_la-md4.lo `test -f 'md4.c' || echo '$(srcdir)/'`md4.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-md4.Tpo $(DEPDIR)/libcurl_la-md4.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='md4.c' object='libcurl_la-md4.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-md4.lo `test -f 'md4.c' || echo '$(srcdir)/'`md4.c
+
+libcurl_la-md5.lo: md5.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-md5.lo -MD -MP -MF $(DEPDIR)/libcurl_la-md5.Tpo -c -o libcurl_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-md5.Tpo $(DEPDIR)/libcurl_la-md5.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='md5.c' object='libcurl_la-md5.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
+
+libcurl_la-memdebug.lo: memdebug.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-memdebug.lo -MD -MP -MF $(DEPDIR)/libcurl_la-memdebug.Tpo -c -o libcurl_la-memdebug.lo `test -f 'memdebug.c' || echo '$(srcdir)/'`memdebug.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-memdebug.Tpo $(DEPDIR)/libcurl_la-memdebug.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='memdebug.c' object='libcurl_la-memdebug.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-memdebug.lo `test -f 'memdebug.c' || echo '$(srcdir)/'`memdebug.c
+
+libcurl_la-mime.lo: mime.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-mime.lo -MD -MP -MF $(DEPDIR)/libcurl_la-mime.Tpo -c -o libcurl_la-mime.lo `test -f 'mime.c' || echo '$(srcdir)/'`mime.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-mime.Tpo $(DEPDIR)/libcurl_la-mime.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='mime.c' object='libcurl_la-mime.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-mime.lo `test -f 'mime.c' || echo '$(srcdir)/'`mime.c
+
+libcurl_la-mprintf.lo: mprintf.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-mprintf.lo -MD -MP -MF $(DEPDIR)/libcurl_la-mprintf.Tpo -c -o libcurl_la-mprintf.lo `test -f 'mprintf.c' || echo '$(srcdir)/'`mprintf.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-mprintf.Tpo $(DEPDIR)/libcurl_la-mprintf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='mprintf.c' object='libcurl_la-mprintf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-mprintf.lo `test -f 'mprintf.c' || echo '$(srcdir)/'`mprintf.c
+
+libcurl_la-mqtt.lo: mqtt.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-mqtt.lo -MD -MP -MF $(DEPDIR)/libcurl_la-mqtt.Tpo -c -o libcurl_la-mqtt.lo `test -f 'mqtt.c' || echo '$(srcdir)/'`mqtt.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-mqtt.Tpo $(DEPDIR)/libcurl_la-mqtt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='mqtt.c' object='libcurl_la-mqtt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-mqtt.lo `test -f 'mqtt.c' || echo '$(srcdir)/'`mqtt.c
+
+libcurl_la-multi.lo: multi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-multi.lo -MD -MP -MF $(DEPDIR)/libcurl_la-multi.Tpo -c -o libcurl_la-multi.lo `test -f 'multi.c' || echo '$(srcdir)/'`multi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-multi.Tpo $(DEPDIR)/libcurl_la-multi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='multi.c' object='libcurl_la-multi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-multi.lo `test -f 'multi.c' || echo '$(srcdir)/'`multi.c
+
+libcurl_la-netrc.lo: netrc.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-netrc.lo -MD -MP -MF $(DEPDIR)/libcurl_la-netrc.Tpo -c -o libcurl_la-netrc.lo `test -f 'netrc.c' || echo '$(srcdir)/'`netrc.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-netrc.Tpo $(DEPDIR)/libcurl_la-netrc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='netrc.c' object='libcurl_la-netrc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-netrc.lo `test -f 'netrc.c' || echo '$(srcdir)/'`netrc.c
+
+libcurl_la-nonblock.lo: nonblock.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-nonblock.lo -MD -MP -MF $(DEPDIR)/libcurl_la-nonblock.Tpo -c -o libcurl_la-nonblock.lo `test -f 'nonblock.c' || echo '$(srcdir)/'`nonblock.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-nonblock.Tpo $(DEPDIR)/libcurl_la-nonblock.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nonblock.c' object='libcurl_la-nonblock.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-nonblock.lo `test -f 'nonblock.c' || echo '$(srcdir)/'`nonblock.c
+
+libcurl_la-noproxy.lo: noproxy.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-noproxy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-noproxy.Tpo -c -o libcurl_la-noproxy.lo `test -f 'noproxy.c' || echo '$(srcdir)/'`noproxy.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-noproxy.Tpo $(DEPDIR)/libcurl_la-noproxy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='noproxy.c' object='libcurl_la-noproxy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-noproxy.lo `test -f 'noproxy.c' || echo '$(srcdir)/'`noproxy.c
+
+libcurl_la-openldap.lo: openldap.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-openldap.lo -MD -MP -MF $(DEPDIR)/libcurl_la-openldap.Tpo -c -o libcurl_la-openldap.lo `test -f 'openldap.c' || echo '$(srcdir)/'`openldap.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-openldap.Tpo $(DEPDIR)/libcurl_la-openldap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='openldap.c' object='libcurl_la-openldap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-openldap.lo `test -f 'openldap.c' || echo '$(srcdir)/'`openldap.c
+
+libcurl_la-parsedate.lo: parsedate.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-parsedate.lo -MD -MP -MF $(DEPDIR)/libcurl_la-parsedate.Tpo -c -o libcurl_la-parsedate.lo `test -f 'parsedate.c' || echo '$(srcdir)/'`parsedate.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-parsedate.Tpo $(DEPDIR)/libcurl_la-parsedate.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='parsedate.c' object='libcurl_la-parsedate.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-parsedate.lo `test -f 'parsedate.c' || echo '$(srcdir)/'`parsedate.c
+
+libcurl_la-pingpong.lo: pingpong.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-pingpong.lo -MD -MP -MF $(DEPDIR)/libcurl_la-pingpong.Tpo -c -o libcurl_la-pingpong.lo `test -f 'pingpong.c' || echo '$(srcdir)/'`pingpong.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-pingpong.Tpo $(DEPDIR)/libcurl_la-pingpong.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='pingpong.c' object='libcurl_la-pingpong.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-pingpong.lo `test -f 'pingpong.c' || echo '$(srcdir)/'`pingpong.c
+
+libcurl_la-pop3.lo: pop3.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-pop3.lo -MD -MP -MF $(DEPDIR)/libcurl_la-pop3.Tpo -c -o libcurl_la-pop3.lo `test -f 'pop3.c' || echo '$(srcdir)/'`pop3.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-pop3.Tpo $(DEPDIR)/libcurl_la-pop3.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='pop3.c' object='libcurl_la-pop3.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-pop3.lo `test -f 'pop3.c' || echo '$(srcdir)/'`pop3.c
+
+libcurl_la-progress.lo: progress.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-progress.lo -MD -MP -MF $(DEPDIR)/libcurl_la-progress.Tpo -c -o libcurl_la-progress.lo `test -f 'progress.c' || echo '$(srcdir)/'`progress.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-progress.Tpo $(DEPDIR)/libcurl_la-progress.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='progress.c' object='libcurl_la-progress.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-progress.lo `test -f 'progress.c' || echo '$(srcdir)/'`progress.c
+
+libcurl_la-psl.lo: psl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-psl.lo -MD -MP -MF $(DEPDIR)/libcurl_la-psl.Tpo -c -o libcurl_la-psl.lo `test -f 'psl.c' || echo '$(srcdir)/'`psl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-psl.Tpo $(DEPDIR)/libcurl_la-psl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='psl.c' object='libcurl_la-psl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-psl.lo `test -f 'psl.c' || echo '$(srcdir)/'`psl.c
+
+libcurl_la-rand.lo: rand.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-rand.lo -MD -MP -MF $(DEPDIR)/libcurl_la-rand.Tpo -c -o libcurl_la-rand.lo `test -f 'rand.c' || echo '$(srcdir)/'`rand.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-rand.Tpo $(DEPDIR)/libcurl_la-rand.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='rand.c' object='libcurl_la-rand.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-rand.lo `test -f 'rand.c' || echo '$(srcdir)/'`rand.c
+
+libcurl_la-rename.lo: rename.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-rename.lo -MD -MP -MF $(DEPDIR)/libcurl_la-rename.Tpo -c -o libcurl_la-rename.lo `test -f 'rename.c' || echo '$(srcdir)/'`rename.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-rename.Tpo $(DEPDIR)/libcurl_la-rename.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='rename.c' object='libcurl_la-rename.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-rename.lo `test -f 'rename.c' || echo '$(srcdir)/'`rename.c
+
+libcurl_la-request.lo: request.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-request.lo -MD -MP -MF $(DEPDIR)/libcurl_la-request.Tpo -c -o libcurl_la-request.lo `test -f 'request.c' || echo '$(srcdir)/'`request.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-request.Tpo $(DEPDIR)/libcurl_la-request.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='request.c' object='libcurl_la-request.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-request.lo `test -f 'request.c' || echo '$(srcdir)/'`request.c
+
+libcurl_la-rtsp.lo: rtsp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-rtsp.lo -MD -MP -MF $(DEPDIR)/libcurl_la-rtsp.Tpo -c -o libcurl_la-rtsp.lo `test -f 'rtsp.c' || echo '$(srcdir)/'`rtsp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-rtsp.Tpo $(DEPDIR)/libcurl_la-rtsp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='rtsp.c' object='libcurl_la-rtsp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-rtsp.lo `test -f 'rtsp.c' || echo '$(srcdir)/'`rtsp.c
+
+libcurl_la-select.lo: select.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-select.lo -MD -MP -MF $(DEPDIR)/libcurl_la-select.Tpo -c -o libcurl_la-select.lo `test -f 'select.c' || echo '$(srcdir)/'`select.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-select.Tpo $(DEPDIR)/libcurl_la-select.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='select.c' object='libcurl_la-select.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-select.lo `test -f 'select.c' || echo '$(srcdir)/'`select.c
+
+libcurl_la-sendf.lo: sendf.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-sendf.lo -MD -MP -MF $(DEPDIR)/libcurl_la-sendf.Tpo -c -o libcurl_la-sendf.lo `test -f 'sendf.c' || echo '$(srcdir)/'`sendf.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-sendf.Tpo $(DEPDIR)/libcurl_la-sendf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sendf.c' object='libcurl_la-sendf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-sendf.lo `test -f 'sendf.c' || echo '$(srcdir)/'`sendf.c
+
+libcurl_la-setopt.lo: setopt.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-setopt.lo -MD -MP -MF $(DEPDIR)/libcurl_la-setopt.Tpo -c -o libcurl_la-setopt.lo `test -f 'setopt.c' || echo '$(srcdir)/'`setopt.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-setopt.Tpo $(DEPDIR)/libcurl_la-setopt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='setopt.c' object='libcurl_la-setopt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-setopt.lo `test -f 'setopt.c' || echo '$(srcdir)/'`setopt.c
+
+libcurl_la-sha256.lo: sha256.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-sha256.lo -MD -MP -MF $(DEPDIR)/libcurl_la-sha256.Tpo -c -o libcurl_la-sha256.lo `test -f 'sha256.c' || echo '$(srcdir)/'`sha256.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-sha256.Tpo $(DEPDIR)/libcurl_la-sha256.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sha256.c' object='libcurl_la-sha256.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-sha256.lo `test -f 'sha256.c' || echo '$(srcdir)/'`sha256.c
+
+libcurl_la-share.lo: share.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-share.lo -MD -MP -MF $(DEPDIR)/libcurl_la-share.Tpo -c -o libcurl_la-share.lo `test -f 'share.c' || echo '$(srcdir)/'`share.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-share.Tpo $(DEPDIR)/libcurl_la-share.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='share.c' object='libcurl_la-share.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-share.lo `test -f 'share.c' || echo '$(srcdir)/'`share.c
+
+libcurl_la-slist.lo: slist.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-slist.lo -MD -MP -MF $(DEPDIR)/libcurl_la-slist.Tpo -c -o libcurl_la-slist.lo `test -f 'slist.c' || echo '$(srcdir)/'`slist.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-slist.Tpo $(DEPDIR)/libcurl_la-slist.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='slist.c' object='libcurl_la-slist.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-slist.lo `test -f 'slist.c' || echo '$(srcdir)/'`slist.c
+
+libcurl_la-smb.lo: smb.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-smb.lo -MD -MP -MF $(DEPDIR)/libcurl_la-smb.Tpo -c -o libcurl_la-smb.lo `test -f 'smb.c' || echo '$(srcdir)/'`smb.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-smb.Tpo $(DEPDIR)/libcurl_la-smb.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='smb.c' object='libcurl_la-smb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-smb.lo `test -f 'smb.c' || echo '$(srcdir)/'`smb.c
+
+libcurl_la-smtp.lo: smtp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-smtp.lo -MD -MP -MF $(DEPDIR)/libcurl_la-smtp.Tpo -c -o libcurl_la-smtp.lo `test -f 'smtp.c' || echo '$(srcdir)/'`smtp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-smtp.Tpo $(DEPDIR)/libcurl_la-smtp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='smtp.c' object='libcurl_la-smtp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-smtp.lo `test -f 'smtp.c' || echo '$(srcdir)/'`smtp.c
+
+libcurl_la-socketpair.lo: socketpair.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-socketpair.lo -MD -MP -MF $(DEPDIR)/libcurl_la-socketpair.Tpo -c -o libcurl_la-socketpair.lo `test -f 'socketpair.c' || echo '$(srcdir)/'`socketpair.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-socketpair.Tpo $(DEPDIR)/libcurl_la-socketpair.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='socketpair.c' object='libcurl_la-socketpair.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-socketpair.lo `test -f 'socketpair.c' || echo '$(srcdir)/'`socketpair.c
+
+libcurl_la-socks.lo: socks.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-socks.lo -MD -MP -MF $(DEPDIR)/libcurl_la-socks.Tpo -c -o libcurl_la-socks.lo `test -f 'socks.c' || echo '$(srcdir)/'`socks.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-socks.Tpo $(DEPDIR)/libcurl_la-socks.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='socks.c' object='libcurl_la-socks.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-socks.lo `test -f 'socks.c' || echo '$(srcdir)/'`socks.c
+
+libcurl_la-socks_gssapi.lo: socks_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-socks_gssapi.lo -MD -MP -MF $(DEPDIR)/libcurl_la-socks_gssapi.Tpo -c -o libcurl_la-socks_gssapi.lo `test -f 'socks_gssapi.c' || echo '$(srcdir)/'`socks_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-socks_gssapi.Tpo $(DEPDIR)/libcurl_la-socks_gssapi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='socks_gssapi.c' object='libcurl_la-socks_gssapi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-socks_gssapi.lo `test -f 'socks_gssapi.c' || echo '$(srcdir)/'`socks_gssapi.c
+
+libcurl_la-socks_sspi.lo: socks_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-socks_sspi.lo -MD -MP -MF $(DEPDIR)/libcurl_la-socks_sspi.Tpo -c -o libcurl_la-socks_sspi.lo `test -f 'socks_sspi.c' || echo '$(srcdir)/'`socks_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-socks_sspi.Tpo $(DEPDIR)/libcurl_la-socks_sspi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='socks_sspi.c' object='libcurl_la-socks_sspi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-socks_sspi.lo `test -f 'socks_sspi.c' || echo '$(srcdir)/'`socks_sspi.c
+
+libcurl_la-speedcheck.lo: speedcheck.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-speedcheck.lo -MD -MP -MF $(DEPDIR)/libcurl_la-speedcheck.Tpo -c -o libcurl_la-speedcheck.lo `test -f 'speedcheck.c' || echo '$(srcdir)/'`speedcheck.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-speedcheck.Tpo $(DEPDIR)/libcurl_la-speedcheck.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='speedcheck.c' object='libcurl_la-speedcheck.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-speedcheck.lo `test -f 'speedcheck.c' || echo '$(srcdir)/'`speedcheck.c
+
+libcurl_la-splay.lo: splay.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-splay.lo -MD -MP -MF $(DEPDIR)/libcurl_la-splay.Tpo -c -o libcurl_la-splay.lo `test -f 'splay.c' || echo '$(srcdir)/'`splay.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-splay.Tpo $(DEPDIR)/libcurl_la-splay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='splay.c' object='libcurl_la-splay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-splay.lo `test -f 'splay.c' || echo '$(srcdir)/'`splay.c
+
+libcurl_la-strcase.lo: strcase.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strcase.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strcase.Tpo -c -o libcurl_la-strcase.lo `test -f 'strcase.c' || echo '$(srcdir)/'`strcase.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strcase.Tpo $(DEPDIR)/libcurl_la-strcase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='strcase.c' object='libcurl_la-strcase.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strcase.lo `test -f 'strcase.c' || echo '$(srcdir)/'`strcase.c
+
+libcurl_la-strdup.lo: strdup.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strdup.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strdup.Tpo -c -o libcurl_la-strdup.lo `test -f 'strdup.c' || echo '$(srcdir)/'`strdup.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strdup.Tpo $(DEPDIR)/libcurl_la-strdup.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='strdup.c' object='libcurl_la-strdup.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strdup.lo `test -f 'strdup.c' || echo '$(srcdir)/'`strdup.c
+
+libcurl_la-strerror.lo: strerror.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strerror.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strerror.Tpo -c -o libcurl_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strerror.Tpo $(DEPDIR)/libcurl_la-strerror.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='strerror.c' object='libcurl_la-strerror.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c
+
+libcurl_la-strtok.lo: strtok.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strtok.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strtok.Tpo -c -o libcurl_la-strtok.lo `test -f 'strtok.c' || echo '$(srcdir)/'`strtok.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strtok.Tpo $(DEPDIR)/libcurl_la-strtok.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='strtok.c' object='libcurl_la-strtok.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strtok.lo `test -f 'strtok.c' || echo '$(srcdir)/'`strtok.c
+
+libcurl_la-strtoofft.lo: strtoofft.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strtoofft.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strtoofft.Tpo -c -o libcurl_la-strtoofft.lo `test -f 'strtoofft.c' || echo '$(srcdir)/'`strtoofft.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strtoofft.Tpo $(DEPDIR)/libcurl_la-strtoofft.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='strtoofft.c' object='libcurl_la-strtoofft.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strtoofft.lo `test -f 'strtoofft.c' || echo '$(srcdir)/'`strtoofft.c
+
+libcurl_la-system_win32.lo: system_win32.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-system_win32.lo -MD -MP -MF $(DEPDIR)/libcurl_la-system_win32.Tpo -c -o libcurl_la-system_win32.lo `test -f 'system_win32.c' || echo '$(srcdir)/'`system_win32.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-system_win32.Tpo $(DEPDIR)/libcurl_la-system_win32.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='system_win32.c' object='libcurl_la-system_win32.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-system_win32.lo `test -f 'system_win32.c' || echo '$(srcdir)/'`system_win32.c
+
+libcurl_la-telnet.lo: telnet.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-telnet.lo -MD -MP -MF $(DEPDIR)/libcurl_la-telnet.Tpo -c -o libcurl_la-telnet.lo `test -f 'telnet.c' || echo '$(srcdir)/'`telnet.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-telnet.Tpo $(DEPDIR)/libcurl_la-telnet.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='telnet.c' object='libcurl_la-telnet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-telnet.lo `test -f 'telnet.c' || echo '$(srcdir)/'`telnet.c
+
+libcurl_la-tftp.lo: tftp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-tftp.lo -MD -MP -MF $(DEPDIR)/libcurl_la-tftp.Tpo -c -o libcurl_la-tftp.lo `test -f 'tftp.c' || echo '$(srcdir)/'`tftp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-tftp.Tpo $(DEPDIR)/libcurl_la-tftp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tftp.c' object='libcurl_la-tftp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-tftp.lo `test -f 'tftp.c' || echo '$(srcdir)/'`tftp.c
+
+libcurl_la-timediff.lo: timediff.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-timediff.lo -MD -MP -MF $(DEPDIR)/libcurl_la-timediff.Tpo -c -o libcurl_la-timediff.lo `test -f 'timediff.c' || echo '$(srcdir)/'`timediff.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-timediff.Tpo $(DEPDIR)/libcurl_la-timediff.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='timediff.c' object='libcurl_la-timediff.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-timediff.lo `test -f 'timediff.c' || echo '$(srcdir)/'`timediff.c
+
+libcurl_la-timeval.lo: timeval.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-timeval.lo -MD -MP -MF $(DEPDIR)/libcurl_la-timeval.Tpo -c -o libcurl_la-timeval.lo `test -f 'timeval.c' || echo '$(srcdir)/'`timeval.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-timeval.Tpo $(DEPDIR)/libcurl_la-timeval.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='timeval.c' object='libcurl_la-timeval.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-timeval.lo `test -f 'timeval.c' || echo '$(srcdir)/'`timeval.c
+
+libcurl_la-transfer.lo: transfer.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-transfer.lo -MD -MP -MF $(DEPDIR)/libcurl_la-transfer.Tpo -c -o libcurl_la-transfer.lo `test -f 'transfer.c' || echo '$(srcdir)/'`transfer.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-transfer.Tpo $(DEPDIR)/libcurl_la-transfer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='transfer.c' object='libcurl_la-transfer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-transfer.lo `test -f 'transfer.c' || echo '$(srcdir)/'`transfer.c
+
+libcurl_la-url.lo: url.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-url.lo -MD -MP -MF $(DEPDIR)/libcurl_la-url.Tpo -c -o libcurl_la-url.lo `test -f 'url.c' || echo '$(srcdir)/'`url.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-url.Tpo $(DEPDIR)/libcurl_la-url.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='url.c' object='libcurl_la-url.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-url.lo `test -f 'url.c' || echo '$(srcdir)/'`url.c
+
+libcurl_la-urlapi.lo: urlapi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-urlapi.lo -MD -MP -MF $(DEPDIR)/libcurl_la-urlapi.Tpo -c -o libcurl_la-urlapi.lo `test -f 'urlapi.c' || echo '$(srcdir)/'`urlapi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-urlapi.Tpo $(DEPDIR)/libcurl_la-urlapi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='urlapi.c' object='libcurl_la-urlapi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-urlapi.lo `test -f 'urlapi.c' || echo '$(srcdir)/'`urlapi.c
+
+libcurl_la-version.lo: version.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-version.lo -MD -MP -MF $(DEPDIR)/libcurl_la-version.Tpo -c -o libcurl_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-version.Tpo $(DEPDIR)/libcurl_la-version.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='version.c' object='libcurl_la-version.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c
+
+libcurl_la-version_win32.lo: version_win32.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-version_win32.lo -MD -MP -MF $(DEPDIR)/libcurl_la-version_win32.Tpo -c -o libcurl_la-version_win32.lo `test -f 'version_win32.c' || echo '$(srcdir)/'`version_win32.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-version_win32.Tpo $(DEPDIR)/libcurl_la-version_win32.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='version_win32.c' object='libcurl_la-version_win32.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-version_win32.lo `test -f 'version_win32.c' || echo '$(srcdir)/'`version_win32.c
+
+libcurl_la-warnless.lo: warnless.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-warnless.lo -MD -MP -MF $(DEPDIR)/libcurl_la-warnless.Tpo -c -o libcurl_la-warnless.lo `test -f 'warnless.c' || echo '$(srcdir)/'`warnless.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-warnless.Tpo $(DEPDIR)/libcurl_la-warnless.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='warnless.c' object='libcurl_la-warnless.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-warnless.lo `test -f 'warnless.c' || echo '$(srcdir)/'`warnless.c
+
+libcurl_la-ws.lo: ws.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-ws.lo -MD -MP -MF $(DEPDIR)/libcurl_la-ws.Tpo -c -o libcurl_la-ws.lo `test -f 'ws.c' || echo '$(srcdir)/'`ws.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-ws.Tpo $(DEPDIR)/libcurl_la-ws.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ws.c' object='libcurl_la-ws.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-ws.lo `test -f 'ws.c' || echo '$(srcdir)/'`ws.c
+
+vauth/libcurl_la-cleartext.lo: vauth/cleartext.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-cleartext.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-cleartext.Tpo -c -o vauth/libcurl_la-cleartext.lo `test -f 'vauth/cleartext.c' || echo '$(srcdir)/'`vauth/cleartext.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-cleartext.Tpo vauth/$(DEPDIR)/libcurl_la-cleartext.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/cleartext.c' object='vauth/libcurl_la-cleartext.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-cleartext.lo `test -f 'vauth/cleartext.c' || echo '$(srcdir)/'`vauth/cleartext.c
+
+vauth/libcurl_la-cram.lo: vauth/cram.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-cram.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-cram.Tpo -c -o vauth/libcurl_la-cram.lo `test -f 'vauth/cram.c' || echo '$(srcdir)/'`vauth/cram.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-cram.Tpo vauth/$(DEPDIR)/libcurl_la-cram.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/cram.c' object='vauth/libcurl_la-cram.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-cram.lo `test -f 'vauth/cram.c' || echo '$(srcdir)/'`vauth/cram.c
+
+vauth/libcurl_la-digest.lo: vauth/digest.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-digest.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-digest.Tpo -c -o vauth/libcurl_la-digest.lo `test -f 'vauth/digest.c' || echo '$(srcdir)/'`vauth/digest.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-digest.Tpo vauth/$(DEPDIR)/libcurl_la-digest.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/digest.c' object='vauth/libcurl_la-digest.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-digest.lo `test -f 'vauth/digest.c' || echo '$(srcdir)/'`vauth/digest.c
+
+vauth/libcurl_la-digest_sspi.lo: vauth/digest_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-digest_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-digest_sspi.Tpo -c -o vauth/libcurl_la-digest_sspi.lo `test -f 'vauth/digest_sspi.c' || echo '$(srcdir)/'`vauth/digest_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-digest_sspi.Tpo vauth/$(DEPDIR)/libcurl_la-digest_sspi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/digest_sspi.c' object='vauth/libcurl_la-digest_sspi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-digest_sspi.lo `test -f 'vauth/digest_sspi.c' || echo '$(srcdir)/'`vauth/digest_sspi.c
+
+vauth/libcurl_la-gsasl.lo: vauth/gsasl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-gsasl.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-gsasl.Tpo -c -o vauth/libcurl_la-gsasl.lo `test -f 'vauth/gsasl.c' || echo '$(srcdir)/'`vauth/gsasl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-gsasl.Tpo vauth/$(DEPDIR)/libcurl_la-gsasl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/gsasl.c' object='vauth/libcurl_la-gsasl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-gsasl.lo `test -f 'vauth/gsasl.c' || echo '$(srcdir)/'`vauth/gsasl.c
+
+vauth/libcurl_la-krb5_gssapi.lo: vauth/krb5_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-krb5_gssapi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Tpo -c -o vauth/libcurl_la-krb5_gssapi.lo `test -f 'vauth/krb5_gssapi.c' || echo '$(srcdir)/'`vauth/krb5_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Tpo vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/krb5_gssapi.c' object='vauth/libcurl_la-krb5_gssapi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-krb5_gssapi.lo `test -f 'vauth/krb5_gssapi.c' || echo '$(srcdir)/'`vauth/krb5_gssapi.c
+
+vauth/libcurl_la-krb5_sspi.lo: vauth/krb5_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-krb5_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Tpo -c -o vauth/libcurl_la-krb5_sspi.lo `test -f 'vauth/krb5_sspi.c' || echo '$(srcdir)/'`vauth/krb5_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Tpo vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/krb5_sspi.c' object='vauth/libcurl_la-krb5_sspi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-krb5_sspi.lo `test -f 'vauth/krb5_sspi.c' || echo '$(srcdir)/'`vauth/krb5_sspi.c
+
+vauth/libcurl_la-ntlm.lo: vauth/ntlm.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-ntlm.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-ntlm.Tpo -c -o vauth/libcurl_la-ntlm.lo `test -f 'vauth/ntlm.c' || echo '$(srcdir)/'`vauth/ntlm.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-ntlm.Tpo vauth/$(DEPDIR)/libcurl_la-ntlm.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/ntlm.c' object='vauth/libcurl_la-ntlm.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-ntlm.lo `test -f 'vauth/ntlm.c' || echo '$(srcdir)/'`vauth/ntlm.c
+
+vauth/libcurl_la-ntlm_sspi.lo: vauth/ntlm_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-ntlm_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Tpo -c -o vauth/libcurl_la-ntlm_sspi.lo `test -f 'vauth/ntlm_sspi.c' || echo '$(srcdir)/'`vauth/ntlm_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Tpo vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/ntlm_sspi.c' object='vauth/libcurl_la-ntlm_sspi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-ntlm_sspi.lo `test -f 'vauth/ntlm_sspi.c' || echo '$(srcdir)/'`vauth/ntlm_sspi.c
+
+vauth/libcurl_la-oauth2.lo: vauth/oauth2.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-oauth2.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-oauth2.Tpo -c -o vauth/libcurl_la-oauth2.lo `test -f 'vauth/oauth2.c' || echo '$(srcdir)/'`vauth/oauth2.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-oauth2.Tpo vauth/$(DEPDIR)/libcurl_la-oauth2.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/oauth2.c' object='vauth/libcurl_la-oauth2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-oauth2.lo `test -f 'vauth/oauth2.c' || echo '$(srcdir)/'`vauth/oauth2.c
+
+vauth/libcurl_la-spnego_gssapi.lo: vauth/spnego_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-spnego_gssapi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Tpo -c -o vauth/libcurl_la-spnego_gssapi.lo `test -f 'vauth/spnego_gssapi.c' || echo '$(srcdir)/'`vauth/spnego_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Tpo vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/spnego_gssapi.c' object='vauth/libcurl_la-spnego_gssapi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-spnego_gssapi.lo `test -f 'vauth/spnego_gssapi.c' || echo '$(srcdir)/'`vauth/spnego_gssapi.c
+
+vauth/libcurl_la-spnego_sspi.lo: vauth/spnego_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-spnego_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Tpo -c -o vauth/libcurl_la-spnego_sspi.lo `test -f 'vauth/spnego_sspi.c' || echo '$(srcdir)/'`vauth/spnego_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Tpo vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/spnego_sspi.c' object='vauth/libcurl_la-spnego_sspi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-spnego_sspi.lo `test -f 'vauth/spnego_sspi.c' || echo '$(srcdir)/'`vauth/spnego_sspi.c
+
+vauth/libcurl_la-vauth.lo: vauth/vauth.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vauth/libcurl_la-vauth.lo -MD -MP -MF vauth/$(DEPDIR)/libcurl_la-vauth.Tpo -c -o vauth/libcurl_la-vauth.lo `test -f 'vauth/vauth.c' || echo '$(srcdir)/'`vauth/vauth.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurl_la-vauth.Tpo vauth/$(DEPDIR)/libcurl_la-vauth.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/vauth.c' object='vauth/libcurl_la-vauth.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurl_la-vauth.lo `test -f 'vauth/vauth.c' || echo '$(srcdir)/'`vauth/vauth.c
+
+vtls/libcurl_la-bearssl.lo: vtls/bearssl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-bearssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-bearssl.Tpo -c -o vtls/libcurl_la-bearssl.lo `test -f 'vtls/bearssl.c' || echo '$(srcdir)/'`vtls/bearssl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-bearssl.Tpo vtls/$(DEPDIR)/libcurl_la-bearssl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/bearssl.c' object='vtls/libcurl_la-bearssl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-bearssl.lo `test -f 'vtls/bearssl.c' || echo '$(srcdir)/'`vtls/bearssl.c
+
+vtls/libcurl_la-gtls.lo: vtls/gtls.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-gtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-gtls.Tpo -c -o vtls/libcurl_la-gtls.lo `test -f 'vtls/gtls.c' || echo '$(srcdir)/'`vtls/gtls.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-gtls.Tpo vtls/$(DEPDIR)/libcurl_la-gtls.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/gtls.c' object='vtls/libcurl_la-gtls.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-gtls.lo `test -f 'vtls/gtls.c' || echo '$(srcdir)/'`vtls/gtls.c
+
+vtls/libcurl_la-hostcheck.lo: vtls/hostcheck.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-hostcheck.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-hostcheck.Tpo -c -o vtls/libcurl_la-hostcheck.lo `test -f 'vtls/hostcheck.c' || echo '$(srcdir)/'`vtls/hostcheck.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-hostcheck.Tpo vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/hostcheck.c' object='vtls/libcurl_la-hostcheck.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-hostcheck.lo `test -f 'vtls/hostcheck.c' || echo '$(srcdir)/'`vtls/hostcheck.c
+
+vtls/libcurl_la-keylog.lo: vtls/keylog.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-keylog.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-keylog.Tpo -c -o vtls/libcurl_la-keylog.lo `test -f 'vtls/keylog.c' || echo '$(srcdir)/'`vtls/keylog.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-keylog.Tpo vtls/$(DEPDIR)/libcurl_la-keylog.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/keylog.c' object='vtls/libcurl_la-keylog.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-keylog.lo `test -f 'vtls/keylog.c' || echo '$(srcdir)/'`vtls/keylog.c
+
+vtls/libcurl_la-mbedtls.lo: vtls/mbedtls.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-mbedtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-mbedtls.Tpo -c -o vtls/libcurl_la-mbedtls.lo `test -f 'vtls/mbedtls.c' || echo '$(srcdir)/'`vtls/mbedtls.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-mbedtls.Tpo vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/mbedtls.c' object='vtls/libcurl_la-mbedtls.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-mbedtls.lo `test -f 'vtls/mbedtls.c' || echo '$(srcdir)/'`vtls/mbedtls.c
+
+vtls/libcurl_la-mbedtls_threadlock.lo: vtls/mbedtls_threadlock.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-mbedtls_threadlock.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Tpo -c -o vtls/libcurl_la-mbedtls_threadlock.lo `test -f 'vtls/mbedtls_threadlock.c' || echo '$(srcdir)/'`vtls/mbedtls_threadlock.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Tpo vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/mbedtls_threadlock.c' object='vtls/libcurl_la-mbedtls_threadlock.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-mbedtls_threadlock.lo `test -f 'vtls/mbedtls_threadlock.c' || echo '$(srcdir)/'`vtls/mbedtls_threadlock.c
+
+vtls/libcurl_la-openssl.lo: vtls/openssl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-openssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-openssl.Tpo -c -o vtls/libcurl_la-openssl.lo `test -f 'vtls/openssl.c' || echo '$(srcdir)/'`vtls/openssl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-openssl.Tpo vtls/$(DEPDIR)/libcurl_la-openssl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/openssl.c' object='vtls/libcurl_la-openssl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-openssl.lo `test -f 'vtls/openssl.c' || echo '$(srcdir)/'`vtls/openssl.c
+
+vtls/libcurl_la-rustls.lo: vtls/rustls.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-rustls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-rustls.Tpo -c -o vtls/libcurl_la-rustls.lo `test -f 'vtls/rustls.c' || echo '$(srcdir)/'`vtls/rustls.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-rustls.Tpo vtls/$(DEPDIR)/libcurl_la-rustls.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/rustls.c' object='vtls/libcurl_la-rustls.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-rustls.lo `test -f 'vtls/rustls.c' || echo '$(srcdir)/'`vtls/rustls.c
+
+vtls/libcurl_la-schannel.lo: vtls/schannel.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-schannel.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-schannel.Tpo -c -o vtls/libcurl_la-schannel.lo `test -f 'vtls/schannel.c' || echo '$(srcdir)/'`vtls/schannel.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-schannel.Tpo vtls/$(DEPDIR)/libcurl_la-schannel.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/schannel.c' object='vtls/libcurl_la-schannel.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-schannel.lo `test -f 'vtls/schannel.c' || echo '$(srcdir)/'`vtls/schannel.c
+
+vtls/libcurl_la-schannel_verify.lo: vtls/schannel_verify.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-schannel_verify.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-schannel_verify.Tpo -c -o vtls/libcurl_la-schannel_verify.lo `test -f 'vtls/schannel_verify.c' || echo '$(srcdir)/'`vtls/schannel_verify.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-schannel_verify.Tpo vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/schannel_verify.c' object='vtls/libcurl_la-schannel_verify.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-schannel_verify.lo `test -f 'vtls/schannel_verify.c' || echo '$(srcdir)/'`vtls/schannel_verify.c
+
+vtls/libcurl_la-sectransp.lo: vtls/sectransp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-sectransp.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-sectransp.Tpo -c -o vtls/libcurl_la-sectransp.lo `test -f 'vtls/sectransp.c' || echo '$(srcdir)/'`vtls/sectransp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-sectransp.Tpo vtls/$(DEPDIR)/libcurl_la-sectransp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/sectransp.c' object='vtls/libcurl_la-sectransp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-sectransp.lo `test -f 'vtls/sectransp.c' || echo '$(srcdir)/'`vtls/sectransp.c
+
+vtls/libcurl_la-vtls.lo: vtls/vtls.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-vtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-vtls.Tpo -c -o vtls/libcurl_la-vtls.lo `test -f 'vtls/vtls.c' || echo '$(srcdir)/'`vtls/vtls.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-vtls.Tpo vtls/$(DEPDIR)/libcurl_la-vtls.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/vtls.c' object='vtls/libcurl_la-vtls.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-vtls.lo `test -f 'vtls/vtls.c' || echo '$(srcdir)/'`vtls/vtls.c
+
+vtls/libcurl_la-wolfssl.lo: vtls/wolfssl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-wolfssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-wolfssl.Tpo -c -o vtls/libcurl_la-wolfssl.lo `test -f 'vtls/wolfssl.c' || echo '$(srcdir)/'`vtls/wolfssl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-wolfssl.Tpo vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/wolfssl.c' object='vtls/libcurl_la-wolfssl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-wolfssl.lo `test -f 'vtls/wolfssl.c' || echo '$(srcdir)/'`vtls/wolfssl.c
+
+vtls/libcurl_la-x509asn1.lo: vtls/x509asn1.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-x509asn1.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-x509asn1.Tpo -c -o vtls/libcurl_la-x509asn1.lo `test -f 'vtls/x509asn1.c' || echo '$(srcdir)/'`vtls/x509asn1.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-x509asn1.Tpo vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/x509asn1.c' object='vtls/libcurl_la-x509asn1.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-x509asn1.lo `test -f 'vtls/x509asn1.c' || echo '$(srcdir)/'`vtls/x509asn1.c
+
+vquic/libcurl_la-curl_msh3.lo: vquic/curl_msh3.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-curl_msh3.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-curl_msh3.Tpo -c -o vquic/libcurl_la-curl_msh3.lo `test -f 'vquic/curl_msh3.c' || echo '$(srcdir)/'`vquic/curl_msh3.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-curl_msh3.Tpo vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vquic/curl_msh3.c' object='vquic/libcurl_la-curl_msh3.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-curl_msh3.lo `test -f 'vquic/curl_msh3.c' || echo '$(srcdir)/'`vquic/curl_msh3.c
+
+vquic/libcurl_la-curl_ngtcp2.lo: vquic/curl_ngtcp2.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-curl_ngtcp2.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Tpo -c -o vquic/libcurl_la-curl_ngtcp2.lo `test -f 'vquic/curl_ngtcp2.c' || echo '$(srcdir)/'`vquic/curl_ngtcp2.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Tpo vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vquic/curl_ngtcp2.c' object='vquic/libcurl_la-curl_ngtcp2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-curl_ngtcp2.lo `test -f 'vquic/curl_ngtcp2.c' || echo '$(srcdir)/'`vquic/curl_ngtcp2.c
+
+vquic/libcurl_la-curl_osslq.lo: vquic/curl_osslq.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-curl_osslq.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-curl_osslq.Tpo -c -o vquic/libcurl_la-curl_osslq.lo `test -f 'vquic/curl_osslq.c' || echo '$(srcdir)/'`vquic/curl_osslq.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-curl_osslq.Tpo vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vquic/curl_osslq.c' object='vquic/libcurl_la-curl_osslq.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-curl_osslq.lo `test -f 'vquic/curl_osslq.c' || echo '$(srcdir)/'`vquic/curl_osslq.c
+
+vquic/libcurl_la-curl_quiche.lo: vquic/curl_quiche.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-curl_quiche.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-curl_quiche.Tpo -c -o vquic/libcurl_la-curl_quiche.lo `test -f 'vquic/curl_quiche.c' || echo '$(srcdir)/'`vquic/curl_quiche.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-curl_quiche.Tpo vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vquic/curl_quiche.c' object='vquic/libcurl_la-curl_quiche.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-curl_quiche.lo `test -f 'vquic/curl_quiche.c' || echo '$(srcdir)/'`vquic/curl_quiche.c
+
+vquic/libcurl_la-vquic.lo: vquic/vquic.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-vquic.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-vquic.Tpo -c -o vquic/libcurl_la-vquic.lo `test -f 'vquic/vquic.c' || echo '$(srcdir)/'`vquic/vquic.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-vquic.Tpo vquic/$(DEPDIR)/libcurl_la-vquic.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vquic/vquic.c' object='vquic/libcurl_la-vquic.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-vquic.lo `test -f 'vquic/vquic.c' || echo '$(srcdir)/'`vquic/vquic.c
+
+vquic/libcurl_la-vquic-tls.lo: vquic/vquic-tls.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-vquic-tls.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-vquic-tls.Tpo -c -o vquic/libcurl_la-vquic-tls.lo `test -f 'vquic/vquic-tls.c' || echo '$(srcdir)/'`vquic/vquic-tls.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-vquic-tls.Tpo vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vquic/vquic-tls.c' object='vquic/libcurl_la-vquic-tls.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-vquic-tls.lo `test -f 'vquic/vquic-tls.c' || echo '$(srcdir)/'`vquic/vquic-tls.c
+
+vssh/libcurl_la-libssh.lo: vssh/libssh.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vssh/libcurl_la-libssh.lo -MD -MP -MF vssh/$(DEPDIR)/libcurl_la-libssh.Tpo -c -o vssh/libcurl_la-libssh.lo `test -f 'vssh/libssh.c' || echo '$(srcdir)/'`vssh/libssh.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurl_la-libssh.Tpo vssh/$(DEPDIR)/libcurl_la-libssh.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vssh/libssh.c' object='vssh/libcurl_la-libssh.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurl_la-libssh.lo `test -f 'vssh/libssh.c' || echo '$(srcdir)/'`vssh/libssh.c
+
+vssh/libcurl_la-libssh2.lo: vssh/libssh2.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vssh/libcurl_la-libssh2.lo -MD -MP -MF vssh/$(DEPDIR)/libcurl_la-libssh2.Tpo -c -o vssh/libcurl_la-libssh2.lo `test -f 'vssh/libssh2.c' || echo '$(srcdir)/'`vssh/libssh2.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurl_la-libssh2.Tpo vssh/$(DEPDIR)/libcurl_la-libssh2.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vssh/libssh2.c' object='vssh/libcurl_la-libssh2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurl_la-libssh2.lo `test -f 'vssh/libssh2.c' || echo '$(srcdir)/'`vssh/libssh2.c
+
+vssh/libcurl_la-wolfssh.lo: vssh/wolfssh.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vssh/libcurl_la-wolfssh.lo -MD -MP -MF vssh/$(DEPDIR)/libcurl_la-wolfssh.Tpo -c -o vssh/libcurl_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurl_la-wolfssh.Tpo vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vssh/wolfssh.c' object='vssh/libcurl_la-wolfssh.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurl_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c
+
+libcurlu_la-altsvc.lo: altsvc.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-altsvc.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-altsvc.Tpo -c -o libcurlu_la-altsvc.lo `test -f 'altsvc.c' || echo '$(srcdir)/'`altsvc.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-altsvc.Tpo $(DEPDIR)/libcurlu_la-altsvc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='altsvc.c' object='libcurlu_la-altsvc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-altsvc.lo `test -f 'altsvc.c' || echo '$(srcdir)/'`altsvc.c
+
+libcurlu_la-amigaos.lo: amigaos.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-amigaos.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-amigaos.Tpo -c -o libcurlu_la-amigaos.lo `test -f 'amigaos.c' || echo '$(srcdir)/'`amigaos.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-amigaos.Tpo $(DEPDIR)/libcurlu_la-amigaos.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='amigaos.c' object='libcurlu_la-amigaos.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-amigaos.lo `test -f 'amigaos.c' || echo '$(srcdir)/'`amigaos.c
+
+libcurlu_la-asyn-ares.lo: asyn-ares.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-asyn-ares.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-asyn-ares.Tpo -c -o libcurlu_la-asyn-ares.lo `test -f 'asyn-ares.c' || echo '$(srcdir)/'`asyn-ares.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-asyn-ares.Tpo $(DEPDIR)/libcurlu_la-asyn-ares.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='asyn-ares.c' object='libcurlu_la-asyn-ares.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-asyn-ares.lo `test -f 'asyn-ares.c' || echo '$(srcdir)/'`asyn-ares.c
+
+libcurlu_la-asyn-thread.lo: asyn-thread.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-asyn-thread.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-asyn-thread.Tpo -c -o libcurlu_la-asyn-thread.lo `test -f 'asyn-thread.c' || echo '$(srcdir)/'`asyn-thread.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-asyn-thread.Tpo $(DEPDIR)/libcurlu_la-asyn-thread.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='asyn-thread.c' object='libcurlu_la-asyn-thread.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-asyn-thread.lo `test -f 'asyn-thread.c' || echo '$(srcdir)/'`asyn-thread.c
+
+libcurlu_la-base64.lo: base64.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-base64.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-base64.Tpo -c -o libcurlu_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-base64.Tpo $(DEPDIR)/libcurlu_la-base64.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='base64.c' object='libcurlu_la-base64.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c
+
+libcurlu_la-bufq.lo: bufq.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-bufq.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-bufq.Tpo -c -o libcurlu_la-bufq.lo `test -f 'bufq.c' || echo '$(srcdir)/'`bufq.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-bufq.Tpo $(DEPDIR)/libcurlu_la-bufq.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='bufq.c' object='libcurlu_la-bufq.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-bufq.lo `test -f 'bufq.c' || echo '$(srcdir)/'`bufq.c
+
+libcurlu_la-bufref.lo: bufref.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-bufref.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-bufref.Tpo -c -o libcurlu_la-bufref.lo `test -f 'bufref.c' || echo '$(srcdir)/'`bufref.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-bufref.Tpo $(DEPDIR)/libcurlu_la-bufref.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='bufref.c' object='libcurlu_la-bufref.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-bufref.lo `test -f 'bufref.c' || echo '$(srcdir)/'`bufref.c
+
+libcurlu_la-c-hyper.lo: c-hyper.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-c-hyper.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-c-hyper.Tpo -c -o libcurlu_la-c-hyper.lo `test -f 'c-hyper.c' || echo '$(srcdir)/'`c-hyper.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-c-hyper.Tpo $(DEPDIR)/libcurlu_la-c-hyper.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='c-hyper.c' object='libcurlu_la-c-hyper.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-c-hyper.lo `test -f 'c-hyper.c' || echo '$(srcdir)/'`c-hyper.c
+
+libcurlu_la-cf-h1-proxy.lo: cf-h1-proxy.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cf-h1-proxy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cf-h1-proxy.Tpo -c -o libcurlu_la-cf-h1-proxy.lo `test -f 'cf-h1-proxy.c' || echo '$(srcdir)/'`cf-h1-proxy.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cf-h1-proxy.Tpo $(DEPDIR)/libcurlu_la-cf-h1-proxy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cf-h1-proxy.c' object='libcurlu_la-cf-h1-proxy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cf-h1-proxy.lo `test -f 'cf-h1-proxy.c' || echo '$(srcdir)/'`cf-h1-proxy.c
+
+libcurlu_la-cf-h2-proxy.lo: cf-h2-proxy.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cf-h2-proxy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cf-h2-proxy.Tpo -c -o libcurlu_la-cf-h2-proxy.lo `test -f 'cf-h2-proxy.c' || echo '$(srcdir)/'`cf-h2-proxy.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cf-h2-proxy.Tpo $(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cf-h2-proxy.c' object='libcurlu_la-cf-h2-proxy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cf-h2-proxy.lo `test -f 'cf-h2-proxy.c' || echo '$(srcdir)/'`cf-h2-proxy.c
+
+libcurlu_la-cf-haproxy.lo: cf-haproxy.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cf-haproxy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cf-haproxy.Tpo -c -o libcurlu_la-cf-haproxy.lo `test -f 'cf-haproxy.c' || echo '$(srcdir)/'`cf-haproxy.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cf-haproxy.Tpo $(DEPDIR)/libcurlu_la-cf-haproxy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cf-haproxy.c' object='libcurlu_la-cf-haproxy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cf-haproxy.lo `test -f 'cf-haproxy.c' || echo '$(srcdir)/'`cf-haproxy.c
+
+libcurlu_la-cf-https-connect.lo: cf-https-connect.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cf-https-connect.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cf-https-connect.Tpo -c -o libcurlu_la-cf-https-connect.lo `test -f 'cf-https-connect.c' || echo '$(srcdir)/'`cf-https-connect.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cf-https-connect.Tpo $(DEPDIR)/libcurlu_la-cf-https-connect.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cf-https-connect.c' object='libcurlu_la-cf-https-connect.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cf-https-connect.lo `test -f 'cf-https-connect.c' || echo '$(srcdir)/'`cf-https-connect.c
+
+libcurlu_la-cf-socket.lo: cf-socket.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cf-socket.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cf-socket.Tpo -c -o libcurlu_la-cf-socket.lo `test -f 'cf-socket.c' || echo '$(srcdir)/'`cf-socket.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cf-socket.Tpo $(DEPDIR)/libcurlu_la-cf-socket.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cf-socket.c' object='libcurlu_la-cf-socket.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cf-socket.lo `test -f 'cf-socket.c' || echo '$(srcdir)/'`cf-socket.c
+
+libcurlu_la-cfilters.lo: cfilters.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cfilters.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cfilters.Tpo -c -o libcurlu_la-cfilters.lo `test -f 'cfilters.c' || echo '$(srcdir)/'`cfilters.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cfilters.Tpo $(DEPDIR)/libcurlu_la-cfilters.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cfilters.c' object='libcurlu_la-cfilters.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cfilters.lo `test -f 'cfilters.c' || echo '$(srcdir)/'`cfilters.c
+
+libcurlu_la-conncache.lo: conncache.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-conncache.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-conncache.Tpo -c -o libcurlu_la-conncache.lo `test -f 'conncache.c' || echo '$(srcdir)/'`conncache.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-conncache.Tpo $(DEPDIR)/libcurlu_la-conncache.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='conncache.c' object='libcurlu_la-conncache.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-conncache.lo `test -f 'conncache.c' || echo '$(srcdir)/'`conncache.c
+
+libcurlu_la-connect.lo: connect.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-connect.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-connect.Tpo -c -o libcurlu_la-connect.lo `test -f 'connect.c' || echo '$(srcdir)/'`connect.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-connect.Tpo $(DEPDIR)/libcurlu_la-connect.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='connect.c' object='libcurlu_la-connect.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-connect.lo `test -f 'connect.c' || echo '$(srcdir)/'`connect.c
+
+libcurlu_la-content_encoding.lo: content_encoding.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-content_encoding.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-content_encoding.Tpo -c -o libcurlu_la-content_encoding.lo `test -f 'content_encoding.c' || echo '$(srcdir)/'`content_encoding.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-content_encoding.Tpo $(DEPDIR)/libcurlu_la-content_encoding.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='content_encoding.c' object='libcurlu_la-content_encoding.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-content_encoding.lo `test -f 'content_encoding.c' || echo '$(srcdir)/'`content_encoding.c
+
+libcurlu_la-cookie.lo: cookie.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cookie.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cookie.Tpo -c -o libcurlu_la-cookie.lo `test -f 'cookie.c' || echo '$(srcdir)/'`cookie.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cookie.Tpo $(DEPDIR)/libcurlu_la-cookie.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cookie.c' object='libcurlu_la-cookie.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cookie.lo `test -f 'cookie.c' || echo '$(srcdir)/'`cookie.c
+
+libcurlu_la-curl_addrinfo.lo: curl_addrinfo.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_addrinfo.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_addrinfo.Tpo -c -o libcurlu_la-curl_addrinfo.lo `test -f 'curl_addrinfo.c' || echo '$(srcdir)/'`curl_addrinfo.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_addrinfo.Tpo $(DEPDIR)/libcurlu_la-curl_addrinfo.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_addrinfo.c' object='libcurlu_la-curl_addrinfo.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_addrinfo.lo `test -f 'curl_addrinfo.c' || echo '$(srcdir)/'`curl_addrinfo.c
+
+libcurlu_la-curl_des.lo: curl_des.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_des.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_des.Tpo -c -o libcurlu_la-curl_des.lo `test -f 'curl_des.c' || echo '$(srcdir)/'`curl_des.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_des.Tpo $(DEPDIR)/libcurlu_la-curl_des.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_des.c' object='libcurlu_la-curl_des.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_des.lo `test -f 'curl_des.c' || echo '$(srcdir)/'`curl_des.c
+
+libcurlu_la-curl_endian.lo: curl_endian.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_endian.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_endian.Tpo -c -o libcurlu_la-curl_endian.lo `test -f 'curl_endian.c' || echo '$(srcdir)/'`curl_endian.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_endian.Tpo $(DEPDIR)/libcurlu_la-curl_endian.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_endian.c' object='libcurlu_la-curl_endian.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_endian.lo `test -f 'curl_endian.c' || echo '$(srcdir)/'`curl_endian.c
+
+libcurlu_la-curl_fnmatch.lo: curl_fnmatch.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_fnmatch.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_fnmatch.Tpo -c -o libcurlu_la-curl_fnmatch.lo `test -f 'curl_fnmatch.c' || echo '$(srcdir)/'`curl_fnmatch.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_fnmatch.Tpo $(DEPDIR)/libcurlu_la-curl_fnmatch.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_fnmatch.c' object='libcurlu_la-curl_fnmatch.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_fnmatch.lo `test -f 'curl_fnmatch.c' || echo '$(srcdir)/'`curl_fnmatch.c
+
+libcurlu_la-curl_get_line.lo: curl_get_line.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_get_line.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_get_line.Tpo -c -o libcurlu_la-curl_get_line.lo `test -f 'curl_get_line.c' || echo '$(srcdir)/'`curl_get_line.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_get_line.Tpo $(DEPDIR)/libcurlu_la-curl_get_line.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_get_line.c' object='libcurlu_la-curl_get_line.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_get_line.lo `test -f 'curl_get_line.c' || echo '$(srcdir)/'`curl_get_line.c
+
+libcurlu_la-curl_gethostname.lo: curl_gethostname.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_gethostname.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_gethostname.Tpo -c -o libcurlu_la-curl_gethostname.lo `test -f 'curl_gethostname.c' || echo '$(srcdir)/'`curl_gethostname.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_gethostname.Tpo $(DEPDIR)/libcurlu_la-curl_gethostname.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_gethostname.c' object='libcurlu_la-curl_gethostname.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_gethostname.lo `test -f 'curl_gethostname.c' || echo '$(srcdir)/'`curl_gethostname.c
+
+libcurlu_la-curl_gssapi.lo: curl_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_gssapi.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_gssapi.Tpo -c -o libcurlu_la-curl_gssapi.lo `test -f 'curl_gssapi.c' || echo '$(srcdir)/'`curl_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_gssapi.Tpo $(DEPDIR)/libcurlu_la-curl_gssapi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_gssapi.c' object='libcurlu_la-curl_gssapi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_gssapi.lo `test -f 'curl_gssapi.c' || echo '$(srcdir)/'`curl_gssapi.c
+
+libcurlu_la-curl_memrchr.lo: curl_memrchr.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_memrchr.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_memrchr.Tpo -c -o libcurlu_la-curl_memrchr.lo `test -f 'curl_memrchr.c' || echo '$(srcdir)/'`curl_memrchr.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_memrchr.Tpo $(DEPDIR)/libcurlu_la-curl_memrchr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_memrchr.c' object='libcurlu_la-curl_memrchr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_memrchr.lo `test -f 'curl_memrchr.c' || echo '$(srcdir)/'`curl_memrchr.c
+
+libcurlu_la-curl_multibyte.lo: curl_multibyte.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_multibyte.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_multibyte.Tpo -c -o libcurlu_la-curl_multibyte.lo `test -f 'curl_multibyte.c' || echo '$(srcdir)/'`curl_multibyte.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_multibyte.Tpo $(DEPDIR)/libcurlu_la-curl_multibyte.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_multibyte.c' object='libcurlu_la-curl_multibyte.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_multibyte.lo `test -f 'curl_multibyte.c' || echo '$(srcdir)/'`curl_multibyte.c
+
+libcurlu_la-curl_ntlm_core.lo: curl_ntlm_core.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_ntlm_core.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_ntlm_core.Tpo -c -o libcurlu_la-curl_ntlm_core.lo `test -f 'curl_ntlm_core.c' || echo '$(srcdir)/'`curl_ntlm_core.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_ntlm_core.Tpo $(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_ntlm_core.c' object='libcurlu_la-curl_ntlm_core.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_ntlm_core.lo `test -f 'curl_ntlm_core.c' || echo '$(srcdir)/'`curl_ntlm_core.c
+
+libcurlu_la-curl_ntlm_wb.lo: curl_ntlm_wb.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_ntlm_wb.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_ntlm_wb.Tpo -c -o libcurlu_la-curl_ntlm_wb.lo `test -f 'curl_ntlm_wb.c' || echo '$(srcdir)/'`curl_ntlm_wb.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_ntlm_wb.Tpo $(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_ntlm_wb.c' object='libcurlu_la-curl_ntlm_wb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_ntlm_wb.lo `test -f 'curl_ntlm_wb.c' || echo '$(srcdir)/'`curl_ntlm_wb.c
+
+libcurlu_la-curl_path.lo: curl_path.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_path.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_path.Tpo -c -o libcurlu_la-curl_path.lo `test -f 'curl_path.c' || echo '$(srcdir)/'`curl_path.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_path.Tpo $(DEPDIR)/libcurlu_la-curl_path.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_path.c' object='libcurlu_la-curl_path.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_path.lo `test -f 'curl_path.c' || echo '$(srcdir)/'`curl_path.c
+
+libcurlu_la-curl_range.lo: curl_range.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_range.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_range.Tpo -c -o libcurlu_la-curl_range.lo `test -f 'curl_range.c' || echo '$(srcdir)/'`curl_range.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_range.Tpo $(DEPDIR)/libcurlu_la-curl_range.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_range.c' object='libcurlu_la-curl_range.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_range.lo `test -f 'curl_range.c' || echo '$(srcdir)/'`curl_range.c
+
+libcurlu_la-curl_rtmp.lo: curl_rtmp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_rtmp.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_rtmp.Tpo -c -o libcurlu_la-curl_rtmp.lo `test -f 'curl_rtmp.c' || echo '$(srcdir)/'`curl_rtmp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_rtmp.Tpo $(DEPDIR)/libcurlu_la-curl_rtmp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_rtmp.c' object='libcurlu_la-curl_rtmp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_rtmp.lo `test -f 'curl_rtmp.c' || echo '$(srcdir)/'`curl_rtmp.c
+
+libcurlu_la-curl_sasl.lo: curl_sasl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_sasl.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_sasl.Tpo -c -o libcurlu_la-curl_sasl.lo `test -f 'curl_sasl.c' || echo '$(srcdir)/'`curl_sasl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_sasl.Tpo $(DEPDIR)/libcurlu_la-curl_sasl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_sasl.c' object='libcurlu_la-curl_sasl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_sasl.lo `test -f 'curl_sasl.c' || echo '$(srcdir)/'`curl_sasl.c
+
+libcurlu_la-curl_sha512_256.lo: curl_sha512_256.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_sha512_256.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_sha512_256.Tpo -c -o libcurlu_la-curl_sha512_256.lo `test -f 'curl_sha512_256.c' || echo '$(srcdir)/'`curl_sha512_256.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_sha512_256.Tpo $(DEPDIR)/libcurlu_la-curl_sha512_256.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_sha512_256.c' object='libcurlu_la-curl_sha512_256.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_sha512_256.lo `test -f 'curl_sha512_256.c' || echo '$(srcdir)/'`curl_sha512_256.c
+
+libcurlu_la-curl_sspi.lo: curl_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_sspi.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_sspi.Tpo -c -o libcurlu_la-curl_sspi.lo `test -f 'curl_sspi.c' || echo '$(srcdir)/'`curl_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_sspi.Tpo $(DEPDIR)/libcurlu_la-curl_sspi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_sspi.c' object='libcurlu_la-curl_sspi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_sspi.lo `test -f 'curl_sspi.c' || echo '$(srcdir)/'`curl_sspi.c
+
+libcurlu_la-curl_threads.lo: curl_threads.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_threads.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_threads.Tpo -c -o libcurlu_la-curl_threads.lo `test -f 'curl_threads.c' || echo '$(srcdir)/'`curl_threads.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_threads.Tpo $(DEPDIR)/libcurlu_la-curl_threads.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_threads.c' object='libcurlu_la-curl_threads.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_threads.lo `test -f 'curl_threads.c' || echo '$(srcdir)/'`curl_threads.c
+
+libcurlu_la-curl_trc.lo: curl_trc.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_trc.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_trc.Tpo -c -o libcurlu_la-curl_trc.lo `test -f 'curl_trc.c' || echo '$(srcdir)/'`curl_trc.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_trc.Tpo $(DEPDIR)/libcurlu_la-curl_trc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='curl_trc.c' object='libcurlu_la-curl_trc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_trc.lo `test -f 'curl_trc.c' || echo '$(srcdir)/'`curl_trc.c
+
+libcurlu_la-cw-out.lo: cw-out.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cw-out.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cw-out.Tpo -c -o libcurlu_la-cw-out.lo `test -f 'cw-out.c' || echo '$(srcdir)/'`cw-out.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cw-out.Tpo $(DEPDIR)/libcurlu_la-cw-out.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cw-out.c' object='libcurlu_la-cw-out.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cw-out.lo `test -f 'cw-out.c' || echo '$(srcdir)/'`cw-out.c
+
+libcurlu_la-dict.lo: dict.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-dict.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-dict.Tpo -c -o libcurlu_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-dict.Tpo $(DEPDIR)/libcurlu_la-dict.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='dict.c' object='libcurlu_la-dict.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c
+
+libcurlu_la-doh.lo: doh.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-doh.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-doh.Tpo -c -o libcurlu_la-doh.lo `test -f 'doh.c' || echo '$(srcdir)/'`doh.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-doh.Tpo $(DEPDIR)/libcurlu_la-doh.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='doh.c' object='libcurlu_la-doh.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-doh.lo `test -f 'doh.c' || echo '$(srcdir)/'`doh.c
+
+libcurlu_la-dynbuf.lo: dynbuf.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-dynbuf.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-dynbuf.Tpo -c -o libcurlu_la-dynbuf.lo `test -f 'dynbuf.c' || echo '$(srcdir)/'`dynbuf.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-dynbuf.Tpo $(DEPDIR)/libcurlu_la-dynbuf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='dynbuf.c' object='libcurlu_la-dynbuf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-dynbuf.lo `test -f 'dynbuf.c' || echo '$(srcdir)/'`dynbuf.c
+
+libcurlu_la-dynhds.lo: dynhds.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-dynhds.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-dynhds.Tpo -c -o libcurlu_la-dynhds.lo `test -f 'dynhds.c' || echo '$(srcdir)/'`dynhds.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-dynhds.Tpo $(DEPDIR)/libcurlu_la-dynhds.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='dynhds.c' object='libcurlu_la-dynhds.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-dynhds.lo `test -f 'dynhds.c' || echo '$(srcdir)/'`dynhds.c
+
+libcurlu_la-easy.lo: easy.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-easy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-easy.Tpo -c -o libcurlu_la-easy.lo `test -f 'easy.c' || echo '$(srcdir)/'`easy.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-easy.Tpo $(DEPDIR)/libcurlu_la-easy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='easy.c' object='libcurlu_la-easy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-easy.lo `test -f 'easy.c' || echo '$(srcdir)/'`easy.c
+
+libcurlu_la-easygetopt.lo: easygetopt.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-easygetopt.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-easygetopt.Tpo -c -o libcurlu_la-easygetopt.lo `test -f 'easygetopt.c' || echo '$(srcdir)/'`easygetopt.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-easygetopt.Tpo $(DEPDIR)/libcurlu_la-easygetopt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='easygetopt.c' object='libcurlu_la-easygetopt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-easygetopt.lo `test -f 'easygetopt.c' || echo '$(srcdir)/'`easygetopt.c
+
+libcurlu_la-easyoptions.lo: easyoptions.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-easyoptions.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-easyoptions.Tpo -c -o libcurlu_la-easyoptions.lo `test -f 'easyoptions.c' || echo '$(srcdir)/'`easyoptions.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-easyoptions.Tpo $(DEPDIR)/libcurlu_la-easyoptions.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='easyoptions.c' object='libcurlu_la-easyoptions.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-easyoptions.lo `test -f 'easyoptions.c' || echo '$(srcdir)/'`easyoptions.c
+
+libcurlu_la-escape.lo: escape.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-escape.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-escape.Tpo -c -o libcurlu_la-escape.lo `test -f 'escape.c' || echo '$(srcdir)/'`escape.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-escape.Tpo $(DEPDIR)/libcurlu_la-escape.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='escape.c' object='libcurlu_la-escape.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-escape.lo `test -f 'escape.c' || echo '$(srcdir)/'`escape.c
+
+libcurlu_la-file.lo: file.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-file.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-file.Tpo -c -o libcurlu_la-file.lo `test -f 'file.c' || echo '$(srcdir)/'`file.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-file.Tpo $(DEPDIR)/libcurlu_la-file.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='file.c' object='libcurlu_la-file.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-file.lo `test -f 'file.c' || echo '$(srcdir)/'`file.c
+
+libcurlu_la-fileinfo.lo: fileinfo.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-fileinfo.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-fileinfo.Tpo -c -o libcurlu_la-fileinfo.lo `test -f 'fileinfo.c' || echo '$(srcdir)/'`fileinfo.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-fileinfo.Tpo $(DEPDIR)/libcurlu_la-fileinfo.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='fileinfo.c' object='libcurlu_la-fileinfo.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-fileinfo.lo `test -f 'fileinfo.c' || echo '$(srcdir)/'`fileinfo.c
+
+libcurlu_la-fopen.lo: fopen.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-fopen.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-fopen.Tpo -c -o libcurlu_la-fopen.lo `test -f 'fopen.c' || echo '$(srcdir)/'`fopen.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-fopen.Tpo $(DEPDIR)/libcurlu_la-fopen.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='fopen.c' object='libcurlu_la-fopen.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-fopen.lo `test -f 'fopen.c' || echo '$(srcdir)/'`fopen.c
+
+libcurlu_la-formdata.lo: formdata.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-formdata.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-formdata.Tpo -c -o libcurlu_la-formdata.lo `test -f 'formdata.c' || echo '$(srcdir)/'`formdata.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-formdata.Tpo $(DEPDIR)/libcurlu_la-formdata.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='formdata.c' object='libcurlu_la-formdata.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-formdata.lo `test -f 'formdata.c' || echo '$(srcdir)/'`formdata.c
+
+libcurlu_la-ftp.lo: ftp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-ftp.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-ftp.Tpo -c -o libcurlu_la-ftp.lo `test -f 'ftp.c' || echo '$(srcdir)/'`ftp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-ftp.Tpo $(DEPDIR)/libcurlu_la-ftp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ftp.c' object='libcurlu_la-ftp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-ftp.lo `test -f 'ftp.c' || echo '$(srcdir)/'`ftp.c
+
+libcurlu_la-ftplistparser.lo: ftplistparser.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-ftplistparser.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-ftplistparser.Tpo -c -o libcurlu_la-ftplistparser.lo `test -f 'ftplistparser.c' || echo '$(srcdir)/'`ftplistparser.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-ftplistparser.Tpo $(DEPDIR)/libcurlu_la-ftplistparser.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ftplistparser.c' object='libcurlu_la-ftplistparser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-ftplistparser.lo `test -f 'ftplistparser.c' || echo '$(srcdir)/'`ftplistparser.c
+
+libcurlu_la-getenv.lo: getenv.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-getenv.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-getenv.Tpo -c -o libcurlu_la-getenv.lo `test -f 'getenv.c' || echo '$(srcdir)/'`getenv.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-getenv.Tpo $(DEPDIR)/libcurlu_la-getenv.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='getenv.c' object='libcurlu_la-getenv.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-getenv.lo `test -f 'getenv.c' || echo '$(srcdir)/'`getenv.c
+
+libcurlu_la-getinfo.lo: getinfo.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-getinfo.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-getinfo.Tpo -c -o libcurlu_la-getinfo.lo `test -f 'getinfo.c' || echo '$(srcdir)/'`getinfo.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-getinfo.Tpo $(DEPDIR)/libcurlu_la-getinfo.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='getinfo.c' object='libcurlu_la-getinfo.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-getinfo.lo `test -f 'getinfo.c' || echo '$(srcdir)/'`getinfo.c
+
+libcurlu_la-gopher.lo: gopher.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-gopher.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-gopher.Tpo -c -o libcurlu_la-gopher.lo `test -f 'gopher.c' || echo '$(srcdir)/'`gopher.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-gopher.Tpo $(DEPDIR)/libcurlu_la-gopher.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gopher.c' object='libcurlu_la-gopher.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-gopher.lo `test -f 'gopher.c' || echo '$(srcdir)/'`gopher.c
+
+libcurlu_la-hash.lo: hash.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hash.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hash.Tpo -c -o libcurlu_la-hash.lo `test -f 'hash.c' || echo '$(srcdir)/'`hash.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hash.Tpo $(DEPDIR)/libcurlu_la-hash.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hash.c' object='libcurlu_la-hash.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hash.lo `test -f 'hash.c' || echo '$(srcdir)/'`hash.c
+
+libcurlu_la-headers.lo: headers.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-headers.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-headers.Tpo -c -o libcurlu_la-headers.lo `test -f 'headers.c' || echo '$(srcdir)/'`headers.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-headers.Tpo $(DEPDIR)/libcurlu_la-headers.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='headers.c' object='libcurlu_la-headers.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-headers.lo `test -f 'headers.c' || echo '$(srcdir)/'`headers.c
+
+libcurlu_la-hmac.lo: hmac.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hmac.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hmac.Tpo -c -o libcurlu_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hmac.Tpo $(DEPDIR)/libcurlu_la-hmac.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hmac.c' object='libcurlu_la-hmac.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c
+
+libcurlu_la-hostasyn.lo: hostasyn.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hostasyn.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hostasyn.Tpo -c -o libcurlu_la-hostasyn.lo `test -f 'hostasyn.c' || echo '$(srcdir)/'`hostasyn.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hostasyn.Tpo $(DEPDIR)/libcurlu_la-hostasyn.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hostasyn.c' object='libcurlu_la-hostasyn.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hostasyn.lo `test -f 'hostasyn.c' || echo '$(srcdir)/'`hostasyn.c
+
+libcurlu_la-hostip.lo: hostip.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hostip.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hostip.Tpo -c -o libcurlu_la-hostip.lo `test -f 'hostip.c' || echo '$(srcdir)/'`hostip.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hostip.Tpo $(DEPDIR)/libcurlu_la-hostip.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hostip.c' object='libcurlu_la-hostip.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hostip.lo `test -f 'hostip.c' || echo '$(srcdir)/'`hostip.c
+
+libcurlu_la-hostip4.lo: hostip4.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hostip4.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hostip4.Tpo -c -o libcurlu_la-hostip4.lo `test -f 'hostip4.c' || echo '$(srcdir)/'`hostip4.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hostip4.Tpo $(DEPDIR)/libcurlu_la-hostip4.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hostip4.c' object='libcurlu_la-hostip4.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hostip4.lo `test -f 'hostip4.c' || echo '$(srcdir)/'`hostip4.c
+
+libcurlu_la-hostip6.lo: hostip6.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hostip6.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hostip6.Tpo -c -o libcurlu_la-hostip6.lo `test -f 'hostip6.c' || echo '$(srcdir)/'`hostip6.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hostip6.Tpo $(DEPDIR)/libcurlu_la-hostip6.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hostip6.c' object='libcurlu_la-hostip6.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hostip6.lo `test -f 'hostip6.c' || echo '$(srcdir)/'`hostip6.c
+
+libcurlu_la-hostsyn.lo: hostsyn.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hostsyn.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hostsyn.Tpo -c -o libcurlu_la-hostsyn.lo `test -f 'hostsyn.c' || echo '$(srcdir)/'`hostsyn.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hostsyn.Tpo $(DEPDIR)/libcurlu_la-hostsyn.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hostsyn.c' object='libcurlu_la-hostsyn.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hostsyn.lo `test -f 'hostsyn.c' || echo '$(srcdir)/'`hostsyn.c
+
+libcurlu_la-hsts.lo: hsts.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hsts.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hsts.Tpo -c -o libcurlu_la-hsts.lo `test -f 'hsts.c' || echo '$(srcdir)/'`hsts.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hsts.Tpo $(DEPDIR)/libcurlu_la-hsts.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='hsts.c' object='libcurlu_la-hsts.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hsts.lo `test -f 'hsts.c' || echo '$(srcdir)/'`hsts.c
+
+libcurlu_la-http.lo: http.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http.Tpo -c -o libcurlu_la-http.lo `test -f 'http.c' || echo '$(srcdir)/'`http.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http.Tpo $(DEPDIR)/libcurlu_la-http.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http.c' object='libcurlu_la-http.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http.lo `test -f 'http.c' || echo '$(srcdir)/'`http.c
+
+libcurlu_la-http1.lo: http1.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http1.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http1.Tpo -c -o libcurlu_la-http1.lo `test -f 'http1.c' || echo '$(srcdir)/'`http1.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http1.Tpo $(DEPDIR)/libcurlu_la-http1.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http1.c' object='libcurlu_la-http1.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http1.lo `test -f 'http1.c' || echo '$(srcdir)/'`http1.c
+
+libcurlu_la-http2.lo: http2.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http2.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http2.Tpo -c -o libcurlu_la-http2.lo `test -f 'http2.c' || echo '$(srcdir)/'`http2.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http2.Tpo $(DEPDIR)/libcurlu_la-http2.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http2.c' object='libcurlu_la-http2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http2.lo `test -f 'http2.c' || echo '$(srcdir)/'`http2.c
+
+libcurlu_la-http_aws_sigv4.lo: http_aws_sigv4.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http_aws_sigv4.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http_aws_sigv4.Tpo -c -o libcurlu_la-http_aws_sigv4.lo `test -f 'http_aws_sigv4.c' || echo '$(srcdir)/'`http_aws_sigv4.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http_aws_sigv4.Tpo $(DEPDIR)/libcurlu_la-http_aws_sigv4.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http_aws_sigv4.c' object='libcurlu_la-http_aws_sigv4.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http_aws_sigv4.lo `test -f 'http_aws_sigv4.c' || echo '$(srcdir)/'`http_aws_sigv4.c
+
+libcurlu_la-http_chunks.lo: http_chunks.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http_chunks.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http_chunks.Tpo -c -o libcurlu_la-http_chunks.lo `test -f 'http_chunks.c' || echo '$(srcdir)/'`http_chunks.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http_chunks.Tpo $(DEPDIR)/libcurlu_la-http_chunks.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http_chunks.c' object='libcurlu_la-http_chunks.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http_chunks.lo `test -f 'http_chunks.c' || echo '$(srcdir)/'`http_chunks.c
+
+libcurlu_la-http_digest.lo: http_digest.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http_digest.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http_digest.Tpo -c -o libcurlu_la-http_digest.lo `test -f 'http_digest.c' || echo '$(srcdir)/'`http_digest.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http_digest.Tpo $(DEPDIR)/libcurlu_la-http_digest.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http_digest.c' object='libcurlu_la-http_digest.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http_digest.lo `test -f 'http_digest.c' || echo '$(srcdir)/'`http_digest.c
+
+libcurlu_la-http_negotiate.lo: http_negotiate.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http_negotiate.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http_negotiate.Tpo -c -o libcurlu_la-http_negotiate.lo `test -f 'http_negotiate.c' || echo '$(srcdir)/'`http_negotiate.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http_negotiate.Tpo $(DEPDIR)/libcurlu_la-http_negotiate.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http_negotiate.c' object='libcurlu_la-http_negotiate.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http_negotiate.lo `test -f 'http_negotiate.c' || echo '$(srcdir)/'`http_negotiate.c
+
+libcurlu_la-http_ntlm.lo: http_ntlm.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http_ntlm.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http_ntlm.Tpo -c -o libcurlu_la-http_ntlm.lo `test -f 'http_ntlm.c' || echo '$(srcdir)/'`http_ntlm.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http_ntlm.Tpo $(DEPDIR)/libcurlu_la-http_ntlm.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http_ntlm.c' object='libcurlu_la-http_ntlm.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http_ntlm.lo `test -f 'http_ntlm.c' || echo '$(srcdir)/'`http_ntlm.c
+
+libcurlu_la-http_proxy.lo: http_proxy.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-http_proxy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-http_proxy.Tpo -c -o libcurlu_la-http_proxy.lo `test -f 'http_proxy.c' || echo '$(srcdir)/'`http_proxy.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-http_proxy.Tpo $(DEPDIR)/libcurlu_la-http_proxy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='http_proxy.c' object='libcurlu_la-http_proxy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-http_proxy.lo `test -f 'http_proxy.c' || echo '$(srcdir)/'`http_proxy.c
+
+libcurlu_la-idn.lo: idn.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-idn.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-idn.Tpo -c -o libcurlu_la-idn.lo `test -f 'idn.c' || echo '$(srcdir)/'`idn.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-idn.Tpo $(DEPDIR)/libcurlu_la-idn.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='idn.c' object='libcurlu_la-idn.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-idn.lo `test -f 'idn.c' || echo '$(srcdir)/'`idn.c
+
+libcurlu_la-if2ip.lo: if2ip.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-if2ip.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-if2ip.Tpo -c -o libcurlu_la-if2ip.lo `test -f 'if2ip.c' || echo '$(srcdir)/'`if2ip.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-if2ip.Tpo $(DEPDIR)/libcurlu_la-if2ip.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='if2ip.c' object='libcurlu_la-if2ip.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-if2ip.lo `test -f 'if2ip.c' || echo '$(srcdir)/'`if2ip.c
+
+libcurlu_la-imap.lo: imap.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-imap.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-imap.Tpo -c -o libcurlu_la-imap.lo `test -f 'imap.c' || echo '$(srcdir)/'`imap.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-imap.Tpo $(DEPDIR)/libcurlu_la-imap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='imap.c' object='libcurlu_la-imap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-imap.lo `test -f 'imap.c' || echo '$(srcdir)/'`imap.c
+
+libcurlu_la-inet_ntop.lo: inet_ntop.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-inet_ntop.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-inet_ntop.Tpo -c -o libcurlu_la-inet_ntop.lo `test -f 'inet_ntop.c' || echo '$(srcdir)/'`inet_ntop.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-inet_ntop.Tpo $(DEPDIR)/libcurlu_la-inet_ntop.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='inet_ntop.c' object='libcurlu_la-inet_ntop.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-inet_ntop.lo `test -f 'inet_ntop.c' || echo '$(srcdir)/'`inet_ntop.c
+
+libcurlu_la-inet_pton.lo: inet_pton.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-inet_pton.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-inet_pton.Tpo -c -o libcurlu_la-inet_pton.lo `test -f 'inet_pton.c' || echo '$(srcdir)/'`inet_pton.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-inet_pton.Tpo $(DEPDIR)/libcurlu_la-inet_pton.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='inet_pton.c' object='libcurlu_la-inet_pton.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-inet_pton.lo `test -f 'inet_pton.c' || echo '$(srcdir)/'`inet_pton.c
+
+libcurlu_la-krb5.lo: krb5.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-krb5.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-krb5.Tpo -c -o libcurlu_la-krb5.lo `test -f 'krb5.c' || echo '$(srcdir)/'`krb5.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-krb5.Tpo $(DEPDIR)/libcurlu_la-krb5.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='krb5.c' object='libcurlu_la-krb5.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-krb5.lo `test -f 'krb5.c' || echo '$(srcdir)/'`krb5.c
+
+libcurlu_la-ldap.lo: ldap.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-ldap.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-ldap.Tpo -c -o libcurlu_la-ldap.lo `test -f 'ldap.c' || echo '$(srcdir)/'`ldap.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-ldap.Tpo $(DEPDIR)/libcurlu_la-ldap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ldap.c' object='libcurlu_la-ldap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-ldap.lo `test -f 'ldap.c' || echo '$(srcdir)/'`ldap.c
+
+libcurlu_la-llist.lo: llist.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-llist.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-llist.Tpo -c -o libcurlu_la-llist.lo `test -f 'llist.c' || echo '$(srcdir)/'`llist.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-llist.Tpo $(DEPDIR)/libcurlu_la-llist.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='llist.c' object='libcurlu_la-llist.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-llist.lo `test -f 'llist.c' || echo '$(srcdir)/'`llist.c
+
+libcurlu_la-macos.lo: macos.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-macos.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-macos.Tpo -c -o libcurlu_la-macos.lo `test -f 'macos.c' || echo '$(srcdir)/'`macos.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-macos.Tpo $(DEPDIR)/libcurlu_la-macos.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='macos.c' object='libcurlu_la-macos.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-macos.lo `test -f 'macos.c' || echo '$(srcdir)/'`macos.c
+
+libcurlu_la-md4.lo: md4.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-md4.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-md4.Tpo -c -o libcurlu_la-md4.lo `test -f 'md4.c' || echo '$(srcdir)/'`md4.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-md4.Tpo $(DEPDIR)/libcurlu_la-md4.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='md4.c' object='libcurlu_la-md4.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-md4.lo `test -f 'md4.c' || echo '$(srcdir)/'`md4.c
+
+libcurlu_la-md5.lo: md5.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-md5.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-md5.Tpo -c -o libcurlu_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-md5.Tpo $(DEPDIR)/libcurlu_la-md5.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='md5.c' object='libcurlu_la-md5.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
+
+libcurlu_la-memdebug.lo: memdebug.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-memdebug.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-memdebug.Tpo -c -o libcurlu_la-memdebug.lo `test -f 'memdebug.c' || echo '$(srcdir)/'`memdebug.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-memdebug.Tpo $(DEPDIR)/libcurlu_la-memdebug.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='memdebug.c' object='libcurlu_la-memdebug.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-memdebug.lo `test -f 'memdebug.c' || echo '$(srcdir)/'`memdebug.c
+
+libcurlu_la-mime.lo: mime.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-mime.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-mime.Tpo -c -o libcurlu_la-mime.lo `test -f 'mime.c' || echo '$(srcdir)/'`mime.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-mime.Tpo $(DEPDIR)/libcurlu_la-mime.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='mime.c' object='libcurlu_la-mime.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-mime.lo `test -f 'mime.c' || echo '$(srcdir)/'`mime.c
+
+libcurlu_la-mprintf.lo: mprintf.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-mprintf.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-mprintf.Tpo -c -o libcurlu_la-mprintf.lo `test -f 'mprintf.c' || echo '$(srcdir)/'`mprintf.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-mprintf.Tpo $(DEPDIR)/libcurlu_la-mprintf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='mprintf.c' object='libcurlu_la-mprintf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-mprintf.lo `test -f 'mprintf.c' || echo '$(srcdir)/'`mprintf.c
+
+libcurlu_la-mqtt.lo: mqtt.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-mqtt.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-mqtt.Tpo -c -o libcurlu_la-mqtt.lo `test -f 'mqtt.c' || echo '$(srcdir)/'`mqtt.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-mqtt.Tpo $(DEPDIR)/libcurlu_la-mqtt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='mqtt.c' object='libcurlu_la-mqtt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-mqtt.lo `test -f 'mqtt.c' || echo '$(srcdir)/'`mqtt.c
+
+libcurlu_la-multi.lo: multi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-multi.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-multi.Tpo -c -o libcurlu_la-multi.lo `test -f 'multi.c' || echo '$(srcdir)/'`multi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-multi.Tpo $(DEPDIR)/libcurlu_la-multi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='multi.c' object='libcurlu_la-multi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-multi.lo `test -f 'multi.c' || echo '$(srcdir)/'`multi.c
+
+libcurlu_la-netrc.lo: netrc.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-netrc.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-netrc.Tpo -c -o libcurlu_la-netrc.lo `test -f 'netrc.c' || echo '$(srcdir)/'`netrc.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-netrc.Tpo $(DEPDIR)/libcurlu_la-netrc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='netrc.c' object='libcurlu_la-netrc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-netrc.lo `test -f 'netrc.c' || echo '$(srcdir)/'`netrc.c
+
+libcurlu_la-nonblock.lo: nonblock.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-nonblock.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-nonblock.Tpo -c -o libcurlu_la-nonblock.lo `test -f 'nonblock.c' || echo '$(srcdir)/'`nonblock.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-nonblock.Tpo $(DEPDIR)/libcurlu_la-nonblock.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='nonblock.c' object='libcurlu_la-nonblock.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-nonblock.lo `test -f 'nonblock.c' || echo '$(srcdir)/'`nonblock.c
+
+libcurlu_la-noproxy.lo: noproxy.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-noproxy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-noproxy.Tpo -c -o libcurlu_la-noproxy.lo `test -f 'noproxy.c' || echo '$(srcdir)/'`noproxy.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-noproxy.Tpo $(DEPDIR)/libcurlu_la-noproxy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='noproxy.c' object='libcurlu_la-noproxy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-noproxy.lo `test -f 'noproxy.c' || echo '$(srcdir)/'`noproxy.c
+
+libcurlu_la-openldap.lo: openldap.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-openldap.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-openldap.Tpo -c -o libcurlu_la-openldap.lo `test -f 'openldap.c' || echo '$(srcdir)/'`openldap.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-openldap.Tpo $(DEPDIR)/libcurlu_la-openldap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='openldap.c' object='libcurlu_la-openldap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-openldap.lo `test -f 'openldap.c' || echo '$(srcdir)/'`openldap.c
+
+libcurlu_la-parsedate.lo: parsedate.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-parsedate.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-parsedate.Tpo -c -o libcurlu_la-parsedate.lo `test -f 'parsedate.c' || echo '$(srcdir)/'`parsedate.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-parsedate.Tpo $(DEPDIR)/libcurlu_la-parsedate.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='parsedate.c' object='libcurlu_la-parsedate.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-parsedate.lo `test -f 'parsedate.c' || echo '$(srcdir)/'`parsedate.c
+
+libcurlu_la-pingpong.lo: pingpong.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-pingpong.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-pingpong.Tpo -c -o libcurlu_la-pingpong.lo `test -f 'pingpong.c' || echo '$(srcdir)/'`pingpong.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-pingpong.Tpo $(DEPDIR)/libcurlu_la-pingpong.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='pingpong.c' object='libcurlu_la-pingpong.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-pingpong.lo `test -f 'pingpong.c' || echo '$(srcdir)/'`pingpong.c
+
+libcurlu_la-pop3.lo: pop3.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-pop3.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-pop3.Tpo -c -o libcurlu_la-pop3.lo `test -f 'pop3.c' || echo '$(srcdir)/'`pop3.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-pop3.Tpo $(DEPDIR)/libcurlu_la-pop3.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='pop3.c' object='libcurlu_la-pop3.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-pop3.lo `test -f 'pop3.c' || echo '$(srcdir)/'`pop3.c
+
+libcurlu_la-progress.lo: progress.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-progress.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-progress.Tpo -c -o libcurlu_la-progress.lo `test -f 'progress.c' || echo '$(srcdir)/'`progress.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-progress.Tpo $(DEPDIR)/libcurlu_la-progress.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='progress.c' object='libcurlu_la-progress.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-progress.lo `test -f 'progress.c' || echo '$(srcdir)/'`progress.c
+
+libcurlu_la-psl.lo: psl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-psl.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-psl.Tpo -c -o libcurlu_la-psl.lo `test -f 'psl.c' || echo '$(srcdir)/'`psl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-psl.Tpo $(DEPDIR)/libcurlu_la-psl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='psl.c' object='libcurlu_la-psl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-psl.lo `test -f 'psl.c' || echo '$(srcdir)/'`psl.c
+
+libcurlu_la-rand.lo: rand.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-rand.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-rand.Tpo -c -o libcurlu_la-rand.lo `test -f 'rand.c' || echo '$(srcdir)/'`rand.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-rand.Tpo $(DEPDIR)/libcurlu_la-rand.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='rand.c' object='libcurlu_la-rand.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-rand.lo `test -f 'rand.c' || echo '$(srcdir)/'`rand.c
+
+libcurlu_la-rename.lo: rename.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-rename.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-rename.Tpo -c -o libcurlu_la-rename.lo `test -f 'rename.c' || echo '$(srcdir)/'`rename.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-rename.Tpo $(DEPDIR)/libcurlu_la-rename.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='rename.c' object='libcurlu_la-rename.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-rename.lo `test -f 'rename.c' || echo '$(srcdir)/'`rename.c
+
+libcurlu_la-request.lo: request.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-request.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-request.Tpo -c -o libcurlu_la-request.lo `test -f 'request.c' || echo '$(srcdir)/'`request.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-request.Tpo $(DEPDIR)/libcurlu_la-request.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='request.c' object='libcurlu_la-request.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-request.lo `test -f 'request.c' || echo '$(srcdir)/'`request.c
+
+libcurlu_la-rtsp.lo: rtsp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-rtsp.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-rtsp.Tpo -c -o libcurlu_la-rtsp.lo `test -f 'rtsp.c' || echo '$(srcdir)/'`rtsp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-rtsp.Tpo $(DEPDIR)/libcurlu_la-rtsp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='rtsp.c' object='libcurlu_la-rtsp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-rtsp.lo `test -f 'rtsp.c' || echo '$(srcdir)/'`rtsp.c
+
+libcurlu_la-select.lo: select.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-select.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-select.Tpo -c -o libcurlu_la-select.lo `test -f 'select.c' || echo '$(srcdir)/'`select.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-select.Tpo $(DEPDIR)/libcurlu_la-select.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='select.c' object='libcurlu_la-select.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-select.lo `test -f 'select.c' || echo '$(srcdir)/'`select.c
+
+libcurlu_la-sendf.lo: sendf.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-sendf.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-sendf.Tpo -c -o libcurlu_la-sendf.lo `test -f 'sendf.c' || echo '$(srcdir)/'`sendf.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-sendf.Tpo $(DEPDIR)/libcurlu_la-sendf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sendf.c' object='libcurlu_la-sendf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-sendf.lo `test -f 'sendf.c' || echo '$(srcdir)/'`sendf.c
+
+libcurlu_la-setopt.lo: setopt.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-setopt.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-setopt.Tpo -c -o libcurlu_la-setopt.lo `test -f 'setopt.c' || echo '$(srcdir)/'`setopt.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-setopt.Tpo $(DEPDIR)/libcurlu_la-setopt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='setopt.c' object='libcurlu_la-setopt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-setopt.lo `test -f 'setopt.c' || echo '$(srcdir)/'`setopt.c
+
+libcurlu_la-sha256.lo: sha256.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-sha256.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-sha256.Tpo -c -o libcurlu_la-sha256.lo `test -f 'sha256.c' || echo '$(srcdir)/'`sha256.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-sha256.Tpo $(DEPDIR)/libcurlu_la-sha256.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sha256.c' object='libcurlu_la-sha256.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-sha256.lo `test -f 'sha256.c' || echo '$(srcdir)/'`sha256.c
+
+libcurlu_la-share.lo: share.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-share.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-share.Tpo -c -o libcurlu_la-share.lo `test -f 'share.c' || echo '$(srcdir)/'`share.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-share.Tpo $(DEPDIR)/libcurlu_la-share.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='share.c' object='libcurlu_la-share.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-share.lo `test -f 'share.c' || echo '$(srcdir)/'`share.c
+
+libcurlu_la-slist.lo: slist.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-slist.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-slist.Tpo -c -o libcurlu_la-slist.lo `test -f 'slist.c' || echo '$(srcdir)/'`slist.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-slist.Tpo $(DEPDIR)/libcurlu_la-slist.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='slist.c' object='libcurlu_la-slist.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-slist.lo `test -f 'slist.c' || echo '$(srcdir)/'`slist.c
+
+libcurlu_la-smb.lo: smb.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-smb.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-smb.Tpo -c -o libcurlu_la-smb.lo `test -f 'smb.c' || echo '$(srcdir)/'`smb.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-smb.Tpo $(DEPDIR)/libcurlu_la-smb.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='smb.c' object='libcurlu_la-smb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-smb.lo `test -f 'smb.c' || echo '$(srcdir)/'`smb.c
+
+libcurlu_la-smtp.lo: smtp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-smtp.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-smtp.Tpo -c -o libcurlu_la-smtp.lo `test -f 'smtp.c' || echo '$(srcdir)/'`smtp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-smtp.Tpo $(DEPDIR)/libcurlu_la-smtp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='smtp.c' object='libcurlu_la-smtp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-smtp.lo `test -f 'smtp.c' || echo '$(srcdir)/'`smtp.c
+
+libcurlu_la-socketpair.lo: socketpair.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-socketpair.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-socketpair.Tpo -c -o libcurlu_la-socketpair.lo `test -f 'socketpair.c' || echo '$(srcdir)/'`socketpair.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-socketpair.Tpo $(DEPDIR)/libcurlu_la-socketpair.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='socketpair.c' object='libcurlu_la-socketpair.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-socketpair.lo `test -f 'socketpair.c' || echo '$(srcdir)/'`socketpair.c
+
+libcurlu_la-socks.lo: socks.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-socks.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-socks.Tpo -c -o libcurlu_la-socks.lo `test -f 'socks.c' || echo '$(srcdir)/'`socks.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-socks.Tpo $(DEPDIR)/libcurlu_la-socks.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='socks.c' object='libcurlu_la-socks.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-socks.lo `test -f 'socks.c' || echo '$(srcdir)/'`socks.c
+
+libcurlu_la-socks_gssapi.lo: socks_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-socks_gssapi.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-socks_gssapi.Tpo -c -o libcurlu_la-socks_gssapi.lo `test -f 'socks_gssapi.c' || echo '$(srcdir)/'`socks_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-socks_gssapi.Tpo $(DEPDIR)/libcurlu_la-socks_gssapi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='socks_gssapi.c' object='libcurlu_la-socks_gssapi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-socks_gssapi.lo `test -f 'socks_gssapi.c' || echo '$(srcdir)/'`socks_gssapi.c
+
+libcurlu_la-socks_sspi.lo: socks_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-socks_sspi.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-socks_sspi.Tpo -c -o libcurlu_la-socks_sspi.lo `test -f 'socks_sspi.c' || echo '$(srcdir)/'`socks_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-socks_sspi.Tpo $(DEPDIR)/libcurlu_la-socks_sspi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='socks_sspi.c' object='libcurlu_la-socks_sspi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-socks_sspi.lo `test -f 'socks_sspi.c' || echo '$(srcdir)/'`socks_sspi.c
+
+libcurlu_la-speedcheck.lo: speedcheck.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-speedcheck.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-speedcheck.Tpo -c -o libcurlu_la-speedcheck.lo `test -f 'speedcheck.c' || echo '$(srcdir)/'`speedcheck.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-speedcheck.Tpo $(DEPDIR)/libcurlu_la-speedcheck.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='speedcheck.c' object='libcurlu_la-speedcheck.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-speedcheck.lo `test -f 'speedcheck.c' || echo '$(srcdir)/'`speedcheck.c
+
+libcurlu_la-splay.lo: splay.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-splay.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-splay.Tpo -c -o libcurlu_la-splay.lo `test -f 'splay.c' || echo '$(srcdir)/'`splay.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-splay.Tpo $(DEPDIR)/libcurlu_la-splay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='splay.c' object='libcurlu_la-splay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-splay.lo `test -f 'splay.c' || echo '$(srcdir)/'`splay.c
+
+libcurlu_la-strcase.lo: strcase.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strcase.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strcase.Tpo -c -o libcurlu_la-strcase.lo `test -f 'strcase.c' || echo '$(srcdir)/'`strcase.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strcase.Tpo $(DEPDIR)/libcurlu_la-strcase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='strcase.c' object='libcurlu_la-strcase.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strcase.lo `test -f 'strcase.c' || echo '$(srcdir)/'`strcase.c
+
+libcurlu_la-strdup.lo: strdup.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strdup.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strdup.Tpo -c -o libcurlu_la-strdup.lo `test -f 'strdup.c' || echo '$(srcdir)/'`strdup.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strdup.Tpo $(DEPDIR)/libcurlu_la-strdup.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='strdup.c' object='libcurlu_la-strdup.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strdup.lo `test -f 'strdup.c' || echo '$(srcdir)/'`strdup.c
+
+libcurlu_la-strerror.lo: strerror.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strerror.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strerror.Tpo -c -o libcurlu_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strerror.Tpo $(DEPDIR)/libcurlu_la-strerror.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='strerror.c' object='libcurlu_la-strerror.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c
+
+libcurlu_la-strtok.lo: strtok.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strtok.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strtok.Tpo -c -o libcurlu_la-strtok.lo `test -f 'strtok.c' || echo '$(srcdir)/'`strtok.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strtok.Tpo $(DEPDIR)/libcurlu_la-strtok.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='strtok.c' object='libcurlu_la-strtok.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strtok.lo `test -f 'strtok.c' || echo '$(srcdir)/'`strtok.c
+
+libcurlu_la-strtoofft.lo: strtoofft.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strtoofft.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strtoofft.Tpo -c -o libcurlu_la-strtoofft.lo `test -f 'strtoofft.c' || echo '$(srcdir)/'`strtoofft.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strtoofft.Tpo $(DEPDIR)/libcurlu_la-strtoofft.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='strtoofft.c' object='libcurlu_la-strtoofft.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strtoofft.lo `test -f 'strtoofft.c' || echo '$(srcdir)/'`strtoofft.c
+
+libcurlu_la-system_win32.lo: system_win32.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-system_win32.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-system_win32.Tpo -c -o libcurlu_la-system_win32.lo `test -f 'system_win32.c' || echo '$(srcdir)/'`system_win32.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-system_win32.Tpo $(DEPDIR)/libcurlu_la-system_win32.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='system_win32.c' object='libcurlu_la-system_win32.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-system_win32.lo `test -f 'system_win32.c' || echo '$(srcdir)/'`system_win32.c
+
+libcurlu_la-telnet.lo: telnet.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-telnet.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-telnet.Tpo -c -o libcurlu_la-telnet.lo `test -f 'telnet.c' || echo '$(srcdir)/'`telnet.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-telnet.Tpo $(DEPDIR)/libcurlu_la-telnet.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='telnet.c' object='libcurlu_la-telnet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-telnet.lo `test -f 'telnet.c' || echo '$(srcdir)/'`telnet.c
+
+libcurlu_la-tftp.lo: tftp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-tftp.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-tftp.Tpo -c -o libcurlu_la-tftp.lo `test -f 'tftp.c' || echo '$(srcdir)/'`tftp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-tftp.Tpo $(DEPDIR)/libcurlu_la-tftp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tftp.c' object='libcurlu_la-tftp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-tftp.lo `test -f 'tftp.c' || echo '$(srcdir)/'`tftp.c
+
+libcurlu_la-timediff.lo: timediff.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-timediff.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-timediff.Tpo -c -o libcurlu_la-timediff.lo `test -f 'timediff.c' || echo '$(srcdir)/'`timediff.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-timediff.Tpo $(DEPDIR)/libcurlu_la-timediff.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='timediff.c' object='libcurlu_la-timediff.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-timediff.lo `test -f 'timediff.c' || echo '$(srcdir)/'`timediff.c
+
+libcurlu_la-timeval.lo: timeval.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-timeval.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-timeval.Tpo -c -o libcurlu_la-timeval.lo `test -f 'timeval.c' || echo '$(srcdir)/'`timeval.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-timeval.Tpo $(DEPDIR)/libcurlu_la-timeval.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='timeval.c' object='libcurlu_la-timeval.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-timeval.lo `test -f 'timeval.c' || echo '$(srcdir)/'`timeval.c
+
+libcurlu_la-transfer.lo: transfer.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-transfer.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-transfer.Tpo -c -o libcurlu_la-transfer.lo `test -f 'transfer.c' || echo '$(srcdir)/'`transfer.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-transfer.Tpo $(DEPDIR)/libcurlu_la-transfer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='transfer.c' object='libcurlu_la-transfer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-transfer.lo `test -f 'transfer.c' || echo '$(srcdir)/'`transfer.c
+
+libcurlu_la-url.lo: url.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-url.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-url.Tpo -c -o libcurlu_la-url.lo `test -f 'url.c' || echo '$(srcdir)/'`url.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-url.Tpo $(DEPDIR)/libcurlu_la-url.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='url.c' object='libcurlu_la-url.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-url.lo `test -f 'url.c' || echo '$(srcdir)/'`url.c
+
+libcurlu_la-urlapi.lo: urlapi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-urlapi.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-urlapi.Tpo -c -o libcurlu_la-urlapi.lo `test -f 'urlapi.c' || echo '$(srcdir)/'`urlapi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-urlapi.Tpo $(DEPDIR)/libcurlu_la-urlapi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='urlapi.c' object='libcurlu_la-urlapi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-urlapi.lo `test -f 'urlapi.c' || echo '$(srcdir)/'`urlapi.c
+
+libcurlu_la-version.lo: version.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-version.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-version.Tpo -c -o libcurlu_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-version.Tpo $(DEPDIR)/libcurlu_la-version.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='version.c' object='libcurlu_la-version.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c
+
+libcurlu_la-version_win32.lo: version_win32.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-version_win32.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-version_win32.Tpo -c -o libcurlu_la-version_win32.lo `test -f 'version_win32.c' || echo '$(srcdir)/'`version_win32.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-version_win32.Tpo $(DEPDIR)/libcurlu_la-version_win32.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='version_win32.c' object='libcurlu_la-version_win32.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-version_win32.lo `test -f 'version_win32.c' || echo '$(srcdir)/'`version_win32.c
+
+libcurlu_la-warnless.lo: warnless.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-warnless.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-warnless.Tpo -c -o libcurlu_la-warnless.lo `test -f 'warnless.c' || echo '$(srcdir)/'`warnless.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-warnless.Tpo $(DEPDIR)/libcurlu_la-warnless.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='warnless.c' object='libcurlu_la-warnless.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-warnless.lo `test -f 'warnless.c' || echo '$(srcdir)/'`warnless.c
+
+libcurlu_la-ws.lo: ws.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-ws.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-ws.Tpo -c -o libcurlu_la-ws.lo `test -f 'ws.c' || echo '$(srcdir)/'`ws.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-ws.Tpo $(DEPDIR)/libcurlu_la-ws.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ws.c' object='libcurlu_la-ws.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-ws.lo `test -f 'ws.c' || echo '$(srcdir)/'`ws.c
+
+vauth/libcurlu_la-cleartext.lo: vauth/cleartext.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-cleartext.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-cleartext.Tpo -c -o vauth/libcurlu_la-cleartext.lo `test -f 'vauth/cleartext.c' || echo '$(srcdir)/'`vauth/cleartext.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-cleartext.Tpo vauth/$(DEPDIR)/libcurlu_la-cleartext.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/cleartext.c' object='vauth/libcurlu_la-cleartext.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-cleartext.lo `test -f 'vauth/cleartext.c' || echo '$(srcdir)/'`vauth/cleartext.c
+
+vauth/libcurlu_la-cram.lo: vauth/cram.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-cram.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-cram.Tpo -c -o vauth/libcurlu_la-cram.lo `test -f 'vauth/cram.c' || echo '$(srcdir)/'`vauth/cram.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-cram.Tpo vauth/$(DEPDIR)/libcurlu_la-cram.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/cram.c' object='vauth/libcurlu_la-cram.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-cram.lo `test -f 'vauth/cram.c' || echo '$(srcdir)/'`vauth/cram.c
+
+vauth/libcurlu_la-digest.lo: vauth/digest.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-digest.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-digest.Tpo -c -o vauth/libcurlu_la-digest.lo `test -f 'vauth/digest.c' || echo '$(srcdir)/'`vauth/digest.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-digest.Tpo vauth/$(DEPDIR)/libcurlu_la-digest.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/digest.c' object='vauth/libcurlu_la-digest.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-digest.lo `test -f 'vauth/digest.c' || echo '$(srcdir)/'`vauth/digest.c
+
+vauth/libcurlu_la-digest_sspi.lo: vauth/digest_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-digest_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Tpo -c -o vauth/libcurlu_la-digest_sspi.lo `test -f 'vauth/digest_sspi.c' || echo '$(srcdir)/'`vauth/digest_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Tpo vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/digest_sspi.c' object='vauth/libcurlu_la-digest_sspi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-digest_sspi.lo `test -f 'vauth/digest_sspi.c' || echo '$(srcdir)/'`vauth/digest_sspi.c
+
+vauth/libcurlu_la-gsasl.lo: vauth/gsasl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-gsasl.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-gsasl.Tpo -c -o vauth/libcurlu_la-gsasl.lo `test -f 'vauth/gsasl.c' || echo '$(srcdir)/'`vauth/gsasl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-gsasl.Tpo vauth/$(DEPDIR)/libcurlu_la-gsasl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/gsasl.c' object='vauth/libcurlu_la-gsasl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-gsasl.lo `test -f 'vauth/gsasl.c' || echo '$(srcdir)/'`vauth/gsasl.c
+
+vauth/libcurlu_la-krb5_gssapi.lo: vauth/krb5_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-krb5_gssapi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Tpo -c -o vauth/libcurlu_la-krb5_gssapi.lo `test -f 'vauth/krb5_gssapi.c' || echo '$(srcdir)/'`vauth/krb5_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Tpo vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/krb5_gssapi.c' object='vauth/libcurlu_la-krb5_gssapi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-krb5_gssapi.lo `test -f 'vauth/krb5_gssapi.c' || echo '$(srcdir)/'`vauth/krb5_gssapi.c
+
+vauth/libcurlu_la-krb5_sspi.lo: vauth/krb5_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-krb5_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Tpo -c -o vauth/libcurlu_la-krb5_sspi.lo `test -f 'vauth/krb5_sspi.c' || echo '$(srcdir)/'`vauth/krb5_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Tpo vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/krb5_sspi.c' object='vauth/libcurlu_la-krb5_sspi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-krb5_sspi.lo `test -f 'vauth/krb5_sspi.c' || echo '$(srcdir)/'`vauth/krb5_sspi.c
+
+vauth/libcurlu_la-ntlm.lo: vauth/ntlm.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-ntlm.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-ntlm.Tpo -c -o vauth/libcurlu_la-ntlm.lo `test -f 'vauth/ntlm.c' || echo '$(srcdir)/'`vauth/ntlm.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-ntlm.Tpo vauth/$(DEPDIR)/libcurlu_la-ntlm.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/ntlm.c' object='vauth/libcurlu_la-ntlm.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-ntlm.lo `test -f 'vauth/ntlm.c' || echo '$(srcdir)/'`vauth/ntlm.c
+
+vauth/libcurlu_la-ntlm_sspi.lo: vauth/ntlm_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-ntlm_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Tpo -c -o vauth/libcurlu_la-ntlm_sspi.lo `test -f 'vauth/ntlm_sspi.c' || echo '$(srcdir)/'`vauth/ntlm_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Tpo vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/ntlm_sspi.c' object='vauth/libcurlu_la-ntlm_sspi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-ntlm_sspi.lo `test -f 'vauth/ntlm_sspi.c' || echo '$(srcdir)/'`vauth/ntlm_sspi.c
+
+vauth/libcurlu_la-oauth2.lo: vauth/oauth2.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-oauth2.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-oauth2.Tpo -c -o vauth/libcurlu_la-oauth2.lo `test -f 'vauth/oauth2.c' || echo '$(srcdir)/'`vauth/oauth2.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-oauth2.Tpo vauth/$(DEPDIR)/libcurlu_la-oauth2.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/oauth2.c' object='vauth/libcurlu_la-oauth2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-oauth2.lo `test -f 'vauth/oauth2.c' || echo '$(srcdir)/'`vauth/oauth2.c
+
+vauth/libcurlu_la-spnego_gssapi.lo: vauth/spnego_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-spnego_gssapi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Tpo -c -o vauth/libcurlu_la-spnego_gssapi.lo `test -f 'vauth/spnego_gssapi.c' || echo '$(srcdir)/'`vauth/spnego_gssapi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Tpo vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/spnego_gssapi.c' object='vauth/libcurlu_la-spnego_gssapi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-spnego_gssapi.lo `test -f 'vauth/spnego_gssapi.c' || echo '$(srcdir)/'`vauth/spnego_gssapi.c
+
+vauth/libcurlu_la-spnego_sspi.lo: vauth/spnego_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-spnego_sspi.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Tpo -c -o vauth/libcurlu_la-spnego_sspi.lo `test -f 'vauth/spnego_sspi.c' || echo '$(srcdir)/'`vauth/spnego_sspi.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Tpo vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/spnego_sspi.c' object='vauth/libcurlu_la-spnego_sspi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-spnego_sspi.lo `test -f 'vauth/spnego_sspi.c' || echo '$(srcdir)/'`vauth/spnego_sspi.c
+
+vauth/libcurlu_la-vauth.lo: vauth/vauth.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vauth/libcurlu_la-vauth.lo -MD -MP -MF vauth/$(DEPDIR)/libcurlu_la-vauth.Tpo -c -o vauth/libcurlu_la-vauth.lo `test -f 'vauth/vauth.c' || echo '$(srcdir)/'`vauth/vauth.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vauth/$(DEPDIR)/libcurlu_la-vauth.Tpo vauth/$(DEPDIR)/libcurlu_la-vauth.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vauth/vauth.c' object='vauth/libcurlu_la-vauth.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vauth/libcurlu_la-vauth.lo `test -f 'vauth/vauth.c' || echo '$(srcdir)/'`vauth/vauth.c
+
+vtls/libcurlu_la-bearssl.lo: vtls/bearssl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-bearssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-bearssl.Tpo -c -o vtls/libcurlu_la-bearssl.lo `test -f 'vtls/bearssl.c' || echo '$(srcdir)/'`vtls/bearssl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-bearssl.Tpo vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/bearssl.c' object='vtls/libcurlu_la-bearssl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-bearssl.lo `test -f 'vtls/bearssl.c' || echo '$(srcdir)/'`vtls/bearssl.c
+
+vtls/libcurlu_la-gtls.lo: vtls/gtls.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-gtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-gtls.Tpo -c -o vtls/libcurlu_la-gtls.lo `test -f 'vtls/gtls.c' || echo '$(srcdir)/'`vtls/gtls.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-gtls.Tpo vtls/$(DEPDIR)/libcurlu_la-gtls.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/gtls.c' object='vtls/libcurlu_la-gtls.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-gtls.lo `test -f 'vtls/gtls.c' || echo '$(srcdir)/'`vtls/gtls.c
+
+vtls/libcurlu_la-hostcheck.lo: vtls/hostcheck.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-hostcheck.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-hostcheck.Tpo -c -o vtls/libcurlu_la-hostcheck.lo `test -f 'vtls/hostcheck.c' || echo '$(srcdir)/'`vtls/hostcheck.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-hostcheck.Tpo vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/hostcheck.c' object='vtls/libcurlu_la-hostcheck.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-hostcheck.lo `test -f 'vtls/hostcheck.c' || echo '$(srcdir)/'`vtls/hostcheck.c
+
+vtls/libcurlu_la-keylog.lo: vtls/keylog.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-keylog.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-keylog.Tpo -c -o vtls/libcurlu_la-keylog.lo `test -f 'vtls/keylog.c' || echo '$(srcdir)/'`vtls/keylog.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-keylog.Tpo vtls/$(DEPDIR)/libcurlu_la-keylog.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/keylog.c' object='vtls/libcurlu_la-keylog.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-keylog.lo `test -f 'vtls/keylog.c' || echo '$(srcdir)/'`vtls/keylog.c
+
+vtls/libcurlu_la-mbedtls.lo: vtls/mbedtls.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-mbedtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-mbedtls.Tpo -c -o vtls/libcurlu_la-mbedtls.lo `test -f 'vtls/mbedtls.c' || echo '$(srcdir)/'`vtls/mbedtls.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-mbedtls.Tpo vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/mbedtls.c' object='vtls/libcurlu_la-mbedtls.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-mbedtls.lo `test -f 'vtls/mbedtls.c' || echo '$(srcdir)/'`vtls/mbedtls.c
+
+vtls/libcurlu_la-mbedtls_threadlock.lo: vtls/mbedtls_threadlock.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-mbedtls_threadlock.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Tpo -c -o vtls/libcurlu_la-mbedtls_threadlock.lo `test -f 'vtls/mbedtls_threadlock.c' || echo '$(srcdir)/'`vtls/mbedtls_threadlock.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Tpo vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/mbedtls_threadlock.c' object='vtls/libcurlu_la-mbedtls_threadlock.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-mbedtls_threadlock.lo `test -f 'vtls/mbedtls_threadlock.c' || echo '$(srcdir)/'`vtls/mbedtls_threadlock.c
+
+vtls/libcurlu_la-openssl.lo: vtls/openssl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-openssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-openssl.Tpo -c -o vtls/libcurlu_la-openssl.lo `test -f 'vtls/openssl.c' || echo '$(srcdir)/'`vtls/openssl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-openssl.Tpo vtls/$(DEPDIR)/libcurlu_la-openssl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/openssl.c' object='vtls/libcurlu_la-openssl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-openssl.lo `test -f 'vtls/openssl.c' || echo '$(srcdir)/'`vtls/openssl.c
+
+vtls/libcurlu_la-rustls.lo: vtls/rustls.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-rustls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-rustls.Tpo -c -o vtls/libcurlu_la-rustls.lo `test -f 'vtls/rustls.c' || echo '$(srcdir)/'`vtls/rustls.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-rustls.Tpo vtls/$(DEPDIR)/libcurlu_la-rustls.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/rustls.c' object='vtls/libcurlu_la-rustls.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-rustls.lo `test -f 'vtls/rustls.c' || echo '$(srcdir)/'`vtls/rustls.c
+
+vtls/libcurlu_la-schannel.lo: vtls/schannel.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-schannel.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-schannel.Tpo -c -o vtls/libcurlu_la-schannel.lo `test -f 'vtls/schannel.c' || echo '$(srcdir)/'`vtls/schannel.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-schannel.Tpo vtls/$(DEPDIR)/libcurlu_la-schannel.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/schannel.c' object='vtls/libcurlu_la-schannel.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-schannel.lo `test -f 'vtls/schannel.c' || echo '$(srcdir)/'`vtls/schannel.c
+
+vtls/libcurlu_la-schannel_verify.lo: vtls/schannel_verify.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-schannel_verify.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Tpo -c -o vtls/libcurlu_la-schannel_verify.lo `test -f 'vtls/schannel_verify.c' || echo '$(srcdir)/'`vtls/schannel_verify.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Tpo vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/schannel_verify.c' object='vtls/libcurlu_la-schannel_verify.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-schannel_verify.lo `test -f 'vtls/schannel_verify.c' || echo '$(srcdir)/'`vtls/schannel_verify.c
+
+vtls/libcurlu_la-sectransp.lo: vtls/sectransp.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-sectransp.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-sectransp.Tpo -c -o vtls/libcurlu_la-sectransp.lo `test -f 'vtls/sectransp.c' || echo '$(srcdir)/'`vtls/sectransp.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-sectransp.Tpo vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/sectransp.c' object='vtls/libcurlu_la-sectransp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-sectransp.lo `test -f 'vtls/sectransp.c' || echo '$(srcdir)/'`vtls/sectransp.c
+
+vtls/libcurlu_la-vtls.lo: vtls/vtls.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-vtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-vtls.Tpo -c -o vtls/libcurlu_la-vtls.lo `test -f 'vtls/vtls.c' || echo '$(srcdir)/'`vtls/vtls.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-vtls.Tpo vtls/$(DEPDIR)/libcurlu_la-vtls.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/vtls.c' object='vtls/libcurlu_la-vtls.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-vtls.lo `test -f 'vtls/vtls.c' || echo '$(srcdir)/'`vtls/vtls.c
+
+vtls/libcurlu_la-wolfssl.lo: vtls/wolfssl.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-wolfssl.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-wolfssl.Tpo -c -o vtls/libcurlu_la-wolfssl.lo `test -f 'vtls/wolfssl.c' || echo '$(srcdir)/'`vtls/wolfssl.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-wolfssl.Tpo vtls/$(DEPDIR)/libcurlu_la-wolfssl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/wolfssl.c' object='vtls/libcurlu_la-wolfssl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-wolfssl.lo `test -f 'vtls/wolfssl.c' || echo '$(srcdir)/'`vtls/wolfssl.c
+
+vtls/libcurlu_la-x509asn1.lo: vtls/x509asn1.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-x509asn1.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-x509asn1.Tpo -c -o vtls/libcurlu_la-x509asn1.lo `test -f 'vtls/x509asn1.c' || echo '$(srcdir)/'`vtls/x509asn1.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-x509asn1.Tpo vtls/$(DEPDIR)/libcurlu_la-x509asn1.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vtls/x509asn1.c' object='vtls/libcurlu_la-x509asn1.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-x509asn1.lo `test -f 'vtls/x509asn1.c' || echo '$(srcdir)/'`vtls/x509asn1.c
+
+vquic/libcurlu_la-curl_msh3.lo: vquic/curl_msh3.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-curl_msh3.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Tpo -c -o vquic/libcurlu_la-curl_msh3.lo `test -f 'vquic/curl_msh3.c' || echo '$(srcdir)/'`vquic/curl_msh3.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Tpo vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vquic/curl_msh3.c' object='vquic/libcurlu_la-curl_msh3.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-curl_msh3.lo `test -f 'vquic/curl_msh3.c' || echo '$(srcdir)/'`vquic/curl_msh3.c
+
+vquic/libcurlu_la-curl_ngtcp2.lo: vquic/curl_ngtcp2.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-curl_ngtcp2.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Tpo -c -o vquic/libcurlu_la-curl_ngtcp2.lo `test -f 'vquic/curl_ngtcp2.c' || echo '$(srcdir)/'`vquic/curl_ngtcp2.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Tpo vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vquic/curl_ngtcp2.c' object='vquic/libcurlu_la-curl_ngtcp2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-curl_ngtcp2.lo `test -f 'vquic/curl_ngtcp2.c' || echo '$(srcdir)/'`vquic/curl_ngtcp2.c
+
+vquic/libcurlu_la-curl_osslq.lo: vquic/curl_osslq.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-curl_osslq.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Tpo -c -o vquic/libcurlu_la-curl_osslq.lo `test -f 'vquic/curl_osslq.c' || echo '$(srcdir)/'`vquic/curl_osslq.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Tpo vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vquic/curl_osslq.c' object='vquic/libcurlu_la-curl_osslq.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-curl_osslq.lo `test -f 'vquic/curl_osslq.c' || echo '$(srcdir)/'`vquic/curl_osslq.c
+
+vquic/libcurlu_la-curl_quiche.lo: vquic/curl_quiche.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-curl_quiche.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Tpo -c -o vquic/libcurlu_la-curl_quiche.lo `test -f 'vquic/curl_quiche.c' || echo '$(srcdir)/'`vquic/curl_quiche.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Tpo vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vquic/curl_quiche.c' object='vquic/libcurlu_la-curl_quiche.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-curl_quiche.lo `test -f 'vquic/curl_quiche.c' || echo '$(srcdir)/'`vquic/curl_quiche.c
+
+vquic/libcurlu_la-vquic.lo: vquic/vquic.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-vquic.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-vquic.Tpo -c -o vquic/libcurlu_la-vquic.lo `test -f 'vquic/vquic.c' || echo '$(srcdir)/'`vquic/vquic.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-vquic.Tpo vquic/$(DEPDIR)/libcurlu_la-vquic.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vquic/vquic.c' object='vquic/libcurlu_la-vquic.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-vquic.lo `test -f 'vquic/vquic.c' || echo '$(srcdir)/'`vquic/vquic.c
+
+vquic/libcurlu_la-vquic-tls.lo: vquic/vquic-tls.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-vquic-tls.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Tpo -c -o vquic/libcurlu_la-vquic-tls.lo `test -f 'vquic/vquic-tls.c' || echo '$(srcdir)/'`vquic/vquic-tls.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Tpo vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vquic/vquic-tls.c' object='vquic/libcurlu_la-vquic-tls.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-vquic-tls.lo `test -f 'vquic/vquic-tls.c' || echo '$(srcdir)/'`vquic/vquic-tls.c
+
+vssh/libcurlu_la-libssh.lo: vssh/libssh.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vssh/libcurlu_la-libssh.lo -MD -MP -MF vssh/$(DEPDIR)/libcurlu_la-libssh.Tpo -c -o vssh/libcurlu_la-libssh.lo `test -f 'vssh/libssh.c' || echo '$(srcdir)/'`vssh/libssh.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurlu_la-libssh.Tpo vssh/$(DEPDIR)/libcurlu_la-libssh.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vssh/libssh.c' object='vssh/libcurlu_la-libssh.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurlu_la-libssh.lo `test -f 'vssh/libssh.c' || echo '$(srcdir)/'`vssh/libssh.c
+
+vssh/libcurlu_la-libssh2.lo: vssh/libssh2.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vssh/libcurlu_la-libssh2.lo -MD -MP -MF vssh/$(DEPDIR)/libcurlu_la-libssh2.Tpo -c -o vssh/libcurlu_la-libssh2.lo `test -f 'vssh/libssh2.c' || echo '$(srcdir)/'`vssh/libssh2.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurlu_la-libssh2.Tpo vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vssh/libssh2.c' object='vssh/libcurlu_la-libssh2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurlu_la-libssh2.lo `test -f 'vssh/libssh2.c' || echo '$(srcdir)/'`vssh/libssh2.c
+
+vssh/libcurlu_la-wolfssh.lo: vssh/wolfssh.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vssh/libcurlu_la-wolfssh.lo -MD -MP -MF vssh/$(DEPDIR)/libcurlu_la-wolfssh.Tpo -c -o vssh/libcurlu_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurlu_la-wolfssh.Tpo vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vssh/wolfssh.c' object='vssh/libcurlu_la-wolfssh.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurlu_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+	-rm -rf vauth/.libs vauth/_libs
+	-rm -rf vquic/.libs vquic/_libs
+	-rm -rf vssh/.libs vssh/_libs
+	-rm -rf vtls/.libs vtls/_libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+@CURLDEBUG_FALSE@all-local:
+all-am: Makefile $(LTLIBRARIES) curl_config.h all-local
+installdirs:
+	for dir in "$(DESTDIR)$(libdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-rm -f vauth/$(DEPDIR)/$(am__dirstamp)
+	-rm -f vauth/$(am__dirstamp)
+	-rm -f vquic/$(DEPDIR)/$(am__dirstamp)
+	-rm -f vquic/$(am__dirstamp)
+	-rm -f vssh/$(DEPDIR)/$(am__dirstamp)
+	-rm -f vssh/$(am__dirstamp)
+	-rm -f vtls/$(DEPDIR)/$(am__dirstamp)
+	-rm -f vtls/$(am__dirstamp)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+		-rm -f ./$(DEPDIR)/libcurl_la-altsvc.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-amigaos.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-asyn-ares.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-asyn-thread.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-base64.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-bufq.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-bufref.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-c-hyper.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cf-h1-proxy.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cf-h2-proxy.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cf-haproxy.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cf-https-connect.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cf-socket.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cfilters.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-conncache.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-connect.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-content_encoding.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cookie.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_addrinfo.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_des.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_endian.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_fnmatch.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_get_line.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_gethostname.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_gssapi.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_memrchr.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_multibyte.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_ntlm_core.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_path.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_range.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_rtmp.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_sasl.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_sha512_256.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_sspi.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_threads.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_trc.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cw-out.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-dict.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-doh.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-dynbuf.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-dynhds.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-easy.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-easygetopt.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-easyoptions.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-escape.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-file.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-fileinfo.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-fopen.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-formdata.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-ftp.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-ftplistparser.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-getenv.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-getinfo.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-gopher.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hash.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-headers.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hmac.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hostasyn.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hostip.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hostip4.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hostip6.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hostsyn.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hsts.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http1.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http2.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http_aws_sigv4.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http_chunks.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http_digest.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http_negotiate.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http_ntlm.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http_proxy.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-idn.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-if2ip.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-imap.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-inet_ntop.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-inet_pton.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-krb5.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-ldap.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-llist.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-macos.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-md4.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-md5.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-memdebug.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-mime.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-mprintf.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-mqtt.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-multi.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-netrc.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-nonblock.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-noproxy.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-openldap.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-parsedate.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-pingpong.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-pop3.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-progress.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-psl.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-rand.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-rename.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-request.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-rtsp.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-select.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-sendf.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-setopt.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-sha256.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-share.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-slist.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-smb.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-smtp.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-socketpair.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-socks.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-socks_gssapi.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-socks_sspi.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-speedcheck.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-splay.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-strcase.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-strdup.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-strerror.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-strtok.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-strtoofft.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-system_win32.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-telnet.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-tftp.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-timediff.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-timeval.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-transfer.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-url.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-urlapi.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-version.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-version_win32.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-warnless.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-ws.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-altsvc.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-amigaos.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-asyn-ares.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-asyn-thread.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-base64.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-bufq.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-bufref.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-c-hyper.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cf-h1-proxy.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cf-haproxy.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cf-https-connect.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cf-socket.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cfilters.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-conncache.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-connect.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-content_encoding.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cookie.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_addrinfo.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_des.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_endian.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_fnmatch.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_get_line.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_gethostname.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_gssapi.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_memrchr.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_multibyte.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_path.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_range.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_rtmp.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_sasl.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_sha512_256.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_sspi.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_threads.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_trc.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cw-out.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-dict.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-doh.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-dynbuf.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-dynhds.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-easy.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-easygetopt.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-easyoptions.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-escape.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-file.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-fileinfo.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-fopen.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-formdata.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-ftp.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-ftplistparser.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-getenv.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-getinfo.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-gopher.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hash.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-headers.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hmac.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hostasyn.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hostip.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hostip4.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hostip6.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hostsyn.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hsts.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http1.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http2.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http_aws_sigv4.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http_chunks.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http_digest.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http_negotiate.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http_ntlm.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http_proxy.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-idn.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-if2ip.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-imap.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-inet_ntop.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-inet_pton.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-krb5.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-ldap.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-llist.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-macos.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-md4.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-md5.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-memdebug.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-mime.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-mprintf.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-mqtt.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-multi.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-netrc.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-nonblock.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-noproxy.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-openldap.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-parsedate.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-pingpong.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-pop3.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-progress.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-psl.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-rand.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-rename.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-request.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-rtsp.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-select.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-sendf.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-setopt.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-sha256.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-share.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-slist.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-smb.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-smtp.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-socketpair.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-socks.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-socks_gssapi.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-socks_sspi.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-speedcheck.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-splay.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-strcase.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-strdup.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-strerror.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-strtok.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-strtoofft.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-system_win32.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-telnet.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-tftp.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-timediff.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-timeval.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-transfer.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-url.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-urlapi.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-version.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-version_win32.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-warnless.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-ws.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-cleartext.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-cram.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-digest.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-digest_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-gsasl.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-ntlm.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-oauth2.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-vauth.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-cleartext.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-cram.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-digest.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-gsasl.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-ntlm.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-oauth2.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-vauth.Plo
+	-rm -f vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo
+	-rm -f vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo
+	-rm -f vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo
+	-rm -f vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo
+	-rm -f vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo
+	-rm -f vquic/$(DEPDIR)/libcurl_la-vquic.Plo
+	-rm -f vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo
+	-rm -f vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo
+	-rm -f vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo
+	-rm -f vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo
+	-rm -f vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo
+	-rm -f vquic/$(DEPDIR)/libcurlu_la-vquic.Plo
+	-rm -f vssh/$(DEPDIR)/libcurl_la-libssh.Plo
+	-rm -f vssh/$(DEPDIR)/libcurl_la-libssh2.Plo
+	-rm -f vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo
+	-rm -f vssh/$(DEPDIR)/libcurlu_la-libssh.Plo
+	-rm -f vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo
+	-rm -f vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-bearssl.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-gtls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-keylog.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-openssl.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-rustls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-schannel.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-sectransp.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-vtls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-gtls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-keylog.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-openssl.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-rustls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-schannel.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-vtls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-wolfssl.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-x509asn1.Plo
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+		-rm -f ./$(DEPDIR)/libcurl_la-altsvc.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-amigaos.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-asyn-ares.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-asyn-thread.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-base64.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-bufq.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-bufref.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-c-hyper.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cf-h1-proxy.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cf-h2-proxy.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cf-haproxy.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cf-https-connect.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cf-socket.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cfilters.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-conncache.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-connect.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-content_encoding.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cookie.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_addrinfo.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_des.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_endian.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_fnmatch.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_get_line.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_gethostname.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_gssapi.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_memrchr.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_multibyte.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_ntlm_core.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_path.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_range.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_rtmp.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_sasl.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_sha512_256.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_sspi.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_threads.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-curl_trc.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-cw-out.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-dict.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-doh.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-dynbuf.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-dynhds.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-easy.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-easygetopt.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-easyoptions.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-escape.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-file.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-fileinfo.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-fopen.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-formdata.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-ftp.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-ftplistparser.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-getenv.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-getinfo.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-gopher.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hash.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-headers.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hmac.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hostasyn.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hostip.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hostip4.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hostip6.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hostsyn.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-hsts.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http1.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http2.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http_aws_sigv4.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http_chunks.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http_digest.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http_negotiate.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http_ntlm.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-http_proxy.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-idn.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-if2ip.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-imap.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-inet_ntop.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-inet_pton.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-krb5.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-ldap.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-llist.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-macos.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-md4.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-md5.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-memdebug.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-mime.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-mprintf.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-mqtt.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-multi.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-netrc.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-nonblock.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-noproxy.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-openldap.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-parsedate.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-pingpong.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-pop3.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-progress.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-psl.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-rand.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-rename.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-request.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-rtsp.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-select.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-sendf.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-setopt.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-sha256.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-share.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-slist.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-smb.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-smtp.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-socketpair.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-socks.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-socks_gssapi.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-socks_sspi.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-speedcheck.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-splay.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-strcase.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-strdup.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-strerror.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-strtok.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-strtoofft.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-system_win32.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-telnet.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-tftp.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-timediff.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-timeval.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-transfer.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-url.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-urlapi.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-version.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-version_win32.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-warnless.Plo
+	-rm -f ./$(DEPDIR)/libcurl_la-ws.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-altsvc.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-amigaos.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-asyn-ares.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-asyn-thread.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-base64.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-bufq.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-bufref.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-c-hyper.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cf-h1-proxy.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cf-haproxy.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cf-https-connect.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cf-socket.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cfilters.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-conncache.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-connect.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-content_encoding.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cookie.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_addrinfo.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_des.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_endian.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_fnmatch.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_get_line.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_gethostname.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_gssapi.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_memrchr.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_multibyte.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_path.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_range.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_rtmp.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_sasl.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_sha512_256.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_sspi.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_threads.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-curl_trc.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-cw-out.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-dict.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-doh.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-dynbuf.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-dynhds.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-easy.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-easygetopt.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-easyoptions.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-escape.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-file.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-fileinfo.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-fopen.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-formdata.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-ftp.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-ftplistparser.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-getenv.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-getinfo.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-gopher.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hash.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-headers.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hmac.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hostasyn.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hostip.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hostip4.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hostip6.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hostsyn.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-hsts.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http1.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http2.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http_aws_sigv4.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http_chunks.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http_digest.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http_negotiate.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http_ntlm.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-http_proxy.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-idn.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-if2ip.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-imap.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-inet_ntop.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-inet_pton.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-krb5.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-ldap.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-llist.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-macos.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-md4.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-md5.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-memdebug.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-mime.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-mprintf.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-mqtt.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-multi.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-netrc.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-nonblock.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-noproxy.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-openldap.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-parsedate.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-pingpong.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-pop3.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-progress.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-psl.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-rand.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-rename.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-request.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-rtsp.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-select.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-sendf.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-setopt.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-sha256.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-share.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-slist.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-smb.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-smtp.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-socketpair.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-socks.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-socks_gssapi.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-socks_sspi.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-speedcheck.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-splay.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-strcase.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-strdup.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-strerror.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-strtok.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-strtoofft.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-system_win32.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-telnet.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-tftp.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-timediff.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-timeval.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-transfer.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-url.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-urlapi.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-version.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-version_win32.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-warnless.Plo
+	-rm -f ./$(DEPDIR)/libcurlu_la-ws.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-cleartext.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-cram.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-digest.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-digest_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-gsasl.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-krb5_gssapi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-krb5_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-ntlm.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-ntlm_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-oauth2.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-spnego_gssapi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-spnego_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurl_la-vauth.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-cleartext.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-cram.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-digest.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-digest_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-gsasl.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-krb5_gssapi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-krb5_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-ntlm.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-ntlm_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-oauth2.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo
+	-rm -f vauth/$(DEPDIR)/libcurlu_la-vauth.Plo
+	-rm -f vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo
+	-rm -f vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo
+	-rm -f vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo
+	-rm -f vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo
+	-rm -f vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo
+	-rm -f vquic/$(DEPDIR)/libcurl_la-vquic.Plo
+	-rm -f vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo
+	-rm -f vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo
+	-rm -f vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo
+	-rm -f vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo
+	-rm -f vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo
+	-rm -f vquic/$(DEPDIR)/libcurlu_la-vquic.Plo
+	-rm -f vssh/$(DEPDIR)/libcurl_la-libssh.Plo
+	-rm -f vssh/$(DEPDIR)/libcurl_la-libssh2.Plo
+	-rm -f vssh/$(DEPDIR)/libcurl_la-wolfssh.Plo
+	-rm -f vssh/$(DEPDIR)/libcurlu_la-libssh.Plo
+	-rm -f vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo
+	-rm -f vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-bearssl.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-gtls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-keylog.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-mbedtls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-mbedtls_threadlock.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-openssl.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-rustls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-schannel.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-schannel_verify.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-sectransp.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-vtls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo
+	-rm -f vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-gtls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-keylog.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-mbedtls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-mbedtls_threadlock.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-openssl.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-rustls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-schannel.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-schannel_verify.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-sectransp.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-vtls.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-wolfssl.Plo
+	-rm -f vtls/$(DEPDIR)/libcurlu_la-x509asn1.Plo
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES
+
+.MAKE: all install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am all-local am--depfiles check \
+	check-am clean clean-generic clean-libLTLIBRARIES \
+	clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-dvi install-dvi-am \
+	install-exec install-exec-am install-html install-html-am \
+	install-info install-info-am install-libLTLIBRARIES \
+	install-man install-pdf install-pdf-am install-ps \
+	install-ps-am install-strip installcheck installcheck-am \
+	installdirs maintainer-clean maintainer-clean-generic \
+	mostlyclean mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+	uninstall-am uninstall-libLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+# This flag accepts an argument of the form current[:revision[:age]]. So,
+# passing -version-info 3:12:1 sets current to 3, revision to 12, and age to
+# 1.
+#
+# Here's the simplified rule guide on how to change -version-info:
+# (current version is C:R:A)
+#
+# 1. if there are only source changes, use C:R+1:A
+# 2. if interfaces were added use C+1:0:A+1
+# 3. if interfaces were removed, then use C+1:0:0
+#
+# For the full guide on libcurl ABI rules, see docs/libcurl/ABI
+@HAVE_WINDRES_TRUE@@USE_CPPFLAG_CURL_STATICLIB_FALSE@$(LIB_RCFILES): $(top_srcdir)/include/curl/curlver.h
+
+checksrc:
+	$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir)    \
+	-W$(srcdir)/curl_config.h $(srcdir)/*.[ch] $(srcdir)/vauth/*.[ch]   \
+	$(srcdir)/vtls/*.[ch] $(srcdir)/vquic/*.[ch] $(srcdir)/vssh/*.[ch])
+
+# for debug builds, we scan the sources on all regular make invokes
+@CURLDEBUG_TRUE@all-local: checksrc
+
+tidy:
+	$(TIDY) $(CSOURCES) $(TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H
+
+optiontable:
+	perl optiontable.pl < $(top_srcdir)/include/curl/curl.h > easyoptions.c
+
+@HAVE_WINDRES_TRUE@.rc.lo:
+@HAVE_WINDRES_TRUE@	$(LIBTOOL) --tag=RC --mode=compile $(RC) -I$(top_srcdir)/include $(RCFLAGS) -i $< -o $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: trunk/src/libs/curl-8.7.1/lib/Makefile.inc
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/Makefile.inc	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/Makefile.inc	(revision 104083)
@@ -0,0 +1,380 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+
+LIB_VAUTH_CFILES =      \
+  vauth/cleartext.c     \
+  vauth/cram.c          \
+  vauth/digest.c        \
+  vauth/digest_sspi.c   \
+  vauth/gsasl.c         \
+  vauth/krb5_gssapi.c   \
+  vauth/krb5_sspi.c     \
+  vauth/ntlm.c          \
+  vauth/ntlm_sspi.c     \
+  vauth/oauth2.c        \
+  vauth/spnego_gssapi.c \
+  vauth/spnego_sspi.c   \
+  vauth/vauth.c
+
+LIB_VAUTH_HFILES =      \
+  vauth/digest.h        \
+  vauth/ntlm.h          \
+  vauth/vauth.h
+
+LIB_VTLS_CFILES =           \
+  vtls/bearssl.c            \
+  vtls/gtls.c               \
+  vtls/hostcheck.c          \
+  vtls/keylog.c             \
+  vtls/mbedtls.c            \
+  vtls/mbedtls_threadlock.c \
+  vtls/openssl.c            \
+  vtls/rustls.c             \
+  vtls/schannel.c           \
+  vtls/schannel_verify.c    \
+  vtls/sectransp.c          \
+  vtls/vtls.c               \
+  vtls/wolfssl.c            \
+  vtls/x509asn1.c
+
+LIB_VTLS_HFILES =           \
+  vtls/bearssl.h            \
+  vtls/gtls.h               \
+  vtls/hostcheck.h          \
+  vtls/keylog.h             \
+  vtls/mbedtls.h            \
+  vtls/mbedtls_threadlock.h \
+  vtls/openssl.h            \
+  vtls/rustls.h             \
+  vtls/schannel.h           \
+  vtls/schannel_int.h       \
+  vtls/sectransp.h          \
+  vtls/vtls.h               \
+  vtls/vtls_int.h           \
+  vtls/wolfssl.h            \
+  vtls/x509asn1.h
+
+LIB_VQUIC_CFILES = \
+  vquic/curl_msh3.c   \
+  vquic/curl_ngtcp2.c   \
+  vquic/curl_osslq.c   \
+  vquic/curl_quiche.c   \
+  vquic/vquic.c \
+  vquic/vquic-tls.c
+
+LIB_VQUIC_HFILES = \
+  vquic/curl_msh3.h   \
+  vquic/curl_ngtcp2.h   \
+  vquic/curl_osslq.h   \
+  vquic/curl_quiche.h   \
+  vquic/vquic.h    \
+  vquic/vquic_int.h \
+  vquic/vquic-tls.h
+
+LIB_VSSH_CFILES =  \
+  vssh/libssh.c    \
+  vssh/libssh2.c   \
+  vssh/wolfssh.c
+
+LIB_VSSH_HFILES =  \
+  vssh/ssh.h
+
+LIB_CFILES =         \
+  altsvc.c           \
+  amigaos.c          \
+  asyn-ares.c        \
+  asyn-thread.c      \
+  base64.c           \
+  bufq.c             \
+  bufref.c           \
+  c-hyper.c          \
+  cf-h1-proxy.c      \
+  cf-h2-proxy.c      \
+  cf-haproxy.c       \
+  cf-https-connect.c \
+  cf-socket.c        \
+  cfilters.c         \
+  conncache.c        \
+  connect.c          \
+  content_encoding.c \
+  cookie.c           \
+  curl_addrinfo.c    \
+  curl_des.c         \
+  curl_endian.c      \
+  curl_fnmatch.c     \
+  curl_get_line.c    \
+  curl_gethostname.c \
+  curl_gssapi.c      \
+  curl_memrchr.c     \
+  curl_multibyte.c   \
+  curl_ntlm_core.c   \
+  curl_ntlm_wb.c     \
+  curl_path.c        \
+  curl_range.c       \
+  curl_rtmp.c        \
+  curl_sasl.c        \
+  curl_sha512_256.c  \
+  curl_sspi.c        \
+  curl_threads.c     \
+  curl_trc.c         \
+  cw-out.c           \
+  dict.c             \
+  doh.c              \
+  dynbuf.c           \
+  dynhds.c           \
+  easy.c             \
+  easygetopt.c       \
+  easyoptions.c      \
+  escape.c           \
+  file.c             \
+  fileinfo.c         \
+  fopen.c            \
+  formdata.c         \
+  ftp.c              \
+  ftplistparser.c    \
+  getenv.c           \
+  getinfo.c          \
+  gopher.c           \
+  hash.c             \
+  headers.c          \
+  hmac.c             \
+  hostasyn.c         \
+  hostip.c           \
+  hostip4.c          \
+  hostip6.c          \
+  hostsyn.c          \
+  hsts.c             \
+  http.c             \
+  http1.c            \
+  http2.c            \
+  http_aws_sigv4.c   \
+  http_chunks.c      \
+  http_digest.c      \
+  http_negotiate.c   \
+  http_ntlm.c        \
+  http_proxy.c       \
+  idn.c              \
+  if2ip.c            \
+  imap.c             \
+  inet_ntop.c        \
+  inet_pton.c        \
+  krb5.c             \
+  ldap.c             \
+  llist.c            \
+  macos.c            \
+  md4.c              \
+  md5.c              \
+  memdebug.c         \
+  mime.c             \
+  mprintf.c          \
+  mqtt.c             \
+  multi.c            \
+  netrc.c            \
+  nonblock.c         \
+  noproxy.c          \
+  openldap.c         \
+  parsedate.c        \
+  pingpong.c         \
+  pop3.c             \
+  progress.c         \
+  psl.c              \
+  rand.c             \
+  rename.c           \
+  request.c          \
+  rtsp.c             \
+  select.c           \
+  sendf.c            \
+  setopt.c           \
+  sha256.c           \
+  share.c            \
+  slist.c            \
+  smb.c              \
+  smtp.c             \
+  socketpair.c       \
+  socks.c            \
+  socks_gssapi.c     \
+  socks_sspi.c       \
+  speedcheck.c       \
+  splay.c            \
+  strcase.c          \
+  strdup.c           \
+  strerror.c         \
+  strtok.c           \
+  strtoofft.c        \
+  system_win32.c     \
+  telnet.c           \
+  tftp.c             \
+  timediff.c         \
+  timeval.c          \
+  transfer.c         \
+  url.c              \
+  urlapi.c           \
+  version.c          \
+  version_win32.c    \
+  warnless.c         \
+  ws.c
+
+LIB_HFILES =         \
+  altsvc.h           \
+  amigaos.h          \
+  arpa_telnet.h      \
+  asyn.h             \
+  bufq.h             \
+  bufref.h           \
+  c-hyper.h          \
+  cf-h1-proxy.h      \
+  cf-h2-proxy.h      \
+  cf-haproxy.h       \
+  cf-https-connect.h \
+  cf-socket.h        \
+  cfilters.h         \
+  conncache.h        \
+  connect.h          \
+  content_encoding.h \
+  cookie.h           \
+  curl_addrinfo.h    \
+  curl_base64.h      \
+  curl_ctype.h       \
+  curl_des.h         \
+  curl_endian.h      \
+  curl_fnmatch.h     \
+  curl_get_line.h    \
+  curl_gethostname.h \
+  curl_gssapi.h      \
+  curl_hmac.h        \
+  curl_krb5.h        \
+  curl_ldap.h        \
+  curl_md4.h         \
+  curl_md5.h         \
+  curl_memory.h      \
+  curl_memrchr.h     \
+  curl_multibyte.h   \
+  curl_ntlm_core.h   \
+  curl_ntlm_wb.h     \
+  curl_path.h        \
+  curl_printf.h      \
+  curl_range.h       \
+  curl_rtmp.h        \
+  curl_sasl.h        \
+  curl_setup.h       \
+  curl_setup_once.h  \
+  curl_sha256.h      \
+  curl_sha512_256.h  \
+  curl_sspi.h        \
+  curl_threads.h     \
+  curl_trc.h         \
+  curlx.h            \
+  cw-out.h           \
+  dict.h             \
+  doh.h              \
+  dynbuf.h           \
+  dynhds.h           \
+  easy_lock.h        \
+  easyif.h           \
+  easyoptions.h      \
+  escape.h           \
+  file.h             \
+  fileinfo.h         \
+  fopen.h            \
+  formdata.h         \
+  ftp.h              \
+  ftplistparser.h    \
+  functypes.h        \
+  getinfo.h          \
+  gopher.h           \
+  hash.h             \
+  headers.h          \
+  hostip.h           \
+  hsts.h             \
+  http.h             \
+  http1.h            \
+  http2.h            \
+  http_aws_sigv4.h   \
+  http_chunks.h      \
+  http_digest.h      \
+  http_negotiate.h   \
+  http_ntlm.h        \
+  http_proxy.h       \
+  idn.h              \
+  if2ip.h            \
+  imap.h             \
+  inet_ntop.h        \
+  inet_pton.h        \
+  llist.h            \
+  macos.h            \
+  memdebug.h         \
+  mime.h             \
+  mqtt.h             \
+  multihandle.h      \
+  multiif.h          \
+  netrc.h            \
+  nonblock.h         \
+  noproxy.h          \
+  parsedate.h        \
+  pingpong.h         \
+  pop3.h             \
+  progress.h         \
+  psl.h              \
+  rand.h             \
+  rename.h           \
+  request.h          \
+  rtsp.h             \
+  select.h           \
+  sendf.h            \
+  setopt.h           \
+  setup-vms.h        \
+  share.h            \
+  sigpipe.h          \
+  slist.h            \
+  smb.h              \
+  smtp.h             \
+  sockaddr.h         \
+  socketpair.h       \
+  socks.h            \
+  speedcheck.h       \
+  splay.h            \
+  strcase.h          \
+  strdup.h           \
+  strerror.h         \
+  strtok.h           \
+  strtoofft.h        \
+  system_win32.h     \
+  telnet.h           \
+  tftp.h             \
+  timediff.h         \
+  timeval.h          \
+  transfer.h         \
+  url.h              \
+  urlapi-int.h       \
+  urldata.h          \
+  version_win32.h    \
+  warnless.h         \
+  ws.h
+
+LIB_RCFILES = libcurl.rc
+
+CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \
+  $(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES)
+HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) \
+  $(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES)
Index: trunk/src/libs/curl-8.7.1/lib/Makefile.mk
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/Makefile.mk	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/Makefile.mk	(revision 104083)
@@ -0,0 +1,334 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+#***************************************************************************
+
+# Makefile to build curl parts with GCC-like toolchains and optional features.
+#
+# Usage:   make -f Makefile.mk CFG=-feat1[-feat2][-feat3][...]
+# Example: make -f Makefile.mk CFG=-zlib-ssl-libssh2-ipv6
+#
+# Look for ' ?=' to find all accepted customization variables.
+
+# This script is reused by 'src' and 'docs/examples' Makefile.mk scripts.
+
+ifndef PROOT
+  PROOT := ..
+  LOCAL := 1
+endif
+
+### Common
+
+CFLAGS ?=
+CPPFLAGS ?=
+LDFLAGS ?=
+LIBS ?=
+
+CROSSPREFIX ?=
+
+ifeq ($(CC),cc)
+  CC := gcc
+endif
+CC := $(CROSSPREFIX)$(CC)
+AR := $(CROSSPREFIX)$(AR)
+
+TRIPLET ?= $(shell $(CC) -dumpmachine)
+
+BIN_EXT :=
+
+ifneq ($(findstring msdos,$(TRIPLET)),)
+  # Cross-tools: https://github.com/andrewwutw/build-djgpp
+  MSDOS := 1
+  BIN_EXT := .exe
+else ifneq ($(findstring amigaos,$(TRIPLET)),)
+  # Cross-tools: https://github.com/bebbo/amiga-gcc
+  AMIGA := 1
+endif
+
+CPPFLAGS += -I. -I$(PROOT)/include
+
+### Deprecated settings. For compatibility.
+
+ifdef WATT_ROOT
+  WATT_PATH := $(realpath $(WATT_ROOT))
+endif
+
+### Optional features
+
+ifneq ($(findstring -debug,$(CFG)),)
+  CFLAGS += -g
+  CPPFLAGS += -DDEBUGBUILD
+else
+  CPPFLAGS += -DNDEBUG
+endif
+ifneq ($(findstring -trackmem,$(CFG)),)
+  CPPFLAGS += -DCURLDEBUG
+endif
+ifneq ($(findstring -map,$(CFG)),)
+  MAP := 1
+endif
+
+# CPPFLAGS below are only necessary when building libcurl via 'lib' (see
+# comments below about exceptions). Always include them anyway to match
+# behavior of other build systems.
+
+ifneq ($(findstring -sync,$(CFG)),)
+  CPPFLAGS += -DUSE_SYNC_DNS
+else ifneq ($(findstring -ares,$(CFG)),)
+  LIBCARES_PATH ?= $(PROOT)/../c-ares
+  CPPFLAGS += -DUSE_ARES
+  CPPFLAGS += -I"$(LIBCARES_PATH)/include"
+  LDFLAGS += -L"$(LIBCARES_PATH)/lib"
+  LIBS += -lcares
+endif
+
+ifneq ($(findstring -rtmp,$(CFG)),)
+  LIBRTMP_PATH ?= $(PROOT)/../librtmp
+  CPPFLAGS += -DUSE_LIBRTMP
+  CPPFLAGS += -I"$(LIBRTMP_PATH)"
+  LDFLAGS += -L"$(LIBRTMP_PATH)/librtmp"
+  LIBS += -lrtmp
+  ZLIB := 1
+endif
+
+ifneq ($(findstring -ssh2,$(CFG)),)
+  LIBSSH2_PATH ?= $(PROOT)/../libssh2
+  CPPFLAGS += -DUSE_LIBSSH2
+  CPPFLAGS += -I"$(LIBSSH2_PATH)/include"
+  LDFLAGS += -L"$(LIBSSH2_PATH)/lib"
+  LIBS += -lssh2
+else ifneq ($(findstring -libssh,$(CFG)),)
+  LIBSSH_PATH ?= $(PROOT)/../libssh
+  CPPFLAGS += -DUSE_LIBSSH
+  CPPFLAGS += -I"$(LIBSSH_PATH)/include"
+  LDFLAGS += -L"$(LIBSSH_PATH)/lib"
+  LIBS += -lssh
+else ifneq ($(findstring -wolfssh,$(CFG)),)
+  WOLFSSH_PATH ?= $(PROOT)/../wolfssh
+  CPPFLAGS += -DUSE_WOLFSSH
+  CPPFLAGS += -I"$(WOLFSSH_PATH)/include"
+  LDFLAGS += -L"$(WOLFSSH_PATH)/lib"
+  LIBS += -lwolfssh
+endif
+
+ifneq ($(findstring -ssl,$(CFG)),)
+  OPENSSL_PATH ?= $(PROOT)/../openssl
+  CPPFLAGS += -DUSE_OPENSSL
+  CPPFLAGS += -DCURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG
+  OPENSSL_INCLUDE ?= $(OPENSSL_PATH)/include
+  OPENSSL_LIBPATH ?= $(OPENSSL_PATH)/lib
+  CPPFLAGS += -I"$(OPENSSL_INCLUDE)"
+  LDFLAGS += -L"$(OPENSSL_LIBPATH)"
+  OPENSSL_LIBS ?= -lssl -lcrypto
+  LIBS += $(OPENSSL_LIBS)
+
+  ifneq ($(findstring -srp,$(CFG)),)
+    ifneq ($(wildcard $(OPENSSL_INCLUDE)/openssl/srp.h),)
+      # OpenSSL 1.0.1 and later.
+      CPPFLAGS += -DHAVE_OPENSSL_SRP -DUSE_TLS_SRP
+    endif
+  endif
+  SSLLIBS += 1
+endif
+ifneq ($(findstring -wolfssl,$(CFG)),)
+  WOLFSSL_PATH ?= $(PROOT)/../wolfssl
+  CPPFLAGS += -DUSE_WOLFSSL
+  CPPFLAGS += -DSIZEOF_LONG_LONG=8
+  CPPFLAGS += -I"$(WOLFSSL_PATH)/include"
+  LDFLAGS += -L"$(WOLFSSL_PATH)/lib"
+  LIBS += -lwolfssl
+  SSLLIBS += 1
+endif
+ifneq ($(findstring -mbedtls,$(CFG)),)
+  MBEDTLS_PATH ?= $(PROOT)/../mbedtls
+  CPPFLAGS += -DUSE_MBEDTLS
+  CPPFLAGS += -I"$(MBEDTLS_PATH)/include"
+  LDFLAGS += -L"$(MBEDTLS_PATH)/lib"
+  LIBS += -lmbedtls -lmbedx509 -lmbedcrypto
+  SSLLIBS += 1
+endif
+
+ifneq ($(findstring -nghttp2,$(CFG)),)
+  NGHTTP2_PATH ?= $(PROOT)/../nghttp2
+  CPPFLAGS += -DUSE_NGHTTP2
+  CPPFLAGS += -I"$(NGHTTP2_PATH)/include"
+  LDFLAGS += -L"$(NGHTTP2_PATH)/lib"
+  LIBS += -lnghttp2
+endif
+
+ifeq ($(findstring -nghttp3,$(CFG))$(findstring -ngtcp2,$(CFG)),-nghttp3-ngtcp2)
+  NGHTTP3_PATH ?= $(PROOT)/../nghttp3
+  CPPFLAGS += -DUSE_NGHTTP3
+  CPPFLAGS += -I"$(NGHTTP3_PATH)/include"
+  LDFLAGS += -L"$(NGHTTP3_PATH)/lib"
+  LIBS += -lnghttp3
+
+  NGTCP2_PATH ?= $(PROOT)/../ngtcp2
+  CPPFLAGS += -DUSE_NGTCP2
+  CPPFLAGS += -I"$(NGTCP2_PATH)/include"
+  LDFLAGS += -L"$(NGTCP2_PATH)/lib"
+
+  NGTCP2_LIBS ?=
+  ifeq ($(NGTCP2_LIBS),)
+    ifneq ($(findstring -ssl,$(CFG)),)
+      ifneq ($(wildcard $(OPENSSL_INCLUDE)/openssl/aead.h),)
+        NGTCP2_LIBS := -lngtcp2_crypto_boringssl
+      else  # including libressl
+        NGTCP2_LIBS := -lngtcp2_crypto_quictls
+      endif
+    else ifneq ($(findstring -wolfssl,$(CFG)),)
+      NGTCP2_LIBS := -lngtcp2_crypto_wolfssl
+    endif
+  endif
+
+  LIBS += -lngtcp2 $(NGTCP2_LIBS)
+endif
+
+ifneq ($(findstring -zlib,$(CFG))$(ZLIB),)
+  ZLIB_PATH ?= $(PROOT)/../zlib
+  # These CPPFLAGS are also required when compiling the curl tool via 'src'.
+  CPPFLAGS += -DHAVE_LIBZ
+  CPPFLAGS += -I"$(ZLIB_PATH)/include"
+  LDFLAGS += -L"$(ZLIB_PATH)/lib"
+  ZLIB_LIBS ?= -lz
+  LIBS += $(ZLIB_LIBS)
+  ZLIB := 1
+endif
+ifneq ($(findstring -zstd,$(CFG)),)
+  ZSTD_PATH ?= $(PROOT)/../zstd
+  CPPFLAGS += -DHAVE_ZSTD
+  CPPFLAGS += -I"$(ZSTD_PATH)/include"
+  LDFLAGS += -L"$(ZSTD_PATH)/lib"
+  ZSTD_LIBS ?= -lzstd
+  LIBS += $(ZSTD_LIBS)
+endif
+ifneq ($(findstring -brotli,$(CFG)),)
+  BROTLI_PATH ?= $(PROOT)/../brotli
+  CPPFLAGS += -DHAVE_BROTLI
+  CPPFLAGS += -I"$(BROTLI_PATH)/include"
+  LDFLAGS += -L"$(BROTLI_PATH)/lib"
+  BROTLI_LIBS ?= -lbrotlidec -lbrotlicommon
+  LIBS += $(BROTLI_LIBS)
+endif
+ifneq ($(findstring -gsasl,$(CFG)),)
+  LIBGSASL_PATH ?= $(PROOT)/../gsasl
+  CPPFLAGS += -DUSE_GSASL
+  CPPFLAGS += -I"$(LIBGSASL_PATH)/include"
+  LDFLAGS += -L"$(LIBGSASL_PATH)/lib"
+  LIBS += -lgsasl
+endif
+
+ifneq ($(findstring -idn2,$(CFG)),)
+  LIBIDN2_PATH ?= $(PROOT)/../libidn2
+  CPPFLAGS += -DUSE_LIBIDN2
+  CPPFLAGS += -I"$(LIBIDN2_PATH)/include"
+  LDFLAGS += -L"$(LIBIDN2_PATH)/lib"
+  LIBS += -lidn2
+
+ifneq ($(findstring -psl,$(CFG)),)
+  LIBPSL_PATH ?= $(PROOT)/../libpsl
+  CPPFLAGS += -DUSE_LIBPSL
+  CPPFLAGS += -I"$(LIBPSL_PATH)/include"
+  LDFLAGS += -L"$(LIBPSL_PATH)/lib"
+  LIBS += -lpsl
+endif
+endif
+
+ifneq ($(findstring -ipv6,$(CFG)),)
+  CPPFLAGS += -DENABLE_IPV6
+endif
+
+ifneq ($(findstring -watt,$(CFG))$(MSDOS),)
+  WATT_PATH ?= $(PROOT)/../watt
+  CPPFLAGS += -I"$(WATT_PATH)/inc"
+  LDFLAGS += -L"$(WATT_PATH)/lib"
+  LIBS += -lwatt
+endif
+
+ifneq ($(findstring 11,$(subst $(subst ,, ),,$(SSLLIBS))),)
+  CPPFLAGS += -DCURL_WITH_MULTI_SSL
+endif
+
+### Common rules
+
+OBJ_DIR := $(TRIPLET)
+
+ifneq ($(findstring /sh,$(SHELL)),)
+DEL   = rm -f $1
+COPY  = -cp -afv $1 $2
+MKDIR = mkdir -p $1
+RMDIR = rm -fr $1
+WHICH = $(SHELL) -c "command -v $1"
+else
+DEL   = -del 2>NUL /q /f $(subst /,\,$1)
+COPY  = -copy 2>NUL /y $(subst /,\,$1) $(subst /,\,$2)
+MKDIR = -md 2>NUL $(subst /,\,$1)
+RMDIR = -rd 2>NUL /q /s $(subst /,\,$1)
+WHICH = where $1
+endif
+
+all: $(TARGETS)
+
+$(OBJ_DIR):
+	-$(call MKDIR, $(OBJ_DIR))
+
+$(OBJ_DIR)/%.o: %.c
+	$(CC) -W -Wall $(CFLAGS) $(CPPFLAGS) -c $< -o $@
+
+clean:
+	@$(call DEL, $(TOCLEAN))
+	@$(RMDIR) $(OBJ_DIR)
+
+distclean vclean: clean
+	@$(call DEL, $(TARGETS) $(TOVCLEAN))
+
+### Local
+
+ifdef LOCAL
+
+CPPFLAGS += -DBUILDING_LIBCURL
+
+### Sources and targets
+
+# Provides CSOURCES, HHEADERS
+include Makefile.inc
+
+vpath %.c vauth vquic vssh vtls
+
+libcurl_a_LIBRARY := libcurl.a
+
+TARGETS := $(libcurl_a_LIBRARY)
+
+libcurl_a_OBJECTS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(notdir $(strip $(CSOURCES))))
+libcurl_a_DEPENDENCIES := $(strip $(CSOURCES) $(HHEADERS))
+
+TOCLEAN :=
+TOVCLEAN :=
+
+### Rules
+
+$(libcurl_a_LIBRARY): $(libcurl_a_OBJECTS) $(libcurl_a_DEPENDENCIES)
+	@$(call DEL, $@)
+	$(AR) rcs $@ $(libcurl_a_OBJECTS)
+
+all: $(OBJ_DIR) $(TARGETS)
+endif
Index: trunk/src/libs/curl-8.7.1/lib/Makefile.soname
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/Makefile.soname	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/Makefile.soname	(revision 104083)
@@ -0,0 +1,42 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+
+VERSIONCHANGE=12
+VERSIONADD=0
+VERSIONDEL=8
+
+# libtool version:
+VERSIONINFO=-version-info $(VERSIONCHANGE):$(VERSIONADD):$(VERSIONDEL)
+# This flag accepts an argument of the form current[:revision[:age]]. So,
+# passing -version-info 3:12:1 sets current to 3, revision to 12, and age to
+# 1.
+#
+# Here's the simplified rule guide on how to change -version-info:
+# (current version is C:R:A)
+#
+# 1. if there are only source changes, use C:R+1:A
+# 2. if interfaces were added use C+1:0:A+1
+# 3. if interfaces were removed, then use C+1:0:0
+#
+# For the full guide on libcurl ABI rules, see docs/libcurl/ABI
Index: trunk/src/libs/curl-8.7.1/lib/altsvc.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/altsvc.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/altsvc.c	(revision 104083)
@@ -0,0 +1,708 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+/*
+ * The Alt-Svc: header is defined in RFC 7838:
+ * https://datatracker.ietf.org/doc/html/rfc7838
+ */
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC)
+#include <curl/curl.h>
+#include "urldata.h"
+#include "altsvc.h"
+#include "curl_get_line.h"
+#include "strcase.h"
+#include "parsedate.h"
+#include "sendf.h"
+#include "warnless.h"
+#include "fopen.h"
+#include "rename.h"
+#include "strdup.h"
+#include "inet_pton.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define MAX_ALTSVC_LINE 4095
+#define MAX_ALTSVC_DATELENSTR "64"
+#define MAX_ALTSVC_DATELEN 64
+#define MAX_ALTSVC_HOSTLENSTR "512"
+#define MAX_ALTSVC_HOSTLEN 512
+#define MAX_ALTSVC_ALPNLENSTR "10"
+#define MAX_ALTSVC_ALPNLEN 10
+
+#define H3VERSION "h3"
+
+static enum alpnid alpn2alpnid(char *name)
+{
+  if(strcasecompare(name, "h1"))
+    return ALPN_h1;
+  if(strcasecompare(name, "h2"))
+    return ALPN_h2;
+  if(strcasecompare(name, H3VERSION))
+    return ALPN_h3;
+  return ALPN_none; /* unknown, probably rubbish input */
+}
+
+/* Given the ALPN ID, return the name */
+const char *Curl_alpnid2str(enum alpnid id)
+{
+  switch(id) {
+  case ALPN_h1:
+    return "h1";
+  case ALPN_h2:
+    return "h2";
+  case ALPN_h3:
+    return H3VERSION;
+  default:
+    return ""; /* bad */
+  }
+}
+
+
+static void altsvc_free(struct altsvc *as)
+{
+  free(as->src.host);
+  free(as->dst.host);
+  free(as);
+}
+
+static struct altsvc *altsvc_createid(const char *srchost,
+                                      const char *dsthost,
+                                      enum alpnid srcalpnid,
+                                      enum alpnid dstalpnid,
+                                      unsigned int srcport,
+                                      unsigned int dstport)
+{
+  struct altsvc *as = calloc(1, sizeof(struct altsvc));
+  size_t hlen;
+  size_t dlen;
+  if(!as)
+    return NULL;
+  hlen = strlen(srchost);
+  dlen = strlen(dsthost);
+  DEBUGASSERT(hlen);
+  DEBUGASSERT(dlen);
+  if(!hlen || !dlen) {
+    /* bad input */
+    free(as);
+    return NULL;
+  }
+  if((hlen > 2) && srchost[0] == '[') {
+    /* IPv6 address, strip off brackets */
+    srchost++;
+    hlen -= 2;
+  }
+  else if(srchost[hlen - 1] == '.')
+    /* strip off trailing dot */
+    hlen--;
+  if((dlen > 2) && dsthost[0] == '[') {
+    /* IPv6 address, strip off brackets */
+    dsthost++;
+    dlen -= 2;
+  }
+
+  as->src.host = Curl_memdup0(srchost, hlen);
+  if(!as->src.host)
+    goto error;
+
+  as->dst.host = Curl_memdup0(dsthost, dlen);
+  if(!as->dst.host)
+    goto error;
+
+  as->src.alpnid = srcalpnid;
+  as->dst.alpnid = dstalpnid;
+  as->src.port = curlx_ultous(srcport);
+  as->dst.port = curlx_ultous(dstport);
+
+  return as;
+error:
+  altsvc_free(as);
+  return NULL;
+}
+
+static struct altsvc *altsvc_create(char *srchost,
+                                    char *dsthost,
+                                    char *srcalpn,
+                                    char *dstalpn,
+                                    unsigned int srcport,
+                                    unsigned int dstport)
+{
+  enum alpnid dstalpnid = alpn2alpnid(dstalpn);
+  enum alpnid srcalpnid = alpn2alpnid(srcalpn);
+  if(!srcalpnid || !dstalpnid)
+    return NULL;
+  return altsvc_createid(srchost, dsthost, srcalpnid, dstalpnid,
+                         srcport, dstport);
+}
+
+/* only returns SERIOUS errors */
+static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
+{
+  /* Example line:
+     h2 example.com 443 h3 shiny.example.com 8443 "20191231 10:00:00" 1
+   */
+  char srchost[MAX_ALTSVC_HOSTLEN + 1];
+  char dsthost[MAX_ALTSVC_HOSTLEN + 1];
+  char srcalpn[MAX_ALTSVC_ALPNLEN + 1];
+  char dstalpn[MAX_ALTSVC_ALPNLEN + 1];
+  char date[MAX_ALTSVC_DATELEN + 1];
+  unsigned int srcport;
+  unsigned int dstport;
+  unsigned int prio;
+  unsigned int persist;
+  int rc;
+
+  rc = sscanf(line,
+              "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u "
+              "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u "
+              "\"%" MAX_ALTSVC_DATELENSTR "[^\"]\" %u %u",
+              srcalpn, srchost, &srcport,
+              dstalpn, dsthost, &dstport,
+              date, &persist, &prio);
+  if(9 == rc) {
+    struct altsvc *as;
+    time_t expires = Curl_getdate_capped(date);
+    as = altsvc_create(srchost, dsthost, srcalpn, dstalpn, srcport, dstport);
+    if(as) {
+      as->expires = expires;
+      as->prio = prio;
+      as->persist = persist ? 1 : 0;
+      Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
+    }
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Load alt-svc entries from the given file. The text based line-oriented file
+ * format is documented here: https://curl.se/docs/alt-svc.html
+ *
+ * This function only returns error on major problems that prevent alt-svc
+ * handling to work completely. It will ignore individual syntactical errors
+ * etc.
+ */
+static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
+{
+  CURLcode result = CURLE_OK;
+  FILE *fp;
+
+  /* we need a private copy of the file name so that the altsvc cache file
+     name survives an easy handle reset */
+  free(asi->filename);
+  asi->filename = strdup(file);
+  if(!asi->filename)
+    return CURLE_OUT_OF_MEMORY;
+
+  fp = fopen(file, FOPEN_READTEXT);
+  if(fp) {
+    struct dynbuf buf;
+    Curl_dyn_init(&buf, MAX_ALTSVC_LINE);
+    while(Curl_get_line(&buf, fp)) {
+      char *lineptr = Curl_dyn_ptr(&buf);
+      while(*lineptr && ISBLANK(*lineptr))
+        lineptr++;
+      if(*lineptr == '#')
+        /* skip commented lines */
+        continue;
+
+      altsvc_add(asi, lineptr);
+    }
+    Curl_dyn_free(&buf); /* free the line buffer */
+    fclose(fp);
+  }
+  return result;
+}
+
+/*
+ * Write this single altsvc entry to a single output line
+ */
+
+static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
+{
+  struct tm stamp;
+  const char *dst6_pre = "";
+  const char *dst6_post = "";
+  const char *src6_pre = "";
+  const char *src6_post = "";
+  CURLcode result = Curl_gmtime(as->expires, &stamp);
+  if(result)
+    return result;
+#ifdef ENABLE_IPV6
+  else {
+    char ipv6_unused[16];
+    if(1 == Curl_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) {
+      dst6_pre = "[";
+      dst6_post = "]";
+    }
+    if(1 == Curl_inet_pton(AF_INET6, as->src.host, ipv6_unused)) {
+      src6_pre = "[";
+      src6_post = "]";
+    }
+  }
+#endif
+  fprintf(fp,
+          "%s %s%s%s %u "
+          "%s %s%s%s %u "
+          "\"%d%02d%02d "
+          "%02d:%02d:%02d\" "
+          "%u %d\n",
+          Curl_alpnid2str(as->src.alpnid),
+          src6_pre, as->src.host, src6_post,
+          as->src.port,
+
+          Curl_alpnid2str(as->dst.alpnid),
+          dst6_pre, as->dst.host, dst6_post,
+          as->dst.port,
+
+          stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
+          stamp.tm_hour, stamp.tm_min, stamp.tm_sec,
+          as->persist, as->prio);
+  return CURLE_OK;
+}
+
+/* ---- library-wide functions below ---- */
+
+/*
+ * Curl_altsvc_init() creates a new altsvc cache.
+ * It returns the new instance or NULL if something goes wrong.
+ */
+struct altsvcinfo *Curl_altsvc_init(void)
+{
+  struct altsvcinfo *asi = calloc(1, sizeof(struct altsvcinfo));
+  if(!asi)
+    return NULL;
+  Curl_llist_init(&asi->list, NULL);
+
+  /* set default behavior */
+  asi->flags = CURLALTSVC_H1
+#ifdef USE_HTTP2
+    | CURLALTSVC_H2
+#endif
+#ifdef ENABLE_QUIC
+    | CURLALTSVC_H3
+#endif
+    ;
+  return asi;
+}
+
+/*
+ * Curl_altsvc_load() loads alt-svc from file.
+ */
+CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file)
+{
+  CURLcode result;
+  DEBUGASSERT(asi);
+  result = altsvc_load(asi, file);
+  return result;
+}
+
+/*
+ * Curl_altsvc_ctrl() passes on the external bitmask.
+ */
+CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl)
+{
+  DEBUGASSERT(asi);
+  asi->flags = ctrl;
+  return CURLE_OK;
+}
+
+/*
+ * Curl_altsvc_cleanup() frees an altsvc cache instance and all associated
+ * resources.
+ */
+void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp)
+{
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *n;
+  if(*altsvcp) {
+    struct altsvcinfo *altsvc = *altsvcp;
+    for(e = altsvc->list.head; e; e = n) {
+      struct altsvc *as = e->ptr;
+      n = e->next;
+      altsvc_free(as);
+    }
+    free(altsvc->filename);
+    free(altsvc);
+    *altsvcp = NULL; /* clear the pointer */
+  }
+}
+
+/*
+ * Curl_altsvc_save() writes the altsvc cache to a file.
+ */
+CURLcode Curl_altsvc_save(struct Curl_easy *data,
+                          struct altsvcinfo *altsvc, const char *file)
+{
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *n;
+  CURLcode result = CURLE_OK;
+  FILE *out;
+  char *tempstore = NULL;
+
+  if(!altsvc)
+    /* no cache activated */
+    return CURLE_OK;
+
+  /* if not new name is given, use the one we stored from the load */
+  if(!file && altsvc->filename)
+    file = altsvc->filename;
+
+  if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file || !file[0])
+    /* marked as read-only, no file or zero length file name */
+    return CURLE_OK;
+
+  result = Curl_fopen(data, file, &out, &tempstore);
+  if(!result) {
+    fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n"
+          "# This file was generated by libcurl! Edit at your own risk.\n",
+          out);
+    for(e = altsvc->list.head; e; e = n) {
+      struct altsvc *as = e->ptr;
+      n = e->next;
+      result = altsvc_out(as, out);
+      if(result)
+        break;
+    }
+    fclose(out);
+    if(!result && tempstore && Curl_rename(tempstore, file))
+      result = CURLE_WRITE_ERROR;
+
+    if(result && tempstore)
+      unlink(tempstore);
+  }
+  free(tempstore);
+  return result;
+}
+
+static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen)
+{
+  size_t len;
+  const char *protop;
+  const char *p = *ptr;
+  while(*p && ISBLANK(*p))
+    p++;
+  protop = p;
+  while(*p && !ISBLANK(*p) && (*p != ';') && (*p != '='))
+    p++;
+  len = p - protop;
+  *ptr = p;
+
+  if(!len || (len >= buflen))
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  memcpy(alpnbuf, protop, len);
+  alpnbuf[len] = 0;
+  return CURLE_OK;
+}
+
+/* hostcompare() returns true if 'host' matches 'check'. The first host
+ * argument may have a trailing dot present that will be ignored.
+ */
+static bool hostcompare(const char *host, const char *check)
+{
+  size_t hlen = strlen(host);
+  size_t clen = strlen(check);
+
+  if(hlen && (host[hlen - 1] == '.'))
+    hlen--;
+  if(hlen != clen)
+    /* they can't match if they have different lengths */
+    return FALSE;
+  return strncasecompare(host, check, hlen);
+}
+
+/* altsvc_flush() removes all alternatives for this source origin from the
+   list */
+static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
+                         const char *srchost, unsigned short srcport)
+{
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *n;
+  for(e = asi->list.head; e; e = n) {
+    struct altsvc *as = e->ptr;
+    n = e->next;
+    if((srcalpnid == as->src.alpnid) &&
+       (srcport == as->src.port) &&
+       hostcompare(srchost, as->src.host)) {
+      Curl_llist_remove(&asi->list, e, NULL);
+      altsvc_free(as);
+    }
+  }
+}
+
+#ifdef DEBUGBUILD
+/* to play well with debug builds, we can *set* a fixed time this will
+   return */
+static time_t altsvc_debugtime(void *unused)
+{
+  char *timestr = getenv("CURL_TIME");
+  (void)unused;
+  if(timestr) {
+    unsigned long val = strtol(timestr, NULL, 10);
+    return (time_t)val;
+  }
+  return time(NULL);
+}
+#undef time
+#define time(x) altsvc_debugtime(x)
+#endif
+
+#define ISNEWLINE(x) (((x) == '\n') || (x) == '\r')
+
+/*
+ * Curl_altsvc_parse() takes an incoming alt-svc response header and stores
+ * the data correctly in the cache.
+ *
+ * 'value' points to the header *value*. That's contents to the right of the
+ * header name.
+ *
+ * Currently this function rejects invalid data without returning an error.
+ * Invalid host name, port number will result in the specific alternative
+ * being rejected. Unknown protocols are skipped.
+ */
+CURLcode Curl_altsvc_parse(struct Curl_easy *data,
+                           struct altsvcinfo *asi, const char *value,
+                           enum alpnid srcalpnid, const char *srchost,
+                           unsigned short srcport)
+{
+  const char *p = value;
+  size_t len;
+  char namebuf[MAX_ALTSVC_HOSTLEN] = "";
+  char alpnbuf[MAX_ALTSVC_ALPNLEN] = "";
+  struct altsvc *as;
+  unsigned short dstport = srcport; /* the same by default */
+  CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
+  size_t entries = 0;
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)data;
+#endif
+  if(result) {
+    infof(data, "Excessive alt-svc header, ignoring.");
+    return CURLE_OK;
+  }
+
+  DEBUGASSERT(asi);
+
+  /* "clear" is a magic keyword */
+  if(strcasecompare(alpnbuf, "clear")) {
+    /* Flush cached alternatives for this source origin */
+    altsvc_flush(asi, srcalpnid, srchost, srcport);
+    return CURLE_OK;
+  }
+
+  do {
+    if(*p == '=') {
+      /* [protocol]="[host][:port]" */
+      enum alpnid dstalpnid = alpn2alpnid(alpnbuf); /* the same by default */
+      p++;
+      if(*p == '\"') {
+        const char *dsthost = "";
+        const char *value_ptr;
+        char option[32];
+        unsigned long num;
+        char *end_ptr;
+        bool quoted = FALSE;
+        time_t maxage = 24 * 3600; /* default is 24 hours */
+        bool persist = FALSE;
+        bool valid = TRUE;
+        p++;
+        if(*p != ':') {
+          /* host name starts here */
+          const char *hostp = p;
+          if(*p == '[') {
+            /* pass all valid IPv6 letters - does not handle zone id */
+            len = strspn(++p, "0123456789abcdefABCDEF:.");
+            if(p[len] != ']')
+              /* invalid host syntax, bail out */
+              break;
+            /* we store the IPv6 numerical address *with* brackets */
+            len += 2;
+            p = &p[len-1];
+          }
+          else {
+            while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
+              p++;
+            len = p - hostp;
+          }
+          if(!len || (len >= MAX_ALTSVC_HOSTLEN)) {
+            infof(data, "Excessive alt-svc host name, ignoring.");
+            valid = FALSE;
+          }
+          else {
+            memcpy(namebuf, hostp, len);
+            namebuf[len] = 0;
+            dsthost = namebuf;
+          }
+        }
+        else {
+          /* no destination name, use source host */
+          dsthost = srchost;
+        }
+        if(*p == ':') {
+          unsigned long port = 0;
+          p++;
+          if(ISDIGIT(*p))
+            /* a port number */
+            port = strtoul(p, &end_ptr, 10);
+          else
+            end_ptr = (char *)p; /* not left uninitialized */
+          if(!port || port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
+            infof(data, "Unknown alt-svc port number, ignoring.");
+            valid = FALSE;
+          }
+          else {
+            dstport = curlx_ultous(port);
+            p = end_ptr;
+          }
+        }
+        if(*p++ != '\"')
+          break;
+        /* Handle the optional 'ma' and 'persist' flags. Unknown flags
+           are skipped. */
+        for(;;) {
+          while(ISBLANK(*p))
+            p++;
+          if(*p != ';')
+            break;
+          p++; /* pass the semicolon */
+          if(!*p || ISNEWLINE(*p))
+            break;
+          result = getalnum(&p, option, sizeof(option));
+          if(result) {
+            /* skip option if name is too long */
+            option[0] = '\0';
+          }
+          while(*p && ISBLANK(*p))
+            p++;
+          if(*p != '=')
+            return CURLE_OK;
+          p++;
+          while(*p && ISBLANK(*p))
+            p++;
+          if(!*p)
+            return CURLE_OK;
+          if(*p == '\"') {
+            /* quoted value */
+            p++;
+            quoted = TRUE;
+          }
+          value_ptr = p;
+          if(quoted) {
+            while(*p && *p != '\"')
+              p++;
+            if(!*p++)
+              return CURLE_OK;
+          }
+          else {
+            while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',')
+              p++;
+          }
+          num = strtoul(value_ptr, &end_ptr, 10);
+          if((end_ptr != value_ptr) && (num < ULONG_MAX)) {
+            if(strcasecompare("ma", option))
+              maxage = num;
+            else if(strcasecompare("persist", option) && (num == 1))
+              persist = TRUE;
+          }
+        }
+        if(dstalpnid && valid) {
+          if(!entries++)
+            /* Flush cached alternatives for this source origin, if any - when
+               this is the first entry of the line. */
+            altsvc_flush(asi, srcalpnid, srchost, srcport);
+
+          as = altsvc_createid(srchost, dsthost,
+                               srcalpnid, dstalpnid,
+                               srcport, dstport);
+          if(as) {
+            /* The expires time also needs to take the Age: value (if any) into
+               account. [See RFC 7838 section 3.1] */
+            as->expires = maxage + time(NULL);
+            as->persist = persist;
+            Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
+            infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
+                  Curl_alpnid2str(dstalpnid));
+          }
+        }
+      }
+      else
+        break;
+      /* after the double quote there can be a comma if there's another
+         string or a semicolon if no more */
+      if(*p == ',') {
+        /* comma means another alternative is presented */
+        p++;
+        result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
+        if(result)
+          break;
+      }
+    }
+    else
+      break;
+  } while(*p && (*p != ';') && (*p != '\n') && (*p != '\r'));
+
+  return CURLE_OK;
+}
+
+/*
+ * Return TRUE on a match
+ */
+bool Curl_altsvc_lookup(struct altsvcinfo *asi,
+                        enum alpnid srcalpnid, const char *srchost,
+                        int srcport,
+                        struct altsvc **dstentry,
+                        const int versions) /* one or more bits */
+{
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *n;
+  time_t now = time(NULL);
+  DEBUGASSERT(asi);
+  DEBUGASSERT(srchost);
+  DEBUGASSERT(dstentry);
+
+  for(e = asi->list.head; e; e = n) {
+    struct altsvc *as = e->ptr;
+    n = e->next;
+    if(as->expires < now) {
+      /* an expired entry, remove */
+      Curl_llist_remove(&asi->list, e, NULL);
+      altsvc_free(as);
+      continue;
+    }
+    if((as->src.alpnid == srcalpnid) &&
+       hostcompare(srchost, as->src.host) &&
+       (as->src.port == srcport) &&
+       (versions & as->dst.alpnid)) {
+      /* match */
+      *dstentry = as;
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */
Index: trunk/src/libs/curl-8.7.1/lib/altsvc.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/altsvc.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/altsvc.h	(revision 104083)
@@ -0,0 +1,81 @@
+#ifndef HEADER_CURL_ALTSVC_H
+#define HEADER_CURL_ALTSVC_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC)
+#include <curl/curl.h>
+#include "llist.h"
+
+enum alpnid {
+  ALPN_none = 0,
+  ALPN_h1 = CURLALTSVC_H1,
+  ALPN_h2 = CURLALTSVC_H2,
+  ALPN_h3 = CURLALTSVC_H3
+};
+
+struct althost {
+  char *host;
+  unsigned short port;
+  enum alpnid alpnid;
+};
+
+struct altsvc {
+  struct althost src;
+  struct althost dst;
+  time_t expires;
+  bool persist;
+  int prio;
+  struct Curl_llist_element node;
+};
+
+struct altsvcinfo {
+  char *filename;
+  struct Curl_llist list; /* list of entries */
+  long flags; /* the publicly set bitmask */
+};
+
+const char *Curl_alpnid2str(enum alpnid id);
+struct altsvcinfo *Curl_altsvc_init(void);
+CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file);
+CURLcode Curl_altsvc_save(struct Curl_easy *data,
+                          struct altsvcinfo *asi, const char *file);
+CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl);
+void Curl_altsvc_cleanup(struct altsvcinfo **altsvc);
+CURLcode Curl_altsvc_parse(struct Curl_easy *data,
+                           struct altsvcinfo *altsvc, const char *value,
+                           enum alpnid srcalpn, const char *srchost,
+                           unsigned short srcport);
+bool Curl_altsvc_lookup(struct altsvcinfo *asi,
+                        enum alpnid srcalpnid, const char *srchost,
+                        int srcport,
+                        struct altsvc **dstentry,
+                        const int versions); /* CURLALTSVC_H* bits */
+#else
+/* disabled */
+#define Curl_altsvc_save(a,b,c)
+#define Curl_altsvc_cleanup(x)
+#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */
+#endif /* HEADER_CURL_ALTSVC_H */
Index: trunk/src/libs/curl-8.7.1/lib/amigaos.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/amigaos.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/amigaos.c	(revision 104083)
@@ -0,0 +1,247 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef __AMIGA__
+
+#include <curl/curl.h>
+
+#include "hostip.h"
+#include "amigaos.h"
+
+#ifdef HAVE_PROTO_BSDSOCKET_H
+#  if defined(__amigaos4__)
+#    include <bsdsocket/socketbasetags.h>
+#  elif !defined(USE_AMISSL)
+#    include <amitcp/socketbasetags.h>
+#  endif
+#  ifdef __libnix__
+#    include <stabs.h>
+#  endif
+#endif
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef HAVE_PROTO_BSDSOCKET_H
+
+#ifdef __amigaos4__
+/*
+ * AmigaOS 4.x specific code
+ */
+
+/*
+ * hostip4.c - Curl_ipv4_resolve_r() replacement code
+ *
+ * Logic that needs to be considered are the following build cases:
+ * - newlib networking
+ * - clib2 networking
+ * - direct bsdsocket.library networking (usually AmiSSL builds)
+ * Each with the threaded resolver enabled or not.
+ *
+ * With the threaded resolver enabled, try to use gethostbyname_r() where
+ * available, otherwise (re)open bsdsocket.library and fallback to
+ * gethostbyname().
+ */
+
+#include <proto/bsdsocket.h>
+
+static struct SocketIFace *__CurlISocket = NULL;
+static uint32 SocketFeatures = 0;
+
+#define HAVE_BSDSOCKET_GETHOSTBYNAME_R 0x01
+#define HAVE_BSDSOCKET_GETADDRINFO     0x02
+
+CURLcode Curl_amiga_init(void)
+{
+  struct SocketIFace *ISocket;
+  struct Library *base = OpenLibrary("bsdsocket.library", 4);
+
+  if(base) {
+    ISocket = (struct SocketIFace *)GetInterface(base, "main", 1, NULL);
+    if(ISocket) {
+      ULONG enabled = 0;
+
+      SocketBaseTags(SBTM_SETVAL(SBTC_CAN_SHARE_LIBRARY_BASES), TRUE,
+                     SBTM_GETREF(SBTC_HAVE_GETHOSTADDR_R_API), (ULONG)&enabled,
+                     TAG_DONE);
+
+      if(enabled) {
+        SocketFeatures |= HAVE_BSDSOCKET_GETHOSTBYNAME_R;
+      }
+
+      __CurlISocket = ISocket;
+
+      atexit(Curl_amiga_cleanup);
+
+      return CURLE_OK;
+    }
+    CloseLibrary(base);
+  }
+
+  return CURLE_FAILED_INIT;
+}
+
+void Curl_amiga_cleanup(void)
+{
+  if(__CurlISocket) {
+    struct Library *base = __CurlISocket->Data.LibBase;
+    DropInterface((struct Interface *)__CurlISocket);
+    CloseLibrary(base);
+    __CurlISocket = NULL;
+  }
+}
+
+#ifdef CURLRES_AMIGA
+/*
+ * Because we need to handle the different cases in hostip4.c at run-time,
+ * not at compile-time, based on what was detected in Curl_amiga_init(),
+ * we replace it completely with our own as to not complicate the baseline
+ * code. Assumes malloc/calloc/free are thread safe because Curl_he2ai()
+ * allocates memory also.
+ */
+
+struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
+                                          int port)
+{
+  struct Curl_addrinfo *ai = NULL;
+  struct hostent *h;
+  struct SocketIFace *ISocket = __CurlISocket;
+
+  if(SocketFeatures & HAVE_BSDSOCKET_GETHOSTBYNAME_R) {
+    LONG h_errnop = 0;
+    struct hostent *buf;
+
+    buf = calloc(1, CURL_HOSTENT_SIZE);
+    if(buf) {
+      h = gethostbyname_r((STRPTR)hostname, buf,
+                          (char *)buf + sizeof(struct hostent),
+                          CURL_HOSTENT_SIZE - sizeof(struct hostent),
+                          &h_errnop);
+      if(h) {
+        ai = Curl_he2ai(h, port);
+      }
+      free(buf);
+    }
+  }
+  else {
+    #ifdef CURLRES_THREADED
+    /* gethostbyname() is not thread safe, so we need to reopen bsdsocket
+     * on the thread's context
+     */
+    struct Library *base = OpenLibrary("bsdsocket.library", 4);
+    if(base) {
+      ISocket = (struct SocketIFace *)GetInterface(base, "main", 1, NULL);
+      if(ISocket) {
+        h = gethostbyname((STRPTR)hostname);
+        if(h) {
+          ai = Curl_he2ai(h, port);
+        }
+        DropInterface((struct Interface *)ISocket);
+      }
+      CloseLibrary(base);
+    }
+    #else
+    /* not using threaded resolver - safe to use this as-is */
+    h = gethostbyname(hostname);
+    if(h) {
+      ai = Curl_he2ai(h, port);
+    }
+    #endif
+  }
+
+  return ai;
+}
+#endif /* CURLRES_AMIGA */
+
+#ifdef USE_AMISSL
+#include <signal.h>
+int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds,
+                      fd_set *errorfds, struct timeval *timeout)
+{
+  int r = WaitSelect(nfds, readfds, writefds, errorfds, timeout, 0);
+  /* Ensure Ctrl-C signal is actioned */
+  if((r == -1) && (SOCKERRNO == EINTR))
+    raise(SIGINT);
+  return r;
+}
+#endif /* USE_AMISSL */
+
+#elif !defined(USE_AMISSL) /* __amigaos4__ */
+/*
+ * Amiga OS3 specific code
+ */
+
+struct Library *SocketBase = NULL;
+extern int errno, h_errno;
+
+#ifdef __libnix__
+void __request(const char *msg);
+#else
+# define __request(msg)       Printf(msg "\n\a")
+#endif
+
+void Curl_amiga_cleanup(void)
+{
+  if(SocketBase) {
+    CloseLibrary(SocketBase);
+    SocketBase = NULL;
+  }
+}
+
+CURLcode Curl_amiga_init(void)
+{
+  if(!SocketBase)
+    SocketBase = OpenLibrary("bsdsocket.library", 4);
+
+  if(!SocketBase) {
+    __request("No TCP/IP Stack running!");
+    return CURLE_FAILED_INIT;
+  }
+
+  if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno,
+                    SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "curl",
+                    TAG_DONE)) {
+    __request("SocketBaseTags ERROR");
+    return CURLE_FAILED_INIT;
+  }
+
+#ifndef __libnix__
+  atexit(Curl_amiga_cleanup);
+#endif
+
+  return CURLE_OK;
+}
+
+#ifdef __libnix__
+ADD2EXIT(Curl_amiga_cleanup, -50);
+#endif
+
+#endif /* !USE_AMISSL */
+
+#endif /* HAVE_PROTO_BSDSOCKET_H */
+
+#endif /* __AMIGA__ */
Index: trunk/src/libs/curl-8.7.1/lib/amigaos.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/amigaos.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/amigaos.h	(revision 104083)
@@ -0,0 +1,41 @@
+#ifndef HEADER_CURL_AMIGAOS_H
+#define HEADER_CURL_AMIGAOS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(__AMIGA__) && defined(HAVE_PROTO_BSDSOCKET_H) && \
+  (!defined(USE_AMISSL) || defined(__amigaos4__))
+
+CURLcode Curl_amiga_init(void);
+void Curl_amiga_cleanup(void);
+
+#else
+
+#define Curl_amiga_init() CURLE_OK
+#define Curl_amiga_cleanup() Curl_nop_stmt
+
+#endif
+
+#endif /* HEADER_CURL_AMIGAOS_H */
Index: trunk/src/libs/curl-8.7.1/lib/arpa_telnet.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/arpa_telnet.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/arpa_telnet.h	(revision 104083)
@@ -0,0 +1,117 @@
+#ifndef HEADER_CURL_ARPA_TELNET_H
+#define HEADER_CURL_ARPA_TELNET_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TELNET
+/*
+ * Telnet option defines. Add more here if in need.
+ */
+#define CURL_TELOPT_BINARY   0  /* binary 8bit data */
+#define CURL_TELOPT_ECHO     1  /* just echo! */
+#define CURL_TELOPT_SGA      3  /* Suppress Go Ahead */
+#define CURL_TELOPT_EXOPL  255  /* EXtended OPtions List */
+#define CURL_TELOPT_TTYPE   24  /* Terminal TYPE */
+#define CURL_TELOPT_NAWS    31  /* Negotiate About Window Size */
+#define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */
+
+#define CURL_TELOPT_NEW_ENVIRON 39  /* NEW ENVIRONment variables */
+#define CURL_NEW_ENV_VAR   0
+#define CURL_NEW_ENV_VALUE 1
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+/*
+ * The telnet options represented as strings
+ */
+static const char * const telnetoptions[]=
+{
+  "BINARY",      "ECHO",           "RCP",           "SUPPRESS GO AHEAD",
+  "NAME",        "STATUS",         "TIMING MARK",   "RCTE",
+  "NAOL",        "NAOP",           "NAOCRD",        "NAOHTS",
+  "NAOHTD",      "NAOFFD",         "NAOVTS",        "NAOVTD",
+  "NAOLFD",      "EXTEND ASCII",   "LOGOUT",        "BYTE MACRO",
+  "DE TERMINAL", "SUPDUP",         "SUPDUP OUTPUT", "SEND LOCATION",
+  "TERM TYPE",   "END OF RECORD",  "TACACS UID",    "OUTPUT MARKING",
+  "TTYLOC",      "3270 REGIME",    "X3 PAD",        "NAWS",
+  "TERM SPEED",  "LFLOW",          "LINEMODE",      "XDISPLOC",
+  "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT",       "NEW-ENVIRON"
+};
+#define CURL_TELOPT(x)    telnetoptions[x]
+#else
+#define CURL_TELOPT(x)    ""
+#endif
+
+#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON
+
+#define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM)
+
+#define CURL_NTELOPTS 40
+
+/*
+ * First some defines
+ */
+#define CURL_xEOF 236 /* End Of File */
+#define CURL_SE   240 /* Sub negotiation End */
+#define CURL_NOP  241 /* No OPeration */
+#define CURL_DM   242 /* Data Mark */
+#define CURL_GA   249 /* Go Ahead, reverse the line */
+#define CURL_SB   250 /* SuBnegotiation */
+#define CURL_WILL 251 /* Our side WILL use this option */
+#define CURL_WONT 252 /* Our side WON'T use this option */
+#define CURL_DO   253 /* DO use this option! */
+#define CURL_DONT 254 /* DON'T use this option! */
+#define CURL_IAC  255 /* Interpret As Command */
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+/*
+ * Then those numbers represented as strings:
+ */
+static const char * const telnetcmds[]=
+{
+  "EOF",  "SUSP",  "ABORT", "EOR",  "SE",
+  "NOP",  "DMARK", "BRK",   "IP",   "AO",
+  "AYT",  "EC",    "EL",    "GA",   "SB",
+  "WILL", "WONT",  "DO",    "DONT", "IAC"
+};
+#endif
+
+#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */
+#define CURL_TELCMD_MAXIMUM CURL_IAC  /* surprise, 255 is the last one! ;-) */
+
+#define CURL_TELQUAL_IS   0
+#define CURL_TELQUAL_SEND 1
+#define CURL_TELQUAL_INFO 2
+#define CURL_TELQUAL_NAME 3
+
+#define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \
+                       ((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) )
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+#define CURL_TELCMD(x)    telnetcmds[(x)-CURL_TELCMD_MINIMUM]
+#else
+#define CURL_TELCMD(x)    ""
+#endif
+
+#endif /* CURL_DISABLE_TELNET */
+
+#endif /* HEADER_CURL_ARPA_TELNET_H */
Index: trunk/src/libs/curl-8.7.1/lib/asyn-ares.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/asyn-ares.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/asyn-ares.c	(revision 104083)
@@ -0,0 +1,958 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+/***********************************************************************
+ * Only for ares-enabled builds
+ * And only for functions that fulfill the asynch resolver backend API
+ * as defined in asyn.h, nothing else belongs in this file!
+ **********************************************************************/
+
+#ifdef CURLRES_ARES
+
+#include <limits.h>
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "url.h"
+#include "multiif.h"
+#include "inet_pton.h"
+#include "connect.h"
+#include "select.h"
+#include "progress.h"
+#include "timediff.h"
+
+#if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) &&   \
+  defined(_WIN32)
+#  define CARES_STATICLIB
+#endif
+#include <ares.h>
+#include <ares_version.h> /* really old c-ares didn't include this by
+                             itself */
+
+#if ARES_VERSION >= 0x010500
+/* c-ares 1.5.0 or later, the callback proto is modified */
+#define HAVE_CARES_CALLBACK_TIMEOUTS 1
+#endif
+
+#if ARES_VERSION >= 0x010601
+/* IPv6 supported since 1.6.1 */
+#define HAVE_CARES_IPV6 1
+#endif
+
+#if ARES_VERSION >= 0x010704
+#define HAVE_CARES_SERVERS_CSV 1
+#define HAVE_CARES_LOCAL_DEV 1
+#define HAVE_CARES_SET_LOCAL 1
+#endif
+
+#if ARES_VERSION >= 0x010b00
+#define HAVE_CARES_PORTS_CSV 1
+#endif
+
+#if ARES_VERSION >= 0x011000
+/* 1.16.0 or later has ares_getaddrinfo */
+#define HAVE_CARES_GETADDRINFO 1
+#endif
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+struct thread_data {
+  int num_pending; /* number of outstanding c-ares requests */
+  struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
+                                    parts */
+  int last_status;
+#ifndef HAVE_CARES_GETADDRINFO
+  struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
+#endif
+  char hostname[1];
+};
+
+/* How long we are willing to wait for additional parallel responses after
+   obtaining a "definitive" one. For old c-ares without getaddrinfo.
+
+   This is intended to equal the c-ares default timeout.  cURL always uses that
+   default value.  Unfortunately, c-ares doesn't expose its default timeout in
+   its API, but it is officially documented as 5 seconds.
+
+   See query_completed_cb() for an explanation of how this is used.
+ */
+#define HAPPY_EYEBALLS_DNS_TIMEOUT 5000
+
+#define CARES_TIMEOUT_PER_ATTEMPT 2000
+
+static int ares_ver = 0;
+
+/*
+ * Curl_resolver_global_init() - the generic low-level asynchronous name
+ * resolve API.  Called from curl_global_init() to initialize global resolver
+ * environment.  Initializes ares library.
+ */
+int Curl_resolver_global_init(void)
+{
+#ifdef CARES_HAVE_ARES_LIBRARY_INIT
+  if(ares_library_init(ARES_LIB_INIT_ALL)) {
+    return CURLE_FAILED_INIT;
+  }
+#endif
+  ares_version(&ares_ver);
+  return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_global_cleanup()
+ *
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ * Deinitializes ares library.
+ */
+void Curl_resolver_global_cleanup(void)
+{
+#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
+  ares_library_cleanup();
+#endif
+}
+
+
+static void sock_state_cb(void *data, ares_socket_t socket_fd,
+                          int readable, int writable)
+{
+  struct Curl_easy *easy = data;
+  if(!readable && !writable) {
+    DEBUGASSERT(easy);
+    Curl_multi_closed(easy, socket_fd);
+  }
+}
+
+/*
+ * Curl_resolver_init()
+ *
+ * Called from curl_easy_init() -> Curl_open() to initialize resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure).  Fills the passed pointer by the initialized ares_channel.
+ */
+CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
+{
+  int status;
+  struct ares_options options;
+  int optmask = ARES_OPT_SOCK_STATE_CB;
+  options.sock_state_cb = sock_state_cb;
+  options.sock_state_cb_data = easy;
+
+  /*
+     if c ares < 1.20.0: curl set timeout to CARES_TIMEOUT_PER_ATTEMPT (2s)
+
+     if c-ares >= 1.20.0 it already has the timeout to 2s, curl does not need
+     to set the timeout value;
+
+     if c-ares >= 1.24.0, user can set the timeout via /etc/resolv.conf to
+     overwrite c-ares' timeout.
+  */
+  DEBUGASSERT(ares_ver);
+  if(ares_ver < 0x011400) {
+    options.timeout = CARES_TIMEOUT_PER_ATTEMPT;
+    optmask |= ARES_OPT_TIMEOUTMS;
+  }
+
+  status = ares_init_options((ares_channel*)resolver, &options, optmask);
+  if(status != ARES_SUCCESS) {
+    if(status == ARES_ENOMEM)
+      return CURLE_OUT_OF_MEMORY;
+    else
+      return CURLE_FAILED_INIT;
+  }
+  return CURLE_OK;
+  /* make sure that all other returns from this function should destroy the
+     ares channel before returning error! */
+}
+
+/*
+ * Curl_resolver_cleanup()
+ *
+ * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure).  Destroys the ares channel.
+ */
+void Curl_resolver_cleanup(void *resolver)
+{
+  ares_destroy((ares_channel)resolver);
+}
+
+/*
+ * Curl_resolver_duphandle()
+ *
+ * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
+ * environment ('resolver' member of the UrlState structure).  Duplicates the
+ * 'from' ares channel and passes the resulting channel to the 'to' pointer.
+ */
+CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
+{
+  (void)from;
+  /*
+   * it would be better to call ares_dup instead, but right now
+   * it is not possible to set 'sock_state_cb_data' outside of
+   * ares_init_options
+   */
+  return Curl_resolver_init(easy, to);
+}
+
+static void destroy_async_data(struct Curl_async *async);
+
+/*
+ * Cancel all possibly still on-going resolves for this connection.
+ */
+void Curl_resolver_cancel(struct Curl_easy *data)
+{
+  DEBUGASSERT(data);
+  if(data->state.async.resolver)
+    ares_cancel((ares_channel)data->state.async.resolver);
+  destroy_async_data(&data->state.async);
+}
+
+/*
+ * We're equivalent to Curl_resolver_cancel() for the c-ares resolver.  We
+ * never block.
+ */
+void Curl_resolver_kill(struct Curl_easy *data)
+{
+  /* We don't need to check the resolver state because we can be called safely
+     at any time and we always do the same thing. */
+  Curl_resolver_cancel(data);
+}
+
+/*
+ * destroy_async_data() cleans up async resolver data.
+ */
+static void destroy_async_data(struct Curl_async *async)
+{
+  if(async->tdata) {
+    struct thread_data *res = async->tdata;
+    if(res) {
+      if(res->temp_ai) {
+        Curl_freeaddrinfo(res->temp_ai);
+        res->temp_ai = NULL;
+      }
+      free(res);
+    }
+    async->tdata = NULL;
+  }
+}
+
+/*
+ * Curl_resolver_getsock() is called when someone from the outside world
+ * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking
+ * with ares. The caller must make sure that this function is only called when
+ * we have a working ares channel.
+ *
+ * Returns: sockets-in-use-bitmap
+ */
+
+int Curl_resolver_getsock(struct Curl_easy *data,
+                          curl_socket_t *socks)
+{
+  struct timeval maxtime;
+  struct timeval timebuf;
+  struct timeval *timeout;
+  long milli;
+  int max = ares_getsock((ares_channel)data->state.async.resolver,
+                         (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
+
+  maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
+  maxtime.tv_usec = 0;
+
+  timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime,
+                         &timebuf);
+  milli = (long)curlx_tvtoms(timeout);
+  if(milli == 0)
+    milli += 10;
+  Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
+
+  return max;
+}
+
+/*
+ * waitperform()
+ *
+ * 1) Ask ares what sockets it currently plays with, then
+ * 2) wait for the timeout period to check for action on ares' sockets.
+ * 3) tell ares to act on all the sockets marked as "with action"
+ *
+ * return number of sockets it worked on, or -1 on error
+ */
+
+static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
+{
+  int nfds;
+  int bitmask;
+  ares_socket_t socks[ARES_GETSOCK_MAXNUM];
+  struct pollfd pfd[ARES_GETSOCK_MAXNUM];
+  int i;
+  int num = 0;
+
+  bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks,
+                         ARES_GETSOCK_MAXNUM);
+
+  for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
+    pfd[i].events = 0;
+    pfd[i].revents = 0;
+    if(ARES_GETSOCK_READABLE(bitmask, i)) {
+      pfd[i].fd = socks[i];
+      pfd[i].events |= POLLRDNORM|POLLIN;
+    }
+    if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
+      pfd[i].fd = socks[i];
+      pfd[i].events |= POLLWRNORM|POLLOUT;
+    }
+    if(pfd[i].events)
+      num++;
+    else
+      break;
+  }
+
+  if(num) {
+    nfds = Curl_poll(pfd, num, timeout_ms);
+    if(nfds < 0)
+      return -1;
+  }
+  else
+    nfds = 0;
+
+  if(!nfds)
+    /* Call ares_process() unconditionally here, even if we simply timed out
+       above, as otherwise the ares name resolve won't timeout! */
+    ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
+                    ARES_SOCKET_BAD);
+  else {
+    /* move through the descriptors and ask for processing on them */
+    for(i = 0; i < num; i++)
+      ares_process_fd((ares_channel)data->state.async.resolver,
+                      (pfd[i].revents & (POLLRDNORM|POLLIN))?
+                      pfd[i].fd:ARES_SOCKET_BAD,
+                      (pfd[i].revents & (POLLWRNORM|POLLOUT))?
+                      pfd[i].fd:ARES_SOCKET_BAD);
+  }
+  return nfds;
+}
+
+/*
+ * Curl_resolver_is_resolved() is called repeatedly to check if a previous
+ * name resolve request has completed. It should also make sure to time-out if
+ * the operation seems to take too long.
+ *
+ * Returns normal CURLcode errors.
+ */
+CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
+                                   struct Curl_dns_entry **dns)
+{
+  struct thread_data *res = data->state.async.tdata;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(dns);
+  *dns = NULL;
+
+  if(waitperform(data, 0) < 0)
+    return CURLE_UNRECOVERABLE_POLL;
+
+#ifndef HAVE_CARES_GETADDRINFO
+  /* Now that we've checked for any last minute results above, see if there are
+     any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
+     expires. */
+  if(res
+     && res->num_pending
+     /* This is only set to non-zero if the timer was started. */
+     && (res->happy_eyeballs_dns_time.tv_sec
+         || res->happy_eyeballs_dns_time.tv_usec)
+     && (Curl_timediff(Curl_now(), res->happy_eyeballs_dns_time)
+         >= HAPPY_EYEBALLS_DNS_TIMEOUT)) {
+    /* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer
+       running. */
+    memset(
+      &res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time));
+
+    /* Cancel the raw c-ares request, which will fire query_completed_cb() with
+       ARES_ECANCELLED synchronously for all pending responses.  This will
+       leave us with res->num_pending == 0, which is perfect for the next
+       block. */
+    ares_cancel((ares_channel)data->state.async.resolver);
+    DEBUGASSERT(res->num_pending == 0);
+  }
+#endif
+
+  if(res && !res->num_pending) {
+    (void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai);
+    /* temp_ai ownership is moved to the connection, so we need not free-up
+       them */
+    res->temp_ai = NULL;
+
+    if(!data->state.async.dns)
+      result = Curl_resolver_error(data);
+    else
+      *dns = data->state.async.dns;
+
+    destroy_async_data(&data->state.async);
+  }
+
+  return result;
+}
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * Waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * 'entry' MUST be non-NULL.
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
+ */
+CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
+                                   struct Curl_dns_entry **entry)
+{
+  CURLcode result = CURLE_OK;
+  timediff_t timeout;
+  struct curltime now = Curl_now();
+
+  DEBUGASSERT(entry);
+  *entry = NULL; /* clear on entry */
+
+  timeout = Curl_timeleft(data, &now, TRUE);
+  if(timeout < 0) {
+    /* already expired! */
+    connclose(data->conn, "Timed out before name resolve started");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+  if(!timeout)
+    timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
+
+  /* Wait for the name resolve query to complete. */
+  while(!result) {
+    struct timeval *tvp, tv, store;
+    int itimeout;
+    timediff_t timeout_ms;
+
+#if TIMEDIFF_T_MAX > INT_MAX
+    itimeout = (timeout > INT_MAX) ? INT_MAX : (int)timeout;
+#else
+    itimeout = (int)timeout;
+#endif
+
+    store.tv_sec = itimeout/1000;
+    store.tv_usec = (itimeout%1000)*1000;
+
+    tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv);
+
+    /* use the timeout period ares returned to us above if less than one
+       second is left, otherwise just use 1000ms to make sure the progress
+       callback gets called frequent enough */
+    if(!tvp->tv_sec)
+      timeout_ms = (timediff_t)(tvp->tv_usec/1000);
+    else
+      timeout_ms = 1000;
+
+    if(waitperform(data, timeout_ms) < 0)
+      return CURLE_UNRECOVERABLE_POLL;
+    result = Curl_resolver_is_resolved(data, entry);
+
+    if(result || data->state.async.done)
+      break;
+
+    if(Curl_pgrsUpdate(data))
+      result = CURLE_ABORTED_BY_CALLBACK;
+    else {
+      struct curltime now2 = Curl_now();
+      timediff_t timediff = Curl_timediff(now2, now); /* spent time */
+      if(timediff <= 0)
+        timeout -= 1; /* always deduct at least 1 */
+      else if(timediff > timeout)
+        timeout = -1;
+      else
+        timeout -= timediff;
+      now = now2; /* for next loop */
+    }
+    if(timeout < 0)
+      result = CURLE_OPERATION_TIMEDOUT;
+  }
+  if(result)
+    /* failure, so we cancel the ares operation */
+    ares_cancel((ares_channel)data->state.async.resolver);
+
+  /* Operation complete, if the lookup was successful we now have the entry
+     in the cache. */
+  if(entry)
+    *entry = data->state.async.dns;
+
+  if(result)
+    /* close the connection, since we can't return failure here without
+       cleaning up this connection properly. */
+    connclose(data->conn, "c-ares resolve failed");
+
+  return result;
+}
+
+#ifndef HAVE_CARES_GETADDRINFO
+
+/* Connects results to the list */
+static void compound_results(struct thread_data *res,
+                             struct Curl_addrinfo *ai)
+{
+  if(!ai)
+    return;
+
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+  if(res->temp_ai && res->temp_ai->ai_family == PF_INET6) {
+    /* We have results already, put the new IPv6 entries at the head of the
+       list. */
+    struct Curl_addrinfo *temp_ai_tail = res->temp_ai;
+
+    while(temp_ai_tail->ai_next)
+      temp_ai_tail = temp_ai_tail->ai_next;
+
+    temp_ai_tail->ai_next = ai;
+  }
+  else
+#endif /* CURLRES_IPV6 */
+  {
+    /* Add the new results to the list of old results. */
+    struct Curl_addrinfo *ai_tail = ai;
+    while(ai_tail->ai_next)
+      ai_tail = ai_tail->ai_next;
+
+    ai_tail->ai_next = res->temp_ai;
+    res->temp_ai = ai;
+  }
+}
+
+/*
+ * ares_query_completed_cb() is the callback that ares will call when
+ * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
+ * when using ares, is completed either successfully or with failure.
+ */
+static void query_completed_cb(void *arg,  /* (struct connectdata *) */
+                               int status,
+#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
+                               int timeouts,
+#endif
+                               struct hostent *hostent)
+{
+  struct Curl_easy *data = (struct Curl_easy *)arg;
+  struct thread_data *res;
+
+#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
+  (void)timeouts; /* ignored */
+#endif
+
+  if(ARES_EDESTRUCTION == status)
+    /* when this ares handle is getting destroyed, the 'arg' pointer may not
+       be valid so only defer it when we know the 'status' says its fine! */
+    return;
+
+  res = data->state.async.tdata;
+  if(res) {
+    res->num_pending--;
+
+    if(CURL_ASYNC_SUCCESS == status) {
+      struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
+      if(ai) {
+        compound_results(res, ai);
+      }
+    }
+    /* A successful result overwrites any previous error */
+    if(res->last_status != ARES_SUCCESS)
+      res->last_status = status;
+
+    /* If there are responses still pending, we presume they must be the
+       complementary IPv4 or IPv6 lookups that we started in parallel in
+       Curl_resolver_getaddrinfo() (for Happy Eyeballs).  If we've got a
+       "definitive" response from one of a set of parallel queries, we need to
+       think about how long we're willing to wait for more responses. */
+    if(res->num_pending
+       /* Only these c-ares status values count as "definitive" for these
+          purposes.  For example, ARES_ENODATA is what we expect when there is
+          no IPv6 entry for a domain name, and that's not a reason to get more
+          aggressive in our timeouts for the other response.  Other errors are
+          either a result of bad input (which should affect all parallel
+          requests), local or network conditions, non-definitive server
+          responses, or us cancelling the request. */
+       && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
+      /* Right now, there can only be up to two parallel queries, so don't
+         bother handling any other cases. */
+      DEBUGASSERT(res->num_pending == 1);
+
+      /* It's possible that one of these parallel queries could succeed
+         quickly, but the other could always fail or timeout (when we're
+         talking to a pool of DNS servers that can only successfully resolve
+         IPv4 address, for example).
+
+         It's also possible that the other request could always just take
+         longer because it needs more time or only the second DNS server can
+         fulfill it successfully.  But, to align with the philosophy of Happy
+         Eyeballs, we don't want to wait _too_ long or users will think
+         requests are slow when IPv6 lookups don't actually work (but IPv4 ones
+         do).
+
+         So, now that we have a usable answer (some IPv4 addresses, some IPv6
+         addresses, or "no such domain"), we start a timeout for the remaining
+         pending responses.  Even though it is typical that this resolved
+         request came back quickly, that needn't be the case.  It might be that
+         this completing request didn't get a result from the first DNS server
+         or even the first round of the whole DNS server pool.  So it could
+         already be quite some time after we issued the DNS queries in the
+         first place.  Without modifying c-ares, we can't know exactly where in
+         its retry cycle we are.  We could guess based on how much time has
+         gone by, but it doesn't really matter.  Happy Eyeballs tells us that,
+         given usable information in hand, we simply don't want to wait "too
+         much longer" after we get a result.
+
+         We simply wait an additional amount of time equal to the default
+         c-ares query timeout.  That is enough time for a typical parallel
+         response to arrive without being "too long".  Even on a network
+         where one of the two types of queries is failing or timing out
+         constantly, this will usually mean we wait a total of the default
+         c-ares timeout (5 seconds) plus the round trip time for the successful
+         request, which seems bearable.  The downside is that c-ares might race
+         with us to issue one more retry just before we give up, but it seems
+         better to "waste" that request instead of trying to guess the perfect
+         timeout to prevent it.  After all, we don't even know where in the
+         c-ares retry cycle each request is.
+      */
+      res->happy_eyeballs_dns_time = Curl_now();
+      Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT,
+                  EXPIRE_HAPPY_EYEBALLS_DNS);
+    }
+  }
+}
+#else
+/* c-ares 1.16.0 or later */
+
+/*
+ * ares2addr() converts an address list provided by c-ares to an internal
+ * libcurl compatible list
+ */
+static struct Curl_addrinfo *ares2addr(struct ares_addrinfo_node *node)
+{
+  /* traverse the ares_addrinfo_node list */
+  struct ares_addrinfo_node *ai;
+  struct Curl_addrinfo *cafirst = NULL;
+  struct Curl_addrinfo *calast = NULL;
+  int error = 0;
+
+  for(ai = node; ai != NULL; ai = ai->ai_next) {
+    size_t ss_size;
+    struct Curl_addrinfo *ca;
+    /* ignore elements with unsupported address family, */
+    /* settle family-specific sockaddr structure size.  */
+    if(ai->ai_family == AF_INET)
+      ss_size = sizeof(struct sockaddr_in);
+#ifdef ENABLE_IPV6
+    else if(ai->ai_family == AF_INET6)
+      ss_size = sizeof(struct sockaddr_in6);
+#endif
+    else
+      continue;
+
+    /* ignore elements without required address info */
+    if(!ai->ai_addr || !(ai->ai_addrlen > 0))
+      continue;
+
+    /* ignore elements with bogus address size */
+    if((size_t)ai->ai_addrlen < ss_size)
+      continue;
+
+    ca = malloc(sizeof(struct Curl_addrinfo) + ss_size);
+    if(!ca) {
+      error = EAI_MEMORY;
+      break;
+    }
+
+    /* copy each structure member individually, member ordering, */
+    /* size, or padding might be different for each platform.    */
+
+    ca->ai_flags     = ai->ai_flags;
+    ca->ai_family    = ai->ai_family;
+    ca->ai_socktype  = ai->ai_socktype;
+    ca->ai_protocol  = ai->ai_protocol;
+    ca->ai_addrlen   = (curl_socklen_t)ss_size;
+    ca->ai_addr      = NULL;
+    ca->ai_canonname = NULL;
+    ca->ai_next      = NULL;
+
+    ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
+    memcpy(ca->ai_addr, ai->ai_addr, ss_size);
+
+    /* if the return list is empty, this becomes the first element */
+    if(!cafirst)
+      cafirst = ca;
+
+    /* add this element last in the return list */
+    if(calast)
+      calast->ai_next = ca;
+    calast = ca;
+  }
+
+  /* if we failed, destroy the Curl_addrinfo list */
+  if(error) {
+    Curl_freeaddrinfo(cafirst);
+    cafirst = NULL;
+  }
+
+  return cafirst;
+}
+
+static void addrinfo_cb(void *arg, int status, int timeouts,
+                        struct ares_addrinfo *result)
+{
+  struct Curl_easy *data = (struct Curl_easy *)arg;
+  struct thread_data *res = data->state.async.tdata;
+  (void)timeouts;
+  if(ARES_SUCCESS == status) {
+    res->temp_ai = ares2addr(result->nodes);
+    res->last_status = CURL_ASYNC_SUCCESS;
+    ares_freeaddrinfo(result);
+  }
+  res->num_pending--;
+}
+
+#endif
+/*
+ * Curl_resolver_getaddrinfo() - when using ares
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'hostent' is returned and the fourth argument will point to
+ * memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ */
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
+                                                const char *hostname,
+                                                int port,
+                                                int *waitp)
+{
+  struct thread_data *res = NULL;
+  size_t namelen = strlen(hostname);
+  *waitp = 0; /* default to synchronous response */
+
+  res = calloc(1, sizeof(struct thread_data) + namelen);
+  if(res) {
+    strcpy(res->hostname, hostname);
+    data->state.async.hostname = res->hostname;
+    data->state.async.port = port;
+    data->state.async.done = FALSE;   /* not done */
+    data->state.async.status = 0;     /* clear */
+    data->state.async.dns = NULL;     /* clear */
+    data->state.async.tdata = res;
+
+    /* initial status - failed */
+    res->last_status = ARES_ENOTFOUND;
+
+#ifdef HAVE_CARES_GETADDRINFO
+    {
+      struct ares_addrinfo_hints hints;
+      char service[12];
+      int pf = PF_INET;
+      memset(&hints, 0, sizeof(hints));
+#ifdef CURLRES_IPV6
+      if((data->conn->ip_version != CURL_IPRESOLVE_V4) &&
+         Curl_ipv6works(data)) {
+        /* The stack seems to be IPv6-enabled */
+        if(data->conn->ip_version == CURL_IPRESOLVE_V6)
+          pf = PF_INET6;
+        else
+          pf = PF_UNSPEC;
+      }
+#endif /* CURLRES_IPV6 */
+      hints.ai_family = pf;
+      hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
+        SOCK_STREAM : SOCK_DGRAM;
+      /* Since the service is a numerical one, set the hint flags
+       * accordingly to save a call to getservbyname in inside C-Ares
+       */
+      hints.ai_flags = ARES_AI_NUMERICSERV;
+      msnprintf(service, sizeof(service), "%d", port);
+      res->num_pending = 1;
+      ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
+                       service, &hints, addrinfo_cb, data);
+    }
+#else
+
+#ifdef HAVE_CARES_IPV6
+    if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
+      /* The stack seems to be IPv6-enabled */
+      res->num_pending = 2;
+
+      /* areschannel is already setup in the Curl_open() function */
+      ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+                          PF_INET, query_completed_cb, data);
+      ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+                          PF_INET6, query_completed_cb, data);
+    }
+    else
+#endif
+    {
+      res->num_pending = 1;
+
+      /* areschannel is already setup in the Curl_open() function */
+      ares_gethostbyname((ares_channel)data->state.async.resolver,
+                         hostname, PF_INET,
+                         query_completed_cb, data);
+    }
+#endif
+    *waitp = 1; /* expect asynchronous response */
+  }
+  return NULL; /* no struct yet */
+}
+
+CURLcode Curl_set_dns_servers(struct Curl_easy *data,
+                              char *servers)
+{
+  CURLcode result = CURLE_NOT_BUILT_IN;
+  int ares_result;
+
+  /* If server is NULL or empty, this would purge all DNS servers
+   * from ares library, which will cause any and all queries to fail.
+   * So, just return OK if none are configured and don't actually make
+   * any changes to c-ares.  This lets c-ares use its defaults, which
+   * it gets from the OS (for instance from /etc/resolv.conf on Linux).
+   */
+  if(!(servers && servers[0]))
+    return CURLE_OK;
+
+#ifdef HAVE_CARES_SERVERS_CSV
+#ifdef HAVE_CARES_PORTS_CSV
+  ares_result = ares_set_servers_ports_csv(data->state.async.resolver,
+                                           servers);
+#else
+  ares_result = ares_set_servers_csv(data->state.async.resolver, servers);
+#endif
+  switch(ares_result) {
+  case ARES_SUCCESS:
+    result = CURLE_OK;
+    break;
+  case ARES_ENOMEM:
+    result = CURLE_OUT_OF_MEMORY;
+    break;
+  case ARES_ENOTINITIALIZED:
+  case ARES_ENODATA:
+  case ARES_EBADSTR:
+  default:
+    DEBUGF(infof(data, "bad servers set"));
+    result = CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+  }
+#else /* too old c-ares version! */
+  (void)data;
+  (void)(ares_result);
+#endif
+  return result;
+}
+
+CURLcode Curl_set_dns_interface(struct Curl_easy *data,
+                                const char *interf)
+{
+#ifdef HAVE_CARES_LOCAL_DEV
+  if(!interf)
+    interf = "";
+
+  ares_set_local_dev((ares_channel)data->state.async.resolver, interf);
+
+  return CURLE_OK;
+#else /* c-ares version too old! */
+  (void)data;
+  (void)interf;
+  return CURLE_NOT_BUILT_IN;
+#endif
+}
+
+CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
+                                const char *local_ip4)
+{
+#ifdef HAVE_CARES_SET_LOCAL
+  struct in_addr a4;
+
+  if((!local_ip4) || (local_ip4[0] == 0)) {
+    a4.s_addr = 0; /* disabled: do not bind to a specific address */
+  }
+  else {
+    if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) {
+      DEBUGF(infof(data, "bad DNS IPv4 address"));
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+  }
+
+  ares_set_local_ip4((ares_channel)data->state.async.resolver,
+                     ntohl(a4.s_addr));
+
+  return CURLE_OK;
+#else /* c-ares version too old! */
+  (void)data;
+  (void)local_ip4;
+  return CURLE_NOT_BUILT_IN;
+#endif
+}
+
+CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
+                                const char *local_ip6)
+{
+#if defined(HAVE_CARES_SET_LOCAL) && defined(ENABLE_IPV6)
+  unsigned char a6[INET6_ADDRSTRLEN];
+
+  if((!local_ip6) || (local_ip6[0] == 0)) {
+    /* disabled: do not bind to a specific address */
+    memset(a6, 0, sizeof(a6));
+  }
+  else {
+    if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) {
+      DEBUGF(infof(data, "bad DNS IPv6 address"));
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+  }
+
+  ares_set_local_ip6((ares_channel)data->state.async.resolver, a6);
+
+  return CURLE_OK;
+#else /* c-ares version too old! */
+  (void)data;
+  (void)local_ip6;
+  return CURLE_NOT_BUILT_IN;
+#endif
+}
+#endif /* CURLRES_ARES */
Index: trunk/src/libs/curl-8.7.1/lib/asyn-thread.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/asyn-thread.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/asyn-thread.c	(revision 104083)
@@ -0,0 +1,985 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "socketpair.h"
+
+/***********************************************************************
+ * Only for threaded name resolves builds
+ **********************************************************************/
+#ifdef CURLRES_THREADED
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+#  include <pthread.h>
+#endif
+
+#ifdef HAVE_GETADDRINFO
+#  define RESOLVER_ENOMEM  EAI_MEMORY
+#else
+#  define RESOLVER_ENOMEM  ENOMEM
+#endif
+
+#include "system_win32.h"
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "url.h"
+#include "multiif.h"
+#include "inet_ntop.h"
+#include "curl_threads.h"
+#include "connect.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+struct resdata {
+  struct curltime start;
+};
+
+/*
+ * Curl_resolver_global_init()
+ * Called from curl_global_init() to initialize global resolver environment.
+ * Does nothing here.
+ */
+int Curl_resolver_global_init(void)
+{
+  return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_global_cleanup()
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ * Does nothing here.
+ */
+void Curl_resolver_global_cleanup(void)
+{
+}
+
+/*
+ * Curl_resolver_init()
+ * Called from curl_easy_init() -> Curl_open() to initialize resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure).
+ */
+CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
+{
+  (void)easy;
+  *resolver = calloc(1, sizeof(struct resdata));
+  if(!*resolver)
+    return CURLE_OUT_OF_MEMORY;
+  return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_cleanup()
+ * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure).
+ */
+void Curl_resolver_cleanup(void *resolver)
+{
+  free(resolver);
+}
+
+/*
+ * Curl_resolver_duphandle()
+ * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
+ * environment ('resolver' member of the UrlState structure).
+ */
+CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
+{
+  (void)from;
+  return Curl_resolver_init(easy, to);
+}
+
+static void destroy_async_data(struct Curl_async *);
+
+/*
+ * Cancel all possibly still on-going resolves for this connection.
+ */
+void Curl_resolver_cancel(struct Curl_easy *data)
+{
+  destroy_async_data(&data->state.async);
+}
+
+/* This function is used to init a threaded resolve */
+static bool init_resolve_thread(struct Curl_easy *data,
+                                const char *hostname, int port,
+                                const struct addrinfo *hints);
+
+#ifdef _WIN32
+/* Thread sync data used by GetAddrInfoExW for win8+ */
+struct thread_sync_data_w8
+{
+  OVERLAPPED overlapped;
+  ADDRINFOEXW_ *res;
+  HANDLE cancel_ev;
+  ADDRINFOEXW_ hints;
+};
+#endif
+
+/* Data for synchronization between resolver thread and its parent */
+struct thread_sync_data {
+#ifdef _WIN32
+  struct thread_sync_data_w8 w8;
+#endif
+  curl_mutex_t *mtx;
+  int done;
+  int port;
+  char *hostname;        /* hostname to resolve, Curl_async.hostname
+                            duplicate */
+#ifndef CURL_DISABLE_SOCKETPAIR
+  struct Curl_easy *data;
+  curl_socket_t sock_pair[2]; /* socket pair */
+#endif
+  int sock_error;
+  struct Curl_addrinfo *res;
+#ifdef HAVE_GETADDRINFO
+  struct addrinfo hints;
+#endif
+  struct thread_data *td; /* for thread-self cleanup */
+};
+
+struct thread_data {
+#ifdef _WIN32
+  HANDLE complete_ev;
+#endif
+  curl_thread_t thread_hnd;
+  unsigned int poll_interval;
+  timediff_t interval_end;
+  struct thread_sync_data tsd;
+};
+
+static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
+{
+  return &(data->state.async.tdata->tsd);
+}
+
+/* Destroy resolver thread synchronization data */
+static
+void destroy_thread_sync_data(struct thread_sync_data *tsd)
+{
+  if(tsd->mtx) {
+    Curl_mutex_destroy(tsd->mtx);
+    free(tsd->mtx);
+  }
+
+  free(tsd->hostname);
+
+  if(tsd->res)
+    Curl_freeaddrinfo(tsd->res);
+
+#ifndef CURL_DISABLE_SOCKETPAIR
+  /*
+   * close one end of the socket pair (may be done in resolver thread);
+   * the other end (for reading) is always closed in the parent thread.
+   */
+  if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
+    wakeup_close(tsd->sock_pair[1]);
+  }
+#endif
+  memset(tsd, 0, sizeof(*tsd));
+}
+
+/* Initialize resolver thread synchronization data */
+static
+int init_thread_sync_data(struct thread_data *td,
+                           const char *hostname,
+                           int port,
+                           const struct addrinfo *hints)
+{
+  struct thread_sync_data *tsd = &td->tsd;
+
+  memset(tsd, 0, sizeof(*tsd));
+
+  tsd->td = td;
+  tsd->port = port;
+  /* Treat the request as done until the thread actually starts so any early
+   * cleanup gets done properly.
+   */
+  tsd->done = 1;
+#ifdef HAVE_GETADDRINFO
+  DEBUGASSERT(hints);
+  tsd->hints = *hints;
+#else
+  (void) hints;
+#endif
+
+  tsd->mtx = malloc(sizeof(curl_mutex_t));
+  if(!tsd->mtx)
+    goto err_exit;
+
+  Curl_mutex_init(tsd->mtx);
+
+#ifndef CURL_DISABLE_SOCKETPAIR
+  /* create socket pair or pipe */
+  if(wakeup_create(&tsd->sock_pair[0]) < 0) {
+    tsd->sock_pair[0] = CURL_SOCKET_BAD;
+    tsd->sock_pair[1] = CURL_SOCKET_BAD;
+    goto err_exit;
+  }
+#endif
+  tsd->sock_error = CURL_ASYNC_SUCCESS;
+
+  /* Copying hostname string because original can be destroyed by parent
+   * thread during gethostbyname execution.
+   */
+  tsd->hostname = strdup(hostname);
+  if(!tsd->hostname)
+    goto err_exit;
+
+  return 1;
+
+err_exit:
+#ifndef CURL_DISABLE_SOCKETPAIR
+  if(tsd->sock_pair[0] != CURL_SOCKET_BAD) {
+    wakeup_close(tsd->sock_pair[0]);
+    tsd->sock_pair[0] = CURL_SOCKET_BAD;
+  }
+#endif
+  destroy_thread_sync_data(tsd);
+  return 0;
+}
+
+static CURLcode getaddrinfo_complete(struct Curl_easy *data)
+{
+  struct thread_sync_data *tsd = conn_thread_sync_data(data);
+  CURLcode result;
+
+  result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
+  /* The tsd->res structure has been copied to async.dns and perhaps the DNS
+     cache.  Set our copy to NULL so destroy_thread_sync_data doesn't free it.
+  */
+  tsd->res = NULL;
+
+  return result;
+}
+
+#ifdef _WIN32
+static VOID WINAPI
+query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
+{
+  size_t ss_size;
+  const ADDRINFOEXW_ *ai;
+  struct Curl_addrinfo *ca;
+  struct Curl_addrinfo *cafirst = NULL;
+  struct Curl_addrinfo *calast = NULL;
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wcast-align"
+#endif
+  struct thread_sync_data *tsd =
+    CONTAINING_RECORD(overlapped, struct thread_sync_data, w8.overlapped);
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+  struct thread_data *td = tsd->td;
+  const ADDRINFOEXW_ *res = tsd->w8.res;
+  int error = (int)err;
+  (void)bytes;
+
+  if(error == ERROR_SUCCESS) {
+    /* traverse the addrinfo list */
+
+    for(ai = res; ai != NULL; ai = ai->ai_next) {
+      size_t namelen = ai->ai_canonname ? wcslen(ai->ai_canonname) + 1 : 0;
+      /* ignore elements with unsupported address family, */
+      /* settle family-specific sockaddr structure size.  */
+      if(ai->ai_family == AF_INET)
+        ss_size = sizeof(struct sockaddr_in);
+#ifdef ENABLE_IPV6
+      else if(ai->ai_family == AF_INET6)
+        ss_size = sizeof(struct sockaddr_in6);
+#endif
+      else
+        continue;
+
+      /* ignore elements without required address info */
+      if(!ai->ai_addr || !(ai->ai_addrlen > 0))
+        continue;
+
+      /* ignore elements with bogus address size */
+      if((size_t)ai->ai_addrlen < ss_size)
+        continue;
+
+      ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen);
+      if(!ca) {
+        error = EAI_MEMORY;
+        break;
+      }
+
+      /* copy each structure member individually, member ordering, */
+      /* size, or padding might be different for each platform.    */
+      ca->ai_flags     = ai->ai_flags;
+      ca->ai_family    = ai->ai_family;
+      ca->ai_socktype  = ai->ai_socktype;
+      ca->ai_protocol  = ai->ai_protocol;
+      ca->ai_addrlen   = (curl_socklen_t)ss_size;
+      ca->ai_addr      = NULL;
+      ca->ai_canonname = NULL;
+      ca->ai_next      = NULL;
+
+      ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
+      memcpy(ca->ai_addr, ai->ai_addr, ss_size);
+
+      if(namelen) {
+        size_t i;
+        ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
+        for(i = 0; i < namelen; ++i) /* convert wide string to ascii */
+          ca->ai_canonname[i] = (char)ai->ai_canonname[i];
+        ca->ai_canonname[namelen] = '\0';
+      }
+
+      /* if the return list is empty, this becomes the first element */
+      if(!cafirst)
+        cafirst = ca;
+
+      /* add this element last in the return list */
+      if(calast)
+        calast->ai_next = ca;
+      calast = ca;
+    }
+
+    /* if we failed, also destroy the Curl_addrinfo list */
+    if(error) {
+      Curl_freeaddrinfo(cafirst);
+      cafirst = NULL;
+    }
+    else if(!cafirst) {
+#ifdef EAI_NONAME
+      /* rfc3493 conformant */
+      error = EAI_NONAME;
+#else
+      /* rfc3493 obsoleted */
+      error = EAI_NODATA;
+#endif
+#ifdef USE_WINSOCK
+      SET_SOCKERRNO(error);
+#endif
+    }
+    tsd->res = cafirst;
+  }
+
+  if(tsd->w8.res) {
+    Curl_FreeAddrInfoExW(tsd->w8.res);
+    tsd->w8.res = NULL;
+  }
+
+  if(error) {
+    tsd->sock_error = SOCKERRNO?SOCKERRNO:error;
+    if(tsd->sock_error == 0)
+      tsd->sock_error = RESOLVER_ENOMEM;
+  }
+  else {
+    Curl_addrinfo_set_port(tsd->res, tsd->port);
+  }
+
+  Curl_mutex_acquire(tsd->mtx);
+  if(tsd->done) {
+    /* too late, gotta clean up the mess */
+    Curl_mutex_release(tsd->mtx);
+    destroy_thread_sync_data(tsd);
+    free(td);
+  }
+  else {
+#ifndef CURL_DISABLE_SOCKETPAIR
+    char buf[1];
+    if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
+      /* DNS has been resolved, signal client task */
+      buf[0] = 1;
+      if(swrite(tsd->sock_pair[1],  buf, sizeof(buf)) < 0) {
+        /* update sock_erro to errno */
+        tsd->sock_error = SOCKERRNO;
+      }
+    }
+#endif
+    tsd->done = 1;
+    Curl_mutex_release(tsd->mtx);
+    if(td->complete_ev)
+      SetEvent(td->complete_ev); /* Notify caller that the query completed */
+  }
+}
+#endif
+
+#ifdef HAVE_GETADDRINFO
+
+/*
+ * getaddrinfo_thread() resolves a name and then exits.
+ *
+ * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
+ * and wait on it.
+ */
+static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
+{
+  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
+  struct thread_data *td = tsd->td;
+  char service[12];
+  int rc;
+#ifndef CURL_DISABLE_SOCKETPAIR
+  char buf[1];
+#endif
+
+  msnprintf(service, sizeof(service), "%d", tsd->port);
+
+  rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
+
+  if(rc) {
+    tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
+    if(tsd->sock_error == 0)
+      tsd->sock_error = RESOLVER_ENOMEM;
+  }
+  else {
+    Curl_addrinfo_set_port(tsd->res, tsd->port);
+  }
+
+  Curl_mutex_acquire(tsd->mtx);
+  if(tsd->done) {
+    /* too late, gotta clean up the mess */
+    Curl_mutex_release(tsd->mtx);
+    destroy_thread_sync_data(tsd);
+    free(td);
+  }
+  else {
+#ifndef CURL_DISABLE_SOCKETPAIR
+    if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
+      /* DNS has been resolved, signal client task */
+      buf[0] = 1;
+      if(wakeup_write(tsd->sock_pair[1],  buf, sizeof(buf)) < 0) {
+        /* update sock_erro to errno */
+        tsd->sock_error = SOCKERRNO;
+      }
+    }
+#endif
+    tsd->done = 1;
+    Curl_mutex_release(tsd->mtx);
+  }
+
+  return 0;
+}
+
+#else /* HAVE_GETADDRINFO */
+
+/*
+ * gethostbyname_thread() resolves a name and then exits.
+ */
+static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
+{
+  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
+  struct thread_data *td = tsd->td;
+
+  tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
+
+  if(!tsd->res) {
+    tsd->sock_error = SOCKERRNO;
+    if(tsd->sock_error == 0)
+      tsd->sock_error = RESOLVER_ENOMEM;
+  }
+
+  Curl_mutex_acquire(tsd->mtx);
+  if(tsd->done) {
+    /* too late, gotta clean up the mess */
+    Curl_mutex_release(tsd->mtx);
+    destroy_thread_sync_data(tsd);
+    free(td);
+  }
+  else {
+    tsd->done = 1;
+    Curl_mutex_release(tsd->mtx);
+  }
+
+  return 0;
+}
+
+#endif /* HAVE_GETADDRINFO */
+
+/*
+ * destroy_async_data() cleans up async resolver data and thread handle.
+ */
+static void destroy_async_data(struct Curl_async *async)
+{
+  if(async->tdata) {
+    struct thread_data *td = async->tdata;
+    int done;
+#ifndef CURL_DISABLE_SOCKETPAIR
+    curl_socket_t sock_rd = td->tsd.sock_pair[0];
+    struct Curl_easy *data = td->tsd.data;
+#endif
+
+    /*
+     * if the thread is still blocking in the resolve syscall, detach it and
+     * let the thread do the cleanup...
+     */
+    Curl_mutex_acquire(td->tsd.mtx);
+    done = td->tsd.done;
+    td->tsd.done = 1;
+    Curl_mutex_release(td->tsd.mtx);
+
+    if(!done) {
+#ifdef _WIN32
+      if(td->complete_ev)
+        CloseHandle(td->complete_ev);
+      else
+#endif
+      Curl_thread_destroy(td->thread_hnd);
+    }
+    else {
+#ifdef _WIN32
+      if(td->complete_ev) {
+        Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
+        WaitForSingleObject(td->complete_ev, INFINITE);
+        CloseHandle(td->complete_ev);
+      }
+#endif
+      if(td->thread_hnd != curl_thread_t_null)
+        Curl_thread_join(&td->thread_hnd);
+
+      destroy_thread_sync_data(&td->tsd);
+
+      free(async->tdata);
+    }
+#ifndef CURL_DISABLE_SOCKETPAIR
+    /*
+     * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
+     * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
+     */
+    Curl_multi_closed(data, sock_rd);
+    wakeup_close(sock_rd);
+#endif
+  }
+  async->tdata = NULL;
+
+  free(async->hostname);
+  async->hostname = NULL;
+}
+
+/*
+ * init_resolve_thread() starts a new thread that performs the actual
+ * resolve. This function returns before the resolve is done.
+ *
+ * Returns FALSE in case of failure, otherwise TRUE.
+ */
+static bool init_resolve_thread(struct Curl_easy *data,
+                                const char *hostname, int port,
+                                const struct addrinfo *hints)
+{
+  struct thread_data *td = calloc(1, sizeof(struct thread_data));
+  int err = ENOMEM;
+  struct Curl_async *asp = &data->state.async;
+
+  data->state.async.tdata = td;
+  if(!td)
+    goto errno_exit;
+
+  asp->port = port;
+  asp->done = FALSE;
+  asp->status = 0;
+  asp->dns = NULL;
+  td->thread_hnd = curl_thread_t_null;
+#ifdef _WIN32
+  td->complete_ev = NULL;
+#endif
+
+  if(!init_thread_sync_data(td, hostname, port, hints)) {
+    asp->tdata = NULL;
+    free(td);
+    goto errno_exit;
+  }
+
+  free(asp->hostname);
+  asp->hostname = strdup(hostname);
+  if(!asp->hostname)
+    goto err_exit;
+
+  /* The thread will set this to 1 when complete. */
+  td->tsd.done = 0;
+
+#ifdef _WIN32
+  if(Curl_isWindows8OrGreater && Curl_FreeAddrInfoExW &&
+     Curl_GetAddrInfoExCancel && Curl_GetAddrInfoExW) {
+#define MAX_NAME_LEN 256 /* max domain name is 253 chars */
+#define MAX_PORT_LEN 8
+    WCHAR namebuf[MAX_NAME_LEN];
+    WCHAR portbuf[MAX_PORT_LEN];
+    /* calculate required length */
+    int w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname,
+                                    -1, NULL, 0);
+    if((w_len > 0) && (w_len < MAX_NAME_LEN)) {
+      /* do utf8 conversion */
+      w_len = MultiByteToWideChar(CP_UTF8, 0, hostname, -1, namebuf, w_len);
+      if((w_len > 0) && (w_len < MAX_NAME_LEN)) {
+        swprintf(portbuf, MAX_PORT_LEN, L"%d", port);
+        td->tsd.w8.hints.ai_family = hints->ai_family;
+        td->tsd.w8.hints.ai_socktype = hints->ai_socktype;
+        td->complete_ev = CreateEvent(NULL, TRUE, FALSE, NULL);
+        if(!td->complete_ev) {
+          /* failed to start, mark it as done here for proper cleanup. */
+          td->tsd.done = 1;
+          goto err_exit;
+        }
+        err = Curl_GetAddrInfoExW(namebuf, portbuf, NS_DNS,
+                                  NULL, &td->tsd.w8.hints, &td->tsd.w8.res,
+                                  NULL, &td->tsd.w8.overlapped,
+                                  &query_complete, &td->tsd.w8.cancel_ev);
+        if(err != WSA_IO_PENDING)
+          query_complete(err, 0, &td->tsd.w8.overlapped);
+        return TRUE;
+      }
+    }
+  }
+#endif
+
+#ifdef HAVE_GETADDRINFO
+  td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
+#else
+  td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
+#endif
+
+  if(!td->thread_hnd) {
+    /* The thread never started, so mark it as done here for proper cleanup. */
+    td->tsd.done = 1;
+    err = errno;
+    goto err_exit;
+  }
+
+  return TRUE;
+
+err_exit:
+  destroy_async_data(asp);
+
+errno_exit:
+  errno = err;
+  return FALSE;
+}
+
+/*
+ * 'entry' may be NULL and then no data is returned
+ */
+static CURLcode thread_wait_resolv(struct Curl_easy *data,
+                                   struct Curl_dns_entry **entry,
+                                   bool report)
+{
+  struct thread_data *td;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(data);
+  td = data->state.async.tdata;
+  DEBUGASSERT(td);
+#ifdef _WIN32
+  DEBUGASSERT(td->complete_ev || td->thread_hnd != curl_thread_t_null);
+#else
+  DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
+#endif
+
+  /* wait for the thread to resolve the name */
+#ifdef _WIN32
+  if(td->complete_ev) {
+    WaitForSingleObject(td->complete_ev, INFINITE);
+    CloseHandle(td->complete_ev);
+    if(entry)
+      result = getaddrinfo_complete(data);
+  }
+  else
+#endif
+  if(Curl_thread_join(&td->thread_hnd)) {
+    if(entry)
+      result = getaddrinfo_complete(data);
+  }
+  else
+    DEBUGASSERT(0);
+
+  data->state.async.done = TRUE;
+
+  if(entry)
+    *entry = data->state.async.dns;
+
+  if(!data->state.async.dns && report)
+    /* a name was not resolved, report error */
+    result = Curl_resolver_error(data);
+
+  destroy_async_data(&data->state.async);
+
+  if(!data->state.async.dns && report)
+    connclose(data->conn, "asynch resolve failed");
+
+  return result;
+}
+
+
+/*
+ * Until we gain a way to signal the resolver threads to stop early, we must
+ * simply wait for them and ignore their results.
+ */
+void Curl_resolver_kill(struct Curl_easy *data)
+{
+  struct thread_data *td = data->state.async.tdata;
+
+  /* If we're still resolving, we must wait for the threads to fully clean up,
+     unfortunately.  Otherwise, we can simply cancel to clean up any resolver
+     data. */
+  if(td && td->thread_hnd != curl_thread_t_null
+     && (data->set.quick_exit != 1L))
+    (void)thread_wait_resolv(data, NULL, FALSE);
+  else
+    Curl_resolver_cancel(data);
+}
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * Waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
+ *
+ * This is the version for resolves-in-a-thread.
+ */
+CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
+                                   struct Curl_dns_entry **entry)
+{
+  return thread_wait_resolv(data, entry, TRUE);
+}
+
+/*
+ * Curl_resolver_is_resolved() is called repeatedly to check if a previous
+ * name resolve request has completed. It should also make sure to time-out if
+ * the operation seems to take too long.
+ */
+CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
+                                   struct Curl_dns_entry **entry)
+{
+  struct thread_data *td = data->state.async.tdata;
+  int done = 0;
+
+  DEBUGASSERT(entry);
+  *entry = NULL;
+
+  if(!td) {
+    DEBUGASSERT(td);
+    return CURLE_COULDNT_RESOLVE_HOST;
+  }
+
+  Curl_mutex_acquire(td->tsd.mtx);
+  done = td->tsd.done;
+  Curl_mutex_release(td->tsd.mtx);
+
+  if(done) {
+    getaddrinfo_complete(data);
+
+    if(!data->state.async.dns) {
+      CURLcode result = Curl_resolver_error(data);
+      destroy_async_data(&data->state.async);
+      return result;
+    }
+    destroy_async_data(&data->state.async);
+    *entry = data->state.async.dns;
+  }
+  else {
+    /* poll for name lookup done with exponential backoff up to 250ms */
+    /* should be fine even if this converts to 32 bit */
+    timediff_t elapsed = Curl_timediff(Curl_now(),
+                                       data->progress.t_startsingle);
+    if(elapsed < 0)
+      elapsed = 0;
+
+    if(td->poll_interval == 0)
+      /* Start at 1ms poll interval */
+      td->poll_interval = 1;
+    else if(elapsed >= td->interval_end)
+      /* Back-off exponentially if last interval expired  */
+      td->poll_interval *= 2;
+
+    if(td->poll_interval > 250)
+      td->poll_interval = 250;
+
+    td->interval_end = elapsed + td->poll_interval;
+    Curl_expire(data, td->poll_interval, EXPIRE_ASYNC_NAME);
+  }
+
+  return CURLE_OK;
+}
+
+int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
+{
+  int ret_val = 0;
+  timediff_t milli;
+  timediff_t ms;
+  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
+#ifndef CURL_DISABLE_SOCKETPAIR
+  struct thread_data *td = data->state.async.tdata;
+#else
+  (void)socks;
+#endif
+
+#ifndef CURL_DISABLE_SOCKETPAIR
+  if(td) {
+    /* return read fd to client for polling the DNS resolution status */
+    socks[0] = td->tsd.sock_pair[0];
+    td->tsd.data = data;
+    ret_val = GETSOCK_READSOCK(0);
+  }
+  else {
+#endif
+    ms = Curl_timediff(Curl_now(), reslv->start);
+    if(ms < 3)
+      milli = 0;
+    else if(ms <= 50)
+      milli = ms/3;
+    else if(ms <= 250)
+      milli = 50;
+    else
+      milli = 200;
+    Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
+#ifndef CURL_DISABLE_SOCKETPAIR
+  }
+#endif
+
+
+  return ret_val;
+}
+
+#ifndef HAVE_GETADDRINFO
+/*
+ * Curl_getaddrinfo() - for platforms without getaddrinfo
+ */
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
+                                                const char *hostname,
+                                                int port,
+                                                int *waitp)
+{
+  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
+
+  *waitp = 0; /* default to synchronous response */
+
+  reslv->start = Curl_now();
+
+  /* fire up a new resolver thread! */
+  if(init_resolve_thread(data, hostname, port, NULL)) {
+    *waitp = 1; /* expect asynchronous response */
+    return NULL;
+  }
+
+  failf(data, "getaddrinfo() thread failed");
+
+  return NULL;
+}
+
+#else /* !HAVE_GETADDRINFO */
+
+/*
+ * Curl_resolver_getaddrinfo() - for getaddrinfo
+ */
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
+                                                const char *hostname,
+                                                int port,
+                                                int *waitp)
+{
+  struct addrinfo hints;
+  int pf = PF_INET;
+  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
+
+  *waitp = 0; /* default to synchronous response */
+
+#ifdef CURLRES_IPV6
+  if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
+    /* The stack seems to be IPv6-enabled */
+    if(data->conn->ip_version == CURL_IPRESOLVE_V6)
+      pf = PF_INET6;
+    else
+      pf = PF_UNSPEC;
+  }
+#endif /* CURLRES_IPV6 */
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = pf;
+  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
+    SOCK_STREAM : SOCK_DGRAM;
+
+  reslv->start = Curl_now();
+  /* fire up a new resolver thread! */
+  if(init_resolve_thread(data, hostname, port, &hints)) {
+    *waitp = 1; /* expect asynchronous response */
+    return NULL;
+  }
+
+  failf(data, "getaddrinfo() thread failed to start");
+  return NULL;
+
+}
+
+#endif /* !HAVE_GETADDRINFO */
+
+CURLcode Curl_set_dns_servers(struct Curl_easy *data,
+                              char *servers)
+{
+  (void)data;
+  (void)servers;
+  return CURLE_NOT_BUILT_IN;
+
+}
+
+CURLcode Curl_set_dns_interface(struct Curl_easy *data,
+                                const char *interf)
+{
+  (void)data;
+  (void)interf;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
+                                const char *local_ip4)
+{
+  (void)data;
+  (void)local_ip4;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
+                                const char *local_ip6)
+{
+  (void)data;
+  (void)local_ip6;
+  return CURLE_NOT_BUILT_IN;
+}
+
+#endif /* CURLRES_THREADED */
Index: trunk/src/libs/curl-8.7.1/lib/asyn.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/asyn.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/asyn.h	(revision 104083)
@@ -0,0 +1,184 @@
+#ifndef HEADER_CURL_ASYN_H
+#define HEADER_CURL_ASYN_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "curl_addrinfo.h"
+
+struct addrinfo;
+struct hostent;
+struct Curl_easy;
+struct connectdata;
+struct Curl_dns_entry;
+
+/*
+ * This header defines all functions in the internal asynch resolver interface.
+ * All asynch resolvers need to provide these functions.
+ * asyn-ares.c and asyn-thread.c are the current implementations of asynch
+ * resolver backends.
+ */
+
+/*
+ * Curl_resolver_global_init()
+ *
+ * Called from curl_global_init() to initialize global resolver environment.
+ * Returning anything else than CURLE_OK fails curl_global_init().
+ */
+int Curl_resolver_global_init(void);
+
+/*
+ * Curl_resolver_global_cleanup()
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ */
+void Curl_resolver_global_cleanup(void);
+
+/*
+ * Curl_resolver_init()
+ * Called from curl_easy_init() -> Curl_open() to initialize resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure).  Should fill the passed pointer by the initialized handler.
+ * Returning anything else than CURLE_OK fails curl_easy_init() with the
+ * correspondent code.
+ */
+CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver);
+
+/*
+ * Curl_resolver_cleanup()
+ * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure).  Should destroy the handler and free all resources connected to
+ * it.
+ */
+void Curl_resolver_cleanup(void *resolver);
+
+/*
+ * Curl_resolver_duphandle()
+ * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
+ * environment ('resolver' member of the UrlState structure).  Should
+ * duplicate the 'from' handle and pass the resulting handle to the 'to'
+ * pointer.  Returning anything else than CURLE_OK causes failed
+ * curl_easy_duphandle() call.
+ */
+CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to,
+                                 void *from);
+
+/*
+ * Curl_resolver_cancel().
+ *
+ * It is called from inside other functions to cancel currently performing
+ * resolver request. Should also free any temporary resources allocated to
+ * perform a request.  This never waits for resolver threads to complete.
+ *
+ * It is safe to call this when conn is in any state.
+ */
+void Curl_resolver_cancel(struct Curl_easy *data);
+
+/*
+ * Curl_resolver_kill().
+ *
+ * This acts like Curl_resolver_cancel() except it will block until any threads
+ * associated with the resolver are complete.  This never blocks for resolvers
+ * that do not use threads.  This is intended to be the "last chance" function
+ * that cleans up an in-progress resolver completely (before its owner is about
+ * to die).
+ *
+ * It is safe to call this when conn is in any state.
+ */
+void Curl_resolver_kill(struct Curl_easy *data);
+
+/* Curl_resolver_getsock()
+ *
+ * This function is called from the multi_getsock() function.  'sock' is a
+ * pointer to an array to hold the file descriptors, with 'numsock' being the
+ * size of that array (in number of entries). This function is supposed to
+ * return bitmask indicating what file descriptors (referring to array indexes
+ * in the 'sock' array) to wait for, read/write.
+ */
+int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *sock);
+
+/*
+ * Curl_resolver_is_resolved()
+ *
+ * Called repeatedly to check if a previous name resolve request has
+ * completed. It should also make sure to time-out if the operation seems to
+ * take too long.
+ *
+ * Returns normal CURLcode errors.
+ */
+CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
+                                   struct Curl_dns_entry **dns);
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * Waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
+ */
+CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
+                                   struct Curl_dns_entry **dnsentry);
+
+/*
+ * Curl_resolver_getaddrinfo() - when using this resolver
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'hostent' is returned and the fourth argument will point to
+ * memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ *
+ * Each resolver backend must of course make sure to return data in the
+ * correct format to comply with this.
+ */
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
+                                                const char *hostname,
+                                                int port,
+                                                int *waitp);
+
+#ifndef CURLRES_ASYNCH
+/* convert these functions if an asynch resolver isn't used */
+#define Curl_resolver_cancel(x) Curl_nop_stmt
+#define Curl_resolver_kill(x) Curl_nop_stmt
+#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
+#define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST
+#define Curl_resolver_duphandle(x,y,z) CURLE_OK
+#define Curl_resolver_init(x,y) CURLE_OK
+#define Curl_resolver_global_init() CURLE_OK
+#define Curl_resolver_global_cleanup() Curl_nop_stmt
+#define Curl_resolver_cleanup(x) Curl_nop_stmt
+#endif
+
+#ifdef CURLRES_ASYNCH
+#define Curl_resolver_asynch() 1
+#else
+#define Curl_resolver_asynch() 0
+#endif
+
+
+/********** end of generic resolver interface functions *****************/
+#endif /* HEADER_CURL_ASYN_H */
Index: trunk/src/libs/curl-8.7.1/lib/base64.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/base64.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/base64.c	(revision 104083)
@@ -0,0 +1,293 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* Base64 encoding/decoding */
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_SSH) || \
+  !defined(CURL_DISABLE_LDAP) || \
+  !defined(CURL_DISABLE_SMTP) || \
+  !defined(CURL_DISABLE_POP3) || \
+  !defined(CURL_DISABLE_IMAP) || \
+  !defined(CURL_DISABLE_DIGEST_AUTH) || \
+  !defined(CURL_DISABLE_DOH) || defined(USE_SSL) || defined(BUILDING_CURL)
+#include "curl/curl.h"
+#include "warnless.h"
+#include "curl_base64.h"
+
+/* The last 2 #include files should be in this order */
+#ifdef BUILDING_LIBCURL
+#include "curl_memory.h"
+#endif
+#include "memdebug.h"
+
+/* ---- Base64 Encoding/Decoding Table --- */
+/* Padding character string starts at offset 64. */
+static const char base64encdec[]=
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+/* The Base 64 encoding with a URL and filename safe alphabet, RFC 4648
+   section 5 */
+static const char base64url[]=
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+static const unsigned char decodetable[] =
+{ 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255,
+  255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+  17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28,
+  29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+  48, 49, 50, 51 };
+/*
+ * Curl_base64_decode()
+ *
+ * Given a base64 NUL-terminated string at src, decode it and return a
+ * pointer in *outptr to a newly allocated memory area holding decoded
+ * data. Size of decoded data is returned in variable pointed by outlen.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * When decoded data length is 0, returns NULL in *outptr.
+ *
+ * @unittest: 1302
+ */
+CURLcode Curl_base64_decode(const char *src,
+                            unsigned char **outptr, size_t *outlen)
+{
+  size_t srclen = 0;
+  size_t padding = 0;
+  size_t i;
+  size_t numQuantums;
+  size_t fullQuantums;
+  size_t rawlen = 0;
+  unsigned char *pos;
+  unsigned char *newstr;
+  unsigned char lookup[256];
+
+  *outptr = NULL;
+  *outlen = 0;
+  srclen = strlen(src);
+
+  /* Check the length of the input string is valid */
+  if(!srclen || srclen % 4)
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* srclen is at least 4 here */
+  while(src[srclen - 1 - padding] == '=') {
+    /* count padding characters */
+    padding++;
+    /* A maximum of two = padding characters is allowed */
+    if(padding > 2)
+      return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Calculate the number of quantums */
+  numQuantums = srclen / 4;
+  fullQuantums = numQuantums - (padding ? 1 : 0);
+
+  /* Calculate the size of the decoded string */
+  rawlen = (numQuantums * 3) - padding;
+
+  /* Allocate our buffer including room for a null-terminator */
+  newstr = malloc(rawlen + 1);
+  if(!newstr)
+    return CURLE_OUT_OF_MEMORY;
+
+  pos = newstr;
+
+  memset(lookup, 0xff, sizeof(lookup));
+  memcpy(&lookup['+'], decodetable, sizeof(decodetable));
+  /* replaces
+  {
+    unsigned char c;
+    const unsigned char *p = (const unsigned char *)base64encdec;
+    for(c = 0; *p; c++, p++)
+      lookup[*p] = c;
+  }
+  */
+
+  /* Decode the complete quantums first */
+  for(i = 0; i < fullQuantums; i++) {
+    unsigned char val;
+    unsigned int x = 0;
+    int j;
+
+    for(j = 0; j < 4; j++) {
+      val = lookup[(unsigned char)*src++];
+      if(val == 0xff) /* bad symbol */
+        goto bad;
+      x = (x << 6) | val;
+    }
+    pos[2] = x & 0xff;
+    pos[1] = (x >> 8) & 0xff;
+    pos[0] = (x >> 16) & 0xff;
+    pos += 3;
+  }
+  if(padding) {
+    /* this means either 8 or 16 bits output */
+    unsigned char val;
+    unsigned int x = 0;
+    int j;
+    size_t padc = 0;
+    for(j = 0; j < 4; j++) {
+      if(*src == '=') {
+        x <<= 6;
+        src++;
+        if(++padc > padding)
+          /* this is a badly placed '=' symbol! */
+          goto bad;
+      }
+      else {
+        val = lookup[(unsigned char)*src++];
+        if(val == 0xff) /* bad symbol */
+          goto bad;
+        x = (x << 6) | val;
+      }
+    }
+    if(padding == 1)
+      pos[1] = (x >> 8) & 0xff;
+    pos[0] = (x >> 16) & 0xff;
+    pos += 3 - padding;
+  }
+
+  /* Zero terminate */
+  *pos = '\0';
+
+  /* Return the decoded data */
+  *outptr = newstr;
+  *outlen = rawlen;
+
+  return CURLE_OK;
+bad:
+  free(newstr);
+  return CURLE_BAD_CONTENT_ENCODING;
+}
+
+static CURLcode base64_encode(const char *table64,
+                              const char *inputbuff, size_t insize,
+                              char **outptr, size_t *outlen)
+{
+  char *output;
+  char *base64data;
+  const unsigned char *in = (unsigned char *)inputbuff;
+  const char *padstr = &table64[64];    /* Point to padding string. */
+
+  *outptr = NULL;
+  *outlen = 0;
+
+  if(!insize)
+    insize = strlen(inputbuff);
+
+#if SIZEOF_SIZE_T == 4
+  if(insize > UINT_MAX/4)
+    return CURLE_OUT_OF_MEMORY;
+#endif
+
+  base64data = output = malloc((insize + 2) / 3 * 4 + 1);
+  if(!output)
+    return CURLE_OUT_OF_MEMORY;
+
+  while(insize >= 3) {
+    *output++ = table64[ in[0] >> 2 ];
+    *output++ = table64[ ((in[0] & 0x03) << 4) | (in[1] >> 4) ];
+    *output++ = table64[ ((in[1] & 0x0F) << 2) | ((in[2] & 0xC0) >> 6) ];
+    *output++ = table64[ in[2] & 0x3F ];
+    insize -= 3;
+    in += 3;
+  }
+  if(insize) {
+    /* this is only one or two bytes now */
+    *output++ = table64[ in[0] >> 2 ];
+    if(insize == 1) {
+      *output++ = table64[ ((in[0] & 0x03) << 4) ];
+      if(*padstr) {
+        *output++ = *padstr;
+        *output++ = *padstr;
+      }
+    }
+    else {
+      /* insize == 2 */
+      *output++ = table64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xF0) >> 4) ];
+      *output++ = table64[ ((in[1] & 0x0F) << 2) ];
+      if(*padstr)
+        *output++ = *padstr;
+    }
+  }
+
+  /* Zero terminate */
+  *output = '\0';
+
+  /* Return the pointer to the new data (allocated memory) */
+  *outptr = base64data;
+
+  /* Return the length of the new data */
+  *outlen = output - base64data;
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_base64_encode()
+ *
+ * Given a pointer to an input buffer and an input size, encode it and
+ * return a pointer in *outptr to a newly allocated memory area holding
+ * encoded data. Size of encoded data is returned in variable pointed by
+ * outlen.
+ *
+ * Input length of 0 indicates input buffer holds a NUL-terminated string.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * @unittest: 1302
+ */
+CURLcode Curl_base64_encode(const char *inputbuff, size_t insize,
+                            char **outptr, size_t *outlen)
+{
+  return base64_encode(base64encdec, inputbuff, insize, outptr, outlen);
+}
+
+/*
+ * Curl_base64url_encode()
+ *
+ * Given a pointer to an input buffer and an input size, encode it and
+ * return a pointer in *outptr to a newly allocated memory area holding
+ * encoded data. Size of encoded data is returned in variable pointed by
+ * outlen.
+ *
+ * Input length of 0 indicates input buffer holds a NUL-terminated string.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * @unittest: 1302
+ */
+CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize,
+                               char **outptr, size_t *outlen)
+{
+  return base64_encode(base64url, inputbuff, insize, outptr, outlen);
+}
+
+#endif /* no users so disabled */
Index: trunk/src/libs/curl-8.7.1/lib/bufq.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/bufq.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/bufq.c	(revision 104083)
@@ -0,0 +1,677 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "bufq.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+static bool chunk_is_empty(const struct buf_chunk *chunk)
+{
+  return chunk->r_offset >= chunk->w_offset;
+}
+
+static bool chunk_is_full(const struct buf_chunk *chunk)
+{
+  return chunk->w_offset >= chunk->dlen;
+}
+
+static size_t chunk_len(const struct buf_chunk *chunk)
+{
+  return chunk->w_offset - chunk->r_offset;
+}
+
+static size_t chunk_space(const struct buf_chunk *chunk)
+{
+  return chunk->dlen - chunk->w_offset;
+}
+
+static void chunk_reset(struct buf_chunk *chunk)
+{
+  chunk->next = NULL;
+  chunk->r_offset = chunk->w_offset = 0;
+}
+
+static size_t chunk_append(struct buf_chunk *chunk,
+                           const unsigned char *buf, size_t len)
+{
+  unsigned char *p = &chunk->x.data[chunk->w_offset];
+  size_t n = chunk->dlen - chunk->w_offset;
+  DEBUGASSERT(chunk->dlen >= chunk->w_offset);
+  if(n) {
+    n = CURLMIN(n, len);
+    memcpy(p, buf, n);
+    chunk->w_offset += n;
+  }
+  return n;
+}
+
+static size_t chunk_read(struct buf_chunk *chunk,
+                         unsigned char *buf, size_t len)
+{
+  unsigned char *p = &chunk->x.data[chunk->r_offset];
+  size_t n = chunk->w_offset - chunk->r_offset;
+  DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
+  if(!n) {
+    return 0;
+  }
+  else if(n <= len) {
+    memcpy(buf, p, n);
+    chunk->r_offset = chunk->w_offset = 0;
+    return n;
+  }
+  else {
+    memcpy(buf, p, len);
+    chunk->r_offset += len;
+    return len;
+  }
+}
+
+static ssize_t chunk_slurpn(struct buf_chunk *chunk, size_t max_len,
+                            Curl_bufq_reader *reader,
+                            void *reader_ctx, CURLcode *err)
+{
+  unsigned char *p = &chunk->x.data[chunk->w_offset];
+  size_t n = chunk->dlen - chunk->w_offset; /* free amount */
+  ssize_t nread;
+
+  DEBUGASSERT(chunk->dlen >= chunk->w_offset);
+  if(!n) {
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+  if(max_len && n > max_len)
+    n = max_len;
+  nread = reader(reader_ctx, p, n, err);
+  if(nread > 0) {
+    DEBUGASSERT((size_t)nread <= n);
+    chunk->w_offset += nread;
+  }
+  return nread;
+}
+
+static void chunk_peek(const struct buf_chunk *chunk,
+                       const unsigned char **pbuf, size_t *plen)
+{
+  DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
+  *pbuf = &chunk->x.data[chunk->r_offset];
+  *plen = chunk->w_offset - chunk->r_offset;
+}
+
+static void chunk_peek_at(const struct buf_chunk *chunk, size_t offset,
+                          const unsigned char **pbuf, size_t *plen)
+{
+  offset += chunk->r_offset;
+  DEBUGASSERT(chunk->w_offset >= offset);
+  *pbuf = &chunk->x.data[offset];
+  *plen = chunk->w_offset - offset;
+}
+
+static size_t chunk_skip(struct buf_chunk *chunk, size_t amount)
+{
+  size_t n = chunk->w_offset - chunk->r_offset;
+  DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
+  if(n) {
+    n = CURLMIN(n, amount);
+    chunk->r_offset += n;
+    if(chunk->r_offset == chunk->w_offset)
+      chunk->r_offset = chunk->w_offset = 0;
+  }
+  return n;
+}
+
+static void chunk_list_free(struct buf_chunk **anchor)
+{
+  struct buf_chunk *chunk;
+  while(*anchor) {
+    chunk = *anchor;
+    *anchor = chunk->next;
+    free(chunk);
+  }
+}
+
+
+
+void Curl_bufcp_init(struct bufc_pool *pool,
+                     size_t chunk_size, size_t spare_max)
+{
+  DEBUGASSERT(chunk_size > 0);
+  DEBUGASSERT(spare_max > 0);
+  memset(pool, 0, sizeof(*pool));
+  pool->chunk_size = chunk_size;
+  pool->spare_max = spare_max;
+}
+
+static CURLcode bufcp_take(struct bufc_pool *pool,
+                           struct buf_chunk **pchunk)
+{
+  struct buf_chunk *chunk = NULL;
+
+  if(pool->spare) {
+    chunk = pool->spare;
+    pool->spare = chunk->next;
+    --pool->spare_count;
+    chunk_reset(chunk);
+    *pchunk = chunk;
+    return CURLE_OK;
+  }
+
+  chunk = calloc(1, sizeof(*chunk) + pool->chunk_size);
+  if(!chunk) {
+    *pchunk = NULL;
+    return CURLE_OUT_OF_MEMORY;
+  }
+  chunk->dlen = pool->chunk_size;
+  *pchunk = chunk;
+  return CURLE_OK;
+}
+
+static void bufcp_put(struct bufc_pool *pool,
+                      struct buf_chunk *chunk)
+{
+  if(pool->spare_count >= pool->spare_max) {
+    free(chunk);
+  }
+  else {
+    chunk_reset(chunk);
+    chunk->next = pool->spare;
+    pool->spare = chunk;
+    ++pool->spare_count;
+  }
+}
+
+void Curl_bufcp_free(struct bufc_pool *pool)
+{
+  chunk_list_free(&pool->spare);
+  pool->spare_count = 0;
+}
+
+static void bufq_init(struct bufq *q, struct bufc_pool *pool,
+                      size_t chunk_size, size_t max_chunks, int opts)
+{
+  DEBUGASSERT(chunk_size > 0);
+  DEBUGASSERT(max_chunks > 0);
+  memset(q, 0, sizeof(*q));
+  q->chunk_size = chunk_size;
+  q->max_chunks = max_chunks;
+  q->pool = pool;
+  q->opts = opts;
+}
+
+void Curl_bufq_init2(struct bufq *q, size_t chunk_size, size_t max_chunks,
+                     int opts)
+{
+  bufq_init(q, NULL, chunk_size, max_chunks, opts);
+}
+
+void Curl_bufq_init(struct bufq *q, size_t chunk_size, size_t max_chunks)
+{
+  bufq_init(q, NULL, chunk_size, max_chunks, BUFQ_OPT_NONE);
+}
+
+void Curl_bufq_initp(struct bufq *q, struct bufc_pool *pool,
+                     size_t max_chunks, int opts)
+{
+  bufq_init(q, pool, pool->chunk_size, max_chunks, opts);
+}
+
+void Curl_bufq_free(struct bufq *q)
+{
+  chunk_list_free(&q->head);
+  chunk_list_free(&q->spare);
+  q->tail = NULL;
+  q->chunk_count = 0;
+}
+
+void Curl_bufq_reset(struct bufq *q)
+{
+  struct buf_chunk *chunk;
+  while(q->head) {
+    chunk = q->head;
+    q->head = chunk->next;
+    chunk->next = q->spare;
+    q->spare = chunk;
+  }
+  q->tail = NULL;
+}
+
+size_t Curl_bufq_len(const struct bufq *q)
+{
+  const struct buf_chunk *chunk = q->head;
+  size_t len = 0;
+  while(chunk) {
+    len += chunk_len(chunk);
+    chunk = chunk->next;
+  }
+  return len;
+}
+
+size_t Curl_bufq_space(const struct bufq *q)
+{
+  size_t space = 0;
+  if(q->tail)
+    space += chunk_space(q->tail);
+  if(q->spare) {
+    struct buf_chunk *chunk = q->spare;
+    while(chunk) {
+      space += chunk->dlen;
+      chunk = chunk->next;
+    }
+  }
+  if(q->chunk_count < q->max_chunks) {
+    space += (q->max_chunks - q->chunk_count) * q->chunk_size;
+  }
+  return space;
+}
+
+bool Curl_bufq_is_empty(const struct bufq *q)
+{
+  return !q->head || chunk_is_empty(q->head);
+}
+
+bool Curl_bufq_is_full(const struct bufq *q)
+{
+  if(!q->tail || q->spare)
+    return FALSE;
+  if(q->chunk_count < q->max_chunks)
+    return FALSE;
+  if(q->chunk_count > q->max_chunks)
+    return TRUE;
+  /* we have no spares and cannot make more, is the tail full? */
+  return chunk_is_full(q->tail);
+}
+
+static struct buf_chunk *get_spare(struct bufq *q)
+{
+  struct buf_chunk *chunk = NULL;
+
+  if(q->spare) {
+    chunk = q->spare;
+    q->spare = chunk->next;
+    chunk_reset(chunk);
+    return chunk;
+  }
+
+  if(q->chunk_count >= q->max_chunks && (!(q->opts & BUFQ_OPT_SOFT_LIMIT)))
+    return NULL;
+
+  if(q->pool) {
+    if(bufcp_take(q->pool, &chunk))
+      return NULL;
+    ++q->chunk_count;
+    return chunk;
+  }
+  else {
+    chunk = calloc(1, sizeof(*chunk) + q->chunk_size);
+    if(!chunk)
+      return NULL;
+    chunk->dlen = q->chunk_size;
+    ++q->chunk_count;
+    return chunk;
+  }
+}
+
+static void prune_head(struct bufq *q)
+{
+  struct buf_chunk *chunk;
+
+  while(q->head && chunk_is_empty(q->head)) {
+    chunk = q->head;
+    q->head = chunk->next;
+    if(q->tail == chunk)
+      q->tail = q->head;
+    if(q->pool) {
+      bufcp_put(q->pool, chunk);
+      --q->chunk_count;
+    }
+    else if((q->chunk_count > q->max_chunks) ||
+       (q->opts & BUFQ_OPT_NO_SPARES)) {
+      /* SOFT_LIMIT allowed us more than max. free spares until
+       * we are at max again. Or free them if we are configured
+       * to not use spares. */
+      free(chunk);
+      --q->chunk_count;
+    }
+    else {
+      chunk->next = q->spare;
+      q->spare = chunk;
+    }
+  }
+}
+
+static struct buf_chunk *get_non_full_tail(struct bufq *q)
+{
+  struct buf_chunk *chunk;
+
+  if(q->tail && !chunk_is_full(q->tail))
+    return q->tail;
+  chunk = get_spare(q);
+  if(chunk) {
+    /* new tail, and possibly new head */
+    if(q->tail) {
+      q->tail->next = chunk;
+      q->tail = chunk;
+    }
+    else {
+      DEBUGASSERT(!q->head);
+      q->head = q->tail = chunk;
+    }
+  }
+  return chunk;
+}
+
+ssize_t Curl_bufq_write(struct bufq *q,
+                        const unsigned char *buf, size_t len,
+                        CURLcode *err)
+{
+  struct buf_chunk *tail;
+  ssize_t nwritten = 0;
+  size_t n;
+
+  DEBUGASSERT(q->max_chunks > 0);
+  while(len) {
+    tail = get_non_full_tail(q);
+    if(!tail) {
+      if((q->chunk_count < q->max_chunks) || (q->opts & BUFQ_OPT_SOFT_LIMIT)) {
+        *err = CURLE_OUT_OF_MEMORY;
+        return -1;
+      }
+      break;
+    }
+    n = chunk_append(tail, buf, len);
+    if(!n)
+      break;
+    nwritten += n;
+    buf += n;
+    len -= n;
+  }
+  if(nwritten == 0 && len) {
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+  *err = CURLE_OK;
+  return nwritten;
+}
+
+CURLcode Curl_bufq_cwrite(struct bufq *q,
+                          const char *buf, size_t len,
+                          size_t *pnwritten)
+{
+  ssize_t n;
+  CURLcode result;
+  n = Curl_bufq_write(q, (const unsigned char *)buf, len, &result);
+  *pnwritten = (n < 0)? 0 : (size_t)n;
+  return result;
+}
+
+ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
+                       CURLcode *err)
+{
+  ssize_t nread = 0;
+  size_t n;
+
+  *err = CURLE_OK;
+  while(len && q->head) {
+    n = chunk_read(q->head, buf, len);
+    if(n) {
+      nread += n;
+      buf += n;
+      len -= n;
+    }
+    prune_head(q);
+  }
+  if(nread == 0) {
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+  return nread;
+}
+
+CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
+                         size_t *pnread)
+{
+  ssize_t n;
+  CURLcode result;
+  n = Curl_bufq_read(q, (unsigned char *)buf, len, &result);
+  *pnread = (n < 0)? 0 : (size_t)n;
+  return result;
+}
+
+bool Curl_bufq_peek(struct bufq *q,
+                    const unsigned char **pbuf, size_t *plen)
+{
+  if(q->head && chunk_is_empty(q->head)) {
+    prune_head(q);
+  }
+  if(q->head && !chunk_is_empty(q->head)) {
+    chunk_peek(q->head, pbuf, plen);
+    return TRUE;
+  }
+  *pbuf = NULL;
+  *plen = 0;
+  return FALSE;
+}
+
+bool Curl_bufq_peek_at(struct bufq *q, size_t offset,
+                       const unsigned char **pbuf, size_t *plen)
+{
+  struct buf_chunk *c = q->head;
+  size_t clen;
+
+  while(c) {
+    clen = chunk_len(c);
+    if(!clen)
+      break;
+    if(offset >= clen) {
+      offset -= clen;
+      c = c->next;
+      continue;
+    }
+    chunk_peek_at(c, offset, pbuf, plen);
+    return TRUE;
+  }
+  *pbuf = NULL;
+  *plen = 0;
+  return FALSE;
+}
+
+void Curl_bufq_skip(struct bufq *q, size_t amount)
+{
+  size_t n;
+
+  while(amount && q->head) {
+    n = chunk_skip(q->head, amount);
+    amount -= n;
+    prune_head(q);
+  }
+}
+
+ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
+                       void *writer_ctx, CURLcode *err)
+{
+  const unsigned char *buf;
+  size_t blen;
+  ssize_t nwritten = 0;
+
+  while(Curl_bufq_peek(q, &buf, &blen)) {
+    ssize_t chunk_written;
+
+    chunk_written = writer(writer_ctx, buf, blen, err);
+    if(chunk_written < 0) {
+      if(!nwritten || *err != CURLE_AGAIN) {
+        /* blocked on first write or real error, fail */
+        nwritten = -1;
+      }
+      break;
+    }
+    if(!chunk_written) {
+      if(!nwritten) {
+        /* treat as blocked */
+        *err = CURLE_AGAIN;
+        nwritten = -1;
+      }
+      break;
+    }
+    Curl_bufq_skip(q, (size_t)chunk_written);
+    nwritten += chunk_written;
+  }
+  return nwritten;
+}
+
+ssize_t Curl_bufq_write_pass(struct bufq *q,
+                             const unsigned char *buf, size_t len,
+                             Curl_bufq_writer *writer, void *writer_ctx,
+                             CURLcode *err)
+{
+  ssize_t nwritten = 0, n;
+
+  *err = CURLE_OK;
+  while(len) {
+    if(Curl_bufq_is_full(q)) {
+      /* try to make room in case we are full */
+      n = Curl_bufq_pass(q, writer, writer_ctx, err);
+      if(n < 0) {
+        if(*err != CURLE_AGAIN) {
+          /* real error, fail */
+          return -1;
+        }
+        /* would block, bufq is full, give up */
+        break;
+      }
+    }
+
+    /* Add whatever is remaining now to bufq */
+    n = Curl_bufq_write(q, buf, len, err);
+    if(n < 0) {
+      if(*err != CURLE_AGAIN) {
+        /* real error, fail */
+        return -1;
+      }
+      /* no room in bufq */
+      break;
+    }
+    /* edge case of writer returning 0 (and len is >0)
+     * break or we might enter an infinite loop here */
+    if(n == 0)
+      break;
+
+    /* Maybe only part of `data` has been added, continue to loop */
+    buf += (size_t)n;
+    len -= (size_t)n;
+    nwritten += (size_t)n;
+  }
+
+  if(!nwritten && len) {
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+  *err = CURLE_OK;
+  return nwritten;
+}
+
+ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len,
+                       Curl_bufq_reader *reader, void *reader_ctx,
+                       CURLcode *err)
+{
+  struct buf_chunk *tail = NULL;
+  ssize_t nread;
+
+  *err = CURLE_AGAIN;
+  tail = get_non_full_tail(q);
+  if(!tail) {
+    if(q->chunk_count < q->max_chunks) {
+      *err = CURLE_OUT_OF_MEMORY;
+      return -1;
+    }
+    /* full, blocked */
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+
+  nread = chunk_slurpn(tail, max_len, reader, reader_ctx, err);
+  if(nread < 0) {
+    return -1;
+  }
+  else if(nread == 0) {
+    /* eof */
+    *err = CURLE_OK;
+  }
+  return nread;
+}
+
+/**
+ * Read up to `max_len` bytes and append it to the end of the buffer queue.
+ * if `max_len` is 0, no limit is imposed and the call behaves exactly
+ * the same as `Curl_bufq_slurp()`.
+ * Returns the total amount of buf read (may be 0) or -1 on other
+ * reader errors.
+ * Note that even in case of a -1 chunks may have been read and
+ * the buffer queue will have different length than before.
+ */
+static ssize_t bufq_slurpn(struct bufq *q, size_t max_len,
+                           Curl_bufq_reader *reader, void *reader_ctx,
+                           CURLcode *err)
+{
+  ssize_t nread = 0, n;
+
+  *err = CURLE_AGAIN;
+  while(1) {
+
+    n = Curl_bufq_sipn(q, max_len, reader, reader_ctx, err);
+    if(n < 0) {
+      if(!nread || *err != CURLE_AGAIN) {
+        /* blocked on first read or real error, fail */
+        nread = -1;
+      }
+      else
+        *err = CURLE_OK;
+      break;
+    }
+    else if(n == 0) {
+      /* eof */
+      *err = CURLE_OK;
+      break;
+    }
+    nread += (size_t)n;
+    if(max_len) {
+      DEBUGASSERT((size_t)n <= max_len);
+      max_len -= (size_t)n;
+      if(!max_len)
+        break;
+    }
+    /* give up slurping when we get less bytes than we asked for */
+    if(q->tail && !chunk_is_full(q->tail))
+      break;
+  }
+  return nread;
+}
+
+ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
+                        void *reader_ctx, CURLcode *err)
+{
+  return bufq_slurpn(q, 0, reader, reader_ctx, err);
+}
Index: trunk/src/libs/curl-8.7.1/lib/bufq.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/bufq.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/bufq.h	(revision 104083)
@@ -0,0 +1,272 @@
+#ifndef HEADER_CURL_BUFQ_H
+#define HEADER_CURL_BUFQ_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+/**
+ * A chunk of bytes for reading and writing.
+ * The size is fixed a creation with read and write offset
+ * for where unread content is.
+ */
+struct buf_chunk {
+  struct buf_chunk *next;  /* to keep it in a list */
+  size_t dlen;             /* the amount of allocated x.data[] */
+  size_t r_offset;         /* first unread bytes */
+  size_t w_offset;         /* one after last written byte */
+  union {
+    unsigned char data[1]; /* the buffer for `dlen` bytes */
+    void *dummy;           /* alignment */
+  } x;
+};
+
+/**
+ * A pool for providing/keeping a number of chunks of the same size
+ *
+ * The same pool can be shared by many `bufq` instances. However, a pool
+ * is not thread safe. All bufqs using it are supposed to operate in the
+ * same thread.
+ */
+struct bufc_pool {
+  struct buf_chunk *spare;  /* list of available spare chunks */
+  size_t chunk_size;        /* the size of chunks in this pool */
+  size_t spare_count;       /* current number of spare chunks in list */
+  size_t spare_max;         /* max number of spares to keep */
+};
+
+void Curl_bufcp_init(struct bufc_pool *pool,
+                     size_t chunk_size, size_t spare_max);
+
+void Curl_bufcp_free(struct bufc_pool *pool);
+
+/**
+ * A queue of byte chunks for reading and writing.
+ * Reading is done from `head`, writing is done to `tail`.
+ *
+ * `bufq`s can be empty or full or neither. Its `len` is the number
+ * of bytes that can be read. For an empty bufq, `len` will be 0.
+ *
+ * By default, a bufq can hold up to `max_chunks * chunk_size` number
+ * of bytes. When `max_chunks` are used (in the `head` list) and the
+ * `tail` chunk is full, the bufq will report that it is full.
+ *
+ * On a full bufq, `len` may be less than the maximum number of bytes,
+ * e.g. when the head chunk is partially read. `len` may also become
+ * larger than the max when option `BUFQ_OPT_SOFT_LIMIT` is used.
+ *
+ * By default, writing to a full bufq will return (-1, CURLE_AGAIN). Same
+ * as reading from an empty bufq.
+ * With `BUFQ_OPT_SOFT_LIMIT` set, a bufq will allow writing becond this
+ * limit and use more than `max_chunks`. However it will report that it
+ * is full nevertheless. This is provided for situation where writes
+ * preferably never fail (except for memory exhaustion).
+ *
+ * By default and without a pool, a bufq will keep chunks that read
+ * read empty in its `spare` list. Option `BUFQ_OPT_NO_SPARES` will
+ * disable that and free chunks once they become empty.
+ *
+ * When providing a pool to a bufq, all chunk creation and spare handling
+ * will be delegated to that pool.
+ */
+struct bufq {
+  struct buf_chunk *head;       /* chunk with bytes to read from */
+  struct buf_chunk *tail;       /* chunk to write to */
+  struct buf_chunk *spare;      /* list of free chunks, unless `pool` */
+  struct bufc_pool *pool;       /* optional pool for free chunks */
+  size_t chunk_count;           /* current number of chunks in `head+spare` */
+  size_t max_chunks;            /* max `head` chunks to use */
+  size_t chunk_size;            /* size of chunks to manage */
+  int opts;                     /* options for handling queue, see below */
+};
+
+/**
+ * Default behaviour: chunk limit is "hard", meaning attempts to write
+ * more bytes than can be hold in `max_chunks` is refused and will return
+ * -1, CURLE_AGAIN. */
+#define BUFQ_OPT_NONE        (0)
+/**
+ * Make `max_chunks` a "soft" limit. A bufq will report that it is "full"
+ * when `max_chunks` are used, but allows writing beyond this limit.
+ */
+#define BUFQ_OPT_SOFT_LIMIT  (1 << 0)
+/**
+ * Do not keep spare chunks.
+ */
+#define BUFQ_OPT_NO_SPARES   (1 << 1)
+
+/**
+ * Initialize a buffer queue that can hold up to `max_chunks` buffers
+ * each of size `chunk_size`. The bufq will not allow writing of
+ * more bytes than can be held in `max_chunks`.
+ */
+void Curl_bufq_init(struct bufq *q, size_t chunk_size, size_t max_chunks);
+
+/**
+ * Initialize a buffer queue that can hold up to `max_chunks` buffers
+ * each of size `chunk_size` with the given options. See `BUFQ_OPT_*`.
+ */
+void Curl_bufq_init2(struct bufq *q, size_t chunk_size,
+                     size_t max_chunks, int opts);
+
+void Curl_bufq_initp(struct bufq *q, struct bufc_pool *pool,
+                     size_t max_chunks, int opts);
+
+/**
+ * Reset the buffer queue to be empty. Will keep any allocated buffer
+ * chunks around.
+ */
+void Curl_bufq_reset(struct bufq *q);
+
+/**
+ * Free all resources held by the buffer queue.
+ */
+void Curl_bufq_free(struct bufq *q);
+
+/**
+ * Return the total amount of data in the queue.
+ */
+size_t Curl_bufq_len(const struct bufq *q);
+
+/**
+ * Return the total amount of free space in the queue.
+ * The returned length is the number of bytes that can
+ * be expected to be written successfully to the bufq,
+ * providing no memory allocations fail.
+ */
+size_t Curl_bufq_space(const struct bufq *q);
+
+/**
+ * Returns TRUE iff there is no data in the buffer queue.
+ */
+bool Curl_bufq_is_empty(const struct bufq *q);
+
+/**
+ * Returns TRUE iff there is no space left in the buffer queue.
+ */
+bool Curl_bufq_is_full(const struct bufq *q);
+
+/**
+ * Write buf to the end of the buffer queue. The buf is copied
+ * and the amount of copied bytes is returned.
+ * A return code of -1 indicates an error, setting `err` to the
+ * cause. An err of CURLE_AGAIN is returned if the buffer queue is full.
+ */
+ssize_t Curl_bufq_write(struct bufq *q,
+                        const unsigned char *buf, size_t len,
+                        CURLcode *err);
+
+CURLcode Curl_bufq_cwrite(struct bufq *q,
+                         const char *buf, size_t len,
+                         size_t *pnwritten);
+
+/**
+ * Read buf from the start of the buffer queue. The buf is copied
+ * and the amount of copied bytes is returned.
+ * A return code of -1 indicates an error, setting `err` to the
+ * cause. An err of CURLE_AGAIN is returned if the buffer queue is empty.
+ */
+ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
+                        CURLcode *err);
+
+CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
+                         size_t *pnread);
+
+/**
+ * Peek at the head chunk in the buffer queue. Returns a pointer to
+ * the chunk buf (at the current offset) and its length. Does not
+ * modify the buffer queue.
+ * Returns TRUE iff bytes are available. Sets `pbuf` to NULL and `plen`
+ * to 0 when no bytes are available.
+ * Repeated calls return the same information until the buffer queue
+ * is modified, see `Curl_bufq_skip()``
+ */
+bool Curl_bufq_peek(struct bufq *q,
+                    const unsigned char **pbuf, size_t *plen);
+
+bool Curl_bufq_peek_at(struct bufq *q, size_t offset,
+                       const unsigned char **pbuf, size_t *plen);
+
+/**
+ * Tell the buffer queue to discard `amount` buf bytes at the head
+ * of the queue. Skipping more buf than is currently buffered will
+ * just empty the queue.
+ */
+void Curl_bufq_skip(struct bufq *q, size_t amount);
+
+typedef ssize_t Curl_bufq_writer(void *writer_ctx,
+                                 const unsigned char *buf, size_t len,
+                                 CURLcode *err);
+/**
+ * Passes the chunks in the buffer queue to the writer and returns
+ * the amount of buf written. A writer may return -1 and CURLE_AGAIN
+ * to indicate blocking at which point the queue will stop and return
+ * the amount of buf passed so far.
+ * -1 is returned on any other errors reported by the writer.
+ * Note that in case of a -1 chunks may have been written and
+ * the buffer queue will have different length than before.
+ */
+ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
+                       void *writer_ctx, CURLcode *err);
+
+typedef ssize_t Curl_bufq_reader(void *reader_ctx,
+                                 unsigned char *buf, size_t len,
+                                 CURLcode *err);
+
+/**
+ * Read date and append it to the end of the buffer queue until the
+ * reader returns blocking or the queue is full. A reader returns
+ * -1 and CURLE_AGAIN to indicate blocking.
+ * Returns the total amount of buf read (may be 0) or -1 on other
+ * reader errors.
+ * Note that in case of a -1 chunks may have been read and
+ * the buffer queue will have different length than before.
+ */
+ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
+                        void *reader_ctx, CURLcode *err);
+
+/**
+ * Read *once* up to `max_len` bytes and append it to the buffer.
+ * if `max_len` is 0, no limit is imposed besides the chunk space.
+ * Returns the total amount of buf read (may be 0) or -1 on other
+ * reader errors.
+ */
+ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len,
+                       Curl_bufq_reader *reader, void *reader_ctx,
+                       CURLcode *err);
+
+/**
+ * Write buf to the end of the buffer queue.
+ * Will write bufq content or passed `buf` directly using the `writer`
+ * callback when it sees fit. 'buf' might get passed directly
+ * on or is placed into the buffer, depending on `len` and current
+ * amount buffered, chunk size, etc.
+ */
+ssize_t Curl_bufq_write_pass(struct bufq *q,
+                             const unsigned char *buf, size_t len,
+                             Curl_bufq_writer *writer, void *writer_ctx,
+                             CURLcode *err);
+
+#endif /* HEADER_CURL_BUFQ_H */
Index: trunk/src/libs/curl-8.7.1/lib/bufref.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/bufref.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/bufref.c	(revision 104083)
@@ -0,0 +1,127 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "urldata.h"
+#include "bufref.h"
+#include "strdup.h"
+
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define SIGNATURE 0x5c48e9b2    /* Random pattern. */
+
+/*
+ * Init a bufref struct.
+ */
+void Curl_bufref_init(struct bufref *br)
+{
+  DEBUGASSERT(br);
+  br->dtor = NULL;
+  br->ptr = NULL;
+  br->len = 0;
+
+#ifdef DEBUGBUILD
+  br->signature = SIGNATURE;
+#endif
+}
+
+/*
+ * Free the buffer and re-init the necessary fields. It doesn't touch the
+ * 'signature' field and thus this buffer reference can be reused.
+ */
+
+void Curl_bufref_free(struct bufref *br)
+{
+  DEBUGASSERT(br);
+  DEBUGASSERT(br->signature == SIGNATURE);
+  DEBUGASSERT(br->ptr || !br->len);
+
+  if(br->ptr && br->dtor)
+    br->dtor((void *) br->ptr);
+
+  br->dtor = NULL;
+  br->ptr = NULL;
+  br->len = 0;
+}
+
+/*
+ * Set the buffer reference to new values. The previously referenced buffer
+ * is released before assignment.
+ */
+void Curl_bufref_set(struct bufref *br, const void *ptr, size_t len,
+                     void (*dtor)(void *))
+{
+  DEBUGASSERT(ptr || !len);
+  DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH);
+
+  Curl_bufref_free(br);
+  br->ptr = (const unsigned char *) ptr;
+  br->len = len;
+  br->dtor = dtor;
+}
+
+/*
+ * Get a pointer to the referenced buffer.
+ */
+const unsigned char *Curl_bufref_ptr(const struct bufref *br)
+{
+  DEBUGASSERT(br);
+  DEBUGASSERT(br->signature == SIGNATURE);
+  DEBUGASSERT(br->ptr || !br->len);
+
+  return br->ptr;
+}
+
+/*
+ * Get the length of the referenced buffer data.
+ */
+size_t Curl_bufref_len(const struct bufref *br)
+{
+  DEBUGASSERT(br);
+  DEBUGASSERT(br->signature == SIGNATURE);
+  DEBUGASSERT(br->ptr || !br->len);
+
+  return br->len;
+}
+
+CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len)
+{
+  unsigned char *cpy = NULL;
+
+  DEBUGASSERT(br);
+  DEBUGASSERT(br->signature == SIGNATURE);
+  DEBUGASSERT(br->ptr || !br->len);
+  DEBUGASSERT(ptr || !len);
+  DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH);
+
+  if(ptr) {
+    cpy = Curl_memdup0(ptr, len);
+    if(!cpy)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  Curl_bufref_set(br, cpy, len, curl_free);
+  return CURLE_OK;
+}
Index: trunk/src/libs/curl-8.7.1/lib/bufref.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/bufref.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/bufref.h	(revision 104083)
@@ -0,0 +1,48 @@
+#ifndef HEADER_CURL_BUFREF_H
+#define HEADER_CURL_BUFREF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Generic buffer reference.
+ */
+struct bufref {
+  void (*dtor)(void *);         /* Associated destructor. */
+  const unsigned char *ptr;     /* Referenced data buffer. */
+  size_t len;                   /* The data size in bytes. */
+#ifdef DEBUGBUILD
+  int signature;                /* Detect API use mistakes. */
+#endif
+};
+
+
+void Curl_bufref_init(struct bufref *br);
+void Curl_bufref_set(struct bufref *br, const void *ptr, size_t len,
+                     void (*dtor)(void *));
+const unsigned char *Curl_bufref_ptr(const struct bufref *br);
+size_t Curl_bufref_len(const struct bufref *br);
+CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len);
+void Curl_bufref_free(struct bufref *br);
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/c-hyper.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/c-hyper.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/c-hyper.c	(revision 104083)
@@ -0,0 +1,1224 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* Curl's integration with Hyper. This replaces certain functions in http.c,
+ * based on configuration #defines. This implementation supports HTTP/1.1 but
+ * not HTTP/2.
+ */
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER)
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include <hyper.h>
+#include "urldata.h"
+#include "cfilters.h"
+#include "sendf.h"
+#include "headers.h"
+#include "transfer.h"
+#include "multiif.h"
+#include "progress.h"
+#include "content_encoding.h"
+#include "ws.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+static CURLcode cr_hyper_add(struct Curl_easy *data);
+
+typedef enum {
+    USERDATA_NOT_SET = 0, /* for tasks with no userdata set; must be zero */
+    USERDATA_RESP_BODY
+} userdata_t;
+
+size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
+                       uint8_t *buf, size_t buflen)
+{
+  struct hyp_io_ctx *io_ctx = userp;
+  struct Curl_easy *data = io_ctx->data;
+  struct connectdata *conn = data->conn;
+  CURLcode result;
+  ssize_t nread;
+  DEBUGASSERT(conn);
+  (void)ctx;
+
+  DEBUGF(infof(data, "Curl_hyper_recv(%zu)", buflen));
+  result = Curl_conn_recv(data, io_ctx->sockindex,
+                          (char *)buf, buflen, &nread);
+  if(result == CURLE_AGAIN) {
+    /* would block, register interest */
+    DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> EAGAIN", buflen));
+    if(data->hyp.read_waker)
+      hyper_waker_free(data->hyp.read_waker);
+    data->hyp.read_waker = hyper_context_waker(ctx);
+    if(!data->hyp.read_waker) {
+      failf(data, "Couldn't make the read hyper_context_waker");
+      return HYPER_IO_ERROR;
+    }
+    return HYPER_IO_PENDING;
+  }
+  else if(result) {
+    failf(data, "Curl_read failed");
+    return HYPER_IO_ERROR;
+  }
+  DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> %zd", buflen, nread));
+  return (size_t)nread;
+}
+
+size_t Curl_hyper_send(void *userp, hyper_context *ctx,
+                       const uint8_t *buf, size_t buflen)
+{
+  struct hyp_io_ctx *io_ctx = userp;
+  struct Curl_easy *data = io_ctx->data;
+  CURLcode result;
+  size_t nwrote;
+
+  DEBUGF(infof(data, "Curl_hyper_send(%zu)", buflen));
+  result = Curl_conn_send(data, io_ctx->sockindex,
+                          (void *)buf, buflen, &nwrote);
+  if(result == CURLE_AGAIN) {
+    DEBUGF(infof(data, "Curl_hyper_send(%zu) -> EAGAIN", buflen));
+    /* would block, register interest */
+    if(data->hyp.write_waker)
+      hyper_waker_free(data->hyp.write_waker);
+    data->hyp.write_waker = hyper_context_waker(ctx);
+    if(!data->hyp.write_waker) {
+      failf(data, "Couldn't make the write hyper_context_waker");
+      return HYPER_IO_ERROR;
+    }
+    return HYPER_IO_PENDING;
+  }
+  else if(result) {
+    failf(data, "Curl_write failed");
+    return HYPER_IO_ERROR;
+  }
+  DEBUGF(infof(data, "Curl_hyper_send(%zu) -> %zd", buflen, nwrote));
+  return (size_t)nwrote;
+}
+
+static int hyper_each_header(void *userdata,
+                             const uint8_t *name,
+                             size_t name_len,
+                             const uint8_t *value,
+                             size_t value_len)
+{
+  struct Curl_easy *data = (struct Curl_easy *)userdata;
+  size_t len;
+  char *headp;
+  CURLcode result;
+  int writetype;
+
+  if(name_len + value_len + 2 > CURL_MAX_HTTP_HEADER) {
+    failf(data, "Too long response header");
+    data->state.hresult = CURLE_TOO_LARGE;
+    return HYPER_ITER_BREAK;
+  }
+
+  Curl_dyn_reset(&data->state.headerb);
+  if(name_len) {
+    if(Curl_dyn_addf(&data->state.headerb, "%.*s: %.*s\r\n",
+                     (int) name_len, name, (int) value_len, value))
+      return HYPER_ITER_BREAK;
+  }
+  else {
+    if(Curl_dyn_addn(&data->state.headerb, STRCONST("\r\n")))
+      return HYPER_ITER_BREAK;
+  }
+  len = Curl_dyn_len(&data->state.headerb);
+  headp = Curl_dyn_ptr(&data->state.headerb);
+
+  result = Curl_http_header(data, data->conn, headp, len);
+  if(result) {
+    data->state.hresult = result;
+    return HYPER_ITER_BREAK;
+  }
+
+  Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
+
+  writetype = CLIENTWRITE_HEADER;
+  if(data->state.hconnect)
+    writetype |= CLIENTWRITE_CONNECT;
+  if(data->req.httpcode/100 == 1)
+    writetype |= CLIENTWRITE_1XX;
+  result = Curl_client_write(data, writetype, headp, len);
+  if(result) {
+    data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
+    return HYPER_ITER_BREAK;
+  }
+
+  result = Curl_bump_headersize(data, len, FALSE);
+  if(result) {
+    data->state.hresult = result;
+    return HYPER_ITER_BREAK;
+  }
+  return HYPER_ITER_CONTINUE;
+}
+
+static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
+{
+  char *buf = (char *)hyper_buf_bytes(chunk);
+  size_t len = hyper_buf_len(chunk);
+  struct Curl_easy *data = (struct Curl_easy *)userdata;
+  struct SingleRequest *k = &data->req;
+  CURLcode result = CURLE_OK;
+
+  if(0 == k->bodywrites) {
+#if defined(USE_NTLM)
+    struct connectdata *conn = data->conn;
+    if(conn->bits.close &&
+       (((data->req.httpcode == 401) &&
+         (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
+        ((data->req.httpcode == 407) &&
+         (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
+      infof(data, "Connection closed while negotiating NTLM");
+      data->state.authproblem = TRUE;
+      Curl_safefree(data->req.newurl);
+    }
+#endif
+    if(Curl_http_exp100_is_selected(data)) {
+      if(data->req.httpcode < 400) {
+        Curl_http_exp100_got100(data);
+        if(data->hyp.send_body_waker) {
+          hyper_waker_wake(data->hyp.send_body_waker);
+          data->hyp.send_body_waker = NULL;
+        }
+      }
+      else { /* >= 4xx */
+        Curl_req_abort_sending(data);
+      }
+    }
+    if(data->state.hconnect && (data->req.httpcode/100 != 2) &&
+       data->state.authproxy.done) {
+      data->req.done = TRUE;
+      result = CURLE_OK;
+    }
+    else
+      result = Curl_http_firstwrite(data);
+    if(result || data->req.done) {
+      infof(data, "Return early from hyper_body_chunk");
+      data->state.hresult = result;
+      return HYPER_ITER_BREAK;
+    }
+  }
+  result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
+
+  if(result) {
+    data->state.hresult = result;
+    return HYPER_ITER_BREAK;
+  }
+
+  return HYPER_ITER_CONTINUE;
+}
+
+/*
+ * Hyper does not consider the status line, the first line in an HTTP/1
+ * response, to be a header. The libcurl API does. This function sends the
+ * status line in the header callback. */
+static CURLcode status_line(struct Curl_easy *data,
+                            struct connectdata *conn,
+                            uint16_t http_status,
+                            int http_version,
+                            const uint8_t *reason, size_t rlen)
+{
+  CURLcode result;
+  size_t len;
+  const char *vstr;
+  int writetype;
+  vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" :
+    (http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0");
+
+  /* We need to set 'httpcodeq' for functions that check the response code in
+     a single place. */
+  data->req.httpcode = http_status;
+  data->req.httpversion = http_version == HYPER_HTTP_VERSION_1_1? 11 :
+                          (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
+  if(data->state.hconnect)
+    /* CONNECT */
+    data->info.httpproxycode = http_status;
+  else {
+    conn->httpversion = (unsigned char)data->req.httpversion;
+    if(http_version == HYPER_HTTP_VERSION_1_0)
+      data->state.httpwant = CURL_HTTP_VERSION_1_0;
+
+    result = Curl_http_statusline(data, conn);
+    if(result)
+      return result;
+  }
+
+  Curl_dyn_reset(&data->state.headerb);
+
+  result = Curl_dyn_addf(&data->state.headerb, "HTTP/%s %03d %.*s\r\n",
+                         vstr,
+                         (int)http_status,
+                         (int)rlen, reason);
+  if(result)
+    return result;
+  len = Curl_dyn_len(&data->state.headerb);
+  Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
+             len);
+
+  writetype = CLIENTWRITE_HEADER|CLIENTWRITE_STATUS;
+  if(data->state.hconnect)
+    writetype |= CLIENTWRITE_CONNECT;
+  result = Curl_client_write(data, writetype,
+                             Curl_dyn_ptr(&data->state.headerb), len);
+  if(result)
+    return result;
+
+  result = Curl_bump_headersize(data, len, FALSE);
+  return result;
+}
+
+/*
+ * Hyper does not pass on the last empty response header. The libcurl API
+ * does. This function sends an empty header in the header callback.
+ */
+static CURLcode empty_header(struct Curl_easy *data)
+{
+  CURLcode result = Curl_http_size(data);
+  if(!result) {
+    result = hyper_each_header(data, NULL, 0, NULL, 0) ?
+      CURLE_WRITE_ERROR : CURLE_OK;
+    if(result)
+      failf(data, "hyperstream: couldn't pass blank header");
+    /* Hyper does chunked decoding itself. If it was added during
+     * response header processing, remove it again. */
+    Curl_cwriter_remove_by_name(data, "chunked");
+  }
+  return result;
+}
+
+CURLcode Curl_hyper_stream(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           int *didwhat,
+                           int select_res)
+{
+  hyper_response *resp = NULL;
+  uint16_t http_status;
+  int http_version;
+  hyper_headers *headers = NULL;
+  hyper_body *resp_body = NULL;
+  struct hyptransfer *h = &data->hyp;
+  hyper_task *task;
+  hyper_task *foreach;
+  const uint8_t *reasonp;
+  size_t reason_len;
+  CURLcode result = CURLE_OK;
+  struct SingleRequest *k = &data->req;
+  (void)conn;
+
+  if(data->hyp.send_body_waker) {
+    hyper_waker_wake(data->hyp.send_body_waker);
+    data->hyp.send_body_waker = NULL;
+  }
+
+  if(select_res & CURL_CSELECT_IN) {
+    if(h->read_waker)
+      hyper_waker_wake(h->read_waker);
+    h->read_waker = NULL;
+  }
+  if(select_res & CURL_CSELECT_OUT) {
+    if(h->write_waker)
+      hyper_waker_wake(h->write_waker);
+    h->write_waker = NULL;
+  }
+
+  do {
+    hyper_task_return_type t;
+    task = hyper_executor_poll(h->exec);
+    if(!task) {
+      *didwhat = KEEP_RECV;
+      break;
+    }
+    t = hyper_task_type(task);
+    if(t == HYPER_TASK_ERROR) {
+      hyper_error *hypererr = hyper_task_value(task);
+      hyper_task_free(task);
+      if(data->state.hresult) {
+        /* override Hyper's view, might not even be an error */
+        result = data->state.hresult;
+        infof(data, "hyperstream is done (by early callback)");
+      }
+      else {
+        uint8_t errbuf[256];
+        size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
+        hyper_code code = hyper_error_code(hypererr);
+        failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
+        switch(code) {
+        case HYPERE_ABORTED_BY_CALLBACK:
+          result = CURLE_OK;
+          break;
+        case HYPERE_UNEXPECTED_EOF:
+          if(!data->req.bytecount)
+            result = CURLE_GOT_NOTHING;
+          else
+            result = CURLE_RECV_ERROR;
+          break;
+        case HYPERE_INVALID_PEER_MESSAGE:
+          /* bump headerbytecount to avoid the count remaining at zero and
+             appearing to not having read anything from the peer at all */
+          data->req.headerbytecount++;
+          result = CURLE_UNSUPPORTED_PROTOCOL; /* maybe */
+          break;
+        default:
+          result = CURLE_RECV_ERROR;
+          break;
+        }
+      }
+      data->req.done = TRUE;
+      hyper_error_free(hypererr);
+      break;
+    }
+    else if(t == HYPER_TASK_EMPTY) {
+      void *userdata = hyper_task_userdata(task);
+      hyper_task_free(task);
+      if((userdata_t)userdata == USERDATA_RESP_BODY) {
+        /* end of transfer */
+        data->req.done = TRUE;
+        infof(data, "hyperstream is done");
+        if(!k->bodywrites) {
+          /* hyper doesn't always call the body write callback */
+          result = Curl_http_firstwrite(data);
+        }
+        break;
+      }
+      else {
+        /* A background task for hyper; ignore */
+        continue;
+      }
+    }
+
+    DEBUGASSERT(HYPER_TASK_RESPONSE);
+
+    resp = hyper_task_value(task);
+    hyper_task_free(task);
+
+    *didwhat = KEEP_RECV;
+    if(!resp) {
+      failf(data, "hyperstream: couldn't get response");
+      return CURLE_RECV_ERROR;
+    }
+
+    http_status = hyper_response_status(resp);
+    http_version = hyper_response_version(resp);
+    reasonp = hyper_response_reason_phrase(resp);
+    reason_len = hyper_response_reason_phrase_len(resp);
+
+    if(http_status == 417 && Curl_http_exp100_is_selected(data)) {
+      infof(data, "Got 417 while waiting for a 100");
+      data->state.disableexpect = TRUE;
+      data->req.newurl = strdup(data->state.url);
+      Curl_req_abort_sending(data);
+    }
+
+    result = status_line(data, conn,
+                         http_status, http_version, reasonp, reason_len);
+    if(result)
+      break;
+
+    headers = hyper_response_headers(resp);
+    if(!headers) {
+      failf(data, "hyperstream: couldn't get response headers");
+      result = CURLE_RECV_ERROR;
+      break;
+    }
+
+    /* the headers are already received */
+    hyper_headers_foreach(headers, hyper_each_header, data);
+    if(data->state.hresult) {
+      result = data->state.hresult;
+      break;
+    }
+
+    result = empty_header(data);
+    if(result)
+      break;
+
+    k->deductheadercount =
+      (100 <= http_status && 199 >= http_status)?k->headerbytecount:0;
+#ifdef USE_WEBSOCKETS
+    if(k->upgr101 == UPGR101_WS) {
+      if(http_status == 101) {
+        /* verify the response */
+        result = Curl_ws_accept(data, NULL, 0);
+        if(result)
+          return result;
+      }
+      else {
+        failf(data, "Expected 101, got %u", k->httpcode);
+        result = CURLE_HTTP_RETURNED_ERROR;
+        break;
+      }
+    }
+#endif
+
+    /* Curl_http_auth_act() checks what authentication methods that are
+     * available and decides which one (if any) to use. It will set 'newurl'
+     * if an auth method was picked. */
+    result = Curl_http_auth_act(data);
+    if(result)
+      break;
+
+    resp_body = hyper_response_body(resp);
+    if(!resp_body) {
+      failf(data, "hyperstream: couldn't get response body");
+      result = CURLE_RECV_ERROR;
+      break;
+    }
+    foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
+    if(!foreach) {
+      failf(data, "hyperstream: body foreach failed");
+      result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+    hyper_task_set_userdata(foreach, (void *)USERDATA_RESP_BODY);
+    if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) {
+      failf(data, "Couldn't hyper_executor_push the body-foreach");
+      result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+
+    hyper_response_free(resp);
+    resp = NULL;
+  } while(1);
+  if(resp)
+    hyper_response_free(resp);
+  return result;
+}
+
+static CURLcode debug_request(struct Curl_easy *data,
+                              const char *method,
+                              const char *path)
+{
+  char *req = aprintf("%s %s HTTP/1.1\r\n", method, path);
+  if(!req)
+    return CURLE_OUT_OF_MEMORY;
+  Curl_debug(data, CURLINFO_HEADER_OUT, req, strlen(req));
+  free(req);
+  return CURLE_OK;
+}
+
+/*
+ * Given a full header line "name: value" (optional CRLF in the input, should
+ * be in the output), add to Hyper and send to the debug callback.
+ *
+ * Supports multiple headers.
+ */
+
+CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
+                           const char *line)
+{
+  const char *p;
+  const char *n;
+  size_t nlen;
+  const char *v;
+  size_t vlen;
+  bool newline = TRUE;
+  int numh = 0;
+
+  if(!line)
+    return CURLE_OK;
+  n = line;
+  do {
+    size_t linelen = 0;
+
+    p = strchr(n, ':');
+    if(!p)
+      /* this is fine if we already added at least one header */
+      return numh ? CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT;
+    nlen = p - n;
+    p++; /* move past the colon */
+    while(*p == ' ')
+      p++;
+    v = p;
+    p = strchr(v, '\r');
+    if(!p) {
+      p = strchr(v, '\n');
+      if(p)
+        linelen = 1; /* LF only */
+      else {
+        p = strchr(v, '\0');
+        newline = FALSE; /* no newline */
+      }
+    }
+    else
+      linelen = 2; /* CRLF ending */
+    linelen += (p - n);
+    vlen = p - v;
+
+    if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen,
+                                      (uint8_t *)v, vlen)) {
+      failf(data, "hyper refused to add header '%s'", line);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    if(data->set.verbose) {
+      char *ptr = NULL;
+      if(!newline) {
+        ptr = aprintf("%.*s\r\n", (int)linelen, line);
+        if(!ptr)
+          return CURLE_OUT_OF_MEMORY;
+        Curl_debug(data, CURLINFO_HEADER_OUT, ptr, linelen + 2);
+        free(ptr);
+      }
+      else
+        Curl_debug(data, CURLINFO_HEADER_OUT, (char *)n, linelen);
+    }
+    numh++;
+    n += linelen;
+  } while(newline);
+  return CURLE_OK;
+}
+
+static CURLcode request_target(struct Curl_easy *data,
+                               struct connectdata *conn,
+                               const char *method,
+                               hyper_request *req)
+{
+  CURLcode result;
+  struct dynbuf r;
+
+  Curl_dyn_init(&r, DYN_HTTP_REQUEST);
+
+  result = Curl_http_target(data, conn, &r);
+  if(result)
+    return result;
+
+  if(hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
+                                       Curl_dyn_len(&r))) {
+    failf(data, "error setting uri to hyper");
+    result = CURLE_OUT_OF_MEMORY;
+  }
+  else
+    result = debug_request(data, method, Curl_dyn_ptr(&r));
+
+  Curl_dyn_free(&r);
+
+  return result;
+}
+
+static int uploadstreamed(void *userdata, hyper_context *ctx,
+                          hyper_buf **chunk)
+{
+  size_t fillcount;
+  struct Curl_easy *data = (struct Curl_easy *)userdata;
+  CURLcode result;
+  char *xfer_ulbuf;
+  size_t xfer_ulblen;
+  bool eos;
+  int rc = HYPER_POLL_ERROR;
+  (void)ctx;
+
+  result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
+  if(result)
+    goto out;
+
+  result = Curl_client_read(data, xfer_ulbuf, xfer_ulblen, &fillcount, &eos);
+  if(result)
+    goto out;
+
+  if(fillcount) {
+    hyper_buf *copy = hyper_buf_copy((uint8_t *)xfer_ulbuf, fillcount);
+    if(copy)
+      *chunk = copy;
+    else {
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
+    /* increasing the writebytecount here is a little premature but we
+       don't know exactly when the body is sent */
+    data->req.writebytecount += fillcount;
+    Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
+    rc = HYPER_POLL_READY;
+  }
+  else if(eos) {
+    *chunk = NULL;
+    rc = HYPER_POLL_READY;
+  }
+  else {
+    /* paused, save a waker */
+    if(data->hyp.send_body_waker)
+      hyper_waker_free(data->hyp.send_body_waker);
+    data->hyp.send_body_waker = hyper_context_waker(ctx);
+    rc = HYPER_POLL_PENDING;
+  }
+
+out:
+  Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);
+  data->state.hresult = result;
+  return rc;
+}
+
+/*
+ * finalize_request() sets up last headers and optional body settings
+ */
+static CURLcode finalize_request(struct Curl_easy *data,
+                                 hyper_headers *headers,
+                                 hyper_request *hyperreq,
+                                 Curl_HttpReq httpreq)
+{
+  CURLcode result = CURLE_OK;
+  struct dynbuf req;
+  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
+    Curl_pgrsSetUploadSize(data, 0); /* no request body */
+  else {
+    hyper_body *body;
+    Curl_dyn_init(&req, DYN_HTTP_REQUEST);
+    result = Curl_http_req_complete(data, &req, httpreq);
+    if(result)
+      return result;
+
+    /* if the "complete" above did produce more than the closing line,
+       parse the added headers */
+    if(Curl_dyn_len(&req) != 2 || strcmp(Curl_dyn_ptr(&req), "\r\n")) {
+      result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
+      if(result)
+        return result;
+    }
+
+    Curl_dyn_free(&req);
+
+    body = hyper_body_new();
+    hyper_body_set_userdata(body, data);
+    hyper_body_set_data_func(body, uploadstreamed);
+
+    if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
+      /* fail */
+      result = CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  return cr_hyper_add(data);
+}
+
+static CURLcode cookies(struct Curl_easy *data,
+                        struct connectdata *conn,
+                        hyper_headers *headers)
+{
+  struct dynbuf req;
+  CURLcode result;
+  Curl_dyn_init(&req, DYN_HTTP_REQUEST);
+
+  result = Curl_http_cookies(data, conn, &req);
+  if(!result)
+    result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
+  Curl_dyn_free(&req);
+  return result;
+}
+
+/* called on 1xx responses */
+static void http1xx_cb(void *arg, struct hyper_response *resp)
+{
+  struct Curl_easy *data = (struct Curl_easy *)arg;
+  hyper_headers *headers = NULL;
+  CURLcode result = CURLE_OK;
+  uint16_t http_status;
+  int http_version;
+  const uint8_t *reasonp;
+  size_t reason_len;
+
+  infof(data, "Got HTTP 1xx informational");
+
+  http_status = hyper_response_status(resp);
+  http_version = hyper_response_version(resp);
+  reasonp = hyper_response_reason_phrase(resp);
+  reason_len = hyper_response_reason_phrase_len(resp);
+
+  result = status_line(data, data->conn,
+                       http_status, http_version, reasonp, reason_len);
+  if(!result) {
+    headers = hyper_response_headers(resp);
+    if(!headers) {
+      failf(data, "hyperstream: couldn't get 1xx response headers");
+      result = CURLE_RECV_ERROR;
+    }
+  }
+  data->state.hresult = result;
+
+  if(!result) {
+    /* the headers are already received */
+    hyper_headers_foreach(headers, hyper_each_header, data);
+    /* this callback also sets data->state.hresult on error */
+
+    if(empty_header(data))
+      result = CURLE_OUT_OF_MEMORY;
+  }
+
+  if(data->state.hresult)
+    infof(data, "ERROR in 1xx, bail out");
+}
+
+/*
+ * Curl_http() gets called from the generic multi_do() function when an HTTP
+ * request is to be performed. This creates and sends a properly constructed
+ * HTTP request.
+ */
+CURLcode Curl_http(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct hyptransfer *h = &data->hyp;
+  hyper_io *io = NULL;
+  hyper_clientconn_options *options = NULL;
+  hyper_task *task = NULL; /* for the handshake */
+  hyper_task *sendtask = NULL; /* for the send */
+  hyper_clientconn *client = NULL;
+  hyper_request *req = NULL;
+  hyper_headers *headers = NULL;
+  hyper_task *handshake = NULL;
+  CURLcode result;
+  const char *p_accept; /* Accept: string */
+  const char *method;
+  Curl_HttpReq httpreq;
+  const char *te = NULL; /* transfer-encoding */
+  hyper_code rc;
+
+  /* Always consider the DO phase done after this function call, even if there
+     may be parts of the request that is not yet sent, since we can deal with
+     the rest of the request in the PERFORM phase. */
+  *done = TRUE;
+  result = Curl_client_start(data);
+  if(result)
+    return result;
+
+  /* Add collecting of headers written to client. For a new connection,
+   * we might have done that already, but reuse
+   * or multiplex needs it here as well. */
+  result = Curl_headers_init(data);
+  if(result)
+    return result;
+
+  infof(data, "Time for the Hyper dance");
+  memset(h, 0, sizeof(struct hyptransfer));
+
+  result = Curl_http_host(data, conn);
+  if(result)
+    return result;
+
+  Curl_http_method(data, conn, &method, &httpreq);
+
+  DEBUGASSERT(data->req.bytecount ==  0);
+
+  /* setup the authentication headers */
+  {
+    char *pq = NULL;
+    if(data->state.up.query) {
+      pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
+      if(!pq)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    result = Curl_http_output_auth(data, conn, method, httpreq,
+                                   (pq ? pq : data->state.up.path), FALSE);
+    free(pq);
+    if(result)
+      return result;
+  }
+
+  result = Curl_http_req_set_reader(data, httpreq, &te);
+  if(result)
+    goto error;
+
+  result = Curl_http_range(data, httpreq);
+  if(result)
+    return result;
+
+  result = Curl_http_useragent(data);
+  if(result)
+    return result;
+
+  io = hyper_io_new();
+  if(!io) {
+    failf(data, "Couldn't create hyper IO");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  /* tell Hyper how to read/write network data */
+  h->io_ctx.data = data;
+  h->io_ctx.sockindex = FIRSTSOCKET;
+  hyper_io_set_userdata(io, &h->io_ctx);
+  hyper_io_set_read(io, Curl_hyper_recv);
+  hyper_io_set_write(io, Curl_hyper_send);
+
+  /* create an executor to poll futures */
+  if(!h->exec) {
+    h->exec = hyper_executor_new();
+    if(!h->exec) {
+      failf(data, "Couldn't create hyper executor");
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
+  }
+
+  options = hyper_clientconn_options_new();
+  if(!options) {
+    failf(data, "Couldn't create hyper client options");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  if(conn->alpn == CURL_HTTP_VERSION_2) {
+    failf(data, "ALPN protocol h2 not supported with Hyper");
+    result = CURLE_UNSUPPORTED_PROTOCOL;
+    goto error;
+  }
+  hyper_clientconn_options_set_preserve_header_case(options, 1);
+  hyper_clientconn_options_set_preserve_header_order(options, 1);
+  hyper_clientconn_options_http1_allow_multiline_headers(options, 1);
+
+  hyper_clientconn_options_exec(options, h->exec);
+
+  /* "Both the `io` and the `options` are consumed in this function call" */
+  handshake = hyper_clientconn_handshake(io, options);
+  if(!handshake) {
+    failf(data, "Couldn't create hyper client handshake");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  io = NULL;
+  options = NULL;
+
+  if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
+    failf(data, "Couldn't hyper_executor_push the handshake");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  handshake = NULL; /* ownership passed on */
+
+  task = hyper_executor_poll(h->exec);
+  if(!task) {
+    failf(data, "Couldn't hyper_executor_poll the handshake");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+
+  client = hyper_task_value(task);
+  hyper_task_free(task);
+
+  req = hyper_request_new();
+  if(!req) {
+    failf(data, "Couldn't hyper_request_new");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+
+  if(!Curl_use_http_1_1plus(data, conn)) {
+    if(HYPERE_OK != hyper_request_set_version(req,
+                                              HYPER_HTTP_VERSION_1_0)) {
+      failf(data, "error setting HTTP version");
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
+  }
+
+  if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
+    failf(data, "error setting method");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+
+  result = request_target(data, conn, method, req);
+  if(result)
+    goto error;
+
+  headers = hyper_request_headers(req);
+  if(!headers) {
+    failf(data, "hyper_request_headers");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+
+  rc = hyper_request_on_informational(req, http1xx_cb, data);
+  if(rc) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+
+  if(data->state.aptr.host) {
+    result = Curl_hyper_header(data, headers, data->state.aptr.host);
+    if(result)
+      goto error;
+  }
+
+  if(data->state.aptr.proxyuserpwd) {
+    result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd);
+    if(result)
+      goto error;
+  }
+
+  if(data->state.aptr.userpwd) {
+    result = Curl_hyper_header(data, headers, data->state.aptr.userpwd);
+    if(result)
+      goto error;
+  }
+
+  if((data->state.use_range && data->state.aptr.rangeline)) {
+    result = Curl_hyper_header(data, headers, data->state.aptr.rangeline);
+    if(result)
+      goto error;
+  }
+
+  if(data->set.str[STRING_USERAGENT] &&
+     *data->set.str[STRING_USERAGENT] &&
+     data->state.aptr.uagent) {
+    result = Curl_hyper_header(data, headers, data->state.aptr.uagent);
+    if(result)
+      goto error;
+  }
+
+  p_accept = Curl_checkheaders(data,
+                               STRCONST("Accept"))?NULL:"Accept: */*\r\n";
+  if(p_accept) {
+    result = Curl_hyper_header(data, headers, p_accept);
+    if(result)
+      goto error;
+  }
+  if(te) {
+    result = Curl_hyper_header(data, headers, te);
+    if(result)
+      goto error;
+  }
+
+#ifndef CURL_DISABLE_ALTSVC
+  if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) {
+    char *altused = aprintf("Alt-Used: %s:%d\r\n",
+                            conn->conn_to_host.name, conn->conn_to_port);
+    if(!altused) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
+    result = Curl_hyper_header(data, headers, altused);
+    if(result)
+      goto error;
+    free(altused);
+  }
+#endif
+
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
+     !Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
+     !Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) {
+    result = Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive");
+    if(result)
+      goto error;
+  }
+#endif
+
+  Curl_safefree(data->state.aptr.ref);
+  if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) {
+    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
+    if(!data->state.aptr.ref)
+      result = CURLE_OUT_OF_MEMORY;
+    else
+      result = Curl_hyper_header(data, headers, data->state.aptr.ref);
+    if(result)
+      goto error;
+  }
+
+#ifdef HAVE_LIBZ
+  /* we only consider transfer-encoding magic if libz support is built-in */
+  result = Curl_transferencode(data);
+  if(result)
+    goto error;
+  result = Curl_hyper_header(data, headers, data->state.aptr.te);
+  if(result)
+    goto error;
+#endif
+
+  if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
+     data->set.str[STRING_ENCODING]) {
+    Curl_safefree(data->state.aptr.accept_encoding);
+    data->state.aptr.accept_encoding =
+      aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
+    if(!data->state.aptr.accept_encoding)
+      result = CURLE_OUT_OF_MEMORY;
+    else
+      result = Curl_hyper_header(data, headers,
+                                 data->state.aptr.accept_encoding);
+    if(result)
+      goto error;
+  }
+  else
+    Curl_safefree(data->state.aptr.accept_encoding);
+
+  result = cookies(data, conn, headers);
+  if(result)
+    goto error;
+
+  if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
+    result = Curl_ws_request(data, headers);
+
+  result = Curl_add_timecondition(data, headers);
+  if(result)
+    goto error;
+
+  result = Curl_add_custom_headers(data, FALSE, headers);
+  if(result)
+    goto error;
+
+  result = finalize_request(data, headers, req, httpreq);
+  if(result)
+    goto error;
+
+  Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
+
+  if(data->req.upload_chunky && data->req.authneg) {
+    data->req.upload_chunky = TRUE;
+  }
+  else {
+    data->req.upload_chunky = FALSE;
+  }
+  sendtask = hyper_clientconn_send(client, req);
+  if(!sendtask) {
+    failf(data, "hyper_clientconn_send");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  req = NULL;
+
+  if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
+    failf(data, "Couldn't hyper_executor_push the send");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  sendtask = NULL; /* ownership passed on */
+
+  hyper_clientconn_free(client);
+  client = NULL;
+
+  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
+    /* HTTP GET/HEAD download */
+    Curl_pgrsSetUploadSize(data, 0); /* nothing */
+  }
+
+  Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
+  conn->datastream = Curl_hyper_stream;
+
+  /* clear userpwd and proxyuserpwd to avoid reusing old credentials
+   * from reused connections */
+  Curl_safefree(data->state.aptr.userpwd);
+  Curl_safefree(data->state.aptr.proxyuserpwd);
+  return CURLE_OK;
+error:
+  DEBUGASSERT(result);
+  if(io)
+    hyper_io_free(io);
+
+  if(options)
+    hyper_clientconn_options_free(options);
+
+  if(handshake)
+    hyper_task_free(handshake);
+
+  if(client)
+    hyper_clientconn_free(client);
+
+  if(req)
+    hyper_request_free(req);
+
+  return result;
+}
+
+void Curl_hyper_done(struct Curl_easy *data)
+{
+  struct hyptransfer *h = &data->hyp;
+  if(h->exec) {
+    hyper_executor_free(h->exec);
+    h->exec = NULL;
+  }
+  if(h->read_waker) {
+    hyper_waker_free(h->read_waker);
+    h->read_waker = NULL;
+  }
+  if(h->write_waker) {
+    hyper_waker_free(h->write_waker);
+    h->write_waker = NULL;
+  }
+  if(h->send_body_waker) {
+    hyper_waker_free(h->send_body_waker);
+    h->send_body_waker = NULL;
+  }
+}
+
+static CURLcode cr_hyper_unpause(struct Curl_easy *data,
+                                 struct Curl_creader *reader)
+{
+  (void)reader;
+  if(data->hyp.send_body_waker) {
+    hyper_waker_wake(data->hyp.send_body_waker);
+    data->hyp.send_body_waker = NULL;
+  }
+  return CURLE_OK;
+}
+
+/* Hyper client reader, handling unpausing */
+static const struct Curl_crtype cr_hyper_protocol = {
+  "cr-hyper",
+  Curl_creader_def_init,
+  Curl_creader_def_read,
+  Curl_creader_def_close,
+  Curl_creader_def_needs_rewind,
+  Curl_creader_def_total_length,
+  Curl_creader_def_resume_from,
+  Curl_creader_def_rewind,
+  cr_hyper_unpause,
+  Curl_creader_def_done,
+  sizeof(struct Curl_creader)
+};
+
+static CURLcode cr_hyper_add(struct Curl_easy *data)
+{
+  struct Curl_creader *reader = NULL;
+  CURLcode result;
+
+  result = Curl_creader_create(&reader, data, &cr_hyper_protocol,
+                               CURL_CR_PROTOCOL);
+  if(!result)
+    result = Curl_creader_add(data, reader);
+
+  if(result && reader)
+    Curl_creader_free(data, reader);
+  return result;
+}
+
+#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */
Index: trunk/src/libs/curl-8.7.1/lib/c-hyper.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/c-hyper.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/c-hyper.h	(revision 104083)
@@ -0,0 +1,63 @@
+#ifndef HEADER_CURL_HYPER_H
+#define HEADER_CURL_HYPER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER)
+
+#include <hyper.h>
+
+struct hyp_io_ctx {
+  struct Curl_easy *data;
+  int sockindex;
+};
+
+/* per-transfer data for the Hyper backend */
+struct hyptransfer {
+  hyper_waker *write_waker;
+  hyper_waker *read_waker;
+  const hyper_executor *exec;
+  hyper_waker *send_body_waker;
+  struct hyp_io_ctx io_ctx;
+};
+
+size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
+                       uint8_t *buf, size_t buflen);
+size_t Curl_hyper_send(void *userp, hyper_context *ctx,
+                       const uint8_t *buf, size_t buflen);
+CURLcode Curl_hyper_stream(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           int *didwhat,
+                           int select_res);
+
+CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
+                           const char *line);
+void Curl_hyper_done(struct Curl_easy *);
+
+#else
+#define Curl_hyper_done(x)
+
+#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */
+#endif /* HEADER_CURL_HYPER_H */
Index: trunk/src/libs/curl-8.7.1/lib/cf-h1-proxy.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cf-h1-proxy.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cf-h1-proxy.c	(revision 104083)
@@ -0,0 +1,1100 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
+
+#include <curl/curl.h>
+#ifdef USE_HYPER
+#include <hyper.h>
+#endif
+#include "urldata.h"
+#include "dynbuf.h"
+#include "sendf.h"
+#include "http.h"
+#include "http1.h"
+#include "http_proxy.h"
+#include "url.h"
+#include "select.h"
+#include "progress.h"
+#include "cfilters.h"
+#include "cf-h1-proxy.h"
+#include "connect.h"
+#include "curl_trc.h"
+#include "curlx.h"
+#include "vtls/vtls.h"
+#include "transfer.h"
+#include "multiif.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+typedef enum {
+    H1_TUNNEL_INIT,     /* init/default/no tunnel state */
+    H1_TUNNEL_CONNECT,  /* CONNECT request is being send */
+    H1_TUNNEL_RECEIVE,  /* CONNECT answer is being received */
+    H1_TUNNEL_RESPONSE, /* CONNECT response received completely */
+    H1_TUNNEL_ESTABLISHED,
+    H1_TUNNEL_FAILED
+} h1_tunnel_state;
+
+/* struct for HTTP CONNECT tunneling */
+struct h1_tunnel_state {
+  struct HTTP CONNECT;
+  struct dynbuf rcvbuf;
+  struct dynbuf request_data;
+  size_t nsent;
+  size_t headerlines;
+  struct Curl_chunker ch;
+  enum keeponval {
+    KEEPON_DONE,
+    KEEPON_CONNECT,
+    KEEPON_IGNORE
+  } keepon;
+  curl_off_t cl; /* size of content to read and ignore */
+  h1_tunnel_state tunnel_state;
+  BIT(chunked_encoding);
+  BIT(close_connection);
+};
+
+
+static bool tunnel_is_established(struct h1_tunnel_state *ts)
+{
+  return ts && (ts->tunnel_state == H1_TUNNEL_ESTABLISHED);
+}
+
+static bool tunnel_is_failed(struct h1_tunnel_state *ts)
+{
+  return ts && (ts->tunnel_state == H1_TUNNEL_FAILED);
+}
+
+static CURLcode tunnel_reinit(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              struct h1_tunnel_state *ts)
+{
+  (void)data;
+  (void)cf;
+  DEBUGASSERT(ts);
+  Curl_dyn_reset(&ts->rcvbuf);
+  Curl_dyn_reset(&ts->request_data);
+  ts->tunnel_state = H1_TUNNEL_INIT;
+  ts->keepon = KEEPON_CONNECT;
+  ts->cl = 0;
+  ts->close_connection = FALSE;
+  return CURLE_OK;
+}
+
+static CURLcode tunnel_init(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            struct h1_tunnel_state **pts)
+{
+  struct h1_tunnel_state *ts;
+
+  if(cf->conn->handler->flags & PROTOPT_NOTCPPROXY) {
+    failf(data, "%s cannot be done over CONNECT", cf->conn->handler->scheme);
+    return CURLE_UNSUPPORTED_PROTOCOL;
+  }
+
+  ts = calloc(1, sizeof(*ts));
+  if(!ts)
+    return CURLE_OUT_OF_MEMORY;
+
+  infof(data, "allocate connect buffer");
+
+  Curl_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
+  Curl_dyn_init(&ts->request_data, DYN_HTTP_REQUEST);
+  Curl_httpchunk_init(data, &ts->ch, TRUE);
+
+  *pts =  ts;
+  connkeep(cf->conn, "HTTP proxy CONNECT");
+  return tunnel_reinit(cf, data, ts);
+}
+
+static void h1_tunnel_go_state(struct Curl_cfilter *cf,
+                               struct h1_tunnel_state *ts,
+                               h1_tunnel_state new_state,
+                               struct Curl_easy *data)
+{
+  if(ts->tunnel_state == new_state)
+    return;
+  /* entering this one */
+  switch(new_state) {
+  case H1_TUNNEL_INIT:
+    CURL_TRC_CF(data, cf, "new tunnel state 'init'");
+    tunnel_reinit(cf, data, ts);
+    break;
+
+  case H1_TUNNEL_CONNECT:
+    CURL_TRC_CF(data, cf, "new tunnel state 'connect'");
+    ts->tunnel_state = H1_TUNNEL_CONNECT;
+    ts->keepon = KEEPON_CONNECT;
+    Curl_dyn_reset(&ts->rcvbuf);
+    break;
+
+  case H1_TUNNEL_RECEIVE:
+    CURL_TRC_CF(data, cf, "new tunnel state 'receive'");
+    ts->tunnel_state = H1_TUNNEL_RECEIVE;
+    break;
+
+  case H1_TUNNEL_RESPONSE:
+    CURL_TRC_CF(data, cf, "new tunnel state 'response'");
+    ts->tunnel_state = H1_TUNNEL_RESPONSE;
+    break;
+
+  case H1_TUNNEL_ESTABLISHED:
+    CURL_TRC_CF(data, cf, "new tunnel state 'established'");
+    infof(data, "CONNECT phase completed");
+    data->state.authproxy.done = TRUE;
+    data->state.authproxy.multipass = FALSE;
+    FALLTHROUGH();
+  case H1_TUNNEL_FAILED:
+    if(new_state == H1_TUNNEL_FAILED)
+      CURL_TRC_CF(data, cf, "new tunnel state 'failed'");
+    ts->tunnel_state = new_state;
+    Curl_dyn_reset(&ts->rcvbuf);
+    Curl_dyn_reset(&ts->request_data);
+    /* restore the protocol pointer */
+    data->info.httpcode = 0; /* clear it as it might've been used for the
+                                proxy */
+    /* If a proxy-authorization header was used for the proxy, then we should
+       make sure that it isn't accidentally used for the document request
+       after we've connected. So let's free and clear it here. */
+    Curl_safefree(data->state.aptr.proxyuserpwd);
+#ifdef USE_HYPER
+    data->state.hconnect = FALSE;
+#endif
+    break;
+  }
+}
+
+static void tunnel_free(struct Curl_cfilter *cf,
+                        struct Curl_easy *data)
+{
+  struct h1_tunnel_state *ts = cf->ctx;
+  if(ts) {
+    h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
+    Curl_dyn_free(&ts->rcvbuf);
+    Curl_dyn_free(&ts->request_data);
+    Curl_httpchunk_free(data, &ts->ch);
+    free(ts);
+    cf->ctx = NULL;
+  }
+}
+
+static bool tunnel_want_send(struct h1_tunnel_state *ts)
+{
+  return (ts->tunnel_state == H1_TUNNEL_CONNECT);
+}
+
+#ifndef USE_HYPER
+static CURLcode start_CONNECT(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              struct h1_tunnel_state *ts)
+{
+  struct httpreq *req = NULL;
+  int http_minor;
+  CURLcode result;
+
+    /* This only happens if we've looped here due to authentication
+       reasons, and we don't really use the newly cloned URL here
+       then. Just free() it. */
+  Curl_safefree(data->req.newurl);
+
+  result = Curl_http_proxy_create_CONNECT(&req, cf, data, 1);
+  if(result)
+    goto out;
+
+  infof(data, "Establish HTTP proxy tunnel to %s", req->authority);
+
+  Curl_dyn_reset(&ts->request_data);
+  ts->nsent = 0;
+  ts->headerlines = 0;
+  http_minor = (cf->conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? 0 : 1;
+
+  result = Curl_h1_req_write_head(req, http_minor, &ts->request_data);
+  if(!result)
+    result = Curl_creader_set_null(data);
+
+out:
+  if(result)
+    failf(data, "Failed sending CONNECT to proxy");
+  if(req)
+    Curl_http_req_free(req);
+  return result;
+}
+
+static CURLcode send_CONNECT(struct Curl_cfilter *cf,
+                             struct Curl_easy *data,
+                             struct h1_tunnel_state *ts,
+                             bool *done)
+{
+  char *buf = Curl_dyn_ptr(&ts->request_data);
+  size_t request_len = Curl_dyn_len(&ts->request_data);
+  size_t blen = request_len;
+  CURLcode result = CURLE_OK;
+  ssize_t nwritten;
+
+  if(blen <= ts->nsent)
+    goto out;  /* we are done */
+
+  blen -= ts->nsent;
+  buf += ts->nsent;
+
+  nwritten = cf->next->cft->do_send(cf->next, data, buf, blen, &result);
+  if(nwritten < 0) {
+    if(result == CURLE_AGAIN) {
+      result = CURLE_OK;
+    }
+    goto out;
+  }
+
+  DEBUGASSERT(blen >= (size_t)nwritten);
+  ts->nsent += (size_t)nwritten;
+  Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)nwritten);
+
+out:
+  if(result)
+    failf(data, "Failed sending CONNECT to proxy");
+  *done = (!result && (ts->nsent >= request_len));
+  return result;
+}
+
+static CURLcode on_resp_header(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               struct h1_tunnel_state *ts,
+                               const char *header)
+{
+  CURLcode result = CURLE_OK;
+  struct SingleRequest *k = &data->req;
+  (void)cf;
+
+  if((checkprefix("WWW-Authenticate:", header) &&
+      (401 == k->httpcode)) ||
+     (checkprefix("Proxy-authenticate:", header) &&
+      (407 == k->httpcode))) {
+
+    bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
+    char *auth = Curl_copy_header_value(header);
+    if(!auth)
+      return CURLE_OUT_OF_MEMORY;
+
+    CURL_TRC_CF(data, cf, "CONNECT: fwd auth header '%s'", header);
+    result = Curl_http_input_auth(data, proxy, auth);
+
+    free(auth);
+
+    if(result)
+      return result;
+  }
+  else if(checkprefix("Content-Length:", header)) {
+    if(k->httpcode/100 == 2) {
+      /* A client MUST ignore any Content-Length or Transfer-Encoding
+         header fields received in a successful response to CONNECT.
+         "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
+      infof(data, "Ignoring Content-Length in CONNECT %03d response",
+            k->httpcode);
+    }
+    else {
+      (void)curlx_strtoofft(header + strlen("Content-Length:"),
+                            NULL, 10, &ts->cl);
+    }
+  }
+  else if(Curl_compareheader(header,
+                             STRCONST("Connection:"), STRCONST("close")))
+    ts->close_connection = TRUE;
+  else if(checkprefix("Transfer-Encoding:", header)) {
+    if(k->httpcode/100 == 2) {
+      /* A client MUST ignore any Content-Length or Transfer-Encoding
+         header fields received in a successful response to CONNECT.
+         "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
+      infof(data, "Ignoring Transfer-Encoding in "
+            "CONNECT %03d response", k->httpcode);
+    }
+    else if(Curl_compareheader(header,
+                               STRCONST("Transfer-Encoding:"),
+                               STRCONST("chunked"))) {
+      infof(data, "CONNECT responded chunked");
+      ts->chunked_encoding = TRUE;
+      /* reset our chunky engine */
+      Curl_httpchunk_reset(data, &ts->ch, TRUE);
+    }
+  }
+  else if(Curl_compareheader(header,
+                             STRCONST("Proxy-Connection:"),
+                             STRCONST("close")))
+    ts->close_connection = TRUE;
+  else if(!strncmp(header, "HTTP/1.", 7) &&
+          ((header[7] == '0') || (header[7] == '1')) &&
+          (header[8] == ' ') &&
+          ISDIGIT(header[9]) && ISDIGIT(header[10]) && ISDIGIT(header[11]) &&
+          !ISDIGIT(header[12])) {
+    /* store the HTTP code from the proxy */
+    data->info.httpproxycode =  k->httpcode = (header[9] - '0') * 100 +
+      (header[10] - '0') * 10 + (header[11] - '0');
+  }
+  return result;
+}
+
+static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  struct h1_tunnel_state *ts,
+                                  bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct SingleRequest *k = &data->req;
+  char *linep;
+  size_t line_len;
+  int error, writetype;
+
+#define SELECT_OK      0
+#define SELECT_ERROR   1
+
+  error = SELECT_OK;
+  *done = FALSE;
+
+  if(!Curl_conn_data_pending(data, cf->sockindex))
+    return CURLE_OK;
+
+  while(ts->keepon) {
+    ssize_t nread;
+    char byte;
+
+    /* Read one byte at a time to avoid a race condition. Wait at most one
+       second before looping to ensure continuous pgrsUpdates. */
+    result = Curl_conn_recv(data, cf->sockindex, &byte, 1, &nread);
+    if(result == CURLE_AGAIN)
+      /* socket buffer drained, return */
+      return CURLE_OK;
+
+    if(Curl_pgrsUpdate(data))
+      return CURLE_ABORTED_BY_CALLBACK;
+
+    if(result) {
+      ts->keepon = KEEPON_DONE;
+      break;
+    }
+
+    if(nread <= 0) {
+      if(data->set.proxyauth && data->state.authproxy.avail &&
+         data->state.aptr.proxyuserpwd) {
+        /* proxy auth was requested and there was proxy auth available,
+           then deem this as "mere" proxy disconnect */
+        ts->close_connection = TRUE;
+        infof(data, "Proxy CONNECT connection closed");
+      }
+      else {
+        error = SELECT_ERROR;
+        failf(data, "Proxy CONNECT aborted");
+      }
+      ts->keepon = KEEPON_DONE;
+      break;
+    }
+
+    if(ts->keepon == KEEPON_IGNORE) {
+      /* This means we are currently ignoring a response-body */
+
+      if(ts->cl) {
+        /* A Content-Length based body: simply count down the counter
+           and make sure to break out of the loop when we're done! */
+        ts->cl--;
+        if(ts->cl <= 0) {
+          ts->keepon = KEEPON_DONE;
+          break;
+        }
+      }
+      else if(ts->chunked_encoding) {
+        /* chunked-encoded body, so we need to do the chunked dance
+           properly to know when the end of the body is reached */
+        size_t consumed = 0;
+
+        /* now parse the chunked piece of data so that we can
+           properly tell when the stream ends */
+        result = Curl_httpchunk_read(data, &ts->ch, &byte, 1, &consumed);
+        if(result)
+          return result;
+        if(Curl_httpchunk_is_done(data, &ts->ch)) {
+          /* we're done reading chunks! */
+          infof(data, "chunk reading DONE");
+          ts->keepon = KEEPON_DONE;
+        }
+      }
+      continue;
+    }
+
+    if(Curl_dyn_addn(&ts->rcvbuf, &byte, 1)) {
+      failf(data, "CONNECT response too large");
+      return CURLE_RECV_ERROR;
+    }
+
+    /* if this is not the end of a header line then continue */
+    if(byte != 0x0a)
+      continue;
+
+    ts->headerlines++;
+    linep = Curl_dyn_ptr(&ts->rcvbuf);
+    line_len = Curl_dyn_len(&ts->rcvbuf); /* amount of bytes in this line */
+
+    /* output debug if that is requested */
+    Curl_debug(data, CURLINFO_HEADER_IN, linep, line_len);
+
+    /* send the header to the callback */
+    writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
+      (ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
+    result = Curl_client_write(data, writetype, linep, line_len);
+    if(result)
+      return result;
+
+    result = Curl_bump_headersize(data, line_len, TRUE);
+    if(result)
+      return result;
+
+    /* Newlines are CRLF, so the CR is ignored as the line isn't
+       really terminated until the LF comes. Treat a following CR
+       as end-of-headers as well.*/
+
+    if(('\r' == linep[0]) ||
+       ('\n' == linep[0])) {
+      /* end of response-headers from the proxy */
+
+      if((407 == k->httpcode) && !data->state.authproblem) {
+        /* If we get a 407 response code with content length
+           when we have no auth problem, we must ignore the
+           whole response-body */
+        ts->keepon = KEEPON_IGNORE;
+
+        if(ts->cl) {
+          infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T
+                " bytes of response-body", ts->cl);
+        }
+        else if(ts->chunked_encoding) {
+          infof(data, "Ignore chunked response-body");
+        }
+        else {
+          /* without content-length or chunked encoding, we
+             can't keep the connection alive since the close is
+             the end signal so we bail out at once instead */
+          CURL_TRC_CF(data, cf, "CONNECT: no content-length or chunked");
+          ts->keepon = KEEPON_DONE;
+        }
+      }
+      else {
+        ts->keepon = KEEPON_DONE;
+      }
+
+      DEBUGASSERT(ts->keepon == KEEPON_IGNORE
+                  || ts->keepon == KEEPON_DONE);
+      continue;
+    }
+
+    result = on_resp_header(cf, data, ts, linep);
+    if(result)
+      return result;
+
+    Curl_dyn_reset(&ts->rcvbuf);
+  } /* while there's buffer left and loop is requested */
+
+  if(error)
+    result = CURLE_RECV_ERROR;
+  *done = (ts->keepon == KEEPON_DONE);
+  if(!result && *done && data->info.httpproxycode/100 != 2) {
+    /* Deal with the possibly already received authenticate
+       headers. 'newurl' is set to a new URL if we must loop. */
+    result = Curl_http_auth_act(data);
+  }
+  return result;
+}
+
+#else /* USE_HYPER */
+
+static CURLcode CONNECT_host(struct Curl_cfilter *cf,
+                             struct Curl_easy *data,
+                             char **pauthority,
+                             char **phost_header)
+{
+  const char *hostname;
+  int port;
+  bool ipv6_ip;
+  CURLcode result;
+  char *authority; /* for CONNECT, the destination host + port */
+  char *host_header = NULL; /* Host: authority */
+
+  result = Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip);
+  if(result)
+    return result;
+
+  authority = aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
+                      port);
+  if(!authority)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* If user is not overriding the Host header later */
+  if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("Host"))) {
+    host_header = aprintf("Host: %s\r\n", authority);
+    if(!host_header) {
+      free(authority);
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  *pauthority = authority;
+  *phost_header = host_header;
+  return CURLE_OK;
+}
+
+/* The Hyper version of CONNECT */
+static CURLcode start_CONNECT(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              struct h1_tunnel_state *ts)
+{
+  struct connectdata *conn = cf->conn;
+  struct hyptransfer *h = &data->hyp;
+  curl_socket_t tunnelsocket = Curl_conn_cf_get_socket(cf, data);
+  hyper_io *io = NULL;
+  hyper_request *req = NULL;
+  hyper_headers *headers = NULL;
+  hyper_clientconn_options *options = NULL;
+  hyper_task *handshake = NULL;
+  hyper_task *task = NULL; /* for the handshake */
+  hyper_clientconn *client = NULL;
+  hyper_task *sendtask = NULL; /* for the send */
+  char *authority = NULL; /* for CONNECT */
+  char *host_header = NULL; /* Host: */
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  (void)ts;
+
+  io = hyper_io_new();
+  if(!io) {
+    failf(data, "Couldn't create hyper IO");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  /* tell Hyper how to read/write network data */
+  h->io_ctx.data = data;
+  h->io_ctx.sockindex = cf->sockindex;
+  hyper_io_set_userdata(io, &h->io_ctx);
+  hyper_io_set_read(io, Curl_hyper_recv);
+  hyper_io_set_write(io, Curl_hyper_send);
+  conn->sockfd = tunnelsocket;
+
+  data->state.hconnect = TRUE;
+
+  /* create an executor to poll futures */
+  if(!h->exec) {
+    h->exec = hyper_executor_new();
+    if(!h->exec) {
+      failf(data, "Couldn't create hyper executor");
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
+  }
+
+  options = hyper_clientconn_options_new();
+  if(!options) {
+    failf(data, "Couldn't create hyper client options");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  hyper_clientconn_options_set_preserve_header_case(options, 1);
+  hyper_clientconn_options_set_preserve_header_order(options, 1);
+
+  hyper_clientconn_options_exec(options, h->exec);
+
+  /* "Both the `io` and the `options` are consumed in this function
+     call" */
+  handshake = hyper_clientconn_handshake(io, options);
+  if(!handshake) {
+    failf(data, "Couldn't create hyper client handshake");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  io = NULL;
+  options = NULL;
+
+  if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
+    failf(data, "Couldn't hyper_executor_push the handshake");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  handshake = NULL; /* ownership passed on */
+
+  task = hyper_executor_poll(h->exec);
+  if(!task) {
+    failf(data, "Couldn't hyper_executor_poll the handshake");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+
+  client = hyper_task_value(task);
+  hyper_task_free(task);
+
+  req = hyper_request_new();
+  if(!req) {
+    failf(data, "Couldn't hyper_request_new");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
+                              strlen("CONNECT"))) {
+    failf(data, "error setting method");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+
+    /* This only happens if we've looped here due to authentication
+       reasons, and we don't really use the newly cloned URL here
+       then. Just free() it. */
+  Curl_safefree(data->req.newurl);
+
+  result = CONNECT_host(cf, data, &authority, &host_header);
+  if(result)
+    goto error;
+
+  infof(data, "Establish HTTP proxy tunnel to %s", authority);
+
+  if(hyper_request_set_uri(req, (uint8_t *)authority,
+                           strlen(authority))) {
+    failf(data, "error setting path");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  if(data->set.verbose) {
+    char *se = aprintf("CONNECT %s HTTP/1.1\r\n", authority);
+    if(!se) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
+    Curl_debug(data, CURLINFO_HEADER_OUT, se, strlen(se));
+    free(se);
+  }
+  /* Setup the proxy-authorization header, if any */
+  result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
+                                 authority, TRUE);
+  if(result)
+    goto error;
+  Curl_safefree(authority);
+
+  /* default is 1.1 */
+  if((conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) &&
+     (HYPERE_OK != hyper_request_set_version(req,
+                                             HYPER_HTTP_VERSION_1_0))) {
+    failf(data, "error setting HTTP version");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+
+  headers = hyper_request_headers(req);
+  if(!headers) {
+    failf(data, "hyper_request_headers");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  if(host_header) {
+    result = Curl_hyper_header(data, headers, host_header);
+    if(result)
+      goto error;
+    Curl_safefree(host_header);
+  }
+
+  if(data->state.aptr.proxyuserpwd) {
+    result = Curl_hyper_header(data, headers,
+                               data->state.aptr.proxyuserpwd);
+    if(result)
+      goto error;
+  }
+
+  if(!Curl_checkProxyheaders(data, conn, STRCONST("User-Agent")) &&
+     data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) {
+    struct dynbuf ua;
+    Curl_dyn_init(&ua, DYN_HTTP_REQUEST);
+    result = Curl_dyn_addf(&ua, "User-Agent: %s\r\n",
+                           data->set.str[STRING_USERAGENT]);
+    if(result)
+      goto error;
+    result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua));
+    if(result)
+      goto error;
+    Curl_dyn_free(&ua);
+  }
+
+  if(!Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) {
+    result = Curl_hyper_header(data, headers,
+                               "Proxy-Connection: Keep-Alive");
+    if(result)
+      goto error;
+  }
+
+  result = Curl_add_custom_headers(data, TRUE, headers);
+  if(result)
+    goto error;
+
+  result = Curl_creader_set_null(data);
+  if(result)
+    goto error;
+
+  sendtask = hyper_clientconn_send(client, req);
+  if(!sendtask) {
+    failf(data, "hyper_clientconn_send");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  req = NULL;
+
+  if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
+    failf(data, "Couldn't hyper_executor_push the send");
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+  sendtask = NULL; /* ownership passed on */
+
+  hyper_clientconn_free(client);
+  client = NULL;
+
+error:
+  free(host_header);
+  free(authority);
+  if(io)
+    hyper_io_free(io);
+  if(options)
+    hyper_clientconn_options_free(options);
+  if(handshake)
+    hyper_task_free(handshake);
+  if(client)
+    hyper_clientconn_free(client);
+  if(req)
+    hyper_request_free(req);
+
+  return result;
+}
+
+static CURLcode send_CONNECT(struct Curl_cfilter *cf,
+                             struct Curl_easy *data,
+                             struct h1_tunnel_state *ts,
+                             bool *done)
+{
+  struct hyptransfer *h = &data->hyp;
+  struct connectdata *conn = cf->conn;
+  hyper_task *task = NULL;
+  hyper_error *hypererr = NULL;
+  CURLcode result = CURLE_OK;
+
+  (void)ts;
+  (void)conn;
+  do {
+    task = hyper_executor_poll(h->exec);
+    if(task) {
+      bool error = hyper_task_type(task) == HYPER_TASK_ERROR;
+      if(error)
+        hypererr = hyper_task_value(task);
+      hyper_task_free(task);
+      if(error) {
+        /* this could probably use a better error code? */
+        result = CURLE_OUT_OF_MEMORY;
+        goto error;
+      }
+    }
+  } while(task);
+error:
+  *done = (result == CURLE_OK);
+  if(hypererr) {
+    uint8_t errbuf[256];
+    size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
+    failf(data, "Hyper: %.*s", (int)errlen, errbuf);
+    hyper_error_free(hypererr);
+  }
+  return result;
+}
+
+static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  struct h1_tunnel_state *ts,
+                                  bool *done)
+{
+  struct hyptransfer *h = &data->hyp;
+  CURLcode result;
+  int didwhat;
+
+  (void)ts;
+  result = Curl_hyper_stream(data, cf->conn, &didwhat,
+                             CURL_CSELECT_IN | CURL_CSELECT_OUT);
+  *done = data->req.done;
+  if(result || !*done)
+    return result;
+  if(h->exec) {
+    hyper_executor_free(h->exec);
+    h->exec = NULL;
+  }
+  if(h->read_waker) {
+    hyper_waker_free(h->read_waker);
+    h->read_waker = NULL;
+  }
+  if(h->write_waker) {
+    hyper_waker_free(h->write_waker);
+    h->write_waker = NULL;
+  }
+  return result;
+}
+
+#endif /* USE_HYPER */
+
+static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           struct h1_tunnel_state *ts)
+{
+  struct connectdata *conn = cf->conn;
+  CURLcode result;
+  bool done;
+
+  if(tunnel_is_established(ts))
+    return CURLE_OK;
+  if(tunnel_is_failed(ts))
+    return CURLE_RECV_ERROR; /* Need a cfilter close and new bootstrap */
+
+  do {
+    timediff_t check;
+
+    check = Curl_timeleft(data, NULL, TRUE);
+    if(check <= 0) {
+      failf(data, "Proxy CONNECT aborted due to timeout");
+      result = CURLE_OPERATION_TIMEDOUT;
+      goto out;
+    }
+
+    switch(ts->tunnel_state) {
+    case H1_TUNNEL_INIT:
+      /* Prepare the CONNECT request and make a first attempt to send. */
+      CURL_TRC_CF(data, cf, "CONNECT start");
+      result = start_CONNECT(cf, data, ts);
+      if(result)
+        goto out;
+      h1_tunnel_go_state(cf, ts, H1_TUNNEL_CONNECT, data);
+      FALLTHROUGH();
+
+    case H1_TUNNEL_CONNECT:
+      /* see that the request is completely sent */
+      CURL_TRC_CF(data, cf, "CONNECT send");
+      result = send_CONNECT(cf, data, ts, &done);
+      if(result || !done)
+        goto out;
+      h1_tunnel_go_state(cf, ts, H1_TUNNEL_RECEIVE, data);
+      FALLTHROUGH();
+
+    case H1_TUNNEL_RECEIVE:
+      /* read what is there */
+      CURL_TRC_CF(data, cf, "CONNECT receive");
+      result = recv_CONNECT_resp(cf, data, ts, &done);
+      if(Curl_pgrsUpdate(data)) {
+        result = CURLE_ABORTED_BY_CALLBACK;
+        goto out;
+      }
+      /* error or not complete yet. return for more multi-multi */
+      if(result || !done)
+        goto out;
+      /* got it */
+      h1_tunnel_go_state(cf, ts, H1_TUNNEL_RESPONSE, data);
+      FALLTHROUGH();
+
+    case H1_TUNNEL_RESPONSE:
+      CURL_TRC_CF(data, cf, "CONNECT response");
+      if(data->req.newurl) {
+        /* not the "final" response, we need to do a follow up request.
+         * If the other side indicated a connection close, or if someone
+         * else told us to close this connection, do so now.
+         */
+        Curl_req_soft_reset(&data->req, data);
+        if(ts->close_connection || conn->bits.close) {
+          /* Close this filter and the sub-chain, re-connect the
+           * sub-chain and continue. Closing this filter will
+           * reset our tunnel state. To avoid recursion, we return
+           * and expect to be called again.
+           */
+          CURL_TRC_CF(data, cf, "CONNECT need to close+open");
+          infof(data, "Connect me again please");
+          Curl_conn_cf_close(cf, data);
+          connkeep(conn, "HTTP proxy CONNECT");
+          result = Curl_conn_cf_connect(cf->next, data, FALSE, &done);
+          goto out;
+        }
+        else {
+          /* staying on this connection, reset state */
+          h1_tunnel_go_state(cf, ts, H1_TUNNEL_INIT, data);
+        }
+      }
+      break;
+
+    default:
+      break;
+    }
+
+  } while(data->req.newurl);
+
+  DEBUGASSERT(ts->tunnel_state == H1_TUNNEL_RESPONSE);
+  if(data->info.httpproxycode/100 != 2) {
+    /* a non-2xx response and we have no next url to try. */
+    Curl_safefree(data->req.newurl);
+    /* failure, close this connection to avoid reuse */
+    streamclose(conn, "proxy CONNECT failure");
+    h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
+    failf(data, "CONNECT tunnel failed, response %d", data->req.httpcode);
+    return CURLE_RECV_ERROR;
+  }
+  /* 2xx response, SUCCESS! */
+  h1_tunnel_go_state(cf, ts, H1_TUNNEL_ESTABLISHED, data);
+  infof(data, "CONNECT tunnel established, response %d",
+        data->info.httpproxycode);
+  result = CURLE_OK;
+
+out:
+  if(result)
+    h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
+  return result;
+}
+
+static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    bool blocking, bool *done)
+{
+  CURLcode result;
+  struct h1_tunnel_state *ts = cf->ctx;
+
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  CURL_TRC_CF(data, cf, "connect");
+  result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+  if(result || !*done)
+    return result;
+
+  *done = FALSE;
+  if(!ts) {
+    result = tunnel_init(cf, data, &ts);
+    if(result)
+      return result;
+    cf->ctx = ts;
+  }
+
+  /* TODO: can we do blocking? */
+  /* We want "seamless" operations through HTTP proxy tunnel */
+
+  result = H1_CONNECT(cf, data, ts);
+  if(result)
+    goto out;
+  Curl_safefree(data->state.aptr.proxyuserpwd);
+
+out:
+  *done = (result == CURLE_OK) && tunnel_is_established(cf->ctx);
+  if(*done) {
+    cf->connected = TRUE;
+    /* The real request will follow the CONNECT, reset request partially */
+    Curl_req_soft_reset(&data->req, data);
+    Curl_client_reset(data);
+    Curl_pgrsSetUploadCounter(data, 0);
+    Curl_pgrsSetDownloadCounter(data, 0);
+
+    tunnel_free(cf, data);
+  }
+  return result;
+}
+
+static void cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf,
+                                        struct Curl_easy *data,
+                                        struct easy_pollset *ps)
+{
+  struct h1_tunnel_state *ts = cf->ctx;
+
+  if(!cf->connected) {
+    /* If we are not connected, but the filter "below" is
+     * and not waiting on something, we are tunneling. */
+    curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
+    if(ts) {
+      /* when we've sent a CONNECT to a proxy, we should rather either
+         wait for the socket to become readable to be able to get the
+         response headers or if we're still sending the request, wait
+         for write. */
+      if(tunnel_want_send(ts))
+        Curl_pollset_set_out_only(data, ps, sock);
+      else
+        Curl_pollset_set_in_only(data, ps, sock);
+    }
+    else
+      Curl_pollset_set_out_only(data, ps, sock);
+  }
+}
+
+static void cf_h1_proxy_destroy(struct Curl_cfilter *cf,
+                                struct Curl_easy *data)
+{
+  CURL_TRC_CF(data, cf, "destroy");
+  tunnel_free(cf, data);
+}
+
+static void cf_h1_proxy_close(struct Curl_cfilter *cf,
+                              struct Curl_easy *data)
+{
+  CURL_TRC_CF(data, cf, "close");
+  cf->connected = FALSE;
+  if(cf->ctx) {
+    h1_tunnel_go_state(cf, cf->ctx, H1_TUNNEL_INIT, data);
+  }
+  if(cf->next)
+    cf->next->cft->do_close(cf->next, data);
+}
+
+
+struct Curl_cftype Curl_cft_h1_proxy = {
+  "H1-PROXY",
+  CF_TYPE_IP_CONNECT,
+  0,
+  cf_h1_proxy_destroy,
+  cf_h1_proxy_connect,
+  cf_h1_proxy_close,
+  Curl_cf_http_proxy_get_host,
+  cf_h1_proxy_adjust_pollset,
+  Curl_cf_def_data_pending,
+  Curl_cf_def_send,
+  Curl_cf_def_recv,
+  Curl_cf_def_cntrl,
+  Curl_cf_def_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  Curl_cf_def_query,
+};
+
+CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf_at,
+                                       struct Curl_easy *data)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result;
+
+  (void)data;
+  result = Curl_cf_create(&cf, &Curl_cft_h1_proxy, NULL);
+  if(!result)
+    Curl_conn_cf_insert_after(cf_at, cf);
+  return result;
+}
+
+#endif /* !CURL_DISABLE_PROXY && ! CURL_DISABLE_HTTP */
Index: trunk/src/libs/curl-8.7.1/lib/cf-h1-proxy.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cf-h1-proxy.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cf-h1-proxy.h	(revision 104083)
@@ -0,0 +1,39 @@
+#ifndef HEADER_CURL_H1_PROXY_H
+#define HEADER_CURL_H1_PROXY_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
+
+CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf,
+                                       struct Curl_easy *data);
+
+extern struct Curl_cftype Curl_cft_h1_proxy;
+
+
+#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */
+
+#endif /* HEADER_CURL_H1_PROXY_H */
Index: trunk/src/libs/curl-8.7.1/lib/cf-h2-proxy.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cf-h2-proxy.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cf-h2-proxy.c	(revision 104083)
@@ -0,0 +1,1576 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY)
+
+#include <nghttp2/nghttp2.h>
+#include "urldata.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "curl_trc.h"
+#include "bufq.h"
+#include "dynbuf.h"
+#include "dynhds.h"
+#include "http1.h"
+#include "http2.h"
+#include "http_proxy.h"
+#include "multiif.h"
+#include "sendf.h"
+#include "cf-h2-proxy.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define PROXY_H2_CHUNK_SIZE  (16*1024)
+
+#define PROXY_HTTP2_HUGE_WINDOW_SIZE (100 * 1024 * 1024)
+#define H2_TUNNEL_WINDOW_SIZE        (10 * 1024 * 1024)
+
+#define PROXY_H2_NW_RECV_CHUNKS  (H2_TUNNEL_WINDOW_SIZE / PROXY_H2_CHUNK_SIZE)
+#define PROXY_H2_NW_SEND_CHUNKS   1
+
+#define H2_TUNNEL_RECV_CHUNKS   (H2_TUNNEL_WINDOW_SIZE / PROXY_H2_CHUNK_SIZE)
+#define H2_TUNNEL_SEND_CHUNKS   ((128 * 1024) / PROXY_H2_CHUNK_SIZE)
+
+
+typedef enum {
+    H2_TUNNEL_INIT,     /* init/default/no tunnel state */
+    H2_TUNNEL_CONNECT,  /* CONNECT request is being send */
+    H2_TUNNEL_RESPONSE, /* CONNECT response received completely */
+    H2_TUNNEL_ESTABLISHED,
+    H2_TUNNEL_FAILED
+} h2_tunnel_state;
+
+struct tunnel_stream {
+  struct http_resp *resp;
+  struct bufq recvbuf;
+  struct bufq sendbuf;
+  char *authority;
+  int32_t stream_id;
+  uint32_t error;
+  size_t upload_blocked_len;
+  h2_tunnel_state state;
+  BIT(has_final_response);
+  BIT(closed);
+  BIT(reset);
+};
+
+static CURLcode tunnel_stream_init(struct Curl_cfilter *cf,
+                                    struct tunnel_stream *ts)
+{
+  const char *hostname;
+  int port;
+  bool ipv6_ip;
+  CURLcode result;
+
+  ts->state = H2_TUNNEL_INIT;
+  ts->stream_id = -1;
+  Curl_bufq_init2(&ts->recvbuf, PROXY_H2_CHUNK_SIZE, H2_TUNNEL_RECV_CHUNKS,
+                  BUFQ_OPT_SOFT_LIMIT);
+  Curl_bufq_init(&ts->sendbuf, PROXY_H2_CHUNK_SIZE, H2_TUNNEL_SEND_CHUNKS);
+
+  result = Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip);
+  if(result)
+    return result;
+
+  ts->authority = /* host:port with IPv6 support */
+    aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", port);
+  if(!ts->authority)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+static void tunnel_stream_clear(struct tunnel_stream *ts)
+{
+  Curl_http_resp_free(ts->resp);
+  Curl_bufq_free(&ts->recvbuf);
+  Curl_bufq_free(&ts->sendbuf);
+  Curl_safefree(ts->authority);
+  memset(ts, 0, sizeof(*ts));
+  ts->state = H2_TUNNEL_INIT;
+}
+
+static void h2_tunnel_go_state(struct Curl_cfilter *cf,
+                               struct tunnel_stream *ts,
+                               h2_tunnel_state new_state,
+                               struct Curl_easy *data)
+{
+  (void)cf;
+
+  if(ts->state == new_state)
+    return;
+  /* leaving this one */
+  switch(ts->state) {
+  case H2_TUNNEL_CONNECT:
+    data->req.ignorebody = FALSE;
+    break;
+  default:
+    break;
+  }
+  /* entering this one */
+  switch(new_state) {
+  case H2_TUNNEL_INIT:
+    CURL_TRC_CF(data, cf, "[%d] new tunnel state 'init'", ts->stream_id);
+    tunnel_stream_clear(ts);
+    break;
+
+  case H2_TUNNEL_CONNECT:
+    CURL_TRC_CF(data, cf, "[%d] new tunnel state 'connect'", ts->stream_id);
+    ts->state = H2_TUNNEL_CONNECT;
+    break;
+
+  case H2_TUNNEL_RESPONSE:
+    CURL_TRC_CF(data, cf, "[%d] new tunnel state 'response'", ts->stream_id);
+    ts->state = H2_TUNNEL_RESPONSE;
+    break;
+
+  case H2_TUNNEL_ESTABLISHED:
+    CURL_TRC_CF(data, cf, "[%d] new tunnel state 'established'",
+                ts->stream_id);
+    infof(data, "CONNECT phase completed");
+    data->state.authproxy.done = TRUE;
+    data->state.authproxy.multipass = FALSE;
+    FALLTHROUGH();
+  case H2_TUNNEL_FAILED:
+    if(new_state == H2_TUNNEL_FAILED)
+      CURL_TRC_CF(data, cf, "[%d] new tunnel state 'failed'", ts->stream_id);
+    ts->state = new_state;
+    /* If a proxy-authorization header was used for the proxy, then we should
+       make sure that it isn't accidentally used for the document request
+       after we've connected. So let's free and clear it here. */
+    Curl_safefree(data->state.aptr.proxyuserpwd);
+    break;
+  }
+}
+
+struct cf_h2_proxy_ctx {
+  nghttp2_session *h2;
+  /* The easy handle used in the current filter call, cleared at return */
+  struct cf_call_data call_data;
+
+  struct bufq inbufq;  /* network receive buffer */
+  struct bufq outbufq; /* network send buffer */
+
+  struct tunnel_stream tunnel; /* our tunnel CONNECT stream */
+  int32_t goaway_error;
+  int32_t last_stream_id;
+  BIT(conn_closed);
+  BIT(goaway);
+  BIT(nw_out_blocked);
+};
+
+/* How to access `call_data` from a cf_h2 filter */
+#undef CF_CTX_CALL_DATA
+#define CF_CTX_CALL_DATA(cf)  \
+  ((struct cf_h2_proxy_ctx *)(cf)->ctx)->call_data
+
+static void cf_h2_proxy_ctx_clear(struct cf_h2_proxy_ctx *ctx)
+{
+  struct cf_call_data save = ctx->call_data;
+
+  if(ctx->h2) {
+    nghttp2_session_del(ctx->h2);
+  }
+  Curl_bufq_free(&ctx->inbufq);
+  Curl_bufq_free(&ctx->outbufq);
+  tunnel_stream_clear(&ctx->tunnel);
+  memset(ctx, 0, sizeof(*ctx));
+  ctx->call_data = save;
+}
+
+static void cf_h2_proxy_ctx_free(struct cf_h2_proxy_ctx *ctx)
+{
+  if(ctx) {
+    cf_h2_proxy_ctx_clear(ctx);
+    free(ctx);
+  }
+}
+
+static void drain_tunnel(struct Curl_cfilter *cf,
+                         struct Curl_easy *data,
+                         struct tunnel_stream *tunnel)
+{
+  unsigned char bits;
+
+  (void)cf;
+  bits = CURL_CSELECT_IN;
+  if(!tunnel->closed && !tunnel->reset && tunnel->upload_blocked_len)
+    bits |= CURL_CSELECT_OUT;
+  if(data->state.select_bits != bits) {
+    CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x",
+                tunnel->stream_id, bits);
+    data->state.select_bits = bits;
+    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+  }
+}
+
+static ssize_t proxy_nw_in_reader(void *reader_ctx,
+                                  unsigned char *buf, size_t buflen,
+                                  CURLcode *err)
+{
+  struct Curl_cfilter *cf = reader_ctx;
+  ssize_t nread;
+
+  if(cf) {
+    struct Curl_easy *data = CF_DATA_CURRENT(cf);
+    nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err);
+    CURL_TRC_CF(data, cf, "[0] nw_in_reader(len=%zu) -> %zd, %d",
+                buflen, nread, *err);
+  }
+  else {
+    nread = 0;
+  }
+  return nread;
+}
+
+static ssize_t proxy_h2_nw_out_writer(void *writer_ctx,
+                                      const unsigned char *buf, size_t buflen,
+                                      CURLcode *err)
+{
+  struct Curl_cfilter *cf = writer_ctx;
+  ssize_t nwritten;
+
+  if(cf) {
+    struct Curl_easy *data = CF_DATA_CURRENT(cf);
+    nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen,
+                                 err);
+    CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %zd, %d",
+                buflen, nwritten, *err);
+  }
+  else {
+    nwritten = 0;
+  }
+  return nwritten;
+}
+
+static int proxy_h2_client_new(struct Curl_cfilter *cf,
+                               nghttp2_session_callbacks *cbs)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  nghttp2_option *o;
+
+  int rc = nghttp2_option_new(&o);
+  if(rc)
+    return rc;
+  /* We handle window updates ourself to enforce buffer limits */
+  nghttp2_option_set_no_auto_window_update(o, 1);
+#if NGHTTP2_VERSION_NUM >= 0x013200
+  /* with 1.50.0 */
+  /* turn off RFC 9113 leading and trailing white spaces validation against
+     HTTP field value. */
+  nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(o, 1);
+#endif
+  rc = nghttp2_session_client_new2(&ctx->h2, cbs, cf, o);
+  nghttp2_option_del(o);
+  return rc;
+}
+
+static ssize_t on_session_send(nghttp2_session *h2,
+                              const uint8_t *buf, size_t blen,
+                              int flags, void *userp);
+static int proxy_h2_on_frame_recv(nghttp2_session *session,
+                                  const nghttp2_frame *frame,
+                                  void *userp);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static int proxy_h2_on_frame_send(nghttp2_session *session,
+                                  const nghttp2_frame *frame,
+                                  void *userp);
+#endif
+static int proxy_h2_on_stream_close(nghttp2_session *session,
+                                    int32_t stream_id,
+                                    uint32_t error_code, void *userp);
+static int proxy_h2_on_header(nghttp2_session *session,
+                              const nghttp2_frame *frame,
+                              const uint8_t *name, size_t namelen,
+                              const uint8_t *value, size_t valuelen,
+                              uint8_t flags,
+                              void *userp);
+static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
+                                int32_t stream_id,
+                                const uint8_t *mem, size_t len, void *userp);
+
+/*
+ * Initialize the cfilter context
+ */
+static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  nghttp2_session_callbacks *cbs = NULL;
+  int rc;
+
+  DEBUGASSERT(!ctx->h2);
+  memset(&ctx->tunnel, 0, sizeof(ctx->tunnel));
+
+  Curl_bufq_init(&ctx->inbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_RECV_CHUNKS);
+  Curl_bufq_init(&ctx->outbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_SEND_CHUNKS);
+
+  if(tunnel_stream_init(cf, &ctx->tunnel))
+    goto out;
+
+  rc = nghttp2_session_callbacks_new(&cbs);
+  if(rc) {
+    failf(data, "Couldn't initialize nghttp2 callbacks");
+    goto out;
+  }
+
+  nghttp2_session_callbacks_set_send_callback(cbs, on_session_send);
+  nghttp2_session_callbacks_set_on_frame_recv_callback(
+    cbs, proxy_h2_on_frame_recv);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  nghttp2_session_callbacks_set_on_frame_send_callback(cbs,
+                                                       proxy_h2_on_frame_send);
+#endif
+  nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
+    cbs, tunnel_recv_callback);
+  nghttp2_session_callbacks_set_on_stream_close_callback(
+    cbs, proxy_h2_on_stream_close);
+  nghttp2_session_callbacks_set_on_header_callback(cbs, proxy_h2_on_header);
+
+  /* The nghttp2 session is not yet setup, do it */
+  rc = proxy_h2_client_new(cf, cbs);
+  if(rc) {
+    failf(data, "Couldn't initialize nghttp2");
+    goto out;
+  }
+
+  {
+    nghttp2_settings_entry iv[3];
+
+    iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
+    iv[0].value = Curl_multi_max_concurrent_streams(data->multi);
+    iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
+    iv[1].value = H2_TUNNEL_WINDOW_SIZE;
+    iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
+    iv[2].value = 0;
+    rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE, iv, 3);
+    if(rc) {
+      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
+            nghttp2_strerror(rc), rc);
+      result = CURLE_HTTP2;
+      goto out;
+    }
+  }
+
+  rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0,
+                                             PROXY_HTTP2_HUGE_WINDOW_SIZE);
+  if(rc) {
+    failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
+          nghttp2_strerror(rc), rc);
+    result = CURLE_HTTP2;
+    goto out;
+  }
+
+
+  /* all set, traffic will be send on connect */
+  result = CURLE_OK;
+
+out:
+  if(cbs)
+    nghttp2_session_callbacks_del(cbs);
+  CURL_TRC_CF(data, cf, "[0] init proxy ctx -> %d", result);
+  return result;
+}
+
+static int proxy_h2_should_close_session(struct cf_h2_proxy_ctx *ctx)
+{
+  return !nghttp2_session_want_read(ctx->h2) &&
+    !nghttp2_session_want_write(ctx->h2);
+}
+
+static CURLcode proxy_h2_nw_out_flush(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  ssize_t nwritten;
+  CURLcode result;
+
+  (void)data;
+  if(Curl_bufq_is_empty(&ctx->outbufq))
+    return CURLE_OK;
+
+  nwritten = Curl_bufq_pass(&ctx->outbufq, proxy_h2_nw_out_writer, cf,
+                            &result);
+  if(nwritten < 0) {
+    if(result == CURLE_AGAIN) {
+      CURL_TRC_CF(data, cf, "[0] flush nw send buffer(%zu) -> EAGAIN",
+                  Curl_bufq_len(&ctx->outbufq));
+      ctx->nw_out_blocked = 1;
+    }
+    return result;
+  }
+  CURL_TRC_CF(data, cf, "[0] nw send buffer flushed");
+  return Curl_bufq_is_empty(&ctx->outbufq)? CURLE_OK: CURLE_AGAIN;
+}
+
+/*
+ * Processes pending input left in network input buffer.
+ * This function returns 0 if it succeeds, or -1 and error code will
+ * be assigned to *err.
+ */
+static int proxy_h2_process_pending_input(struct Curl_cfilter *cf,
+                                          struct Curl_easy *data,
+                                          CURLcode *err)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  const unsigned char *buf;
+  size_t blen;
+  ssize_t rv;
+
+  while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) {
+
+    rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen);
+    CURL_TRC_CF(data, cf, "[0] %zu bytes to nghttp2 -> %zd", blen, rv);
+    if(rv < 0) {
+      failf(data,
+            "process_pending_input: nghttp2_session_mem_recv() returned "
+            "%zd:%s", rv, nghttp2_strerror((int)rv));
+      *err = CURLE_RECV_ERROR;
+      return -1;
+    }
+    Curl_bufq_skip(&ctx->inbufq, (size_t)rv);
+    if(Curl_bufq_is_empty(&ctx->inbufq)) {
+      CURL_TRC_CF(data, cf, "[0] all data in connection buffer processed");
+      break;
+    }
+    else {
+      CURL_TRC_CF(data, cf, "[0] process_pending_input: %zu bytes left "
+                  "in connection buffer", Curl_bufq_len(&ctx->inbufq));
+    }
+  }
+
+  return 0;
+}
+
+static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf,
+                                          struct Curl_easy *data)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
+  ssize_t nread;
+
+  /* Process network input buffer fist */
+  if(!Curl_bufq_is_empty(&ctx->inbufq)) {
+    CURL_TRC_CF(data, cf, "[0] process %zu bytes in connection buffer",
+                Curl_bufq_len(&ctx->inbufq));
+    if(proxy_h2_process_pending_input(cf, data, &result) < 0)
+      return result;
+  }
+
+  /* Receive data from the "lower" filters, e.g. network until
+   * it is time to stop or we have enough data for this stream */
+  while(!ctx->conn_closed &&               /* not closed the connection */
+        !ctx->tunnel.closed &&             /* nor the tunnel */
+        Curl_bufq_is_empty(&ctx->inbufq) && /* and we consumed our input */
+        !Curl_bufq_is_full(&ctx->tunnel.recvbuf)) {
+
+    nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
+    CURL_TRC_CF(data, cf, "[0] read %zu bytes nw data -> %zd, %d",
+                Curl_bufq_len(&ctx->inbufq), nread, result);
+    if(nread < 0) {
+      if(result != CURLE_AGAIN) {
+        failf(data, "Failed receiving HTTP2 data");
+        return result;
+      }
+      break;
+    }
+    else if(nread == 0) {
+      ctx->conn_closed = TRUE;
+      break;
+    }
+
+    if(proxy_h2_process_pending_input(cf, data, &result))
+      return result;
+  }
+
+  if(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) {
+    connclose(cf->conn, "GOAWAY received");
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode proxy_h2_progress_egress(struct Curl_cfilter *cf,
+                                         struct Curl_easy *data)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  int rv = 0;
+
+  ctx->nw_out_blocked = 0;
+  while(!rv && !ctx->nw_out_blocked && nghttp2_session_want_write(ctx->h2))
+    rv = nghttp2_session_send(ctx->h2);
+
+  if(nghttp2_is_fatal(rv)) {
+    CURL_TRC_CF(data, cf, "[0] nghttp2_session_send error (%s)%d",
+                nghttp2_strerror(rv), rv);
+    return CURLE_SEND_ERROR;
+  }
+  return proxy_h2_nw_out_flush(cf, data);
+}
+
+static ssize_t on_session_send(nghttp2_session *h2,
+                               const uint8_t *buf, size_t blen, int flags,
+                               void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  ssize_t nwritten;
+  CURLcode result = CURLE_OK;
+
+  (void)h2;
+  (void)flags;
+  DEBUGASSERT(data);
+
+  nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
+                                  proxy_h2_nw_out_writer, cf, &result);
+  if(nwritten < 0) {
+    if(result == CURLE_AGAIN) {
+      return NGHTTP2_ERR_WOULDBLOCK;
+    }
+    failf(data, "Failed sending HTTP2 data");
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  }
+
+  if(!nwritten)
+    return NGHTTP2_ERR_WOULDBLOCK;
+
+  return nwritten;
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static int proxy_h2_fr_print(const nghttp2_frame *frame,
+                             char *buffer, size_t blen)
+{
+  switch(frame->hd.type) {
+    case NGHTTP2_DATA: {
+      return msnprintf(buffer, blen,
+                       "FRAME[DATA, len=%d, eos=%d, padlen=%d]",
+                       (int)frame->hd.length,
+                       !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM),
+                       (int)frame->data.padlen);
+    }
+    case NGHTTP2_HEADERS: {
+      return msnprintf(buffer, blen,
+                       "FRAME[HEADERS, len=%d, hend=%d, eos=%d]",
+                       (int)frame->hd.length,
+                       !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS),
+                       !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM));
+    }
+    case NGHTTP2_PRIORITY: {
+      return msnprintf(buffer, blen,
+                       "FRAME[PRIORITY, len=%d, flags=%d]",
+                       (int)frame->hd.length, frame->hd.flags);
+    }
+    case NGHTTP2_RST_STREAM: {
+      return msnprintf(buffer, blen,
+                       "FRAME[RST_STREAM, len=%d, flags=%d, error=%u]",
+                       (int)frame->hd.length, frame->hd.flags,
+                       frame->rst_stream.error_code);
+    }
+    case NGHTTP2_SETTINGS: {
+      if(frame->hd.flags & NGHTTP2_FLAG_ACK) {
+        return msnprintf(buffer, blen, "FRAME[SETTINGS, ack=1]");
+      }
+      return msnprintf(buffer, blen,
+                       "FRAME[SETTINGS, len=%d]", (int)frame->hd.length);
+    }
+    case NGHTTP2_PUSH_PROMISE: {
+      return msnprintf(buffer, blen,
+                       "FRAME[PUSH_PROMISE, len=%d, hend=%d]",
+                       (int)frame->hd.length,
+                       !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS));
+    }
+    case NGHTTP2_PING: {
+      return msnprintf(buffer, blen,
+                       "FRAME[PING, len=%d, ack=%d]",
+                       (int)frame->hd.length,
+                       frame->hd.flags&NGHTTP2_FLAG_ACK);
+    }
+    case NGHTTP2_GOAWAY: {
+      char scratch[128];
+      size_t s_len = sizeof(scratch)/sizeof(scratch[0]);
+        size_t len = (frame->goaway.opaque_data_len < s_len)?
+                      frame->goaway.opaque_data_len : s_len-1;
+        if(len)
+          memcpy(scratch, frame->goaway.opaque_data, len);
+        scratch[len] = '\0';
+        return msnprintf(buffer, blen, "FRAME[GOAWAY, error=%d, reason='%s', "
+                         "last_stream=%d]", frame->goaway.error_code,
+                         scratch, frame->goaway.last_stream_id);
+    }
+    case NGHTTP2_WINDOW_UPDATE: {
+      return msnprintf(buffer, blen,
+                       "FRAME[WINDOW_UPDATE, incr=%d]",
+                       frame->window_update.window_size_increment);
+    }
+    default:
+      return msnprintf(buffer, blen, "FRAME[%d, len=%d, flags=%d]",
+                       frame->hd.type, (int)frame->hd.length,
+                       frame->hd.flags);
+  }
+}
+
+static int proxy_h2_on_frame_send(nghttp2_session *session,
+                                  const nghttp2_frame *frame,
+                                  void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+
+  (void)session;
+  DEBUGASSERT(data);
+  if(data && Curl_trc_cf_is_verbose(cf, data)) {
+    char buffer[256];
+    int len;
+    len = proxy_h2_fr_print(frame, buffer, sizeof(buffer)-1);
+    buffer[len] = 0;
+    CURL_TRC_CF(data, cf, "[%d] -> %s", frame->hd.stream_id, buffer);
+  }
+  return 0;
+}
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+
+static int proxy_h2_on_frame_recv(nghttp2_session *session,
+                                  const nghttp2_frame *frame,
+                                  void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  int32_t stream_id = frame->hd.stream_id;
+
+  (void)session;
+  DEBUGASSERT(data);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  if(Curl_trc_cf_is_verbose(cf, data)) {
+    char buffer[256];
+    int len;
+    len = proxy_h2_fr_print(frame, buffer, sizeof(buffer)-1);
+    buffer[len] = 0;
+    CURL_TRC_CF(data, cf, "[%d] <- %s",frame->hd.stream_id, buffer);
+  }
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+
+  if(!stream_id) {
+    /* stream ID zero is for connection-oriented stuff */
+    DEBUGASSERT(data);
+    switch(frame->hd.type) {
+    case NGHTTP2_SETTINGS:
+      /* Since the initial stream window is 64K, a request might be on HOLD,
+       * due to exhaustion. The (initial) SETTINGS may announce a much larger
+       * window and *assume* that we treat this like a WINDOW_UPDATE. Some
+       * servers send an explicit WINDOW_UPDATE, but not all seem to do that.
+       * To be safe, we UNHOLD a stream in order not to stall. */
+      if(CURL_WANT_SEND(data)) {
+        drain_tunnel(cf, data, &ctx->tunnel);
+      }
+      break;
+    case NGHTTP2_GOAWAY:
+      ctx->goaway = TRUE;
+      break;
+    default:
+      break;
+    }
+    return 0;
+  }
+
+  if(stream_id != ctx->tunnel.stream_id) {
+    CURL_TRC_CF(data, cf, "[%d] rcvd FRAME not for tunnel", stream_id);
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  }
+
+  switch(frame->hd.type) {
+  case NGHTTP2_HEADERS:
+    /* nghttp2 guarantees that :status is received, and we store it to
+       stream->status_code. Fuzzing has proven this can still be reached
+       without status code having been set. */
+    if(!ctx->tunnel.resp)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+    /* Only final status code signals the end of header */
+    CURL_TRC_CF(data, cf, "[%d] got http status: %d",
+                stream_id, ctx->tunnel.resp->status);
+    if(!ctx->tunnel.has_final_response) {
+      if(ctx->tunnel.resp->status / 100 != 1) {
+        ctx->tunnel.has_final_response = TRUE;
+      }
+    }
+    break;
+  case NGHTTP2_WINDOW_UPDATE:
+    if(CURL_WANT_SEND(data)) {
+      drain_tunnel(cf, data, &ctx->tunnel);
+    }
+    break;
+  default:
+    break;
+  }
+  return 0;
+}
+
+static int proxy_h2_on_header(nghttp2_session *session,
+                              const nghttp2_frame *frame,
+                              const uint8_t *name, size_t namelen,
+                              const uint8_t *value, size_t valuelen,
+                              uint8_t flags,
+                              void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  int32_t stream_id = frame->hd.stream_id;
+  CURLcode result;
+
+  (void)flags;
+  (void)data;
+  (void)session;
+  DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
+  if(stream_id != ctx->tunnel.stream_id) {
+    CURL_TRC_CF(data, cf, "[%d] header for non-tunnel stream: "
+                "%.*s: %.*s", stream_id,
+                (int)namelen, name, (int)valuelen, value);
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  }
+
+  if(frame->hd.type == NGHTTP2_PUSH_PROMISE)
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+  if(ctx->tunnel.has_final_response) {
+    /* we do not do anything with trailers for tunnel streams */
+    return 0;
+  }
+
+  if(namelen == sizeof(HTTP_PSEUDO_STATUS) - 1 &&
+     memcmp(HTTP_PSEUDO_STATUS, name, namelen) == 0) {
+    int http_status;
+    struct http_resp *resp;
+
+    /* status: always comes first, we might get more than one response,
+     * link the previous ones for keepers */
+    result = Curl_http_decode_status(&http_status,
+                                    (const char *)value, valuelen);
+    if(result)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+    result = Curl_http_resp_make(&resp, http_status, NULL);
+    if(result)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+    resp->prev = ctx->tunnel.resp;
+    ctx->tunnel.resp = resp;
+    CURL_TRC_CF(data, cf, "[%d] status: HTTP/2 %03d",
+                stream_id, ctx->tunnel.resp->status);
+    return 0;
+  }
+
+  if(!ctx->tunnel.resp)
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+  result = Curl_dynhds_add(&ctx->tunnel.resp->headers,
+                           (const char *)name, namelen,
+                           (const char *)value, valuelen);
+  if(result)
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+  CURL_TRC_CF(data, cf, "[%d] header: %.*s: %.*s",
+              stream_id, (int)namelen, name, (int)valuelen, value);
+
+  return 0; /* 0 is successful */
+}
+
+static ssize_t tunnel_send_callback(nghttp2_session *session,
+                                    int32_t stream_id,
+                                    uint8_t *buf, size_t length,
+                                    uint32_t *data_flags,
+                                    nghttp2_data_source *source,
+                                    void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  struct tunnel_stream *ts;
+  CURLcode result;
+  ssize_t nread;
+
+  (void)source;
+  (void)data;
+  (void)ctx;
+
+  if(!stream_id)
+    return NGHTTP2_ERR_INVALID_ARGUMENT;
+
+  ts = nghttp2_session_get_stream_user_data(session, stream_id);
+  if(!ts)
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  DEBUGASSERT(ts == &ctx->tunnel);
+
+  nread = Curl_bufq_read(&ts->sendbuf, buf, length, &result);
+  if(nread < 0) {
+    if(result != CURLE_AGAIN)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+    return NGHTTP2_ERR_DEFERRED;
+  }
+  if(ts->closed && Curl_bufq_is_empty(&ts->sendbuf))
+    *data_flags = NGHTTP2_DATA_FLAG_EOF;
+
+  CURL_TRC_CF(data, cf, "[%d] tunnel_send_callback -> %zd",
+              ts->stream_id, nread);
+  return nread;
+}
+
+static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
+                                int32_t stream_id,
+                                const uint8_t *mem, size_t len, void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  ssize_t nwritten;
+  CURLcode result;
+
+  (void)flags;
+  (void)session;
+  DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
+
+  if(stream_id != ctx->tunnel.stream_id)
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+  nwritten = Curl_bufq_write(&ctx->tunnel.recvbuf, mem, len, &result);
+  if(nwritten < 0) {
+    if(result != CURLE_AGAIN)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+    nwritten = 0;
+  }
+  DEBUGASSERT((size_t)nwritten == len);
+  return 0;
+}
+
+static int proxy_h2_on_stream_close(nghttp2_session *session,
+                                    int32_t stream_id,
+                                    uint32_t error_code, void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+
+  (void)session;
+  (void)data;
+
+  if(stream_id != ctx->tunnel.stream_id)
+    return 0;
+
+  CURL_TRC_CF(data, cf, "[%d] proxy_h2_on_stream_close, %s (err %d)",
+              stream_id, nghttp2_http2_strerror(error_code), error_code);
+  ctx->tunnel.closed = TRUE;
+  ctx->tunnel.error = error_code;
+
+  return 0;
+}
+
+static CURLcode proxy_h2_submit(int32_t *pstream_id,
+                                struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                nghttp2_session *h2,
+                                struct httpreq *req,
+                                const nghttp2_priority_spec *pri_spec,
+                                void *stream_user_data,
+                               nghttp2_data_source_read_callback read_callback,
+                                void *read_ctx)
+{
+  struct dynhds h2_headers;
+  nghttp2_nv *nva = NULL;
+  int32_t stream_id = -1;
+  size_t nheader;
+  CURLcode result;
+
+  (void)cf;
+  Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
+  result = Curl_http_req_to_h2(&h2_headers, req, data);
+  if(result)
+    goto out;
+
+  nva = Curl_dynhds_to_nva(&h2_headers, &nheader);
+  if(!nva) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+
+  if(read_callback) {
+    nghttp2_data_provider data_prd;
+
+    data_prd.read_callback = read_callback;
+    data_prd.source.ptr = read_ctx;
+    stream_id = nghttp2_submit_request(h2, pri_spec, nva, nheader,
+                                       &data_prd, stream_user_data);
+  }
+  else {
+    stream_id = nghttp2_submit_request(h2, pri_spec, nva, nheader,
+                                       NULL, stream_user_data);
+  }
+
+  if(stream_id < 0) {
+    failf(data, "nghttp2_session_upgrade2() failed: %s(%d)",
+          nghttp2_strerror(stream_id), stream_id);
+    result = CURLE_SEND_ERROR;
+    goto out;
+  }
+  result = CURLE_OK;
+
+out:
+  free(nva);
+  Curl_dynhds_free(&h2_headers);
+  *pstream_id = stream_id;
+  return result;
+}
+
+static CURLcode submit_CONNECT(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               struct tunnel_stream *ts)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  CURLcode result;
+  struct httpreq *req = NULL;
+
+  result = Curl_http_proxy_create_CONNECT(&req, cf, data, 2);
+  if(result)
+    goto out;
+  result = Curl_creader_set_null(data);
+  if(result)
+    goto out;
+
+  infof(data, "Establish HTTP/2 proxy tunnel to %s", req->authority);
+
+  result = proxy_h2_submit(&ts->stream_id, cf, data, ctx->h2, req,
+                           NULL, ts, tunnel_send_callback, cf);
+  if(result) {
+    CURL_TRC_CF(data, cf, "[%d] send, nghttp2_submit_request error: %s",
+                ts->stream_id, nghttp2_strerror(ts->stream_id));
+  }
+
+out:
+  if(req)
+    Curl_http_req_free(req);
+  if(result)
+    failf(data, "Failed sending CONNECT to proxy");
+  return result;
+}
+
+static CURLcode inspect_response(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 struct tunnel_stream *ts)
+{
+  CURLcode result = CURLE_OK;
+  struct dynhds_entry *auth_reply = NULL;
+  (void)cf;
+
+  DEBUGASSERT(ts->resp);
+  if(ts->resp->status/100 == 2) {
+    infof(data, "CONNECT tunnel established, response %d", ts->resp->status);
+    h2_tunnel_go_state(cf, ts, H2_TUNNEL_ESTABLISHED, data);
+    return CURLE_OK;
+  }
+
+  if(ts->resp->status == 401) {
+    auth_reply = Curl_dynhds_cget(&ts->resp->headers, "WWW-Authenticate");
+  }
+  else if(ts->resp->status == 407) {
+    auth_reply = Curl_dynhds_cget(&ts->resp->headers, "Proxy-Authenticate");
+  }
+
+  if(auth_reply) {
+    CURL_TRC_CF(data, cf, "[0] CONNECT: fwd auth header '%s'",
+                auth_reply->value);
+    result = Curl_http_input_auth(data, ts->resp->status == 407,
+                                  auth_reply->value);
+    if(result)
+      return result;
+    if(data->req.newurl) {
+      /* Indicator that we should try again */
+      Curl_safefree(data->req.newurl);
+      h2_tunnel_go_state(cf, ts, H2_TUNNEL_INIT, data);
+      return CURLE_OK;
+    }
+  }
+
+  /* Seems to have failed */
+  return CURLE_RECV_ERROR;
+}
+
+static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           struct tunnel_stream *ts)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(ts);
+  DEBUGASSERT(ts->authority);
+  do {
+    switch(ts->state) {
+    case H2_TUNNEL_INIT:
+      /* Prepare the CONNECT request and make a first attempt to send. */
+      CURL_TRC_CF(data, cf, "[0] CONNECT start for %s", ts->authority);
+      result = submit_CONNECT(cf, data, ts);
+      if(result)
+        goto out;
+      h2_tunnel_go_state(cf, ts, H2_TUNNEL_CONNECT, data);
+      FALLTHROUGH();
+
+    case H2_TUNNEL_CONNECT:
+      /* see that the request is completely sent */
+      result = proxy_h2_progress_ingress(cf, data);
+      if(!result)
+        result = proxy_h2_progress_egress(cf, data);
+      if(result && result != CURLE_AGAIN) {
+        h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data);
+        break;
+      }
+
+      if(ts->has_final_response) {
+        h2_tunnel_go_state(cf, ts, H2_TUNNEL_RESPONSE, data);
+      }
+      else {
+        result = CURLE_OK;
+        goto out;
+      }
+      FALLTHROUGH();
+
+    case H2_TUNNEL_RESPONSE:
+      DEBUGASSERT(ts->has_final_response);
+      result = inspect_response(cf, data, ts);
+      if(result)
+        goto out;
+      break;
+
+    case H2_TUNNEL_ESTABLISHED:
+      return CURLE_OK;
+
+    case H2_TUNNEL_FAILED:
+      return CURLE_RECV_ERROR;
+
+    default:
+      break;
+    }
+
+  } while(ts->state == H2_TUNNEL_INIT);
+
+out:
+  if(result || ctx->tunnel.closed)
+    h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data);
+  return result;
+}
+
+static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    bool blocking, bool *done)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
+  struct cf_call_data save;
+  timediff_t check;
+  struct tunnel_stream *ts = &ctx->tunnel;
+
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  /* Connect the lower filters first */
+  if(!cf->next->connected) {
+    result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+    if(result || !*done)
+      return result;
+  }
+
+  *done = FALSE;
+
+  CF_DATA_SAVE(save, cf, data);
+  if(!ctx->h2) {
+    result = cf_h2_proxy_ctx_init(cf, data);
+    if(result)
+      goto out;
+  }
+  DEBUGASSERT(ts->authority);
+
+  check = Curl_timeleft(data, NULL, TRUE);
+  if(check <= 0) {
+    failf(data, "Proxy CONNECT aborted due to timeout");
+    result = CURLE_OPERATION_TIMEDOUT;
+    goto out;
+  }
+
+  /* for the secondary socket (FTP), use the "connect to host"
+   * but ignore the "connect to port" (use the secondary port)
+   */
+  result = H2_CONNECT(cf, data, ts);
+
+out:
+  *done = (result == CURLE_OK) && (ts->state == H2_TUNNEL_ESTABLISHED);
+  if(*done) {
+    cf->connected = TRUE;
+    /* The real request will follow the CONNECT, reset request partially */
+    Curl_req_soft_reset(&data->req, data);
+    Curl_client_reset(data);
+  }
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
+static void cf_h2_proxy_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+
+  if(ctx) {
+    struct cf_call_data save;
+
+    CF_DATA_SAVE(save, cf, data);
+    cf_h2_proxy_ctx_clear(ctx);
+    CF_DATA_RESTORE(cf, save);
+  }
+  if(cf->next)
+    cf->next->cft->do_close(cf->next, data);
+}
+
+static void cf_h2_proxy_destroy(struct Curl_cfilter *cf,
+                                struct Curl_easy *data)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+
+  (void)data;
+  if(ctx) {
+    cf_h2_proxy_ctx_free(ctx);
+    cf->ctx = NULL;
+  }
+}
+
+static bool cf_h2_proxy_data_pending(struct Curl_cfilter *cf,
+                                     const struct Curl_easy *data)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  if((ctx && !Curl_bufq_is_empty(&ctx->inbufq)) ||
+     (ctx && ctx->tunnel.state == H2_TUNNEL_ESTABLISHED &&
+      !Curl_bufq_is_empty(&ctx->tunnel.recvbuf)))
+    return TRUE;
+  return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
+}
+
+static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
+                                       struct Curl_easy *data,
+                                       struct easy_pollset *ps)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
+  bool want_recv, want_send;
+
+  Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
+  if(ctx->h2 && (want_recv || want_send)) {
+    struct cf_call_data save;
+    bool c_exhaust, s_exhaust;
+
+    CF_DATA_SAVE(save, cf, data);
+    c_exhaust = !nghttp2_session_get_remote_window_size(ctx->h2);
+    s_exhaust = ctx->tunnel.stream_id >= 0 &&
+                !nghttp2_session_get_stream_remote_window_size(
+                   ctx->h2, ctx->tunnel.stream_id);
+    want_recv = (want_recv || c_exhaust || s_exhaust);
+    want_send = (!s_exhaust && want_send) ||
+                (!c_exhaust && nghttp2_session_want_write(ctx->h2));
+
+    Curl_pollset_set(data, ps, sock, want_recv, want_send);
+    CF_DATA_RESTORE(cf, save);
+  }
+}
+
+static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data,
+                                      CURLcode *err)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  ssize_t rv = 0;
+
+  if(ctx->tunnel.error == NGHTTP2_REFUSED_STREAM) {
+    CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
+                "connection", ctx->tunnel.stream_id);
+    connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */
+    *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
+    return -1;
+  }
+  else if(ctx->tunnel.error != NGHTTP2_NO_ERROR) {
+    failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
+          ctx->tunnel.stream_id, nghttp2_http2_strerror(ctx->tunnel.error),
+          ctx->tunnel.error);
+    *err = CURLE_HTTP2_STREAM;
+    return -1;
+  }
+  else if(ctx->tunnel.reset) {
+    failf(data, "HTTP/2 stream %u was reset", ctx->tunnel.stream_id);
+    *err = CURLE_RECV_ERROR;
+    return -1;
+  }
+
+  *err = CURLE_OK;
+  rv = 0;
+  CURL_TRC_CF(data, cf, "[%d] handle_tunnel_close -> %zd, %d",
+              ctx->tunnel.stream_id, rv, *err);
+  return rv;
+}
+
+static ssize_t tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                           char *buf, size_t len, CURLcode *err)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  ssize_t nread = -1;
+
+  *err = CURLE_AGAIN;
+  if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) {
+    nread = Curl_bufq_read(&ctx->tunnel.recvbuf,
+                           (unsigned char *)buf, len, err);
+    if(nread < 0)
+      goto out;
+    DEBUGASSERT(nread > 0);
+  }
+
+  if(nread < 0) {
+    if(ctx->tunnel.closed) {
+      nread = h2_handle_tunnel_close(cf, data, err);
+    }
+    else if(ctx->tunnel.reset ||
+            (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
+            (ctx->goaway && ctx->last_stream_id < ctx->tunnel.stream_id)) {
+      *err = CURLE_RECV_ERROR;
+      nread = -1;
+    }
+  }
+  else if(nread == 0) {
+    *err = CURLE_AGAIN;
+    nread = -1;
+  }
+
+out:
+  CURL_TRC_CF(data, cf, "[%d] tunnel_recv(len=%zu) -> %zd, %d",
+              ctx->tunnel.stream_id, len, nread, *err);
+  return nread;
+}
+
+static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                char *buf, size_t len, CURLcode *err)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  ssize_t nread = -1;
+  struct cf_call_data save;
+  CURLcode result;
+
+  if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
+    *err = CURLE_RECV_ERROR;
+    return -1;
+  }
+  CF_DATA_SAVE(save, cf, data);
+
+  if(Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) {
+    *err = proxy_h2_progress_ingress(cf, data);
+    if(*err)
+      goto out;
+  }
+
+  nread = tunnel_recv(cf, data, buf, len, err);
+
+  if(nread > 0) {
+    CURL_TRC_CF(data, cf, "[%d] increase window by %zd",
+                ctx->tunnel.stream_id, nread);
+    nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, (size_t)nread);
+  }
+
+  result = proxy_h2_progress_egress(cf, data);
+  if(result == CURLE_AGAIN) {
+    /* pending data to send, need to be called again. Ideally, we'd
+     * monitor the socket for POLLOUT, but we might not be in SENDING
+     * transfer state any longer and are unable to make this happen.
+     */
+    CURL_TRC_CF(data, cf, "[%d] egress blocked, DRAIN",
+                ctx->tunnel.stream_id);
+    drain_tunnel(cf, data, &ctx->tunnel);
+  }
+  else if(result) {
+    *err = result;
+    nread = -1;
+  }
+
+out:
+  if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) &&
+     (nread >= 0 || *err == CURLE_AGAIN)) {
+    /* data pending and no fatal error to report. Need to trigger
+     * draining to avoid stalling when no socket events happen. */
+    drain_tunnel(cf, data, &ctx->tunnel);
+  }
+  CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d",
+              ctx->tunnel.stream_id, len, nread, *err);
+  CF_DATA_RESTORE(cf, save);
+  return nread;
+}
+
+static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                const void *buf, size_t len, CURLcode *err)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  struct cf_call_data save;
+  int rv;
+  ssize_t nwritten;
+  CURLcode result;
+  int blocked = 0;
+
+  if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
+    *err = CURLE_SEND_ERROR;
+    return -1;
+  }
+  CF_DATA_SAVE(save, cf, data);
+
+  if(ctx->tunnel.closed) {
+    nwritten = -1;
+    *err = CURLE_SEND_ERROR;
+    goto out;
+  }
+  else if(ctx->tunnel.upload_blocked_len) {
+    /* the data in `buf` has already been submitted or added to the
+     * buffers, but have been EAGAINed on the last invocation. */
+    DEBUGASSERT(len >= ctx->tunnel.upload_blocked_len);
+    if(len < ctx->tunnel.upload_blocked_len) {
+      /* Did we get called again with a smaller `len`? This should not
+       * happen. We are not prepared to handle that. */
+      failf(data, "HTTP/2 proxy, send again with decreased length");
+      *err = CURLE_HTTP2;
+      nwritten = -1;
+      goto out;
+    }
+    nwritten = (ssize_t)ctx->tunnel.upload_blocked_len;
+    ctx->tunnel.upload_blocked_len = 0;
+    *err = CURLE_OK;
+  }
+  else {
+    nwritten = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, err);
+    if(nwritten < 0) {
+      if(*err != CURLE_AGAIN)
+        goto out;
+      nwritten = 0;
+    }
+  }
+
+  if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
+    /* req body data is buffered, resume the potentially suspended stream */
+    rv = nghttp2_session_resume_data(ctx->h2, ctx->tunnel.stream_id);
+    if(nghttp2_is_fatal(rv)) {
+      *err = CURLE_SEND_ERROR;
+      nwritten = -1;
+      goto out;
+    }
+  }
+
+  result = proxy_h2_progress_ingress(cf, data);
+  if(result) {
+    *err = result;
+    nwritten = -1;
+    goto out;
+  }
+
+  /* Call the nghttp2 send loop and flush to write ALL buffered data,
+   * headers and/or request body completely out to the network */
+  result = proxy_h2_progress_egress(cf, data);
+  if(result == CURLE_AGAIN) {
+    blocked = 1;
+  }
+  else if(result) {
+    *err = result;
+    nwritten = -1;
+    goto out;
+  }
+  else if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
+    /* although we wrote everything that nghttp2 wants to send now,
+     * there is data left in our stream send buffer unwritten. This may
+     * be due to the stream's HTTP/2 flow window being exhausted. */
+    blocked = 1;
+  }
+
+  if(blocked) {
+    /* Unable to send all data, due to connection blocked or H2 window
+     * exhaustion. Data is left in our stream buffer, or nghttp2's internal
+     * frame buffer or our network out buffer. */
+    size_t rwin = nghttp2_session_get_stream_remote_window_size(
+                    ctx->h2, ctx->tunnel.stream_id);
+    if(rwin == 0) {
+      /* H2 flow window exhaustion.
+       * FIXME: there is no way to HOLD all transfers that use this
+       * proxy connection AND to UNHOLD all of them again when the
+       * window increases.
+       * We *could* iterate over all data on this conn maybe? */
+      CURL_TRC_CF(data, cf, "[%d] remote flow "
+                  "window is exhausted", ctx->tunnel.stream_id);
+    }
+
+    /* Whatever the cause, we need to return CURL_EAGAIN for this call.
+     * We have unwritten state that needs us being invoked again and EAGAIN
+     * is the only way to ensure that. */
+    ctx->tunnel.upload_blocked_len = nwritten;
+    CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) BLOCK: win %u/%zu "
+                "blocked_len=%zu",
+                ctx->tunnel.stream_id, len,
+                nghttp2_session_get_remote_window_size(ctx->h2), rwin,
+                nwritten);
+    drain_tunnel(cf, data, &ctx->tunnel);
+    *err = CURLE_AGAIN;
+    nwritten = -1;
+    goto out;
+  }
+  else if(proxy_h2_should_close_session(ctx)) {
+    /* nghttp2 thinks this session is done. If the stream has not been
+     * closed, this is an error state for out transfer */
+    if(ctx->tunnel.closed) {
+      *err = CURLE_SEND_ERROR;
+      nwritten = -1;
+    }
+    else {
+      CURL_TRC_CF(data, cf, "[0] send: nothing to do in this session");
+      *err = CURLE_HTTP2;
+      nwritten = -1;
+    }
+  }
+
+out:
+  if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) &&
+     (nwritten >= 0 || *err == CURLE_AGAIN)) {
+    /* data pending and no fatal error to report. Need to trigger
+     * draining to avoid stalling when no socket events happen. */
+    drain_tunnel(cf, data, &ctx->tunnel);
+  }
+  CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, "
+              "h2 windows %d-%d (stream-conn), buffers %zu-%zu (stream-conn)",
+              ctx->tunnel.stream_id, len, nwritten, *err,
+              nghttp2_session_get_stream_remote_window_size(
+                  ctx->h2, ctx->tunnel.stream_id),
+              nghttp2_session_get_remote_window_size(ctx->h2),
+              Curl_bufq_len(&ctx->tunnel.sendbuf),
+              Curl_bufq_len(&ctx->outbufq));
+  CF_DATA_RESTORE(cf, save);
+  return nwritten;
+}
+
+static bool proxy_h2_connisalive(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 bool *input_pending)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  bool alive = TRUE;
+
+  *input_pending = FALSE;
+  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
+    return FALSE;
+
+  if(*input_pending) {
+    /* This happens before we've sent off a request and the connection is
+       not in use by any other transfer, there shouldn't be any data here,
+       only "protocol frames" */
+    CURLcode result;
+    ssize_t nread = -1;
+
+    *input_pending = FALSE;
+    nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
+    if(nread != -1) {
+      if(proxy_h2_process_pending_input(cf, data, &result) < 0)
+        /* immediate error, considered dead */
+        alive = FALSE;
+      else {
+        alive = !proxy_h2_should_close_session(ctx);
+      }
+    }
+    else if(result != CURLE_AGAIN) {
+      /* the read failed so let's say this is dead anyway */
+      alive = FALSE;
+    }
+  }
+
+  return alive;
+}
+
+static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 bool *input_pending)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  CURLcode result;
+  struct cf_call_data save;
+
+  CF_DATA_SAVE(save, cf, data);
+  result = (ctx && ctx->h2 && proxy_h2_connisalive(cf, data, input_pending));
+  CURL_TRC_CF(data, cf, "[0] conn alive -> %d, input_pending=%d",
+              result, *input_pending);
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
+struct Curl_cftype Curl_cft_h2_proxy = {
+  "H2-PROXY",
+  CF_TYPE_IP_CONNECT,
+  CURL_LOG_LVL_NONE,
+  cf_h2_proxy_destroy,
+  cf_h2_proxy_connect,
+  cf_h2_proxy_close,
+  Curl_cf_http_proxy_get_host,
+  cf_h2_proxy_adjust_pollset,
+  cf_h2_proxy_data_pending,
+  cf_h2_proxy_send,
+  cf_h2_proxy_recv,
+  Curl_cf_def_cntrl,
+  cf_h2_proxy_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  Curl_cf_def_query,
+};
+
+CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf,
+                                       struct Curl_easy *data)
+{
+  struct Curl_cfilter *cf_h2_proxy = NULL;
+  struct cf_h2_proxy_ctx *ctx;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+
+  (void)data;
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx)
+    goto out;
+
+  result = Curl_cf_create(&cf_h2_proxy, &Curl_cft_h2_proxy, ctx);
+  if(result)
+    goto out;
+
+  Curl_conn_cf_insert_after(cf, cf_h2_proxy);
+  result = CURLE_OK;
+
+out:
+  if(result)
+    cf_h2_proxy_ctx_free(ctx);
+  return result;
+}
+
+#endif /* defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY) */
Index: trunk/src/libs/curl-8.7.1/lib/cf-h2-proxy.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cf-h2-proxy.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cf-h2-proxy.h	(revision 104083)
@@ -0,0 +1,39 @@
+#ifndef HEADER_CURL_H2_PROXY_H
+#define HEADER_CURL_H2_PROXY_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY)
+
+CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf,
+                                       struct Curl_easy *data);
+
+extern struct Curl_cftype Curl_cft_h2_proxy;
+
+
+#endif /* defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY) */
+
+#endif /* HEADER_CURL_H2_PROXY_H */
Index: trunk/src/libs/curl-8.7.1/lib/cf-haproxy.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cf-haproxy.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cf-haproxy.c	(revision 104083)
@@ -0,0 +1,250 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_PROXY)
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "cfilters.h"
+#include "cf-haproxy.h"
+#include "curl_trc.h"
+#include "multiif.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+typedef enum {
+    HAPROXY_INIT,     /* init/default/no tunnel state */
+    HAPROXY_SEND,     /* data_out being sent */
+    HAPROXY_DONE      /* all work done */
+} haproxy_state;
+
+struct cf_haproxy_ctx {
+  int state;
+  struct dynbuf data_out;
+};
+
+static void cf_haproxy_ctx_reset(struct cf_haproxy_ctx *ctx)
+{
+  DEBUGASSERT(ctx);
+  ctx->state = HAPROXY_INIT;
+  Curl_dyn_reset(&ctx->data_out);
+}
+
+static void cf_haproxy_ctx_free(struct cf_haproxy_ctx *ctx)
+{
+  if(ctx) {
+    Curl_dyn_free(&ctx->data_out);
+    free(ctx);
+  }
+}
+
+static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
+                                        struct Curl_easy *data)
+{
+  struct cf_haproxy_ctx *ctx = cf->ctx;
+  CURLcode result;
+  const char *tcp_version;
+  const char *client_ip;
+
+  DEBUGASSERT(ctx);
+  DEBUGASSERT(ctx->state == HAPROXY_INIT);
+#ifdef USE_UNIX_SOCKETS
+  if(cf->conn->unix_domain_socket)
+    /* the buffer is large enough to hold this! */
+    result = Curl_dyn_addn(&ctx->data_out, STRCONST("PROXY UNKNOWN\r\n"));
+  else {
+#endif /* USE_UNIX_SOCKETS */
+  /* Emit the correct prefix for IPv6 */
+  tcp_version = cf->conn->bits.ipv6 ? "TCP6" : "TCP4";
+  if(data->set.str[STRING_HAPROXY_CLIENT_IP])
+    client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP];
+  else
+    client_ip = data->info.primary.local_ip;
+
+  result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
+                         tcp_version,
+                         client_ip,
+                         data->info.primary.remote_ip,
+                         data->info.primary.local_port,
+                         data->info.primary.remote_port);
+
+#ifdef USE_UNIX_SOCKETS
+  }
+#endif /* USE_UNIX_SOCKETS */
+  return result;
+}
+
+static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   bool blocking, bool *done)
+{
+  struct cf_haproxy_ctx *ctx = cf->ctx;
+  CURLcode result;
+  size_t len;
+
+  DEBUGASSERT(ctx);
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+  if(result || !*done)
+    return result;
+
+  switch(ctx->state) {
+  case HAPROXY_INIT:
+    result = cf_haproxy_date_out_set(cf, data);
+    if(result)
+      goto out;
+    ctx->state = HAPROXY_SEND;
+    FALLTHROUGH();
+  case HAPROXY_SEND:
+    len = Curl_dyn_len(&ctx->data_out);
+    if(len > 0) {
+      size_t written;
+      result = Curl_conn_send(data, cf->sockindex,
+                              Curl_dyn_ptr(&ctx->data_out),
+                              len, &written);
+      if(result == CURLE_AGAIN) {
+        result = CURLE_OK;
+        written = 0;
+      }
+      else if(result)
+        goto out;
+      Curl_dyn_tail(&ctx->data_out, len - written);
+      if(Curl_dyn_len(&ctx->data_out) > 0) {
+        result = CURLE_OK;
+        goto out;
+      }
+    }
+    ctx->state = HAPROXY_DONE;
+    FALLTHROUGH();
+  default:
+    Curl_dyn_free(&ctx->data_out);
+    break;
+  }
+
+out:
+  *done = (!result) && (ctx->state == HAPROXY_DONE);
+  cf->connected = *done;
+  return result;
+}
+
+static void cf_haproxy_destroy(struct Curl_cfilter *cf,
+                               struct Curl_easy *data)
+{
+  (void)data;
+  CURL_TRC_CF(data, cf, "destroy");
+  cf_haproxy_ctx_free(cf->ctx);
+}
+
+static void cf_haproxy_close(struct Curl_cfilter *cf,
+                             struct Curl_easy *data)
+{
+  CURL_TRC_CF(data, cf, "close");
+  cf->connected = FALSE;
+  cf_haproxy_ctx_reset(cf->ctx);
+  if(cf->next)
+    cf->next->cft->do_close(cf->next, data);
+}
+
+static void cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data,
+                                      struct easy_pollset *ps)
+{
+  if(cf->next->connected && !cf->connected) {
+    /* If we are not connected, but the filter "below" is
+     * and not waiting on something, we are sending. */
+    Curl_pollset_set_out_only(data, ps, Curl_conn_cf_get_socket(cf, data));
+  }
+}
+
+struct Curl_cftype Curl_cft_haproxy = {
+  "HAPROXY",
+  0,
+  0,
+  cf_haproxy_destroy,
+  cf_haproxy_connect,
+  cf_haproxy_close,
+  Curl_cf_def_get_host,
+  cf_haproxy_adjust_pollset,
+  Curl_cf_def_data_pending,
+  Curl_cf_def_send,
+  Curl_cf_def_recv,
+  Curl_cf_def_cntrl,
+  Curl_cf_def_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  Curl_cf_def_query,
+};
+
+static CURLcode cf_haproxy_create(struct Curl_cfilter **pcf,
+                                  struct Curl_easy *data)
+{
+  struct Curl_cfilter *cf = NULL;
+  struct cf_haproxy_ctx *ctx;
+  CURLcode result;
+
+  (void)data;
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  ctx->state = HAPROXY_INIT;
+  Curl_dyn_init(&ctx->data_out, DYN_HAXPROXY);
+
+  result = Curl_cf_create(&cf, &Curl_cft_haproxy, ctx);
+  if(result)
+    goto out;
+  ctx = NULL;
+
+out:
+  cf_haproxy_ctx_free(ctx);
+  *pcf = result? NULL : cf;
+  return result;
+}
+
+CURLcode Curl_cf_haproxy_insert_after(struct Curl_cfilter *cf_at,
+                                      struct Curl_easy *data)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result;
+
+  result = cf_haproxy_create(&cf, data);
+  if(result)
+    goto out;
+  Curl_conn_cf_insert_after(cf_at, cf);
+
+out:
+  return result;
+}
+
+#endif /* !CURL_DISABLE_PROXY */
Index: trunk/src/libs/curl-8.7.1/lib/cf-haproxy.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cf-haproxy.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cf-haproxy.h	(revision 104083)
@@ -0,0 +1,39 @@
+#ifndef HEADER_CURL_CF_HAPROXY_H
+#define HEADER_CURL_CF_HAPROXY_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "urldata.h"
+
+#if !defined(CURL_DISABLE_PROXY)
+
+CURLcode Curl_cf_haproxy_insert_after(struct Curl_cfilter *cf_at,
+                                      struct Curl_easy *data);
+
+extern struct Curl_cftype Curl_cft_haproxy;
+
+#endif /* !CURL_DISABLE_PROXY */
+
+#endif /* HEADER_CURL_CF_HAPROXY_H */
Index: trunk/src/libs/curl-8.7.1/lib/cf-https-connect.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cf-https-connect.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cf-https-connect.c	(revision 104083)
@@ -0,0 +1,531 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "curl_trc.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "multiif.h"
+#include "cf-https-connect.h"
+#include "http2.h"
+#include "vquic/vquic.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+typedef enum {
+  CF_HC_INIT,
+  CF_HC_CONNECT,
+  CF_HC_SUCCESS,
+  CF_HC_FAILURE
+} cf_hc_state;
+
+struct cf_hc_baller {
+  const char *name;
+  struct Curl_cfilter *cf;
+  CURLcode result;
+  struct curltime started;
+  int reply_ms;
+  bool enabled;
+};
+
+static void cf_hc_baller_reset(struct cf_hc_baller *b,
+                               struct Curl_easy *data)
+{
+  if(b->cf) {
+    Curl_conn_cf_close(b->cf, data);
+    Curl_conn_cf_discard_chain(&b->cf, data);
+    b->cf = NULL;
+  }
+  b->result = CURLE_OK;
+  b->reply_ms = -1;
+}
+
+static bool cf_hc_baller_is_active(struct cf_hc_baller *b)
+{
+  return b->enabled && b->cf && !b->result;
+}
+
+static bool cf_hc_baller_has_started(struct cf_hc_baller *b)
+{
+  return !!b->cf;
+}
+
+static int cf_hc_baller_reply_ms(struct cf_hc_baller *b,
+                                 struct Curl_easy *data)
+{
+  if(b->reply_ms < 0)
+    b->cf->cft->query(b->cf, data, CF_QUERY_CONNECT_REPLY_MS,
+                      &b->reply_ms, NULL);
+  return b->reply_ms;
+}
+
+static bool cf_hc_baller_data_pending(struct cf_hc_baller *b,
+                                      const struct Curl_easy *data)
+{
+  return b->cf && !b->result && b->cf->cft->has_data_pending(b->cf, data);
+}
+
+struct cf_hc_ctx {
+  cf_hc_state state;
+  const struct Curl_dns_entry *remotehost;
+  struct curltime started;  /* when connect started */
+  CURLcode result;          /* overall result */
+  struct cf_hc_baller h3_baller;
+  struct cf_hc_baller h21_baller;
+  int soft_eyeballs_timeout_ms;
+  int hard_eyeballs_timeout_ms;
+};
+
+static void cf_hc_baller_init(struct cf_hc_baller *b,
+                              struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              const char *name,
+                              int transport)
+{
+  struct cf_hc_ctx *ctx = cf->ctx;
+  struct Curl_cfilter *save = cf->next;
+
+  b->name = name;
+  cf->next = NULL;
+  b->started = Curl_now();
+  b->result = Curl_cf_setup_insert_after(cf, data, ctx->remotehost,
+                                         transport, CURL_CF_SSL_ENABLE);
+  b->cf = cf->next;
+  cf->next = save;
+}
+
+static CURLcode cf_hc_baller_connect(struct cf_hc_baller *b,
+                                     struct Curl_cfilter *cf,
+                                     struct Curl_easy *data,
+                                     bool *done)
+{
+  struct Curl_cfilter *save = cf->next;
+
+  cf->next = b->cf;
+  b->result = Curl_conn_cf_connect(cf->next, data, FALSE, done);
+  b->cf = cf->next; /* it might mutate */
+  cf->next = save;
+  return b->result;
+}
+
+static void cf_hc_reset(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_hc_ctx *ctx = cf->ctx;
+
+  if(ctx) {
+    cf_hc_baller_reset(&ctx->h3_baller, data);
+    cf_hc_baller_reset(&ctx->h21_baller, data);
+    ctx->state = CF_HC_INIT;
+    ctx->result = CURLE_OK;
+    ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout;
+    ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 2;
+  }
+}
+
+static CURLcode baller_connected(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 struct cf_hc_baller *winner)
+{
+  struct cf_hc_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(winner->cf);
+  if(winner != &ctx->h3_baller)
+    cf_hc_baller_reset(&ctx->h3_baller, data);
+  if(winner != &ctx->h21_baller)
+    cf_hc_baller_reset(&ctx->h21_baller, data);
+
+  CURL_TRC_CF(data, cf, "connect+handshake %s: %dms, 1st data: %dms",
+              winner->name, (int)Curl_timediff(Curl_now(), winner->started),
+              cf_hc_baller_reply_ms(winner, data));
+  cf->next = winner->cf;
+  winner->cf = NULL;
+
+  switch(cf->conn->alpn) {
+  case CURL_HTTP_VERSION_3:
+    infof(data, "using HTTP/3");
+    break;
+  case CURL_HTTP_VERSION_2:
+#ifdef USE_NGHTTP2
+    /* Using nghttp2, we add the filter "below" us, so when the conn
+     * closes, we tear it down for a fresh reconnect */
+    result = Curl_http2_switch_at(cf, data);
+    if(result) {
+      ctx->state = CF_HC_FAILURE;
+      ctx->result = result;
+      return result;
+    }
+#endif
+    infof(data, "using HTTP/2");
+    break;
+  default:
+    infof(data, "using HTTP/1.x");
+    break;
+  }
+  ctx->state = CF_HC_SUCCESS;
+  cf->connected = TRUE;
+  Curl_conn_cf_cntrl(cf->next, data, TRUE,
+                     CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
+  return result;
+}
+
+
+static bool time_to_start_h21(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              struct curltime now)
+{
+  struct cf_hc_ctx *ctx = cf->ctx;
+  timediff_t elapsed_ms;
+
+  if(!ctx->h21_baller.enabled || cf_hc_baller_has_started(&ctx->h21_baller))
+    return FALSE;
+
+  if(!ctx->h3_baller.enabled || !cf_hc_baller_is_active(&ctx->h3_baller))
+    return TRUE;
+
+  elapsed_ms = Curl_timediff(now, ctx->started);
+  if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) {
+    CURL_TRC_CF(data, cf, "hard timeout of %dms reached, starting h21",
+                ctx->hard_eyeballs_timeout_ms);
+    return TRUE;
+  }
+
+  if(elapsed_ms >= ctx->soft_eyeballs_timeout_ms) {
+    if(cf_hc_baller_reply_ms(&ctx->h3_baller, data) < 0) {
+      CURL_TRC_CF(data, cf, "soft timeout of %dms reached, h3 has not "
+                  "seen any data, starting h21",
+                  ctx->soft_eyeballs_timeout_ms);
+      return TRUE;
+    }
+    /* set the effective hard timeout again */
+    Curl_expire(data, ctx->hard_eyeballs_timeout_ms - elapsed_ms,
+                EXPIRE_ALPN_EYEBALLS);
+  }
+  return FALSE;
+}
+
+static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              bool blocking, bool *done)
+{
+  struct cf_hc_ctx *ctx = cf->ctx;
+  struct curltime now;
+  CURLcode result = CURLE_OK;
+
+  (void)blocking;
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  *done = FALSE;
+  now = Curl_now();
+  switch(ctx->state) {
+  case CF_HC_INIT:
+    DEBUGASSERT(!ctx->h3_baller.cf);
+    DEBUGASSERT(!ctx->h21_baller.cf);
+    DEBUGASSERT(!cf->next);
+    CURL_TRC_CF(data, cf, "connect, init");
+    ctx->started = now;
+    if(ctx->h3_baller.enabled) {
+      cf_hc_baller_init(&ctx->h3_baller, cf, data, "h3", TRNSPRT_QUIC);
+      if(ctx->h21_baller.enabled)
+        Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
+    }
+    else if(ctx->h21_baller.enabled)
+      cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
+                       cf->conn->transport);
+    ctx->state = CF_HC_CONNECT;
+    FALLTHROUGH();
+
+  case CF_HC_CONNECT:
+    if(cf_hc_baller_is_active(&ctx->h3_baller)) {
+      result = cf_hc_baller_connect(&ctx->h3_baller, cf, data, done);
+      if(!result && *done) {
+        result = baller_connected(cf, data, &ctx->h3_baller);
+        goto out;
+      }
+    }
+
+    if(time_to_start_h21(cf, data, now)) {
+      cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
+                        cf->conn->transport);
+    }
+
+    if(cf_hc_baller_is_active(&ctx->h21_baller)) {
+      CURL_TRC_CF(data, cf, "connect, check h21");
+      result = cf_hc_baller_connect(&ctx->h21_baller, cf, data, done);
+      if(!result && *done) {
+        result = baller_connected(cf, data, &ctx->h21_baller);
+        goto out;
+      }
+    }
+
+    if((!ctx->h3_baller.enabled || ctx->h3_baller.result) &&
+       (!ctx->h21_baller.enabled || ctx->h21_baller.result)) {
+      /* both failed or disabled. we give up */
+      CURL_TRC_CF(data, cf, "connect, all failed");
+      result = ctx->result = ctx->h3_baller.enabled?
+                              ctx->h3_baller.result : ctx->h21_baller.result;
+      ctx->state = CF_HC_FAILURE;
+      goto out;
+    }
+    result = CURLE_OK;
+    *done = FALSE;
+    break;
+
+  case CF_HC_FAILURE:
+    result = ctx->result;
+    cf->connected = FALSE;
+    *done = FALSE;
+    break;
+
+  case CF_HC_SUCCESS:
+    result = CURLE_OK;
+    cf->connected = TRUE;
+    *done = TRUE;
+    break;
+  }
+
+out:
+  CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done);
+  return result;
+}
+
+static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  struct easy_pollset *ps)
+{
+  if(!cf->connected) {
+    struct cf_hc_ctx *ctx = cf->ctx;
+    struct cf_hc_baller *ballers[2];
+    size_t i;
+
+    ballers[0] = &ctx->h3_baller;
+    ballers[1] = &ctx->h21_baller;
+    for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
+      struct cf_hc_baller *b = ballers[i];
+      if(!cf_hc_baller_is_active(b))
+        continue;
+      Curl_conn_cf_adjust_pollset(b->cf, data, ps);
+    }
+    CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
+  }
+}
+
+static bool cf_hc_data_pending(struct Curl_cfilter *cf,
+                               const struct Curl_easy *data)
+{
+  struct cf_hc_ctx *ctx = cf->ctx;
+
+  if(cf->connected)
+    return cf->next->cft->has_data_pending(cf->next, data);
+
+  CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending");
+  return cf_hc_baller_data_pending(&ctx->h3_baller, data)
+         || cf_hc_baller_data_pending(&ctx->h21_baller, data);
+}
+
+static struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf,
+                                              struct Curl_easy *data,
+                                              int query)
+{
+  struct cf_hc_ctx *ctx = cf->ctx;
+  struct Curl_cfilter *cfb;
+  struct curltime t, tmax;
+
+  memset(&tmax, 0, sizeof(tmax));
+  memset(&t, 0, sizeof(t));
+  cfb = ctx->h21_baller.enabled? ctx->h21_baller.cf : NULL;
+  if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
+    if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+      tmax = t;
+  }
+  memset(&t, 0, sizeof(t));
+  cfb = ctx->h3_baller.enabled? ctx->h3_baller.cf : NULL;
+  if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
+    if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+      tmax = t;
+  }
+  return tmax;
+}
+
+static CURLcode cf_hc_query(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            int query, int *pres1, void *pres2)
+{
+  if(!cf->connected) {
+    switch(query) {
+    case CF_QUERY_TIMER_CONNECT: {
+      struct curltime *when = pres2;
+      *when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT);
+      return CURLE_OK;
+    }
+    case CF_QUERY_TIMER_APPCONNECT: {
+      struct curltime *when = pres2;
+      *when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT);
+      return CURLE_OK;
+    }
+    default:
+      break;
+    }
+  }
+  return cf->next?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
+}
+
+static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  CURL_TRC_CF(data, cf, "close");
+  cf_hc_reset(cf, data);
+  cf->connected = FALSE;
+
+  if(cf->next) {
+    cf->next->cft->do_close(cf->next, data);
+    Curl_conn_cf_discard_chain(&cf->next, data);
+  }
+}
+
+static void cf_hc_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_hc_ctx *ctx = cf->ctx;
+
+  (void)data;
+  CURL_TRC_CF(data, cf, "destroy");
+  cf_hc_reset(cf, data);
+  Curl_safefree(ctx);
+}
+
+struct Curl_cftype Curl_cft_http_connect = {
+  "HTTPS-CONNECT",
+  0,
+  CURL_LOG_LVL_NONE,
+  cf_hc_destroy,
+  cf_hc_connect,
+  cf_hc_close,
+  Curl_cf_def_get_host,
+  cf_hc_adjust_pollset,
+  cf_hc_data_pending,
+  Curl_cf_def_send,
+  Curl_cf_def_recv,
+  Curl_cf_def_cntrl,
+  Curl_cf_def_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  cf_hc_query,
+};
+
+static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
+                             struct Curl_easy *data,
+                             const struct Curl_dns_entry *remotehost,
+                             bool try_h3, bool try_h21)
+{
+  struct Curl_cfilter *cf = NULL;
+  struct cf_hc_ctx *ctx;
+  CURLcode result = CURLE_OK;
+
+  (void)data;
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  ctx->remotehost = remotehost;
+  ctx->h3_baller.enabled = try_h3;
+  ctx->h21_baller.enabled = try_h21;
+
+  result = Curl_cf_create(&cf, &Curl_cft_http_connect, ctx);
+  if(result)
+    goto out;
+  ctx = NULL;
+  cf_hc_reset(cf, data);
+
+out:
+  *pcf = result? NULL : cf;
+  free(ctx);
+  return result;
+}
+
+static CURLcode cf_http_connect_add(struct Curl_easy *data,
+                                    struct connectdata *conn,
+                                    int sockindex,
+                                    const struct Curl_dns_entry *remotehost,
+                                    bool try_h3, bool try_h21)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(data);
+  result = cf_hc_create(&cf, data, remotehost, try_h3, try_h21);
+  if(result)
+    goto out;
+  Curl_conn_cf_add(data, conn, sockindex, cf);
+out:
+  return result;
+}
+
+CURLcode Curl_cf_https_setup(struct Curl_easy *data,
+                             struct connectdata *conn,
+                             int sockindex,
+                             const struct Curl_dns_entry *remotehost)
+{
+  bool try_h3 = FALSE, try_h21 = TRUE; /* defaults, for now */
+  CURLcode result = CURLE_OK;
+
+  (void)sockindex;
+  (void)remotehost;
+
+  if(!conn->bits.tls_enable_alpn)
+    goto out;
+
+  if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
+    result = Curl_conn_may_http3(data, conn);
+    if(result) /* can't do it */
+      goto out;
+    try_h3 = TRUE;
+    try_h21 = FALSE;
+  }
+  else if(data->state.httpwant >= CURL_HTTP_VERSION_3) {
+    /* We assume that silently not even trying H3 is ok here */
+    /* TODO: should we fail instead? */
+    try_h3 = (Curl_conn_may_http3(data, conn) == CURLE_OK);
+    try_h21 = TRUE;
+  }
+
+  result = cf_http_connect_add(data, conn, sockindex, remotehost,
+                               try_h3, try_h21);
+out:
+  return result;
+}
+
+#endif /* !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) */
Index: trunk/src/libs/curl-8.7.1/lib/cf-https-connect.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cf-https-connect.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cf-https-connect.h	(revision 104083)
@@ -0,0 +1,58 @@
+#ifndef HEADER_CURL_CF_HTTP_H
+#define HEADER_CURL_CF_HTTP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+
+struct Curl_cfilter;
+struct Curl_easy;
+struct connectdata;
+struct Curl_cftype;
+struct Curl_dns_entry;
+
+extern struct Curl_cftype Curl_cft_http_connect;
+
+CURLcode Curl_cf_http_connect_add(struct Curl_easy *data,
+                                  struct connectdata *conn,
+                                  int sockindex,
+                                  const struct Curl_dns_entry *remotehost,
+                                  bool try_h3, bool try_h21);
+
+CURLcode
+Curl_cf_http_connect_insert_after(struct Curl_cfilter *cf_at,
+                                  struct Curl_easy *data,
+                                  const struct Curl_dns_entry *remotehost,
+                                  bool try_h3, bool try_h21);
+
+
+CURLcode Curl_cf_https_setup(struct Curl_easy *data,
+                             struct connectdata *conn,
+                             int sockindex,
+                             const struct Curl_dns_entry *remotehost);
+
+
+#endif /* !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) */
+#endif /* HEADER_CURL_CF_HTTP_H */
Index: trunk/src/libs/curl-8.7.1/lib/cf-socket.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cf-socket.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cf-socket.c	(revision 104083)
@@ -0,0 +1,1972 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h> /* <netinet/tcp.h> may need it */
+#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h> /* for sockaddr_un */
+#endif
+#ifdef HAVE_LINUX_TCP_H
+#include <linux/tcp.h>
+#elif defined(HAVE_NETINET_TCP_H)
+#include <netinet/tcp.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "urldata.h"
+#include "bufq.h"
+#include "sendf.h"
+#include "if2ip.h"
+#include "strerror.h"
+#include "cfilters.h"
+#include "cf-socket.h"
+#include "connect.h"
+#include "select.h"
+#include "url.h" /* for Curl_safefree() */
+#include "multiif.h"
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "inet_ntop.h"
+#include "inet_pton.h"
+#include "progress.h"
+#include "warnless.h"
+#include "conncache.h"
+#include "multihandle.h"
+#include "rand.h"
+#include "share.h"
+#include "version_win32.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+#if defined(ENABLE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
+/* It makes support for IPv4-mapped IPv6 addresses.
+ * Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
+ * Windows Vista and later: default is on;
+ * DragonFly BSD: acts like off, and dummy setting;
+ * OpenBSD and earlier Windows: unsupported.
+ * Linux: controlled by /proc/sys/net/ipv6/bindv6only.
+ */
+static void set_ipv6_v6only(curl_socket_t sockfd, int on)
+{
+  (void)setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on));
+}
+#else
+#define set_ipv6_v6only(x,y)
+#endif
+
+static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
+{
+#if defined(TCP_NODELAY)
+  curl_socklen_t onoff = (curl_socklen_t) 1;
+  int level = IPPROTO_TCP;
+  char buffer[STRERROR_LEN];
+
+  if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
+                sizeof(onoff)) < 0)
+    infof(data, "Could not set TCP_NODELAY: %s",
+          Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+#else
+  (void)data;
+  (void)sockfd;
+#endif
+}
+
+#ifdef SO_NOSIGPIPE
+/* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
+   sending data to a dead peer (instead of relying on the 4th argument to send
+   being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
+   systems? */
+static void nosigpipe(struct Curl_easy *data,
+                      curl_socket_t sockfd)
+{
+  int onoff = 1;
+  (void)data;
+  if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
+                sizeof(onoff)) < 0) {
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+    char buffer[STRERROR_LEN];
+    infof(data, "Could not set SO_NOSIGPIPE: %s",
+          Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+#endif
+  }
+}
+#else
+#define nosigpipe(x,y) Curl_nop_stmt
+#endif
+
+#if defined(__DragonFly__) || defined(USE_WINSOCK)
+/* DragonFlyBSD and Windows use millisecond units */
+#define KEEPALIVE_FACTOR(x) (x *= 1000)
+#else
+#define KEEPALIVE_FACTOR(x)
+#endif
+
+#if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS)
+#define SIO_KEEPALIVE_VALS    _WSAIOW(IOC_VENDOR,4)
+
+struct tcp_keepalive {
+  u_long onoff;
+  u_long keepalivetime;
+  u_long keepaliveinterval;
+};
+#endif
+
+static void
+tcpkeepalive(struct Curl_easy *data,
+             curl_socket_t sockfd)
+{
+  int optval = data->set.tcp_keepalive?1:0;
+
+  /* only set IDLE and INTVL if setting KEEPALIVE is successful */
+  if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
+        (void *)&optval, sizeof(optval)) < 0) {
+    infof(data, "Failed to set SO_KEEPALIVE on fd "
+          "%" CURL_FORMAT_SOCKET_T ": errno %d",
+          sockfd, SOCKERRNO);
+  }
+  else {
+#if defined(SIO_KEEPALIVE_VALS)
+    struct tcp_keepalive vals;
+    DWORD dummy;
+    vals.onoff = 1;
+    optval = curlx_sltosi(data->set.tcp_keepidle);
+    KEEPALIVE_FACTOR(optval);
+    vals.keepalivetime = optval;
+    optval = curlx_sltosi(data->set.tcp_keepintvl);
+    KEEPALIVE_FACTOR(optval);
+    vals.keepaliveinterval = optval;
+    if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
+                NULL, 0, &dummy, NULL, NULL) != 0) {
+      infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd "
+                  "%" CURL_FORMAT_SOCKET_T ": errno %d",
+                  sockfd, SOCKERRNO);
+    }
+#else
+#ifdef TCP_KEEPIDLE
+    optval = curlx_sltosi(data->set.tcp_keepidle);
+    KEEPALIVE_FACTOR(optval);
+    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
+          (void *)&optval, sizeof(optval)) < 0) {
+      infof(data, "Failed to set TCP_KEEPIDLE on fd "
+            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            sockfd, SOCKERRNO);
+    }
+#elif defined(TCP_KEEPALIVE)
+    /* Mac OS X style */
+    optval = curlx_sltosi(data->set.tcp_keepidle);
+    KEEPALIVE_FACTOR(optval);
+    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
+      (void *)&optval, sizeof(optval)) < 0) {
+      infof(data, "Failed to set TCP_KEEPALIVE on fd "
+            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            sockfd, SOCKERRNO);
+    }
+#endif
+#ifdef TCP_KEEPINTVL
+    optval = curlx_sltosi(data->set.tcp_keepintvl);
+    KEEPALIVE_FACTOR(optval);
+    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
+          (void *)&optval, sizeof(optval)) < 0) {
+      infof(data, "Failed to set TCP_KEEPINTVL on fd "
+            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            sockfd, SOCKERRNO);
+    }
+#endif
+#endif
+  }
+}
+
+/**
+ * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
+ * set the transport used.
+ */
+void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
+                           const struct Curl_addrinfo *ai,
+                           int transport)
+{
+  /*
+   * The Curl_sockaddr_ex structure is basically libcurl's external API
+   * curl_sockaddr structure with enough space available to directly hold
+   * any protocol-specific address structures. The variable declared here
+   * will be used to pass / receive data to/from the fopensocket callback
+   * if this has been set, before that, it is initialized from parameters.
+   */
+  dest->family = ai->ai_family;
+  switch(transport) {
+  case TRNSPRT_TCP:
+    dest->socktype = SOCK_STREAM;
+    dest->protocol = IPPROTO_TCP;
+    break;
+  case TRNSPRT_UNIX:
+    dest->socktype = SOCK_STREAM;
+    dest->protocol = IPPROTO_IP;
+    break;
+  default: /* UDP and QUIC */
+    dest->socktype = SOCK_DGRAM;
+    dest->protocol = IPPROTO_UDP;
+    break;
+  }
+  dest->addrlen = ai->ai_addrlen;
+
+  if(dest->addrlen > sizeof(struct Curl_sockaddr_storage))
+    dest->addrlen = sizeof(struct Curl_sockaddr_storage);
+  memcpy(&dest->sa_addr, ai->ai_addr, dest->addrlen);
+}
+
+static CURLcode socket_open(struct Curl_easy *data,
+                            struct Curl_sockaddr_ex *addr,
+                            curl_socket_t *sockfd)
+{
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  if(data->set.fopensocket) {
+   /*
+    * If the opensocket callback is set, all the destination address
+    * information is passed to the callback. Depending on this information the
+    * callback may opt to abort the connection, this is indicated returning
+    * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
+    * the callback returns a valid socket the destination address information
+    * might have been changed and this 'new' address will actually be used
+    * here to connect.
+    */
+    Curl_set_in_callback(data, true);
+    *sockfd = data->set.fopensocket(data->set.opensocket_client,
+                                    CURLSOCKTYPE_IPCXN,
+                                    (struct curl_sockaddr *)addr);
+    Curl_set_in_callback(data, false);
+  }
+  else {
+    /* opensocket callback not set, so simply create the socket now */
+    *sockfd = socket(addr->family, addr->socktype, addr->protocol);
+  }
+
+  if(*sockfd == CURL_SOCKET_BAD)
+    /* no socket, no connection */
+    return CURLE_COULDNT_CONNECT;
+
+#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
+  if(data->conn->scope_id && (addr->family == AF_INET6)) {
+    struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
+    sa6->sin6_scope_id = data->conn->scope_id;
+  }
+#endif
+  return CURLE_OK;
+}
+
+/*
+ * Create a socket based on info from 'conn' and 'ai'.
+ *
+ * 'addr' should be a pointer to the correct struct to get data back, or NULL.
+ * 'sockfd' must be a pointer to a socket descriptor.
+ *
+ * If the open socket callback is set, used that!
+ *
+ */
+CURLcode Curl_socket_open(struct Curl_easy *data,
+                            const struct Curl_addrinfo *ai,
+                            struct Curl_sockaddr_ex *addr,
+                            int transport,
+                            curl_socket_t *sockfd)
+{
+  struct Curl_sockaddr_ex dummy;
+
+  if(!addr)
+    /* if the caller doesn't want info back, use a local temp copy */
+    addr = &dummy;
+
+  Curl_sock_assign_addr(addr, ai, transport);
+  return socket_open(data, addr, sockfd);
+}
+
+static int socket_close(struct Curl_easy *data, struct connectdata *conn,
+                        int use_callback, curl_socket_t sock)
+{
+  if(use_callback && conn && conn->fclosesocket) {
+    int rc;
+    Curl_multi_closed(data, sock);
+    Curl_set_in_callback(data, true);
+    rc = conn->fclosesocket(conn->closesocket_client, sock);
+    Curl_set_in_callback(data, false);
+    return rc;
+  }
+
+  if(conn)
+    /* tell the multi-socket code about this */
+    Curl_multi_closed(data, sock);
+
+  sclose(sock);
+
+  return 0;
+}
+
+/*
+ * Close a socket.
+ *
+ * 'conn' can be NULL, beware!
+ */
+int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
+                      curl_socket_t sock)
+{
+  return socket_close(data, conn, FALSE, sock);
+}
+
+#ifdef USE_WINSOCK
+/* When you run a program that uses the Windows Sockets API, you may
+   experience slow performance when you copy data to a TCP server.
+
+   https://support.microsoft.com/kb/823764
+
+   Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
+   Buffer Size
+
+   The problem described in this knowledge-base is applied only to pre-Vista
+   Windows.  Following function trying to detect OS version and skips
+   SO_SNDBUF adjustment for Windows Vista and above.
+*/
+#define DETECT_OS_NONE 0
+#define DETECT_OS_PREVISTA 1
+#define DETECT_OS_VISTA_OR_LATER 2
+
+void Curl_sndbufset(curl_socket_t sockfd)
+{
+  int val = CURL_MAX_WRITE_SIZE + 32;
+  int curval = 0;
+  int curlen = sizeof(curval);
+
+  static int detectOsState = DETECT_OS_NONE;
+
+  if(detectOsState == DETECT_OS_NONE) {
+    if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
+                                    VERSION_GREATER_THAN_EQUAL))
+      detectOsState = DETECT_OS_VISTA_OR_LATER;
+    else
+      detectOsState = DETECT_OS_PREVISTA;
+  }
+
+  if(detectOsState == DETECT_OS_VISTA_OR_LATER)
+    return;
+
+  if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
+    if(curval > val)
+      return;
+
+  setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
+}
+#endif
+
+#ifndef CURL_DISABLE_BINDLOCAL
+static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
+                          curl_socket_t sockfd, int af, unsigned int scope)
+{
+  struct Curl_sockaddr_storage sa;
+  struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
+  curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
+  struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
+#ifdef ENABLE_IPV6
+  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
+#endif
+
+  struct Curl_dns_entry *h = NULL;
+  unsigned short port = data->set.localport; /* use this port number, 0 for
+                                                "random" */
+  /* how many port numbers to try to bind to, increasing one at a time */
+  int portnum = data->set.localportrange;
+  const char *dev = data->set.str[STRING_DEVICE];
+  int error;
+#ifdef IP_BIND_ADDRESS_NO_PORT
+  int on = 1;
+#endif
+#ifndef ENABLE_IPV6
+  (void)scope;
+#endif
+
+  /*************************************************************
+   * Select device to bind socket to
+   *************************************************************/
+  if(!dev && !port)
+    /* no local kind of binding was requested */
+    return CURLE_OK;
+
+  memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
+
+  if(dev && (strlen(dev)<255) ) {
+    char myhost[256] = "";
+    int done = 0; /* -1 for error, 1 for address found */
+    bool is_interface = FALSE;
+    bool is_host = FALSE;
+    static const char *if_prefix = "if!";
+    static const char *host_prefix = "host!";
+
+    if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
+      dev += strlen(if_prefix);
+      is_interface = TRUE;
+    }
+    else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
+      dev += strlen(host_prefix);
+      is_host = TRUE;
+    }
+
+    /* interface */
+    if(!is_host) {
+#ifdef SO_BINDTODEVICE
+      /*
+       * This binds the local socket to a particular interface. This will
+       * force even requests to other local interfaces to go out the external
+       * interface. Only bind to the interface when specified as interface,
+       * not just as a hostname or ip address.
+       *
+       * The interface might be a VRF, eg: vrf-blue, which means it cannot be
+       * converted to an IP address and would fail Curl_if2ip. Simply try to
+       * use it straight away.
+       */
+      if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+                    dev, (curl_socklen_t)strlen(dev) + 1) == 0) {
+        /* This is often "errno 1, error: Operation not permitted" if you're
+         * not running as root or another suitable privileged user. If it
+         * succeeds it means the parameter was a valid interface and not an IP
+         * address. Return immediately.
+         */
+        infof(data, "socket successfully bound to interface '%s'", dev);
+        return CURLE_OK;
+      }
+#endif
+
+      switch(Curl_if2ip(af,
+#ifdef ENABLE_IPV6
+                        scope, conn->scope_id,
+#endif
+                        dev, myhost, sizeof(myhost))) {
+        case IF2IP_NOT_FOUND:
+          if(is_interface) {
+            /* Do not fall back to treating it as a host name */
+            failf(data, "Couldn't bind to interface '%s'", dev);
+            return CURLE_INTERFACE_FAILED;
+          }
+          break;
+        case IF2IP_AF_NOT_SUPPORTED:
+          /* Signal the caller to try another address family if available */
+          return CURLE_UNSUPPORTED_PROTOCOL;
+        case IF2IP_FOUND:
+          is_interface = TRUE;
+          /*
+           * We now have the numerical IP address in the 'myhost' buffer
+           */
+          infof(data, "Local Interface %s is ip %s using address family %i",
+                dev, myhost, af);
+          done = 1;
+          break;
+      }
+    }
+    if(!is_interface) {
+      /*
+       * This was not an interface, resolve the name as a host name
+       * or IP number
+       *
+       * Temporarily force name resolution to use only the address type
+       * of the connection. The resolve functions should really be changed
+       * to take a type parameter instead.
+       */
+      unsigned char ipver = conn->ip_version;
+      int rc;
+
+      if(af == AF_INET)
+        conn->ip_version = CURL_IPRESOLVE_V4;
+#ifdef ENABLE_IPV6
+      else if(af == AF_INET6)
+        conn->ip_version = CURL_IPRESOLVE_V6;
+#endif
+
+      rc = Curl_resolv(data, dev, 80, FALSE, &h);
+      if(rc == CURLRESOLV_PENDING)
+        (void)Curl_resolver_wait_resolv(data, &h);
+      conn->ip_version = ipver;
+
+      if(h) {
+        /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
+        Curl_printable_address(h->addr, myhost, sizeof(myhost));
+        infof(data, "Name '%s' family %i resolved to '%s' family %i",
+              dev, af, myhost, h->addr->ai_family);
+        Curl_resolv_unlock(data, h);
+        if(af != h->addr->ai_family) {
+          /* bad IP version combo, signal the caller to try another address
+             family if available */
+          return CURLE_UNSUPPORTED_PROTOCOL;
+        }
+        done = 1;
+      }
+      else {
+        /*
+         * provided dev was no interface (or interfaces are not supported
+         * e.g. solaris) no ip address and no domain we fail here
+         */
+        done = -1;
+      }
+    }
+
+    if(done > 0) {
+#ifdef ENABLE_IPV6
+      /* IPv6 address */
+      if(af == AF_INET6) {
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+        char *scope_ptr = strchr(myhost, '%');
+        if(scope_ptr)
+          *(scope_ptr++) = '\0';
+#endif
+        if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
+          si6->sin6_family = AF_INET6;
+          si6->sin6_port = htons(port);
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+          if(scope_ptr) {
+            /* The "myhost" string either comes from Curl_if2ip or from
+               Curl_printable_address. The latter returns only numeric scope
+               IDs and the former returns none at all.  So the scope ID, if
+               present, is known to be numeric */
+            unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
+            if(scope_id > UINT_MAX)
+              return CURLE_UNSUPPORTED_PROTOCOL;
+
+            si6->sin6_scope_id = (unsigned int)scope_id;
+          }
+#endif
+        }
+        sizeof_sa = sizeof(struct sockaddr_in6);
+      }
+      else
+#endif
+      /* IPv4 address */
+      if((af == AF_INET) &&
+         (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
+        si4->sin_family = AF_INET;
+        si4->sin_port = htons(port);
+        sizeof_sa = sizeof(struct sockaddr_in);
+      }
+    }
+
+    if(done < 1) {
+      /* errorbuf is set false so failf will overwrite any message already in
+         the error buffer, so the user receives this error message instead of a
+         generic resolve error. */
+      data->state.errorbuf = FALSE;
+      failf(data, "Couldn't bind to '%s'", dev);
+      return CURLE_INTERFACE_FAILED;
+    }
+  }
+  else {
+    /* no device was given, prepare sa to match af's needs */
+#ifdef ENABLE_IPV6
+    if(af == AF_INET6) {
+      si6->sin6_family = AF_INET6;
+      si6->sin6_port = htons(port);
+      sizeof_sa = sizeof(struct sockaddr_in6);
+    }
+    else
+#endif
+    if(af == AF_INET) {
+      si4->sin_family = AF_INET;
+      si4->sin_port = htons(port);
+      sizeof_sa = sizeof(struct sockaddr_in);
+    }
+  }
+#ifdef IP_BIND_ADDRESS_NO_PORT
+  (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
+#endif
+  for(;;) {
+    if(bind(sockfd, sock, sizeof_sa) >= 0) {
+      /* we succeeded to bind */
+      struct Curl_sockaddr_storage add;
+      curl_socklen_t size = sizeof(add);
+      memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
+      if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
+        char buffer[STRERROR_LEN];
+        data->state.os_errno = error = SOCKERRNO;
+        failf(data, "getsockname() failed with errno %d: %s",
+              error, Curl_strerror(error, buffer, sizeof(buffer)));
+        return CURLE_INTERFACE_FAILED;
+      }
+      infof(data, "Local port: %hu", port);
+      conn->bits.bound = TRUE;
+      return CURLE_OK;
+    }
+
+    if(--portnum > 0) {
+      port++; /* try next port */
+      if(port == 0)
+        break;
+      infof(data, "Bind to local port %d failed, trying next", port - 1);
+      /* We reuse/clobber the port variable here below */
+      if(sock->sa_family == AF_INET)
+        si4->sin_port = ntohs(port);
+#ifdef ENABLE_IPV6
+      else
+        si6->sin6_port = ntohs(port);
+#endif
+    }
+    else
+      break;
+  }
+  {
+    char buffer[STRERROR_LEN];
+    data->state.os_errno = error = SOCKERRNO;
+    failf(data, "bind failed with errno %d: %s",
+          error, Curl_strerror(error, buffer, sizeof(buffer)));
+  }
+
+  return CURLE_INTERFACE_FAILED;
+}
+#endif
+
+/*
+ * verifyconnect() returns TRUE if the connect really has happened.
+ */
+static bool verifyconnect(curl_socket_t sockfd, int *error)
+{
+  bool rc = TRUE;
+#ifdef SO_ERROR
+  int err = 0;
+  curl_socklen_t errSize = sizeof(err);
+
+#ifdef _WIN32
+  /*
+   * In October 2003 we effectively nullified this function on Windows due to
+   * problems with it using all CPU in multi-threaded cases.
+   *
+   * In May 2004, we bring it back to offer more info back on connect failures.
+   * Gisle Vanem could reproduce the former problems with this function, but
+   * could avoid them by adding this SleepEx() call below:
+   *
+   *    "I don't have Rational Quantify, but the hint from his post was
+   *    ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
+   *    just Sleep(0) would be enough?) would release whatever
+   *    mutex/critical-section the ntdll call is waiting on.
+   *
+   *    Someone got to verify this on Win-NT 4.0, 2000."
+   */
+
+#ifdef _WIN32_WCE
+  Sleep(0);
+#else
+  SleepEx(0, FALSE);
+#endif
+
+#endif
+
+  if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
+    err = SOCKERRNO;
+#ifdef _WIN32_WCE
+  /* Old WinCE versions don't support SO_ERROR */
+  if(WSAENOPROTOOPT == err) {
+    SET_SOCKERRNO(0);
+    err = 0;
+  }
+#endif
+#if defined(EBADIOCTL) && defined(__minix)
+  /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
+  if(EBADIOCTL == err) {
+    SET_SOCKERRNO(0);
+    err = 0;
+  }
+#endif
+  if((0 == err) || (EISCONN == err))
+    /* we are connected, awesome! */
+    rc = TRUE;
+  else
+    /* This wasn't a successful connect */
+    rc = FALSE;
+  if(error)
+    *error = err;
+#else
+  (void)sockfd;
+  if(error)
+    *error = SOCKERRNO;
+#endif
+  return rc;
+}
+
+/**
+ * Determine the curl code for a socket connect() == -1 with errno.
+ */
+static CURLcode socket_connect_result(struct Curl_easy *data,
+                                      const char *ipaddress, int error)
+{
+  switch(error) {
+  case EINPROGRESS:
+  case EWOULDBLOCK:
+#if defined(EAGAIN)
+#if (EAGAIN) != (EWOULDBLOCK)
+    /* On some platforms EAGAIN and EWOULDBLOCK are the
+     * same value, and on others they are different, hence
+     * the odd #if
+     */
+  case EAGAIN:
+#endif
+#endif
+    return CURLE_OK;
+
+  default:
+    /* unknown error, fallthrough and try another address! */
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+    (void)ipaddress;
+#else
+    {
+      char buffer[STRERROR_LEN];
+      infof(data, "Immediate connect fail for %s: %s",
+            ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
+    }
+#endif
+    data->state.os_errno = error;
+    /* connect failed */
+    return CURLE_COULDNT_CONNECT;
+  }
+}
+
+/* We have a recv buffer to enhance reads with len < NW_SMALL_READS.
+ * This happens often on TLS connections where the TLS implementation
+ * tries to read the head of a TLS record, determine the length of the
+ * full record and then make a subsequent read for that.
+ * On large reads, we will not fill the buffer to avoid the double copy. */
+#define NW_RECV_CHUNK_SIZE    (64 * 1024)
+#define NW_RECV_CHUNKS         1
+#define NW_SMALL_READS        (1024)
+
+struct cf_socket_ctx {
+  int transport;
+  struct Curl_sockaddr_ex addr;      /* address to connect to */
+  curl_socket_t sock;                /* current attempt socket */
+  struct bufq recvbuf;               /* used when `buffer_recv` is set */
+  struct ip_quadruple ip;            /* The IP quadruple 2x(addr+port) */
+  struct curltime started_at;        /* when socket was created */
+  struct curltime connected_at;      /* when socket connected/got first byte */
+  struct curltime first_byte_at;     /* when first byte was recvd */
+  int error;                         /* errno of last failure or 0 */
+#ifdef DEBUGBUILD
+  int wblock_percent;                /* percent of writes doing EAGAIN */
+  int wpartial_percent;              /* percent of bytes written in send */
+  int rblock_percent;                /* percent of reads doing EAGAIN */
+  size_t recv_max;                  /* max enforced read size */
+#endif
+  BIT(got_first_byte);               /* if first byte was received */
+  BIT(accepted);                     /* socket was accepted, not connected */
+  BIT(sock_connected);               /* socket is "connected", e.g. in UDP */
+  BIT(active);
+  BIT(buffer_recv);
+};
+
+static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
+                               const struct Curl_addrinfo *ai,
+                               int transport)
+{
+  memset(ctx, 0, sizeof(*ctx));
+  ctx->sock = CURL_SOCKET_BAD;
+  ctx->transport = transport;
+  Curl_sock_assign_addr(&ctx->addr, ai, transport);
+  Curl_bufq_init(&ctx->recvbuf, NW_RECV_CHUNK_SIZE, NW_RECV_CHUNKS);
+#ifdef DEBUGBUILD
+  {
+    char *p = getenv("CURL_DBG_SOCK_WBLOCK");
+    if(p) {
+      long l = strtol(p, NULL, 10);
+      if(l >= 0 && l <= 100)
+        ctx->wblock_percent = (int)l;
+    }
+    p = getenv("CURL_DBG_SOCK_WPARTIAL");
+    if(p) {
+      long l = strtol(p, NULL, 10);
+      if(l >= 0 && l <= 100)
+        ctx->wpartial_percent = (int)l;
+    }
+    p = getenv("CURL_DBG_SOCK_RBLOCK");
+    if(p) {
+      long l = strtol(p, NULL, 10);
+      if(l >= 0 && l <= 100)
+        ctx->rblock_percent = (int)l;
+    }
+    p = getenv("CURL_DBG_SOCK_RMAX");
+    if(p) {
+      long l = strtol(p, NULL, 10);
+      if(l >= 0)
+        ctx->recv_max = (size_t)l;
+    }
+  }
+#endif
+}
+
+struct reader_ctx {
+  struct Curl_cfilter *cf;
+  struct Curl_easy *data;
+};
+
+static ssize_t nw_in_read(void *reader_ctx,
+                           unsigned char *buf, size_t len,
+                           CURLcode *err)
+{
+  struct reader_ctx *rctx = reader_ctx;
+  struct cf_socket_ctx *ctx = rctx->cf->ctx;
+  ssize_t nread;
+
+  *err = CURLE_OK;
+  nread = sread(ctx->sock, buf, len);
+
+  if(-1 == nread) {
+    int sockerr = SOCKERRNO;
+
+    if(
+#ifdef WSAEWOULDBLOCK
+      /* This is how Windows does it */
+      (WSAEWOULDBLOCK == sockerr)
+#else
+      /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
+         due to its inability to send off data without blocking. We therefore
+         treat both error codes the same here */
+      (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
+#endif
+      ) {
+      /* this is just a case of EWOULDBLOCK */
+      *err = CURLE_AGAIN;
+      nread = -1;
+    }
+    else {
+      char buffer[STRERROR_LEN];
+
+      failf(rctx->data, "Recv failure: %s",
+            Curl_strerror(sockerr, buffer, sizeof(buffer)));
+      rctx->data->state.os_errno = sockerr;
+      *err = CURLE_RECV_ERROR;
+      nread = -1;
+    }
+  }
+  CURL_TRC_CF(rctx->data, rctx->cf, "nw_in_read(len=%zu, fd=%"
+              CURL_FORMAT_SOCKET_T ") -> %d, err=%d",
+              len, ctx->sock, (int)nread, *err);
+  return nread;
+}
+
+static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+
+  if(ctx && CURL_SOCKET_BAD != ctx->sock) {
+    CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
+                ")", ctx->sock);
+    if(ctx->sock == cf->conn->sock[cf->sockindex])
+      cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
+    socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
+    ctx->sock = CURL_SOCKET_BAD;
+    if(ctx->active && cf->sockindex == FIRSTSOCKET)
+      cf->conn->remote_addr = NULL;
+    Curl_bufq_reset(&ctx->recvbuf);
+    ctx->active = FALSE;
+    ctx->buffer_recv = FALSE;
+    memset(&ctx->started_at, 0, sizeof(ctx->started_at));
+    memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
+  }
+
+  cf->connected = FALSE;
+}
+
+static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+
+  cf_socket_close(cf, data);
+  CURL_TRC_CF(data, cf, "destroy");
+  Curl_bufq_free(&ctx->recvbuf);
+  free(ctx);
+  cf->ctx = NULL;
+}
+
+static CURLcode set_local_ip(struct Curl_cfilter *cf,
+                             struct Curl_easy *data)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+
+#ifdef HAVE_GETSOCKNAME
+  if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) {
+    /* TFTP does not connect, so it cannot get the IP like this */
+
+    char buffer[STRERROR_LEN];
+    struct Curl_sockaddr_storage ssloc;
+    curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage);
+
+    memset(&ssloc, 0, sizeof(ssloc));
+    if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) {
+      int error = SOCKERRNO;
+      failf(data, "getsockname() failed with errno %d: %s",
+            error, Curl_strerror(error, buffer, sizeof(buffer)));
+      return CURLE_FAILED_INIT;
+    }
+    if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
+                         ctx->ip.local_ip, &ctx->ip.local_port)) {
+      failf(data, "ssloc inet_ntop() failed with errno %d: %s",
+            errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+      return CURLE_FAILED_INIT;
+    }
+  }
+#else
+  (void)data;
+  ctx->l_ip[0] = 0;
+  ctx->l_port = -1;
+#endif
+  return CURLE_OK;
+}
+
+static CURLcode set_remote_ip(struct Curl_cfilter *cf,
+                              struct Curl_easy *data)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+
+  /* store remote address and port used in this connection attempt */
+  if(!Curl_addr2string(&ctx->addr.sa_addr, ctx->addr.addrlen,
+                       ctx->ip.remote_ip, &ctx->ip.remote_port)) {
+    char buffer[STRERROR_LEN];
+
+    ctx->error = errno;
+    /* malformed address or bug in inet_ntop, try next address */
+    failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
+          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+    return CURLE_FAILED_INIT;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode cf_socket_open(struct Curl_cfilter *cf,
+                              struct Curl_easy *data)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+  int error = 0;
+  bool isconnected = FALSE;
+  CURLcode result = CURLE_COULDNT_CONNECT;
+  bool is_tcp;
+
+  (void)data;
+  DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
+  ctx->started_at = Curl_now();
+  result = socket_open(data, &ctx->addr, &ctx->sock);
+  if(result)
+    goto out;
+
+  result = set_remote_ip(cf, data);
+  if(result)
+    goto out;
+
+#ifdef ENABLE_IPV6
+  if(ctx->addr.family == AF_INET6) {
+    set_ipv6_v6only(ctx->sock, 0);
+    infof(data, "  Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
+  }
+  else
+#endif
+    infof(data, "  Trying %s:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
+
+#ifdef ENABLE_IPV6
+  is_tcp = (ctx->addr.family == AF_INET
+            || ctx->addr.family == AF_INET6) &&
+           ctx->addr.socktype == SOCK_STREAM;
+#else
+  is_tcp = (ctx->addr.family == AF_INET) &&
+           ctx->addr.socktype == SOCK_STREAM;
+#endif
+  if(is_tcp && data->set.tcp_nodelay)
+    tcpnodelay(data, ctx->sock);
+
+  nosigpipe(data, ctx->sock);
+
+  Curl_sndbufset(ctx->sock);
+
+  if(is_tcp && data->set.tcp_keepalive)
+    tcpkeepalive(data, ctx->sock);
+
+  if(data->set.fsockopt) {
+    /* activate callback for setting socket options */
+    Curl_set_in_callback(data, true);
+    error = data->set.fsockopt(data->set.sockopt_client,
+                               ctx->sock,
+                               CURLSOCKTYPE_IPCXN);
+    Curl_set_in_callback(data, false);
+
+    if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
+      isconnected = TRUE;
+    else if(error) {
+      result = CURLE_ABORTED_BY_CALLBACK;
+      goto out;
+    }
+  }
+
+#ifndef CURL_DISABLE_BINDLOCAL
+  /* possibly bind the local end to an IP, interface or port */
+  if(ctx->addr.family == AF_INET
+#ifdef ENABLE_IPV6
+     || ctx->addr.family == AF_INET6
+#endif
+    ) {
+    result = bindlocal(data, cf->conn, ctx->sock, ctx->addr.family,
+                       Curl_ipv6_scope(&ctx->addr.sa_addr));
+    if(result) {
+      if(result == CURLE_UNSUPPORTED_PROTOCOL) {
+        /* The address family is not supported on this interface.
+           We can continue trying addresses */
+        result = CURLE_COULDNT_CONNECT;
+      }
+      goto out;
+    }
+  }
+#endif
+
+  /* set socket non-blocking */
+  (void)curlx_nonblock(ctx->sock, TRUE);
+  ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
+out:
+  if(result) {
+    if(ctx->sock != CURL_SOCKET_BAD) {
+      socket_close(data, cf->conn, TRUE, ctx->sock);
+      ctx->sock = CURL_SOCKET_BAD;
+    }
+  }
+  else if(isconnected) {
+    set_local_ip(cf, data);
+    ctx->connected_at = Curl_now();
+    cf->connected = TRUE;
+  }
+  CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" CURL_FORMAT_SOCKET_T,
+              result, ctx->sock);
+  return result;
+}
+
+static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
+                      bool is_tcp_fastopen)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+#ifdef TCP_FASTOPEN_CONNECT
+  int optval = 1;
+#endif
+  int rc = -1;
+
+  (void)data;
+  if(is_tcp_fastopen) {
+#if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
+#  if defined(HAVE_BUILTIN_AVAILABLE)
+    /* while connectx function is available since macOS 10.11 / iOS 9,
+       it did not have the interface declared correctly until
+       Xcode 9 / macOS SDK 10.13 */
+    if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
+      sa_endpoints_t endpoints;
+      endpoints.sae_srcif = 0;
+      endpoints.sae_srcaddr = NULL;
+      endpoints.sae_srcaddrlen = 0;
+      endpoints.sae_dstaddr = &ctx->addr.sa_addr;
+      endpoints.sae_dstaddrlen = ctx->addr.addrlen;
+
+      rc = connectx(ctx->sock, &endpoints, SAE_ASSOCID_ANY,
+                    CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
+                    NULL, 0, NULL, NULL);
+    }
+    else {
+      rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
+    }
+#  else
+    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
+#  endif /* HAVE_BUILTIN_AVAILABLE */
+#elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
+    if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
+                  (void *)&optval, sizeof(optval)) < 0)
+      infof(data, "Failed to enable TCP Fast Open on fd %"
+            CURL_FORMAT_SOCKET_T, ctx->sock);
+
+    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
+#elif defined(MSG_FASTOPEN) /* old Linux */
+    if(cf->conn->given->flags & PROTOPT_SSL)
+      rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
+    else
+      rc = 0; /* Do nothing */
+#endif
+  }
+  else {
+    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
+  }
+  return rc;
+}
+
+static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               bool blocking, bool *done)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_COULDNT_CONNECT;
+  int rc = 0;
+
+  (void)data;
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  /* TODO: need to support blocking connect? */
+  if(blocking)
+    return CURLE_UNSUPPORTED_PROTOCOL;
+
+  *done = FALSE; /* a very negative world view is best */
+  if(ctx->sock == CURL_SOCKET_BAD) {
+    int error;
+
+    result = cf_socket_open(cf, data);
+    if(result)
+      goto out;
+
+    if(cf->connected) {
+      *done = TRUE;
+      return CURLE_OK;
+    }
+
+    /* Connect TCP socket */
+    rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
+    error = SOCKERRNO;
+    set_local_ip(cf, data);
+    CURL_TRC_CF(data, cf, "local address %s port %d...",
+                ctx->ip.local_ip, ctx->ip.local_port);
+    if(-1 == rc) {
+      result = socket_connect_result(data, ctx->ip.remote_ip, error);
+      goto out;
+    }
+  }
+
+#ifdef mpeix
+  /* Call this function once now, and ignore the results. We do this to
+     "clear" the error state on the socket so that we can later read it
+     reliably. This is reported necessary on the MPE/iX operating
+     system. */
+  (void)verifyconnect(ctx->sock, NULL);
+#endif
+  /* check socket for connect */
+  rc = SOCKET_WRITABLE(ctx->sock, 0);
+
+  if(rc == 0) { /* no connection yet */
+    CURL_TRC_CF(data, cf, "not connected yet");
+    return CURLE_OK;
+  }
+  else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
+    if(verifyconnect(ctx->sock, &ctx->error)) {
+      /* we are connected with TCP, awesome! */
+      ctx->connected_at = Curl_now();
+      set_local_ip(cf, data);
+      *done = TRUE;
+      cf->connected = TRUE;
+      CURL_TRC_CF(data, cf, "connected");
+      return CURLE_OK;
+    }
+  }
+  else if(rc & CURL_CSELECT_ERR) {
+    (void)verifyconnect(ctx->sock, &ctx->error);
+    result = CURLE_COULDNT_CONNECT;
+  }
+
+out:
+  if(result) {
+    if(ctx->error) {
+      set_local_ip(cf, data);
+      data->state.os_errno = ctx->error;
+      SET_SOCKERRNO(ctx->error);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+      {
+        char buffer[STRERROR_LEN];
+        infof(data, "connect to %s port %u from %s port %d failed: %s",
+              ctx->ip.remote_ip, ctx->ip.remote_port,
+              ctx->ip.local_ip, ctx->ip.local_port,
+              Curl_strerror(ctx->error, buffer, sizeof(buffer)));
+      }
+#endif
+    }
+    if(ctx->sock != CURL_SOCKET_BAD) {
+      socket_close(data, cf->conn, TRUE, ctx->sock);
+      ctx->sock = CURL_SOCKET_BAD;
+    }
+    *done = FALSE;
+  }
+  return result;
+}
+
+static void cf_socket_get_host(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               const char **phost,
+                               const char **pdisplay_host,
+                               int *pport)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+  (void)data;
+  *phost = cf->conn->host.name;
+  *pdisplay_host = cf->conn->host.dispname;
+  *pport = ctx->ip.remote_port;
+}
+
+static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data,
+                                      struct easy_pollset *ps)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+
+  if(ctx->sock != CURL_SOCKET_BAD) {
+    if(!cf->connected) {
+      Curl_pollset_set_out_only(data, ps, ctx->sock);
+      CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
+                  CURL_FORMAT_SOCKET_T, ctx->sock);
+    }
+    else if(!ctx->active) {
+      Curl_pollset_add_in(data, ps, ctx->sock);
+      CURL_TRC_CF(data, cf, "adjust_pollset, !active, POLLIN fd=%"
+                  CURL_FORMAT_SOCKET_T, ctx->sock);
+    }
+  }
+}
+
+static bool cf_socket_data_pending(struct Curl_cfilter *cf,
+                                   const struct Curl_easy *data)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+  int readable;
+
+  (void)data;
+  if(!Curl_bufq_is_empty(&ctx->recvbuf))
+    return TRUE;
+
+  readable = SOCKET_READABLE(ctx->sock, 0);
+  return (readable > 0 && (readable & CURL_CSELECT_IN));
+}
+
+static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              const void *buf, size_t len, CURLcode *err)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+  curl_socket_t fdsave;
+  ssize_t nwritten;
+  size_t orig_len = len;
+
+  *err = CURLE_OK;
+  fdsave = cf->conn->sock[cf->sockindex];
+  cf->conn->sock[cf->sockindex] = ctx->sock;
+
+#ifdef DEBUGBUILD
+  /* simulate network blocking/partial writes */
+  if(ctx->wblock_percent > 0) {
+    unsigned char c;
+    Curl_rand(data, &c, 1);
+    if(c >= ((100-ctx->wblock_percent)*256/100)) {
+      CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
+      *err = CURLE_AGAIN;
+      nwritten = -1;
+      cf->conn->sock[cf->sockindex] = fdsave;
+      return nwritten;
+    }
+  }
+  if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) {
+    len = len * ctx->wpartial_percent / 100;
+    if(!len)
+      len = 1;
+    CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE partial write of %zu bytes",
+                orig_len, len);
+  }
+#endif
+
+#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
+  if(cf->conn->bits.tcp_fastopen) {
+    nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
+                      &cf->conn->remote_addr->sa_addr,
+                      cf->conn->remote_addr->addrlen);
+    cf->conn->bits.tcp_fastopen = FALSE;
+  }
+  else
+#endif
+    nwritten = swrite(ctx->sock, buf, len);
+
+  if(-1 == nwritten) {
+    int sockerr = SOCKERRNO;
+
+    if(
+#ifdef WSAEWOULDBLOCK
+      /* This is how Windows does it */
+      (WSAEWOULDBLOCK == sockerr)
+#else
+      /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
+         due to its inability to send off data without blocking. We therefore
+         treat both error codes the same here */
+      (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) ||
+      (EINPROGRESS == sockerr)
+#endif
+      ) {
+      /* this is just a case of EWOULDBLOCK */
+      *err = CURLE_AGAIN;
+    }
+    else {
+      char buffer[STRERROR_LEN];
+      failf(data, "Send failure: %s",
+            Curl_strerror(sockerr, buffer, sizeof(buffer)));
+      data->state.os_errno = sockerr;
+      *err = CURLE_SEND_ERROR;
+    }
+  }
+
+  CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
+              orig_len, (int)nwritten, *err);
+  cf->conn->sock[cf->sockindex] = fdsave;
+  return nwritten;
+}
+
+static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              char *buf, size_t len, CURLcode *err)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+  curl_socket_t fdsave;
+  ssize_t nread;
+
+  *err = CURLE_OK;
+
+  fdsave = cf->conn->sock[cf->sockindex];
+  cf->conn->sock[cf->sockindex] = ctx->sock;
+
+#ifdef DEBUGBUILD
+  /* simulate network blocking/partial reads */
+  if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
+    unsigned char c;
+    Curl_rand(data, &c, 1);
+    if(c >= ((100-ctx->rblock_percent)*256/100)) {
+      CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
+      *err = CURLE_AGAIN;
+      nread = -1;
+      cf->conn->sock[cf->sockindex] = fdsave;
+      return nread;
+    }
+  }
+  if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
+    size_t orig_len = len;
+    len = ctx->recv_max;
+    CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes",
+                orig_len, len);
+  }
+#endif
+
+  if(ctx->buffer_recv && !Curl_bufq_is_empty(&ctx->recvbuf)) {
+    CURL_TRC_CF(data, cf, "recv from buffer");
+    nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
+  }
+  else {
+    struct reader_ctx rctx;
+
+    rctx.cf = cf;
+    rctx.data = data;
+
+    /* "small" reads may trigger filling our buffer, "large" reads
+     * are probably not worth the additional copy */
+    if(ctx->buffer_recv && len < NW_SMALL_READS) {
+      ssize_t nwritten;
+      nwritten = Curl_bufq_slurp(&ctx->recvbuf, nw_in_read, &rctx, err);
+      if(nwritten < 0 && !Curl_bufq_is_empty(&ctx->recvbuf)) {
+        /* we have a partial read with an error. need to deliver
+         * what we got, return the error later. */
+        CURL_TRC_CF(data, cf, "partial read: empty buffer first");
+        nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
+      }
+      else if(nwritten < 0) {
+        nread = -1;
+        goto out;
+      }
+      else if(nwritten == 0) {
+        /* eof */
+        *err = CURLE_OK;
+        nread = 0;
+      }
+      else {
+        CURL_TRC_CF(data, cf, "buffered %zd additional bytes", nwritten);
+        nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
+      }
+    }
+    else {
+      nread = nw_in_read(&rctx, (unsigned char *)buf, len, err);
+    }
+  }
+
+out:
+  CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
+              *err);
+  if(nread > 0 && !ctx->got_first_byte) {
+    ctx->first_byte_at = Curl_now();
+    ctx->got_first_byte = TRUE;
+  }
+  cf->conn->sock[cf->sockindex] = fdsave;
+  return nread;
+}
+
+static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+
+  /* use this socket from now on */
+  cf->conn->sock[cf->sockindex] = ctx->sock;
+  set_local_ip(cf, data);
+  if(cf->sockindex == SECONDARYSOCKET)
+    cf->conn->secondary = ctx->ip;
+  else
+    cf->conn->primary = ctx->ip;
+  /* the first socket info gets some specials */
+  if(cf->sockindex == FIRSTSOCKET) {
+    cf->conn->remote_addr = &ctx->addr;
+  #ifdef ENABLE_IPV6
+    cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
+  #endif
+    Curl_persistconninfo(data, cf->conn, &ctx->ip);
+    /* buffering is currently disabled by default because we have stalls
+     * in parallel transfers where not all buffered data is consumed and no
+     * socket events happen.
+     */
+    ctx->buffer_recv = FALSE;
+  }
+  ctx->active = TRUE;
+}
+
+static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                int event, int arg1, void *arg2)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+
+  (void)arg1;
+  (void)arg2;
+  switch(event) {
+  case CF_CTRL_CONN_INFO_UPDATE:
+    cf_socket_active(cf, data);
+    break;
+  case CF_CTRL_DATA_SETUP:
+    Curl_persistconninfo(data, cf->conn, &ctx->ip);
+    break;
+  case CF_CTRL_FORGET_SOCKET:
+    ctx->sock = CURL_SOCKET_BAD;
+    break;
+  }
+  return CURLE_OK;
+}
+
+static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    bool *input_pending)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+  struct pollfd pfd[1];
+  int r;
+
+  *input_pending = FALSE;
+  (void)data;
+  if(!ctx || ctx->sock == CURL_SOCKET_BAD)
+    return FALSE;
+
+  /* Check with 0 timeout if there are any events pending on the socket */
+  pfd[0].fd = ctx->sock;
+  pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
+  pfd[0].revents = 0;
+
+  r = Curl_poll(pfd, 1, 0);
+  if(r < 0) {
+    CURL_TRC_CF(data, cf, "is_alive: poll error, assume dead");
+    return FALSE;
+  }
+  else if(r == 0) {
+    CURL_TRC_CF(data, cf, "is_alive: poll timeout, assume alive");
+    return TRUE;
+  }
+  else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) {
+    CURL_TRC_CF(data, cf, "is_alive: err/hup/etc events, assume dead");
+    return FALSE;
+  }
+
+  CURL_TRC_CF(data, cf, "is_alive: valid events, looks alive");
+  *input_pending = TRUE;
+  return TRUE;
+}
+
+static CURLcode cf_socket_query(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                int query, int *pres1, void *pres2)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+
+  switch(query) {
+  case CF_QUERY_SOCKET:
+    DEBUGASSERT(pres2);
+    *((curl_socket_t *)pres2) = ctx->sock;
+    return CURLE_OK;
+  case CF_QUERY_CONNECT_REPLY_MS:
+    if(ctx->got_first_byte) {
+      timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
+      *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
+    }
+    else
+      *pres1 = -1;
+    return CURLE_OK;
+  case CF_QUERY_TIMER_CONNECT: {
+    struct curltime *when = pres2;
+    switch(ctx->transport) {
+    case TRNSPRT_UDP:
+    case TRNSPRT_QUIC:
+      /* Since UDP connected sockets work different from TCP, we use the
+       * time of the first byte from the peer as the "connect" time. */
+      if(ctx->got_first_byte) {
+        *when = ctx->first_byte_at;
+        break;
+      }
+      FALLTHROUGH();
+    default:
+      *when = ctx->connected_at;
+      break;
+    }
+    return CURLE_OK;
+  }
+  default:
+    break;
+  }
+  return cf->next?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
+}
+
+struct Curl_cftype Curl_cft_tcp = {
+  "TCP",
+  CF_TYPE_IP_CONNECT,
+  CURL_LOG_LVL_NONE,
+  cf_socket_destroy,
+  cf_tcp_connect,
+  cf_socket_close,
+  cf_socket_get_host,
+  cf_socket_adjust_pollset,
+  cf_socket_data_pending,
+  cf_socket_send,
+  cf_socket_recv,
+  cf_socket_cntrl,
+  cf_socket_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  cf_socket_query,
+};
+
+CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
+                            struct Curl_easy *data,
+                            struct connectdata *conn,
+                            const struct Curl_addrinfo *ai,
+                            int transport)
+{
+  struct cf_socket_ctx *ctx = NULL;
+  struct Curl_cfilter *cf = NULL;
+  CURLcode result;
+
+  (void)data;
+  (void)conn;
+  DEBUGASSERT(transport == TRNSPRT_TCP);
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  cf_socket_ctx_init(ctx, ai, transport);
+
+  result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx);
+
+out:
+  *pcf = (!result)? cf : NULL;
+  if(result) {
+    Curl_safefree(cf);
+    Curl_safefree(ctx);
+  }
+
+  return result;
+}
+
+static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
+                               struct Curl_easy *data)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+  int rc;
+
+  /* QUIC needs a connected socket, nonblocking */
+  DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
+
+#if defined(__APPLE__) && defined(USE_OPENSSL_QUIC)
+  (void)rc;
+  /* On macOS OpenSSL QUIC fails on connected sockets.
+   * see: <https://github.com/openssl/openssl/issues/23251> */
+#else
+  rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
+  if(-1 == rc) {
+    return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
+  }
+  ctx->sock_connected = TRUE;
+#endif
+  set_local_ip(cf, data);
+  CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
+              " connected: [%s:%d] -> [%s:%d]",
+              (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
+              ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
+              ctx->ip.remote_ip, ctx->ip.remote_port);
+
+  (void)curlx_nonblock(ctx->sock, TRUE);
+  switch(ctx->addr.family) {
+#if defined(__linux__) && defined(IP_MTU_DISCOVER)
+  case AF_INET: {
+    int val = IP_PMTUDISC_DO;
+    (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
+                     sizeof(val));
+    break;
+  }
+#endif
+#if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
+  case AF_INET6: {
+    int val = IPV6_PMTUDISC_DO;
+    (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
+                     sizeof(val));
+    break;
+  }
+#endif
+  }
+  return CURLE_OK;
+}
+
+static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               bool blocking, bool *done)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_COULDNT_CONNECT;
+
+  (void)blocking;
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+  *done = FALSE;
+  if(ctx->sock == CURL_SOCKET_BAD) {
+    result = cf_socket_open(cf, data);
+    if(result) {
+      CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d", result);
+      goto out;
+    }
+
+    if(ctx->transport == TRNSPRT_QUIC) {
+      result = cf_udp_setup_quic(cf, data);
+      if(result)
+        goto out;
+      CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
+                  CURL_FORMAT_SOCKET_T " (%s:%d)",
+                  ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
+    }
+    else {
+      CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
+                  CURL_FORMAT_SOCKET_T " (unconnected)", ctx->sock);
+    }
+    *done = TRUE;
+    cf->connected = TRUE;
+  }
+out:
+  return result;
+}
+
+struct Curl_cftype Curl_cft_udp = {
+  "UDP",
+  CF_TYPE_IP_CONNECT,
+  CURL_LOG_LVL_NONE,
+  cf_socket_destroy,
+  cf_udp_connect,
+  cf_socket_close,
+  cf_socket_get_host,
+  cf_socket_adjust_pollset,
+  cf_socket_data_pending,
+  cf_socket_send,
+  cf_socket_recv,
+  cf_socket_cntrl,
+  cf_socket_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  cf_socket_query,
+};
+
+CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
+                            struct Curl_easy *data,
+                            struct connectdata *conn,
+                            const struct Curl_addrinfo *ai,
+                            int transport)
+{
+  struct cf_socket_ctx *ctx = NULL;
+  struct Curl_cfilter *cf = NULL;
+  CURLcode result;
+
+  (void)data;
+  (void)conn;
+  DEBUGASSERT(transport == TRNSPRT_UDP || transport == TRNSPRT_QUIC);
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  cf_socket_ctx_init(ctx, ai, transport);
+
+  result = Curl_cf_create(&cf, &Curl_cft_udp, ctx);
+
+out:
+  *pcf = (!result)? cf : NULL;
+  if(result) {
+    Curl_safefree(cf);
+    Curl_safefree(ctx);
+  }
+
+  return result;
+}
+
+/* this is the TCP filter which can also handle this case */
+struct Curl_cftype Curl_cft_unix = {
+  "UNIX",
+  CF_TYPE_IP_CONNECT,
+  CURL_LOG_LVL_NONE,
+  cf_socket_destroy,
+  cf_tcp_connect,
+  cf_socket_close,
+  cf_socket_get_host,
+  cf_socket_adjust_pollset,
+  cf_socket_data_pending,
+  cf_socket_send,
+  cf_socket_recv,
+  cf_socket_cntrl,
+  cf_socket_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  cf_socket_query,
+};
+
+CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
+                             struct Curl_easy *data,
+                             struct connectdata *conn,
+                             const struct Curl_addrinfo *ai,
+                             int transport)
+{
+  struct cf_socket_ctx *ctx = NULL;
+  struct Curl_cfilter *cf = NULL;
+  CURLcode result;
+
+  (void)data;
+  (void)conn;
+  DEBUGASSERT(transport == TRNSPRT_UNIX);
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  cf_socket_ctx_init(ctx, ai, transport);
+
+  result = Curl_cf_create(&cf, &Curl_cft_unix, ctx);
+
+out:
+  *pcf = (!result)? cf : NULL;
+  if(result) {
+    Curl_safefree(cf);
+    Curl_safefree(ctx);
+  }
+
+  return result;
+}
+
+static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data,
+                                      bool blocking, bool *done)
+{
+  /* we start accepted, if we ever close, we cannot go on */
+  (void)data;
+  (void)blocking;
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+  return CURLE_FAILED_INIT;
+}
+
+struct Curl_cftype Curl_cft_tcp_accept = {
+  "TCP-ACCEPT",
+  CF_TYPE_IP_CONNECT,
+  CURL_LOG_LVL_NONE,
+  cf_socket_destroy,
+  cf_tcp_accept_connect,
+  cf_socket_close,
+  cf_socket_get_host,              /* TODO: not accurate */
+  cf_socket_adjust_pollset,
+  cf_socket_data_pending,
+  cf_socket_send,
+  cf_socket_recv,
+  cf_socket_cntrl,
+  cf_socket_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  cf_socket_query,
+};
+
+CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
+                                  struct connectdata *conn,
+                                  int sockindex, curl_socket_t *s)
+{
+  CURLcode result;
+  struct Curl_cfilter *cf = NULL;
+  struct cf_socket_ctx *ctx = NULL;
+
+  /* replace any existing */
+  Curl_conn_cf_discard_all(data, conn, sockindex);
+  DEBUGASSERT(conn->sock[sockindex] == CURL_SOCKET_BAD);
+
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  ctx->transport = conn->transport;
+  ctx->sock = *s;
+  ctx->accepted = FALSE;
+  result = Curl_cf_create(&cf, &Curl_cft_tcp_accept, ctx);
+  if(result)
+    goto out;
+  Curl_conn_cf_add(data, conn, sockindex, cf);
+
+  conn->sock[sockindex] = ctx->sock;
+  set_local_ip(cf, data);
+  ctx->active = TRUE;
+  ctx->connected_at = Curl_now();
+  cf->connected = TRUE;
+  CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%"
+              CURL_FORMAT_SOCKET_T ")", ctx->sock);
+
+out:
+  if(result) {
+    Curl_safefree(cf);
+    Curl_safefree(ctx);
+  }
+  return result;
+}
+
+static void set_accepted_remote_ip(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+#ifdef HAVE_GETPEERNAME
+  char buffer[STRERROR_LEN];
+  struct Curl_sockaddr_storage ssrem;
+  curl_socklen_t plen;
+
+  ctx->ip.remote_ip[0] = 0;
+  ctx->ip.remote_port = 0;
+  plen = sizeof(ssrem);
+  memset(&ssrem, 0, plen);
+  if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
+    int error = SOCKERRNO;
+    failf(data, "getpeername() failed with errno %d: %s",
+          error, Curl_strerror(error, buffer, sizeof(buffer)));
+    return;
+  }
+  if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
+                       ctx->ip.remote_ip, &ctx->ip.remote_port)) {
+    failf(data, "ssrem inet_ntop() failed with errno %d: %s",
+          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+    return;
+  }
+#else
+  ctx->ip.remote_ip[0] = 0;
+  ctx->ip.remote_port = 0;
+  (void)data;
+#endif
+}
+
+CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
+                                    struct connectdata *conn,
+                                    int sockindex, curl_socket_t *s)
+{
+  struct Curl_cfilter *cf = NULL;
+  struct cf_socket_ctx *ctx = NULL;
+
+  cf = conn->cfilter[sockindex];
+  if(!cf || cf->cft != &Curl_cft_tcp_accept)
+    return CURLE_FAILED_INIT;
+
+  ctx = cf->ctx;
+  /* discard the listen socket */
+  socket_close(data, conn, TRUE, ctx->sock);
+  ctx->sock = *s;
+  conn->sock[sockindex] = ctx->sock;
+  set_accepted_remote_ip(cf, data);
+  set_local_ip(cf, data);
+  ctx->active = TRUE;
+  ctx->accepted = TRUE;
+  ctx->connected_at = Curl_now();
+  cf->connected = TRUE;
+  CURL_TRC_CF(data, cf, "accepted_set(sock=%" CURL_FORMAT_SOCKET_T
+              ", remote=%s port=%d)",
+              ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
+
+  return CURLE_OK;
+}
+
+/**
+ * Return TRUE iff `cf` is a socket filter.
+ */
+static bool cf_is_socket(struct Curl_cfilter *cf)
+{
+  return cf && (cf->cft == &Curl_cft_tcp ||
+                cf->cft == &Curl_cft_udp ||
+                cf->cft == &Curl_cft_unix ||
+                cf->cft == &Curl_cft_tcp_accept);
+}
+
+CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
+                             struct Curl_easy *data,
+                             curl_socket_t *psock,
+                             const struct Curl_sockaddr_ex **paddr,
+                             struct ip_quadruple *pip)
+{
+  (void)data;
+  if(cf_is_socket(cf) && cf->ctx) {
+    struct cf_socket_ctx *ctx = cf->ctx;
+
+    if(psock)
+      *psock = ctx->sock;
+    if(paddr)
+      *paddr = &ctx->addr;
+    if(pip)
+      *pip = ctx->ip;
+    return CURLE_OK;
+  }
+  return CURLE_FAILED_INIT;
+}
Index: trunk/src/libs/curl-8.7.1/lib/cf-socket.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cf-socket.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cf-socket.h	(revision 104083)
@@ -0,0 +1,171 @@
+#ifndef HEADER_CURL_CF_SOCKET_H
+#define HEADER_CURL_CF_SOCKET_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */
+#include "sockaddr.h"
+
+struct Curl_addrinfo;
+struct Curl_cfilter;
+struct Curl_easy;
+struct connectdata;
+struct Curl_sockaddr_ex;
+struct ip_quadruple;
+
+/*
+ * The Curl_sockaddr_ex structure is basically libcurl's external API
+ * curl_sockaddr structure with enough space available to directly hold any
+ * protocol-specific address structures. The variable declared here will be
+ * used to pass / receive data to/from the fopensocket callback if this has
+ * been set, before that, it is initialized from parameters.
+ */
+struct Curl_sockaddr_ex {
+  int family;
+  int socktype;
+  int protocol;
+  unsigned int addrlen;
+  union {
+    struct sockaddr addr;
+    struct Curl_sockaddr_storage buff;
+  } _sa_ex_u;
+};
+#define sa_addr _sa_ex_u.addr
+
+
+/*
+ * Create a socket based on info from 'conn' and 'ai'.
+ *
+ * Fill in 'addr' and 'sockfd' accordingly if OK is returned. If the open
+ * socket callback is set, used that!
+ *
+ */
+CURLcode Curl_socket_open(struct Curl_easy *data,
+                            const struct Curl_addrinfo *ai,
+                            struct Curl_sockaddr_ex *addr,
+                            int transport,
+                            curl_socket_t *sockfd);
+
+int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
+                      curl_socket_t sock);
+
+#ifdef USE_WINSOCK
+/* When you run a program that uses the Windows Sockets API, you may
+   experience slow performance when you copy data to a TCP server.
+
+   https://support.microsoft.com/kb/823764
+
+   Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
+   Buffer Size
+
+*/
+void Curl_sndbufset(curl_socket_t sockfd);
+#else
+#define Curl_sndbufset(y) Curl_nop_stmt
+#endif
+
+/**
+ * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
+ * set the transport used.
+ */
+void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
+                           const struct Curl_addrinfo *ai,
+                           int transport);
+
+/**
+ * Creates a cfilter that opens a TCP socket to the given address
+ * when calling its `connect` implementation.
+ * The filter will not touch any connection/data flags and can be
+ * used in happy eyeballing. Once selected for use, its `_active()`
+ * method needs to be called.
+ */
+CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
+                            struct Curl_easy *data,
+                            struct connectdata *conn,
+                            const struct Curl_addrinfo *ai,
+                            int transport);
+
+/**
+ * Creates a cfilter that opens a UDP socket to the given address
+ * when calling its `connect` implementation.
+ * The filter will not touch any connection/data flags and can be
+ * used in happy eyeballing. Once selected for use, its `_active()`
+ * method needs to be called.
+ */
+CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
+                            struct Curl_easy *data,
+                            struct connectdata *conn,
+                            const struct Curl_addrinfo *ai,
+                            int transport);
+
+/**
+ * Creates a cfilter that opens a UNIX socket to the given address
+ * when calling its `connect` implementation.
+ * The filter will not touch any connection/data flags and can be
+ * used in happy eyeballing. Once selected for use, its `_active()`
+ * method needs to be called.
+ */
+CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
+                             struct Curl_easy *data,
+                             struct connectdata *conn,
+                             const struct Curl_addrinfo *ai,
+                             int transport);
+
+/**
+ * Creates a cfilter that keeps a listening socket.
+ */
+CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
+                                  struct connectdata *conn,
+                                  int sockindex,
+                                  curl_socket_t *s);
+
+/**
+ * Replace the listen socket with the accept()ed one.
+ */
+CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
+                                    struct connectdata *conn,
+                                    int sockindex,
+                                    curl_socket_t *s);
+
+/**
+ * Peek at the socket and remote ip/port the socket filter is using.
+ * The filter owns all returned values.
+ * @param psock             pointer to hold socket descriptor or NULL
+ * @param paddr             pointer to hold addr reference or NULL
+ * @param pip               pointer to get IP quadruple or NULL
+ * Returns error if the filter is of invalid type.
+ */
+CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
+                             struct Curl_easy *data,
+                             curl_socket_t *psock,
+                             const struct Curl_sockaddr_ex **paddr,
+                             struct ip_quadruple *pip);
+
+extern struct Curl_cftype Curl_cft_tcp;
+extern struct Curl_cftype Curl_cft_udp;
+extern struct Curl_cftype Curl_cft_unix;
+extern struct Curl_cftype Curl_cft_tcp_accept;
+
+#endif /* HEADER_CURL_CF_SOCKET_H */
Index: trunk/src/libs/curl-8.7.1/lib/cfilters.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cfilters.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cfilters.c	(revision 104083)
@@ -0,0 +1,848 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "urldata.h"
+#include "strerror.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "url.h" /* for Curl_safefree() */
+#include "sendf.h"
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "multiif.h"
+#include "progress.h"
+#include "select.h"
+#include "warnless.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+#ifdef DEBUGBUILD
+/* used by unit2600.c */
+void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  cf->connected = FALSE;
+  if(cf->next)
+    cf->next->cft->do_close(cf->next, data);
+}
+#endif
+
+static void conn_report_connect_stats(struct Curl_easy *data,
+                                      struct connectdata *conn);
+
+void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          const char **phost, const char **pdisplay_host,
+                          int *pport)
+{
+  if(cf->next)
+    cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
+  else {
+    *phost = cf->conn->host.name;
+    *pdisplay_host = cf->conn->host.dispname;
+    *pport = cf->conn->primary.remote_port;
+  }
+}
+
+void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 struct easy_pollset *ps)
+{
+  /* NOP */
+  (void)cf;
+  (void)data;
+  (void)ps;
+}
+
+bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
+                              const struct Curl_easy *data)
+{
+  return cf->next?
+    cf->next->cft->has_data_pending(cf->next, data) : FALSE;
+}
+
+ssize_t  Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          const void *buf, size_t len, CURLcode *err)
+{
+  return cf->next?
+    cf->next->cft->do_send(cf->next, data, buf, len, err) :
+    CURLE_RECV_ERROR;
+}
+
+ssize_t  Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          char *buf, size_t len, CURLcode *err)
+{
+  return cf->next?
+    cf->next->cft->do_recv(cf->next, data, buf, len, err) :
+    CURLE_SEND_ERROR;
+}
+
+bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               bool *input_pending)
+{
+  return cf->next?
+    cf->next->cft->is_alive(cf->next, data, input_pending) :
+    FALSE; /* pessimistic in absence of data */
+}
+
+CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data)
+{
+  return cf->next?
+    cf->next->cft->keep_alive(cf->next, data) :
+    CURLE_OK;
+}
+
+CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           int query, int *pres1, void *pres2)
+{
+  return cf->next?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
+}
+
+void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf,
+                                struct Curl_easy *data)
+{
+  struct Curl_cfilter *cfn, *cf = *pcf;
+
+  if(cf) {
+    *pcf = NULL;
+    while(cf) {
+      cfn = cf->next;
+      /* prevent destroying filter to mess with its sub-chain, since
+       * we have the reference now and will call destroy on it.
+       */
+      cf->next = NULL;
+      cf->cft->destroy(cf, data);
+      free(cf);
+      cf = cfn;
+    }
+  }
+}
+
+void Curl_conn_cf_discard_all(struct Curl_easy *data,
+                              struct connectdata *conn, int index)
+{
+  Curl_conn_cf_discard_chain(&conn->cfilter[index], data);
+}
+
+void Curl_conn_close(struct Curl_easy *data, int index)
+{
+  struct Curl_cfilter *cf;
+
+  DEBUGASSERT(data->conn);
+  /* it is valid to call that without filters being present */
+  cf = data->conn->cfilter[index];
+  if(cf) {
+    cf->cft->do_close(cf, data);
+  }
+}
+
+ssize_t Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
+                     size_t len, CURLcode *code)
+{
+  struct Curl_cfilter *cf;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  *code = CURLE_OK;
+  cf = data->conn->cfilter[num];
+  while(cf && !cf->connected) {
+    cf = cf->next;
+  }
+  if(cf) {
+    ssize_t nread = cf->cft->do_recv(cf, data, buf, len, code);
+    DEBUGASSERT(nread >= 0 || *code);
+    DEBUGASSERT(nread < 0 || !*code);
+    return nread;
+  }
+  failf(data, "recv: no filter connected");
+  *code = CURLE_FAILED_INIT;
+  return -1;
+}
+
+ssize_t Curl_cf_send(struct Curl_easy *data, int num,
+                     const void *mem, size_t len, CURLcode *code)
+{
+  struct Curl_cfilter *cf;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  *code = CURLE_OK;
+  cf = data->conn->cfilter[num];
+  while(cf && !cf->connected) {
+    cf = cf->next;
+  }
+  if(cf) {
+    ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, code);
+    DEBUGASSERT(nwritten >= 0 || *code);
+    DEBUGASSERT(nwritten < 0 || !*code || !len);
+    return nwritten;
+  }
+  failf(data, "send: no filter connected");
+  DEBUGASSERT(0);
+  *code = CURLE_FAILED_INIT;
+  return -1;
+}
+
+CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
+                        const struct Curl_cftype *cft,
+                        void *ctx)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+
+  DEBUGASSERT(cft);
+  cf = calloc(1, sizeof(*cf));
+  if(!cf)
+    goto out;
+
+  cf->cft = cft;
+  cf->ctx = ctx;
+  result = CURLE_OK;
+out:
+  *pcf = cf;
+  return result;
+}
+
+void Curl_conn_cf_add(struct Curl_easy *data,
+                      struct connectdata *conn,
+                      int index,
+                      struct Curl_cfilter *cf)
+{
+  (void)data;
+  DEBUGASSERT(conn);
+  DEBUGASSERT(!cf->conn);
+  DEBUGASSERT(!cf->next);
+
+  cf->next = conn->cfilter[index];
+  cf->conn = conn;
+  cf->sockindex = index;
+  conn->cfilter[index] = cf;
+  CURL_TRC_CF(data, cf, "added");
+}
+
+void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
+                               struct Curl_cfilter *cf_new)
+{
+  struct Curl_cfilter *tail, **pnext;
+
+  DEBUGASSERT(cf_at);
+  DEBUGASSERT(cf_new);
+  DEBUGASSERT(!cf_new->conn);
+
+  tail = cf_at->next;
+  cf_at->next = cf_new;
+  do {
+    cf_new->conn = cf_at->conn;
+    cf_new->sockindex = cf_at->sockindex;
+    pnext = &cf_new->next;
+    cf_new = cf_new->next;
+  } while(cf_new);
+  *pnext = tail;
+}
+
+bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
+                              struct Curl_cfilter *discard,
+                              struct Curl_easy *data,
+                              bool destroy_always)
+{
+  struct Curl_cfilter **pprev = &cf->next;
+  bool found = FALSE;
+
+  /* remove from sub-chain and destroy */
+  DEBUGASSERT(cf);
+  while(*pprev) {
+    if(*pprev == cf) {
+      *pprev = discard->next;
+      discard->next = NULL;
+      found = TRUE;
+      break;
+    }
+    pprev = &((*pprev)->next);
+  }
+  if(found || destroy_always) {
+    discard->next = NULL;
+    discard->cft->destroy(discard, data);
+    free(discard);
+  }
+  return found;
+}
+
+CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              bool blocking, bool *done)
+{
+  if(cf)
+    return cf->cft->do_connect(cf, data, blocking, done);
+  return CURLE_FAILED_INIT;
+}
+
+void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  if(cf)
+    cf->cft->do_close(cf, data);
+}
+
+ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          const void *buf, size_t len, CURLcode *err)
+{
+  if(cf)
+    return cf->cft->do_send(cf, data, buf, len, err);
+  *err = CURLE_SEND_ERROR;
+  return -1;
+}
+
+ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          char *buf, size_t len, CURLcode *err)
+{
+  if(cf)
+    return cf->cft->do_recv(cf, data, buf, len, err);
+  *err = CURLE_RECV_ERROR;
+  return -1;
+}
+
+CURLcode Curl_conn_connect(struct Curl_easy *data,
+                           int sockindex,
+                           bool blocking,
+                           bool *done)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+
+  cf = data->conn->cfilter[sockindex];
+  DEBUGASSERT(cf);
+  if(!cf)
+    return CURLE_FAILED_INIT;
+
+  *done = cf->connected;
+  if(!*done) {
+    result = cf->cft->do_connect(cf, data, blocking, done);
+    if(!result && *done) {
+      Curl_conn_ev_update_info(data, data->conn);
+      conn_report_connect_stats(data, data->conn);
+      data->conn->keepalive = Curl_now();
+    }
+    else if(result) {
+      conn_report_connect_stats(data, data->conn);
+    }
+  }
+
+  return result;
+}
+
+bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
+{
+  struct Curl_cfilter *cf;
+
+  cf = conn->cfilter[sockindex];
+  return cf && cf->connected;
+}
+
+bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex)
+{
+  struct Curl_cfilter *cf;
+
+  cf = data->conn->cfilter[sockindex];
+  while(cf) {
+    if(cf->connected)
+      return TRUE;
+    if(cf->cft->flags & CF_TYPE_IP_CONNECT)
+      return FALSE;
+    cf = cf->next;
+  }
+  return FALSE;
+}
+
+bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf)
+{
+  for(; cf; cf = cf->next) {
+    if(cf->cft->flags & CF_TYPE_SSL)
+      return TRUE;
+    if(cf->cft->flags & CF_TYPE_IP_CONNECT)
+      return FALSE;
+  }
+  return FALSE;
+}
+
+bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
+{
+  return conn? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
+}
+
+bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
+{
+  struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+
+  for(; cf; cf = cf->next) {
+    if(cf->cft->flags & CF_TYPE_MULTIPLEX)
+      return TRUE;
+    if(cf->cft->flags & CF_TYPE_IP_CONNECT
+       || cf->cft->flags & CF_TYPE_SSL)
+      return FALSE;
+  }
+  return FALSE;
+}
+
+bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
+{
+  struct Curl_cfilter *cf;
+
+  (void)data;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+
+  cf = data->conn->cfilter[sockindex];
+  while(cf && !cf->connected) {
+    cf = cf->next;
+  }
+  if(cf) {
+    return cf->cft->has_data_pending(cf, data);
+  }
+  return FALSE;
+}
+
+void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 struct easy_pollset *ps)
+{
+  /* Get the lowest not-connected filter, if there are any */
+  while(cf && !cf->connected && cf->next && !cf->next->connected)
+    cf = cf->next;
+  /* From there on, give all filters a chance to adjust the pollset.
+   * Lower filters are called later, so they may override */
+  while(cf) {
+    cf->cft->adjust_pollset(cf, data, ps);
+    cf = cf->next;
+  }
+}
+
+void Curl_conn_adjust_pollset(struct Curl_easy *data,
+                               struct easy_pollset *ps)
+{
+  int i;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  for(i = 0; i < 2; ++i) {
+    Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
+  }
+}
+
+void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
+                        const char **phost, const char **pdisplay_host,
+                        int *pport)
+{
+  struct Curl_cfilter *cf;
+
+  DEBUGASSERT(data->conn);
+  cf = data->conn->cfilter[sockindex];
+  if(cf) {
+    cf->cft->get_host(cf, data, phost, pdisplay_host, pport);
+  }
+  else {
+    /* Some filter ask during shutdown for this, mainly for debugging
+     * purposes. We hand out the defaults, however this is not always
+     * accurate, as the connection might be tunneled, etc. But all that
+     * state is already gone here. */
+    *phost = data->conn->host.name;
+    *pdisplay_host = data->conn->host.dispname;
+    *pport = data->conn->remote_port;
+  }
+}
+
+CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                int event, int arg1, void *arg2)
+{
+  (void)cf;
+  (void)data;
+  (void)event;
+  (void)arg1;
+  (void)arg2;
+  return CURLE_OK;
+}
+
+CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            bool ignore_result,
+                            int event, int arg1, void *arg2)
+{
+  CURLcode result = CURLE_OK;
+
+  for(; cf; cf = cf->next) {
+    if(Curl_cf_def_cntrl == cf->cft->cntrl)
+      continue;
+    result = cf->cft->cntrl(cf, data, event, arg1, arg2);
+    if(!ignore_result && result)
+      break;
+  }
+  return result;
+}
+
+curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data)
+{
+  curl_socket_t sock;
+  if(cf && !cf->cft->query(cf, data, CF_QUERY_SOCKET, NULL, &sock))
+    return sock;
+  return CURL_SOCKET_BAD;
+}
+
+curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
+{
+  struct Curl_cfilter *cf;
+
+  cf = data->conn? data->conn->cfilter[sockindex] : NULL;
+  /* if the top filter has not connected, ask it (and its sub-filters)
+   * for the socket. Otherwise conn->sock[sockindex] should have it.
+   */
+  if(cf && !cf->connected)
+    return Curl_conn_cf_get_socket(cf, data);
+  return data->conn? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
+}
+
+void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex)
+{
+  if(data->conn) {
+    struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
+    if(cf)
+      (void)Curl_conn_cf_cntrl(cf, data, TRUE,
+                               CF_CTRL_FORGET_SOCKET, 0, NULL);
+    fake_sclose(data->conn->sock[sockindex]);
+    data->conn->sock[sockindex] = CURL_SOCKET_BAD;
+  }
+}
+
+static CURLcode cf_cntrl_all(struct connectdata *conn,
+                             struct Curl_easy *data,
+                             bool ignore_result,
+                             int event, int arg1, void *arg2)
+{
+  CURLcode result = CURLE_OK;
+  size_t i;
+
+  for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
+    result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
+                                event, arg1, arg2);
+    if(!ignore_result && result)
+      break;
+  }
+  return result;
+}
+
+void Curl_conn_ev_data_attach(struct connectdata *conn,
+                              struct Curl_easy *data)
+{
+  cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_ATTACH, 0, NULL);
+}
+
+void Curl_conn_ev_data_detach(struct connectdata *conn,
+                              struct Curl_easy *data)
+{
+  cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_DETACH, 0, NULL);
+}
+
+CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
+{
+  return cf_cntrl_all(data->conn, data, FALSE,
+                      CF_CTRL_DATA_SETUP, 0, NULL);
+}
+
+CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
+{
+  return cf_cntrl_all(data->conn, data, FALSE,
+                      CF_CTRL_DATA_IDLE, 0, NULL);
+}
+
+/**
+ * Notify connection filters that the transfer represented by `data`
+ * is donw with sending data (e.g. has uploaded everything).
+ */
+void Curl_conn_ev_data_done_send(struct Curl_easy *data)
+{
+  cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE_SEND, 0, NULL);
+}
+
+/**
+ * Notify connection filters that the transfer represented by `data`
+ * is finished - eventually premature, e.g. before being complete.
+ */
+void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature)
+{
+  cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE, premature, NULL);
+}
+
+CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause)
+{
+  return cf_cntrl_all(data->conn, data, FALSE,
+                      CF_CTRL_DATA_PAUSE, do_pause, NULL);
+}
+
+void Curl_conn_ev_update_info(struct Curl_easy *data,
+                              struct connectdata *conn)
+{
+  cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
+}
+
+/**
+ * Update connection statistics
+ */
+static void conn_report_connect_stats(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
+  if(cf) {
+    struct curltime connected;
+    struct curltime appconnected;
+
+    memset(&connected, 0, sizeof(connected));
+    cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
+    if(connected.tv_sec || connected.tv_usec)
+      Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
+
+    memset(&appconnected, 0, sizeof(appconnected));
+    cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
+    if(appconnected.tv_sec || appconnected.tv_usec)
+      Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
+  }
+}
+
+bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
+                        bool *input_pending)
+{
+  struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
+  return cf && !cf->conn->bits.close &&
+         cf->cft->is_alive(cf, data, input_pending);
+}
+
+CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
+                              struct connectdata *conn,
+                              int sockindex)
+{
+  struct Curl_cfilter *cf = conn->cfilter[sockindex];
+  return cf? cf->cft->keep_alive(cf, data) : CURLE_OK;
+}
+
+size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
+                                     struct connectdata *conn,
+                                     int sockindex)
+{
+  CURLcode result;
+  int n = 0;
+
+  struct Curl_cfilter *cf = conn->cfilter[sockindex];
+  result = cf? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT,
+                              &n, NULL) : CURLE_UNKNOWN_OPTION;
+  return (result || n <= 0)? 1 : (size_t)n;
+}
+
+int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
+{
+  if(data && data->conn &&
+     sockfd != CURL_SOCKET_BAD && sockfd == data->conn->sock[SECONDARYSOCKET])
+    return SECONDARYSOCKET;
+  return FIRSTSOCKET;
+}
+
+CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
+                        char *buf, size_t blen, ssize_t *n)
+{
+  CURLcode result = CURLE_OK;
+  ssize_t nread;
+
+  DEBUGASSERT(data->conn);
+  nread = data->conn->recv[sockindex](data, sockindex, buf, blen, &result);
+  DEBUGASSERT(nread >= 0 || result);
+  DEBUGASSERT(nread < 0 || !result);
+  *n = (nread >= 0)? (size_t)nread : 0;
+  return result;
+}
+
+CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
+                        const void *buf, size_t blen,
+                        size_t *pnwritten)
+{
+  ssize_t nwritten;
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn;
+
+  DEBUGASSERT(sockindex >= 0 && sockindex < 2);
+  DEBUGASSERT(pnwritten);
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  conn = data->conn;
+#ifdef CURLDEBUG
+  {
+    /* Allow debug builds to override this logic to force short sends
+    */
+    char *p = getenv("CURL_SMALLSENDS");
+    if(p) {
+      size_t altsize = (size_t)strtoul(p, NULL, 10);
+      if(altsize)
+        blen = CURLMIN(blen, altsize);
+    }
+  }
+#endif
+  nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
+  DEBUGASSERT((nwritten >= 0) || result);
+  *pnwritten = (nwritten < 0)? 0 : (size_t)nwritten;
+  return result;
+}
+
+void Curl_pollset_reset(struct Curl_easy *data,
+                        struct easy_pollset *ps)
+{
+  size_t i;
+  (void)data;
+  memset(ps, 0, sizeof(*ps));
+  for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
+    ps->sockets[i] = CURL_SOCKET_BAD;
+}
+
+/**
+ *
+ */
+void Curl_pollset_change(struct Curl_easy *data,
+                       struct easy_pollset *ps, curl_socket_t sock,
+                       int add_flags, int remove_flags)
+{
+  unsigned int i;
+
+  (void)data;
+  DEBUGASSERT(VALID_SOCK(sock));
+  if(!VALID_SOCK(sock))
+    return;
+
+  DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
+  DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
+  DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */
+  for(i = 0; i < ps->num; ++i) {
+    if(ps->sockets[i] == sock) {
+      ps->actions[i] &= (unsigned char)(~remove_flags);
+      ps->actions[i] |= (unsigned char)add_flags;
+      /* all gone? remove socket */
+      if(!ps->actions[i]) {
+        if((i + 1) < ps->num) {
+          memmove(&ps->sockets[i], &ps->sockets[i + 1],
+                  (ps->num - (i + 1)) * sizeof(ps->sockets[0]));
+          memmove(&ps->actions[i], &ps->actions[i + 1],
+                  (ps->num - (i + 1)) * sizeof(ps->actions[0]));
+        }
+        --ps->num;
+      }
+      return;
+    }
+  }
+  /* not present */
+  if(add_flags) {
+    /* Having more SOCKETS per easy handle than what is defined
+     * is a programming error. This indicates that we need
+     * to raise this limit, making easy_pollset larger.
+     * Since we use this in tight loops, we do not want to make
+     * the pollset dynamic unnecessarily.
+     * The current maximum in practise is HTTP/3 eyeballing where
+     * we have up to 4 sockets involved in connection setup.
+     */
+    DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE);
+    if(i < MAX_SOCKSPEREASYHANDLE) {
+      ps->sockets[i] = sock;
+      ps->actions[i] = (unsigned char)add_flags;
+      ps->num = i + 1;
+    }
+  }
+}
+
+void Curl_pollset_set(struct Curl_easy *data,
+                      struct easy_pollset *ps, curl_socket_t sock,
+                      bool do_in, bool do_out)
+{
+  Curl_pollset_change(data, ps, sock,
+                      (do_in?CURL_POLL_IN:0)|(do_out?CURL_POLL_OUT:0),
+                      (!do_in?CURL_POLL_IN:0)|(!do_out?CURL_POLL_OUT:0));
+}
+
+static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
+                   int bitmap, curl_socket_t *socks)
+{
+  if(bitmap) {
+    int i;
+    for(i = 0; i < MAX_SOCKSPEREASYHANDLE; ++i) {
+      if(!(bitmap & GETSOCK_MASK_RW(i)) || !VALID_SOCK((socks[i]))) {
+        break;
+      }
+      if(bitmap & GETSOCK_READSOCK(i)) {
+        if(bitmap & GETSOCK_WRITESOCK(i))
+          Curl_pollset_add_inout(data, ps, socks[i]);
+        else
+          /* is READ, since we checked MASK_RW above */
+          Curl_pollset_add_in(data, ps, socks[i]);
+      }
+      else
+        Curl_pollset_add_out(data, ps, socks[i]);
+    }
+  }
+}
+
+void Curl_pollset_add_socks(struct Curl_easy *data,
+                            struct easy_pollset *ps,
+                            int (*get_socks_cb)(struct Curl_easy *data,
+                                                curl_socket_t *socks))
+{
+  curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
+  int bitmap;
+
+  bitmap = get_socks_cb(data, socks);
+  ps_add(data, ps, bitmap, socks);
+}
+
+void Curl_pollset_check(struct Curl_easy *data,
+                        struct easy_pollset *ps, curl_socket_t sock,
+                        bool *pwant_read, bool *pwant_write)
+{
+  unsigned int i;
+
+  (void)data;
+  DEBUGASSERT(VALID_SOCK(sock));
+  for(i = 0; i < ps->num; ++i) {
+    if(ps->sockets[i] == sock) {
+      *pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
+      *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
+      return;
+    }
+  }
+  *pwant_read = *pwant_write = FALSE;
+}
Index: trunk/src/libs/curl-8.7.1/lib/cfilters.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cfilters.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cfilters.h	(revision 104083)
@@ -0,0 +1,635 @@
+#ifndef HEADER_CURL_CFILTERS_H
+#define HEADER_CURL_CFILTERS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+
+struct Curl_cfilter;
+struct Curl_easy;
+struct Curl_dns_entry;
+struct connectdata;
+
+/* Callback to destroy resources held by this filter instance.
+ * Implementations MUST NOT chain calls to cf->next.
+ */
+typedef void     Curl_cft_destroy_this(struct Curl_cfilter *cf,
+                                       struct Curl_easy *data);
+
+typedef void     Curl_cft_close(struct Curl_cfilter *cf,
+                                struct Curl_easy *data);
+
+typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  bool blocking, bool *done);
+
+/* Return the hostname and port the connection goes to.
+ * This may change with the connection state of filters when tunneling
+ * is involved.
+ * @param cf     the filter to ask
+ * @param data   the easy handle currently active
+ * @param phost  on return, points to the relevant, real hostname.
+ *               this is owned by the connection.
+ * @param pdisplay_host  on return, points to the printable hostname.
+ *               this is owned by the connection.
+ * @param pport  on return, contains the port number
+ */
+typedef void     Curl_cft_get_host(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  const char **phost,
+                                  const char **pdisplay_host,
+                                  int *pport);
+
+struct easy_pollset;
+
+/* Passing in an easy_pollset for monitoring of sockets, let
+ * filters add or remove sockets actions (CURL_POLL_OUT, CURL_POLL_IN).
+ * This may add a socket or, in case no actions remain, remove
+ * a socket from the set.
+ *
+ * Filter implementations need to call filters "below" *after* they have
+ * made their adjustments. This allows lower filters to override "upper"
+ * actions. If a "lower" filter is unable to write, it needs to be able
+ * to disallow POLL_OUT.
+ *
+ * A filter without own restrictions/preferences should not modify
+ * the pollset. Filters, whose filter "below" is not connected, should
+ * also do no adjustments.
+ *
+ * Examples: a TLS handshake, while ongoing, might remove POLL_IN
+ * when it needs to write, or vice versa. A HTTP/2 filter might remove
+ * POLL_OUT when a stream window is exhausted and a WINDOW_UPDATE needs
+ * to be received first and add instead POLL_IN.
+ *
+ * @param cf     the filter to ask
+ * @param data   the easy handle the pollset is about
+ * @param ps     the pollset (inout) for the easy handle
+ */
+typedef void     Curl_cft_adjust_pollset(struct Curl_cfilter *cf,
+                                          struct Curl_easy *data,
+                                          struct easy_pollset *ps);
+
+typedef bool     Curl_cft_data_pending(struct Curl_cfilter *cf,
+                                       const struct Curl_easy *data);
+
+typedef ssize_t  Curl_cft_send(struct Curl_cfilter *cf,
+                               struct Curl_easy *data, /* transfer */
+                               const void *buf,        /* data to write */
+                               size_t len,             /* amount to write */
+                               CURLcode *err);         /* error to return */
+
+typedef ssize_t  Curl_cft_recv(struct Curl_cfilter *cf,
+                               struct Curl_easy *data, /* transfer */
+                               char *buf,              /* store data here */
+                               size_t len,             /* amount to read */
+                               CURLcode *err);         /* error to return */
+
+typedef bool     Curl_cft_conn_is_alive(struct Curl_cfilter *cf,
+                                        struct Curl_easy *data,
+                                        bool *input_pending);
+
+typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf,
+                                          struct Curl_easy *data);
+
+/**
+ * Events/controls for connection filters, their arguments and
+ * return code handling. Filter callbacks are invoked "top down".
+ * Return code handling:
+ * "first fail" meaning that the first filter returning != CURLE_OK, will
+ *              abort further event distribution and determine the result.
+ * "ignored" meaning return values are ignored and the event is distributed
+ *           to all filters in the chain. Overall result is always CURLE_OK.
+ */
+/*      data event                          arg1       arg2     return */
+#define CF_CTRL_DATA_ATTACH           1  /* 0          NULL     ignored */
+#define CF_CTRL_DATA_DETACH           2  /* 0          NULL     ignored */
+#define CF_CTRL_DATA_SETUP            4  /* 0          NULL     first fail */
+#define CF_CTRL_DATA_IDLE             5  /* 0          NULL     first fail */
+#define CF_CTRL_DATA_PAUSE            6  /* on/off     NULL     first fail */
+#define CF_CTRL_DATA_DONE             7  /* premature  NULL     ignored */
+#define CF_CTRL_DATA_DONE_SEND        8  /* 0          NULL     ignored */
+/* update conn info at connection and data */
+#define CF_CTRL_CONN_INFO_UPDATE (256+0) /* 0          NULL     ignored */
+#define CF_CTRL_FORGET_SOCKET    (256+1) /* 0          NULL     ignored */
+
+/**
+ * Handle event/control for the filter.
+ * Implementations MUST NOT chain calls to cf->next.
+ */
+typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                int event, int arg1, void *arg2);
+
+
+/**
+ * Queries to ask via a `Curl_cft_query *query` method on a cfilter chain.
+ * - MAX_CONCURRENT: the maximum number of parallel transfers the filter
+ *                   chain expects to handle at the same time.
+ *                   default: 1 if no filter overrides.
+ * - CONNECT_REPLY_MS: milliseconds until the first indication of a server
+ *                   response was received on a connect. For TCP, this
+ *                   reflects the time until the socket connected. On UDP
+ *                   this gives the time the first bytes from the server
+ *                   were received.
+ *                   -1 if not determined yet.
+ * - CF_QUERY_SOCKET: the socket used by the filter chain
+ */
+/*      query                             res1       res2     */
+#define CF_QUERY_MAX_CONCURRENT     1  /* number     -        */
+#define CF_QUERY_CONNECT_REPLY_MS   2  /* number     -        */
+#define CF_QUERY_SOCKET             3  /* -          curl_socket_t */
+#define CF_QUERY_TIMER_CONNECT      4  /* -          struct curltime */
+#define CF_QUERY_TIMER_APPCONNECT   5  /* -          struct curltime */
+
+/**
+ * Query the cfilter for properties. Filters ignorant of a query will
+ * pass it "down" the filter chain.
+ */
+typedef CURLcode Curl_cft_query(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                int query, int *pres1, void *pres2);
+
+/**
+ * Type flags for connection filters. A filter can have none, one or
+ * many of those. Use to evaluate state/capabilities of a filter chain.
+ *
+ * CF_TYPE_IP_CONNECT: provides an IP connection or sth equivalent, like
+ *                     a CONNECT tunnel, a UNIX domain socket, a QUIC
+ *                     connection, etc.
+ * CF_TYPE_SSL:        provide SSL/TLS
+ * CF_TYPE_MULTIPLEX:  provides multiplexing of easy handles
+ */
+#define CF_TYPE_IP_CONNECT  (1 << 0)
+#define CF_TYPE_SSL         (1 << 1)
+#define CF_TYPE_MULTIPLEX   (1 << 2)
+
+/* A connection filter type, e.g. specific implementation. */
+struct Curl_cftype {
+  const char *name;                       /* name of the filter type */
+  int flags;                              /* flags of filter type */
+  int log_level;                          /* log level for such filters */
+  Curl_cft_destroy_this *destroy;         /* destroy resources of this cf */
+  Curl_cft_connect *do_connect;           /* establish connection */
+  Curl_cft_close *do_close;               /* close conn */
+  Curl_cft_get_host *get_host;            /* host filter talks to */
+  Curl_cft_adjust_pollset *adjust_pollset; /* adjust transfer poll set */
+  Curl_cft_data_pending *has_data_pending;/* conn has data pending */
+  Curl_cft_send *do_send;                 /* send data */
+  Curl_cft_recv *do_recv;                 /* receive data */
+  Curl_cft_cntrl *cntrl;                  /* events/control */
+  Curl_cft_conn_is_alive *is_alive;       /* FALSE if conn is dead, Jim! */
+  Curl_cft_conn_keep_alive *keep_alive;   /* try to keep it alive */
+  Curl_cft_query *query;                  /* query filter chain */
+};
+
+/* A connection filter instance, e.g. registered at a connection */
+struct Curl_cfilter {
+  const struct Curl_cftype *cft; /* the type providing implementation */
+  struct Curl_cfilter *next;     /* next filter in chain */
+  void *ctx;                     /* filter type specific settings */
+  struct connectdata *conn;      /* the connection this filter belongs to */
+  int sockindex;                 /* the index the filter is installed at */
+  BIT(connected);                /* != 0 iff this filter is connected */
+};
+
+/* Default implementations for the type functions, implementing nop. */
+void Curl_cf_def_destroy_this(struct Curl_cfilter *cf,
+                              struct Curl_easy *data);
+
+/* Default implementations for the type functions, implementing pass-through
+ * the filter chain. */
+void     Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              const char **phost, const char **pdisplay_host,
+                              int *pport);
+void     Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data,
+                                     struct easy_pollset *ps);
+bool     Curl_cf_def_data_pending(struct Curl_cfilter *cf,
+                                  const struct Curl_easy *data);
+ssize_t  Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          const void *buf, size_t len, CURLcode *err);
+ssize_t  Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          char *buf, size_t len, CURLcode *err);
+CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                int event, int arg1, void *arg2);
+bool     Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   bool *input_pending);
+CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data);
+CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           int query, int *pres1, void *pres2);
+
+/**
+ * Create a new filter instance, unattached to the filter chain.
+ * Use Curl_conn_cf_add() to add it to the chain.
+ * @param pcf  on success holds the created instance
+ * @param cft   the filter type
+ * @param ctx  the type specific context to use
+ */
+CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
+                        const struct Curl_cftype *cft,
+                        void *ctx);
+
+/**
+ * Add a filter instance to the `sockindex` filter chain at connection
+ * `conn`. The filter must not already be attached. It is inserted at
+ * the start of the chain (top).
+ */
+void Curl_conn_cf_add(struct Curl_easy *data,
+                      struct connectdata *conn,
+                      int sockindex,
+                      struct Curl_cfilter *cf);
+
+/**
+ * Insert a filter (chain) after `cf_at`.
+ * `cf_new` must not already be attached.
+ */
+void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
+                               struct Curl_cfilter *cf_new);
+
+/**
+ * Discard, e.g. remove and destroy `discard` iff
+ * it still is in the filter chain below `cf`. If `discard`
+ * is no longer found beneath `cf` return FALSE.
+ * if `destroy_always` is TRUE, will call `discard`s destroy
+ * function and free it even if not found in the subchain.
+ */
+bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
+                              struct Curl_cfilter *discard,
+                              struct Curl_easy *data,
+                              bool destroy_always);
+
+/**
+ * Discard all cfilters starting with `*pcf` and clearing it afterwards.
+ */
+void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf,
+                                struct Curl_easy *data);
+
+/**
+ * Remove and destroy all filters at chain `sockindex` on connection `conn`.
+ */
+void Curl_conn_cf_discard_all(struct Curl_easy *data,
+                              struct connectdata *conn,
+                              int sockindex);
+
+
+CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              bool blocking, bool *done);
+void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data);
+ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          const void *buf, size_t len, CURLcode *err);
+ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          char *buf, size_t len, CURLcode *err);
+CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            bool ignore_result,
+                            int event, int arg1, void *arg2);
+
+/**
+ * Determine if the connection filter chain is using SSL to the remote host
+ * (or will be once connected).
+ */
+bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf);
+
+/**
+ * Get the socket used by the filter chain starting at `cf`.
+ * Returns CURL_SOCKET_BAD if not available.
+ */
+curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data);
+
+
+#define CURL_CF_SSL_DEFAULT  -1
+#define CURL_CF_SSL_DISABLE  0
+#define CURL_CF_SSL_ENABLE   1
+
+/**
+ * Bring the filter chain at `sockindex` for connection `data->conn` into
+ * connected state. Which will set `*done` to TRUE.
+ * This can be called on an already connected chain with no side effects.
+ * When not `blocking`, calls may return without error and `*done != TRUE`,
+ * while the individual filters negotiated the connection.
+ */
+CURLcode Curl_conn_connect(struct Curl_easy *data, int sockindex,
+                           bool blocking, bool *done);
+
+/**
+ * Check if the filter chain at `sockindex` for connection `conn` is
+ * completely connected.
+ */
+bool Curl_conn_is_connected(struct connectdata *conn, int sockindex);
+
+/**
+ * Determine if we have reached the remote host on IP level, e.g.
+ * have a TCP connection. This turns TRUE before a possible SSL
+ * handshake has been started/done.
+ */
+bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex);
+
+/**
+ * Determine if the connection is using SSL to the remote host
+ * (or will be once connected). This will return FALSE, if SSL
+ * is only used in proxying and not for the tunnel itself.
+ */
+bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex);
+
+/**
+ * Connection provides multiplexing of easy handles at `socketindex`.
+ */
+bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex);
+
+/**
+ * Close the filter chain at `sockindex` for connection `data->conn`.
+  * Filters remain in place and may be connected again afterwards.
+ */
+void Curl_conn_close(struct Curl_easy *data, int sockindex);
+
+/**
+ * Return if data is pending in some connection filter at chain
+ * `sockindex` for connection `data->conn`.
+ */
+bool Curl_conn_data_pending(struct Curl_easy *data,
+                            int sockindex);
+
+/**
+ * Return the socket used on data's connection for the index.
+ * Returns CURL_SOCKET_BAD if not available.
+ */
+curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex);
+
+/**
+ * Tell filters to forget about the socket at sockindex.
+ */
+void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex);
+
+/**
+ * Adjust the pollset for the filter chain startgin at `cf`.
+ */
+void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 struct easy_pollset *ps);
+
+/**
+ * Adjust pollset from filters installed at transfer's connection.
+ */
+void Curl_conn_adjust_pollset(struct Curl_easy *data,
+                               struct easy_pollset *ps);
+
+/**
+ * Receive data through the filter chain at `sockindex` for connection
+ * `data->conn`. Copy at most `len` bytes into `buf`. Return the
+ * actual number of bytes copied or a negative value on error.
+ * The error code is placed into `*code`.
+ */
+ssize_t Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
+                     size_t len, CURLcode *code);
+
+/**
+ * Send `len` bytes of data from `buf` through the filter chain `sockindex`
+ * at connection `data->conn`. Return the actual number of bytes written
+ * or a negative value on error.
+ * The error code is placed into `*code`.
+ */
+ssize_t Curl_cf_send(struct Curl_easy *data, int sockindex,
+                     const void *buf, size_t len, CURLcode *code);
+
+/**
+ * The easy handle `data` is being attached to `conn`. This does
+ * not mean that data will actually do a transfer. Attachment is
+ * also used for temporary actions on the connection.
+ */
+void Curl_conn_ev_data_attach(struct connectdata *conn,
+                              struct Curl_easy *data);
+
+/**
+ * The easy handle `data` is being detached (no longer served)
+ * by connection `conn`. All filters are informed to release any resources
+ * related to `data`.
+ * Note: there may be several `data` attached to a connection at the same
+ * time.
+ */
+void Curl_conn_ev_data_detach(struct connectdata *conn,
+                              struct Curl_easy *data);
+
+/**
+ * Notify connection filters that they need to setup data for
+ * a transfer.
+ */
+CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data);
+
+/**
+ * Notify connection filters that now would be a good time to
+ * perform any idle, e.g. time related, actions.
+ */
+CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data);
+
+/**
+ * Notify connection filters that the transfer represented by `data`
+ * is donw with sending data (e.g. has uploaded everything).
+ */
+void Curl_conn_ev_data_done_send(struct Curl_easy *data);
+
+/**
+ * Notify connection filters that the transfer represented by `data`
+ * is finished - eventually premature, e.g. before being complete.
+ */
+void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature);
+
+/**
+ * Notify connection filters that the transfer of data is paused/unpaused.
+ */
+CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause);
+
+/**
+ * Inform connection filters to update their info in `conn`.
+ */
+void Curl_conn_ev_update_info(struct Curl_easy *data,
+                              struct connectdata *conn);
+
+/**
+ * Check if FIRSTSOCKET's cfilter chain deems connection alive.
+ */
+bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
+                        bool *input_pending);
+
+/**
+ * Try to upkeep the connection filters at sockindex.
+ */
+CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
+                              struct connectdata *conn,
+                              int sockindex);
+
+void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data);
+void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
+                        const char **phost, const char **pdisplay_host,
+                        int *pport);
+
+/**
+ * Get the maximum number of parallel transfers the connection
+ * expects to be able to handle at `sockindex`.
+ */
+size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
+                                    struct connectdata *conn,
+                                    int sockindex);
+
+
+/**
+ * Get the index of the given socket in the connection's sockets.
+ * Useful in calling `Curl_conn_send()/Curl_conn_recv()` with the
+ * correct socket index.
+ */
+int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd);
+
+/*
+ * Receive data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
+ * Will return CURLE_AGAIN iff blocked on receiving.
+ */
+CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
+                        char *buf, size_t buffersize,
+                        ssize_t *pnread);
+
+/*
+ * Send data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
+ * Will return CURLE_AGAIN iff blocked on sending.
+ */
+CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
+                        const void *buf, size_t blen,
+                        size_t *pnwritten);
+
+
+void Curl_pollset_reset(struct Curl_easy *data,
+                        struct easy_pollset *ps);
+
+/* Change the poll flags (CURL_POLL_IN/CURL_POLL_OUT) to the poll set for
+ * socket `sock`. If the socket is not already part of the poll set, it
+ * will be added.
+ * If the socket is present and all poll flags are cleared, it will be removed.
+ */
+void Curl_pollset_change(struct Curl_easy *data,
+                         struct easy_pollset *ps, curl_socket_t sock,
+                         int add_flags, int remove_flags);
+
+void Curl_pollset_set(struct Curl_easy *data,
+                      struct easy_pollset *ps, curl_socket_t sock,
+                      bool do_in, bool do_out);
+
+#define Curl_pollset_add_in(data, ps, sock) \
+          Curl_pollset_change((data), (ps), (sock), CURL_POLL_IN, 0)
+#define Curl_pollset_add_out(data, ps, sock) \
+          Curl_pollset_change((data), (ps), (sock), CURL_POLL_OUT, 0)
+#define Curl_pollset_add_inout(data, ps, sock) \
+          Curl_pollset_change((data), (ps), (sock), \
+                               CURL_POLL_IN|CURL_POLL_OUT, 0)
+#define Curl_pollset_set_in_only(data, ps, sock) \
+          Curl_pollset_change((data), (ps), (sock), \
+                               CURL_POLL_IN, CURL_POLL_OUT)
+#define Curl_pollset_set_out_only(data, ps, sock) \
+          Curl_pollset_change((data), (ps), (sock), \
+                               CURL_POLL_OUT, CURL_POLL_IN)
+
+void Curl_pollset_add_socks(struct Curl_easy *data,
+                            struct easy_pollset *ps,
+                            int (*get_socks_cb)(struct Curl_easy *data,
+                                                curl_socket_t *socks));
+
+/**
+ * Check if the pollset, as is, wants to read and/or write regarding
+ * the given socket.
+ */
+void Curl_pollset_check(struct Curl_easy *data,
+                        struct easy_pollset *ps, curl_socket_t sock,
+                        bool *pwant_read, bool *pwant_write);
+
+/**
+ * Types and macros used to keep the current easy handle in filter calls,
+ * allowing for nested invocations. See #10336.
+ *
+ * `cf_call_data` is intended to be a member of the cfilter's `ctx` type.
+ * A filter defines the macro `CF_CTX_CALL_DATA` to give access to that.
+ *
+ * With all values 0, the default, this indicates that there is no cfilter
+ * call with `data` ongoing.
+ * Macro `CF_DATA_SAVE` preserves the current `cf_call_data` in a local
+ * variable and sets the `data` given, incrementing the `depth` counter.
+ *
+ * Macro `CF_DATA_RESTORE` restores the old values from the local variable,
+ * while checking that `depth` values are as expected (debug build), catching
+ * cases where a "lower" RESTORE was not called.
+ *
+ * Finally, macro `CF_DATA_CURRENT` gives the easy handle of the current
+ * invocation.
+ */
+struct cf_call_data {
+  struct Curl_easy *data;
+#ifdef DEBUGBUILD
+  int depth;
+#endif
+};
+
+/**
+ * define to access the `struct cf_call_data for a cfilter. Normally
+ * a member in the cfilter's `ctx`.
+ *
+ * #define CF_CTX_CALL_DATA(cf)   -> struct cf_call_data instance
+*/
+
+#ifdef DEBUGBUILD
+
+#define CF_DATA_SAVE(save, cf, data) \
+  do { \
+    (save) = CF_CTX_CALL_DATA(cf); \
+    DEBUGASSERT((save).data == NULL || (save).depth > 0); \
+    CF_CTX_CALL_DATA(cf).depth++;  \
+    CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)data; \
+  } while(0)
+
+#define CF_DATA_RESTORE(cf, save) \
+  do { \
+    DEBUGASSERT(CF_CTX_CALL_DATA(cf).depth == (save).depth + 1); \
+    DEBUGASSERT((save).data == NULL || (save).depth > 0); \
+    CF_CTX_CALL_DATA(cf) = (save); \
+  } while(0)
+
+#else /* DEBUGBUILD */
+
+#define CF_DATA_SAVE(save, cf, data) \
+  do { \
+    (save) = CF_CTX_CALL_DATA(cf); \
+    CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)data; \
+  } while(0)
+
+#define CF_DATA_RESTORE(cf, save) \
+  do { \
+    CF_CTX_CALL_DATA(cf) = (save); \
+  } while(0)
+
+#endif /* !DEBUGBUILD */
+
+#define CF_DATA_CURRENT(cf) \
+  ((cf)? (CF_CTX_CALL_DATA(cf).data) : NULL)
+
+#endif /* HEADER_CURL_CFILTERS_H */
Index: trunk/src/libs/curl-8.7.1/lib/config-amigaos.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/config-amigaos.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/config-amigaos.h	(revision 104083)
@@ -0,0 +1,129 @@
+#ifndef HEADER_CURL_CONFIG_AMIGAOS_H
+#define HEADER_CURL_CONFIG_AMIGAOS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/*               Hand crafted config file for AmigaOS               */
+/* ================================================================ */
+
+#ifdef __AMIGA__ /* Any AmigaOS flavour */
+
+#define HAVE_ARPA_INET_H 1
+#define HAVE_CLOSESOCKET_CAMEL 1
+#define HAVE_IOCTLSOCKET_CAMEL 1
+#define HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1
+#define HAVE_LONGLONG 1
+#define HAVE_NETDB_H 1
+#define HAVE_NETINET_IN_H 1
+#define HAVE_NET_IF_H 1
+#define HAVE_PWD_H 1
+#define HAVE_SELECT 1
+#define HAVE_SIGNAL 1
+#define HAVE_SOCKET 1
+#define HAVE_STRCASECMP 1
+#define HAVE_STRDUP 1
+#define HAVE_STRICMP 1
+#define HAVE_STRINGS_H 1
+#define HAVE_STRUCT_TIMEVAL 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_SOCKET_H 1
+#define HAVE_SYS_SOCKIO_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UTIME 1
+#define HAVE_UTIME_H 1
+#define HAVE_WRITABLE_ARGV 1
+#define HAVE_SYS_IOCTL_H 1
+
+#define NEED_MALLOC_H 1
+
+#define SIZEOF_INT 4
+#define SIZEOF_SIZE_T 4
+
+#ifndef SIZEOF_CURL_OFF_T
+#define SIZEOF_CURL_OFF_T 8
+#endif
+
+#define USE_MANUAL 1
+#define CURL_DISABLE_LDAP 1
+
+#ifndef OS
+#define OS "AmigaOS"
+#endif
+
+#define PACKAGE "curl"
+#define PACKAGE_BUGREPORT "a suitable mailing list: https://curl.se/mail/"
+#define PACKAGE_NAME "curl"
+#define PACKAGE_STRING "curl -"
+#define PACKAGE_TARNAME "curl"
+#define PACKAGE_VERSION "-"
+
+#if defined(USE_AMISSL)
+#define CURL_CA_PATH "AmiSSL:Certs"
+#elif defined(__MORPHOS__)
+#define CURL_CA_BUNDLE "MOSSYS:Data/SSL/curl-ca-bundle.crt"
+#else
+#define CURL_CA_BUNDLE "s:curl-ca-bundle.crt"
+#endif
+
+#define STDC_HEADERS 1
+
+#define in_addr_t int
+
+#ifndef F_OK
+#  define F_OK 0
+#endif
+
+#ifndef O_RDONLY
+#  define O_RDONLY 0x0000
+#endif
+
+#ifndef LONG_MAX
+#  define LONG_MAX 0x7fffffffL
+#endif
+
+#ifndef LONG_MIN
+#  define LONG_MIN (-0x7fffffffL-1)
+#endif
+
+#define HAVE_RECV 1
+#define RECV_TYPE_ARG1 long
+#define RECV_TYPE_ARG2 char *
+#define RECV_TYPE_ARG3 long
+#define RECV_TYPE_ARG4 long
+#define RECV_TYPE_RETV long
+
+#define HAVE_SEND 1
+#define SEND_TYPE_ARG1 int
+#define SEND_QUAL_ARG2 const
+#define SEND_TYPE_ARG2 char *
+#define SEND_TYPE_ARG3 int
+#define SEND_TYPE_ARG4 int
+#define SEND_TYPE_RETV int
+
+#endif /* __AMIGA__ */
+#endif /* HEADER_CURL_CONFIG_AMIGAOS_H */
Index: trunk/src/libs/curl-8.7.1/lib/config-dos.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/config-dos.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/config-dos.h	(revision 104083)
@@ -0,0 +1,138 @@
+#ifndef HEADER_CURL_CONFIG_DOS_H
+#define HEADER_CURL_CONFIG_DOS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+
+/* ================================================================ */
+/*       lib/config-dos.h - Hand crafted config file for DOS        */
+/* ================================================================ */
+
+#ifndef OS
+#if defined(DJGPP)
+  #define OS  "MSDOS/djgpp"
+#elif defined(__HIGHC__)
+  #define OS  "MSDOS/HighC"
+#else
+  #define OS  "MSDOS/?"
+#endif
+#endif
+
+#define PACKAGE  "curl"
+
+#define USE_MANUAL 1
+
+#define HAVE_ARPA_INET_H       1
+#define HAVE_FCNTL_H           1
+#define HAVE_FREEADDRINFO      1
+#define HAVE_GETADDRINFO       1
+#define HAVE_GETTIMEOFDAY      1
+#define HAVE_IO_H              1
+#define HAVE_IOCTL_FIONBIO     1
+#define HAVE_IOCTLSOCKET       1
+#define HAVE_IOCTLSOCKET_FIONBIO   1
+#define HAVE_LOCALE_H          1
+#define HAVE_LONGLONG          1
+#define HAVE_NETDB_H           1
+#define HAVE_NETINET_IN_H      1
+#define HAVE_NETINET_TCP_H     1
+#define HAVE_NET_IF_H          1
+#define HAVE_RECV              1
+#define HAVE_SELECT            1
+#define HAVE_SEND              1
+#define HAVE_SETLOCALE         1
+#define HAVE_SETMODE           1
+#define HAVE_SIGNAL            1
+#define HAVE_SOCKET            1
+#define HAVE_STRDUP            1
+#define HAVE_STRICMP           1
+#define HAVE_STRTOLL           1
+#define HAVE_STRUCT_TIMEVAL    1
+#define HAVE_SYS_IOCTL_H       1
+#define HAVE_SYS_SOCKET_H      1
+#define HAVE_SYS_STAT_H        1
+#define HAVE_SYS_TYPES_H       1
+#define HAVE_UNISTD_H          1
+
+#define NEED_MALLOC_H          1
+
+#define SIZEOF_INT             4
+#define SIZEOF_LONG            4
+#define SIZEOF_SIZE_T          4
+#define SIZEOF_CURL_OFF_T      8
+#define STDC_HEADERS           1
+
+/* Qualifiers for send() and recv() */
+
+#define SEND_TYPE_ARG1         int
+#define SEND_QUAL_ARG2         const
+#define SEND_TYPE_ARG2         void *
+#define SEND_TYPE_ARG3         int
+#define SEND_TYPE_ARG4         int
+#define SEND_TYPE_RETV         int
+
+#define RECV_TYPE_ARG1         int
+#define RECV_TYPE_ARG2         void *
+#define RECV_TYPE_ARG3         int
+#define RECV_TYPE_ARG4         int
+#define RECV_TYPE_RETV         int
+
+#define BSD
+
+/* CURLDEBUG definition enables memory tracking */
+/* #define CURLDEBUG */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP        1
+
+#define in_addr_t  u_long
+
+#if defined(__HIGHC__) || \
+    (defined(__GNUC__) && (__GNUC__ < 4))
+  #define ssize_t  int
+#endif
+
+/* Target HAVE_x section */
+
+#if defined(DJGPP)
+  #define HAVE_BASENAME   1
+  #define HAVE_STRCASECMP 1
+  #define HAVE_SIGACTION  1
+  #define HAVE_SIGSETJMP  1
+  #define HAVE_SYS_TIME_H 1
+  #define HAVE_TERMIOS_H  1
+
+#elif defined(__HIGHC__)
+  #define HAVE_SYS_TIME_H 1
+  #define strerror(e) strerror_s_((e))
+#endif
+
+#ifdef MSDOS  /* Watt-32 */
+  #define HAVE_CLOSE_S    1
+#endif
+
+#undef word
+#undef byte
+
+#endif /* HEADER_CURL_CONFIG_DOS_H */
Index: trunk/src/libs/curl-8.7.1/lib/config-mac.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/config-mac.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/config-mac.h	(revision 104083)
@@ -0,0 +1,103 @@
+#ifndef HEADER_CURL_CONFIG_MAC_H
+#define HEADER_CURL_CONFIG_MAC_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* =================================================================== */
+/*                Hand crafted config file for Mac OS 9                */
+/* =================================================================== */
+/*  On Mac OS X you must run configure to generate curl_config.h file  */
+/* =================================================================== */
+
+#ifndef OS
+#define OS "mac"
+#endif
+
+#include <ConditionalMacros.h>
+#if TYPE_LONGLONG
+#define HAVE_LONGLONG           1
+#endif
+
+/* Define if you want the built-in manual */
+#define USE_MANUAL              1
+
+#define HAVE_NETINET_IN_H       1
+#define HAVE_SYS_SOCKET_H       1
+#define HAVE_NETDB_H            1
+#define HAVE_ARPA_INET_H        1
+#define HAVE_UNISTD_H           1
+#define HAVE_NET_IF_H           1
+#define HAVE_SYS_TYPES_H        1
+#define HAVE_GETTIMEOFDAY       1
+#define HAVE_FCNTL_H            1
+#define HAVE_SYS_STAT_H         1
+#define HAVE_UTIME_H            1
+#define HAVE_SYS_TIME_H         1
+#define HAVE_SYS_UTIME_H        1
+#define HAVE_SYS_IOCTL_H        1
+#define HAVE_ALARM              1
+#define HAVE_FTRUNCATE          1
+#define HAVE_UTIME              1
+#define HAVE_SELECT             1
+#define HAVE_SOCKET             1
+#define HAVE_STRUCT_TIMEVAL     1
+
+#define HAVE_SIGACTION          1
+
+#ifdef MACOS_SSL_SUPPORT
+#  define USE_OPENSSL           1
+#endif
+
+#define CURL_DISABLE_LDAP       1
+
+#define HAVE_IOCTL_FIONBIO      1
+
+#define SIZEOF_INT              4
+#define SIZEOF_LONG             4
+#define SIZEOF_SIZE_T           4
+#ifdef HAVE_LONGLONG
+#define SIZEOF_CURL_OFF_T       8
+#else
+#define SIZEOF_CURL_OFF_T       4
+#endif
+
+#define HAVE_RECV 1
+#define RECV_TYPE_ARG1 int
+#define RECV_TYPE_ARG2 void *
+#define RECV_TYPE_ARG3 size_t
+#define RECV_TYPE_ARG4 int
+#define RECV_TYPE_RETV ssize_t
+
+#define HAVE_SEND 1
+#define SEND_TYPE_ARG1 int
+#define SEND_QUAL_ARG2 const
+#define SEND_TYPE_ARG2 void *
+#define SEND_TYPE_ARG3 size_t
+#define SEND_TYPE_ARG4 int
+#define SEND_TYPE_RETV ssize_t
+
+#define HAVE_EXTRA_STRICMP_H 1
+#define HAVE_EXTRA_STRDUP_H  1
+
+#endif /* HEADER_CURL_CONFIG_MAC_H */
Index: trunk/src/libs/curl-8.7.1/lib/config-os400.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/config-os400.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/config-os400.h	(revision 104083)
@@ -0,0 +1,334 @@
+#ifndef HEADER_CURL_CONFIG_OS400_H
+#define HEADER_CURL_CONFIG_OS400_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/*                Hand crafted config file for OS/400               */
+/* ================================================================ */
+
+#pragma enum(int)
+
+#undef PACKAGE
+
+/* Version number of this archive. */
+#undef VERSION
+
+/* Define cpu-machine-OS */
+#ifndef OS
+#define OS "OS/400"
+#endif
+
+/* OS400 supports a 3-argument ASCII version of gethostbyaddr_r(), but its
+ *  prototype is incompatible with the "standard" one (1st argument is not
+ *  const). However, getaddrinfo() is supported (ASCII version defined as
+ *  a local wrapper in setup-os400.h) in a threadsafe way: we can then
+ *  configure getaddrinfo() as such and get rid of gethostbyname_r() without
+ *  loss of threadsafeness. */
+#undef HAVE_GETHOSTBYNAME_R
+#undef HAVE_GETHOSTBYNAME_R_3
+#undef HAVE_GETHOSTBYNAME_R_5
+#undef HAVE_GETHOSTBYNAME_R_6
+#define HAVE_GETADDRINFO
+#define HAVE_GETADDRINFO_THREADSAFE
+
+/* Define if you need the _REENTRANT define for some functions */
+#undef NEED_REENTRANT
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6
+
+/* Define if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define this to 'int' if ssize_t is not an available typedefed type */
+#undef ssize_t
+
+/* Define this as a suitable file to read random data from */
+#undef RANDOM_FILE
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H
+
+/* Define if you have the `closesocket' function. */
+#undef HAVE_CLOSESOCKET
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H
+
+/* Define if you have the `geteuid' function. */
+#define HAVE_GETEUID
+
+/* Define if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME
+
+/* Define if you have the `getpass_r' function. */
+#undef HAVE_GETPASS_R
+
+/* Define to 1 if you have the getpeername function. */
+#define HAVE_GETPEERNAME 1
+
+/* Define if you have the `getpwuid' function. */
+#define HAVE_GETPWUID
+
+/* Define to 1 if you have the getsockname function. */
+#define HAVE_GETSOCKNAME 1
+
+/* Define if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY
+
+/* Define if you have the `timeval' struct. */
+#define HAVE_STRUCT_TIMEVAL
+
+/* Define if you have the <io.h> header file. */
+#undef HAVE_IO_H
+
+/* Define if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define if you have GSS API. */
+#define HAVE_GSSAPI
+
+/* Define if you have the GNU gssapi libraries */
+#undef HAVE_GSSGNU
+
+/* Define if you need the malloc.h header file even with stdlib.h  */
+/* #define NEED_MALLOC_H 1 */
+
+/* Define if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H
+
+/* Define if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H
+
+/* Define if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H
+
+/* Define if you have the <pwd.h> header file. */
+#define HAVE_PWD_H
+
+/* Define if you have the `select' function. */
+#define HAVE_SELECT
+
+/* Define if you have the `sigaction' function. */
+#define HAVE_SIGACTION
+
+/* Define if you have the `signal' function. */
+#undef HAVE_SIGNAL
+
+/* Define if you have the `socket' function. */
+#define HAVE_SOCKET
+
+
+/* The following define is needed on OS400 to enable strcmpi(), stricmp() and
+   strdup(). */
+#define __cplusplus__strings__
+
+/* Define if you have the `strcasecmp' function. */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the `strcmpi' function. */
+#define HAVE_STRCMPI
+
+/* Define if you have the `stricmp' function. */
+#define HAVE_STRICMP
+
+/* Define if you have the `strdup' function. */
+#define HAVE_STRDUP
+
+/* Define if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H
+
+/* Define if you have the <stropts.h> header file. */
+#undef HAVE_STROPTS_H
+
+/* Define if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R
+
+/* Define if you have the `strtoll' function. */
+#undef HAVE_STRTOLL             /* Allows ASCII compile on V5R1. */
+
+/* Define if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H
+
+/* Define if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H
+
+/* Define if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H
+
+/* Define if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H
+
+/* Define if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H
+
+/* Define if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT              4
+
+/* Define if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG
+
+/* The size of a `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG        8
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG             4
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T           4
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T       8
+
+/* Define this if you have struct sockaddr_storage */
+#define HAVE_STRUCT_SOCKADDR_STORAGE
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS
+
+/* Define to enable HTTP3 support (experimental, requires NGTCP2, QUICHE or
+   MSH3) */
+#undef ENABLE_QUIC
+
+/* Version number of package */
+#undef VERSION
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#define _LARGE_FILES
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* type to use in place of in_addr_t if not defined */
+#define in_addr_t       unsigned long
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO
+
+/* Define if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR
+
+/* To disable LDAP */
+#undef CURL_DISABLE_LDAP
+
+/* Definition to make a library symbol externally visible. */
+#define CURL_EXTERN_SYMBOL
+
+/* Define if you have the ldap_url_parse procedure. */
+/* #define HAVE_LDAP_URL_PARSE */    /* Disabled because of an IBM bug. */
+
+/* Define if you have the recv function. */
+#define HAVE_RECV
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define if you have the send function. */
+#define HAVE_SEND
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* Define to use the OS/400 crypto library. */
+#define USE_OS400CRYPTO
+
+/* Define to use Unix sockets. */
+#define USE_UNIX_SOCKETS
+
+/* Use the system keyring as the default CA bundle. */
+#define CURL_CA_BUNDLE  "/QIBM/UserData/ICSS/Cert/Server/DEFAULT.KDB"
+
+/* ---------------------------------------------------------------- */
+/*                       ADDITIONAL DEFINITIONS                     */
+/* ---------------------------------------------------------------- */
+
+/* The following must be defined BEFORE system header files inclusion. */
+
+#define __ptr128                       /* No teraspace. */
+#define qadrt_use_fputc_inline         /* Generate fputc() wrapper inline. */
+#define qadrt_use_fread_inline         /* Generate fread() wrapper inline. */
+#define qadrt_use_fwrite_inline        /* Generate fwrite() wrapper inline. */
+
+#endif /* HEADER_CURL_CONFIG_OS400_H */
Index: trunk/src/libs/curl-8.7.1/lib/config-plan9.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/config-plan9.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/config-plan9.h	(revision 104083)
@@ -0,0 +1,147 @@
+#ifndef HEADER_CURL_CONFIG_PLAN9_H
+#define HEADER_CURL_CONFIG_PLAN9_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#define BUILDING_LIBCURL 1
+#define CURL_CA_BUNDLE "/sys/lib/tls/ca.pem"
+#define CURL_CA_PATH "/sys/lib/tls"
+#define CURL_STATICLIB 1
+#define ENABLE_IPV6 1
+#define CURL_DISABLE_LDAP 1
+
+#define NEED_REENTRANT 1
+#ifndef OS
+#define OS "plan9"
+#endif
+#define PACKAGE "curl"
+#define PACKAGE_NAME "curl"
+#define PACKAGE_BUGREPORT "a suitable mailing list: https://curl.se/mail/"
+#define PACKAGE_STRING "curl -"
+#define PACKAGE_TARNAME "curl"
+#define PACKAGE_VERSION "-"
+#define RANDOM_FILE "/dev/random"
+#define VERSION "0.0.0" /* TODO */
+
+#define STDC_HEADERS 1
+
+#ifdef _BITS64
+#error not implement
+#else
+#define SIZEOF_INT 4
+#define SIZEOF_LONG 4
+#define SIZEOF_OFF_T 8
+#define SIZEOF_CURL_OFF_T 4 /* curl_off_t = timediff_t = int */
+#define SIZEOF_SIZE_T 4
+#define SIZEOF_TIME_T 4
+#endif
+
+#define HAVE_RECV 1
+#define RECV_TYPE_ARG1 int
+#define RECV_TYPE_ARG2 void *
+#define RECV_TYPE_ARG3 int
+#define RECV_TYPE_ARG4 int
+#define RECV_TYPE_RETV int
+
+#define HAVE_SELECT 1
+
+#define HAVE_SEND 1
+#define SEND_TYPE_ARG1 int
+#define SEND_TYPE_ARG2 void *
+#define SEND_QUAL_ARG2
+#define SEND_TYPE_ARG3 int
+#define SEND_TYPE_ARG4 int
+#define SEND_TYPE_RETV int
+
+#define HAVE_ALARM 1
+#define HAVE_ARPA_INET_H 1
+#define HAVE_BASENAME 1
+#define HAVE_BOOL_T 1
+#define HAVE_FCNTL 1
+#define HAVE_FCNTL_H 1
+#define HAVE_FREEADDRINFO 1
+#define HAVE_FTRUNCATE 1
+#define HAVE_GETADDRINFO 1
+#define HAVE_GETEUID 1
+#define HAVE_GETHOSTNAME 1
+#define HAVE_GETPPID 1
+#define HAVE_GETPWUID 1
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_GMTIME_R 1
+#define HAVE_INET_NTOP 1
+#define HAVE_INET_PTON 1
+#define HAVE_LIBGEN_H 1
+#define HAVE_LIBZ 1
+#define HAVE_LOCALE_H 1
+#define HAVE_LONGLONG 1
+#define HAVE_NETDB_H 1
+#define HAVE_NETINET_IN_H 1
+#define HAVE_NETINET_TCP_H 1
+#define HAVE_PWD_H 1
+#define HAVE_SYS_SELECT_H 1
+
+#define USE_OPENSSL 1
+
+#define HAVE_PIPE 1
+#define HAVE_POLL_FINE 1
+#define HAVE_POLL_H 1
+#define HAVE_PTHREAD_H 1
+#define HAVE_SETLOCALE 1
+
+#define HAVE_SIGACTION 1
+#define HAVE_SIGNAL 1
+#define HAVE_SIGSETJMP 1
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+#define HAVE_SOCKET 1
+#define HAVE_SSL_GET_SHUTDOWN 1
+#define HAVE_STDBOOL_H 1
+#define HAVE_STRCASECMP 1
+#define HAVE_STRDUP 1
+#define HAVE_STRTOK_R 1
+#define HAVE_STRTOLL 1
+#define HAVE_STRUCT_TIMEVAL 1
+#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_RESOURCE_H 1
+#define HAVE_SYS_SOCKET_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_UN_H 1
+#define HAVE_TERMIOS_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UTIME 1
+#define HAVE_UTIME_H 1
+
+#define HAVE_POSIX_STRERROR_R 1
+#define HAVE_STRERROR_R 1
+#define USE_MANUAL 1
+
+#define __attribute__(x)
+
+#ifndef __cplusplus
+#undef inline
+#endif
+
+#endif /* HEADER_CURL_CONFIG_PLAN9_H */
Index: trunk/src/libs/curl-8.7.1/lib/config-riscos.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/config-riscos.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/config-riscos.h	(revision 104083)
@@ -0,0 +1,280 @@
+#ifndef HEADER_CURL_CONFIG_RISCOS_H
+#define HEADER_CURL_CONFIG_RISCOS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/*               Hand crafted config file for RISC OS               */
+/* ================================================================ */
+
+/* Name of this package! */
+#undef PACKAGE
+
+/* Version number of this archive. */
+#undef VERSION
+
+/* Define cpu-machine-OS */
+#ifndef OS
+#define OS "ARM-RISC OS"
+#endif
+
+/* Define if you want the built-in manual */
+#define USE_MANUAL
+
+/* Define if you have the gethostbyname_r() function with 3 arguments */
+#undef HAVE_GETHOSTBYNAME_R_3
+
+/* Define if you have the gethostbyname_r() function with 5 arguments */
+#undef HAVE_GETHOSTBYNAME_R_5
+
+/* Define if you have the gethostbyname_r() function with 6 arguments */
+#undef HAVE_GETHOSTBYNAME_R_6
+
+/* Define if you need the _REENTRANT define for some functions */
+#undef NEED_REENTRANT
+
+/* Define if you want to enable IPv6 support */
+#undef ENABLE_IPV6
+
+/* Define if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define this to 'int' if ssize_t is not an available typedefed type */
+#undef ssize_t
+
+/* Define this as a suitable file to read random data from */
+#undef RANDOM_FILE
+
+/* Define if you want to enable IPv6 support */
+#undef ENABLE_IPV6
+
+/* Define if you have the alarm function. */
+#define HAVE_ALARM
+
+/* Define if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H
+
+/* Define if you have the `closesocket' function. */
+#undef HAVE_CLOSESOCKET
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H
+
+/* Define if you have the `ftruncate' function. */
+#define HAVE_FTRUNCATE
+
+/* Define if getaddrinfo exists and works */
+#define HAVE_GETADDRINFO
+
+/* Define if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define if you have the `gethostbyname_r' function. */
+#undef HAVE_GETHOSTBYNAME_R
+
+/* Define if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME
+
+/* Define if you have the `getpass_r' function. */
+#undef HAVE_GETPASS_R
+
+/* Define if you have the `getpwuid' function. */
+#undef HAVE_GETPWUID
+
+/* Define if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY
+
+/* Define if you have the `timeval' struct. */
+#define HAVE_STRUCT_TIMEVAL
+
+/* Define if you have the <io.h> header file. */
+#undef HAVE_IO_H
+
+/* Define if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define if you need the malloc.h header file even with stdlib.h  */
+/* #define NEED_MALLOC_H 1 */
+
+/* Define if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H
+
+/* Define if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H
+
+/* Define if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H
+
+/* Define if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* Define if you have the `select' function. */
+#define HAVE_SELECT
+
+/* Define if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define if you have the `signal' function. */
+#define HAVE_SIGNAL
+
+/* Define if you have the `socket' function. */
+#define HAVE_SOCKET
+
+/* Define if you have the `strcasecmp' function. */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the `strcmpi' function. */
+#undef HAVE_STRCMPI
+
+/* Define if you have the `strdup' function. */
+#define HAVE_STRDUP
+
+/* Define if you have the `stricmp' function. */
+#define HAVE_STRICMP
+
+/* Define if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define if you have the `strtok_r' function. */
+#undef HAVE_STRTOK_R
+
+/* Define if you have the `strtoll' function. */
+#undef HAVE_STRTOLL
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H
+
+/* Define if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H
+
+/* Define if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H
+
+/* Define if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef ssize_t
+
+/* Define if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP
+
+/* Define if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+#endif /* HEADER_CURL_CONFIG_RISCOS_H */
Index: trunk/src/libs/curl-8.7.1/lib/config-win32.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/config-win32.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/config-win32.h	(revision 104083)
@@ -0,0 +1,516 @@
+#ifndef HEADER_CURL_CONFIG_WIN32_H
+#define HEADER_CURL_CONFIG_WIN32_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/*               Hand crafted config file for Windows               */
+/* ================================================================ */
+
+/* ---------------------------------------------------------------- */
+/*                          HEADER FILES                            */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have the <arpa/inet.h> header file. */
+/* #define HAVE_ARPA_INET_H 1 */
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* Define if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define if you need <malloc.h> header even with <stdlib.h> header file. */
+#define NEED_MALLOC_H 1
+
+/* Define if you have the <netdb.h> header file. */
+/* #define HAVE_NETDB_H 1 */
+
+/* Define if you have the <netinet/in.h> header file. */
+/* #define HAVE_NETINET_IN_H 1 */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || defined(__MINGW32__)
+#define HAVE_STDBOOL_H 1
+#endif
+
+/* Define if you have the <sys/param.h> header file. */
+#if defined(__MINGW32__)
+#define HAVE_SYS_PARAM_H 1
+#endif
+
+/* Define if you have the <sys/select.h> header file. */
+/* #define HAVE_SYS_SELECT_H 1 */
+
+/* Define if you have the <sys/socket.h> header file. */
+/* #define HAVE_SYS_SOCKET_H 1 */
+
+/* Define if you have the <sys/sockio.h> header file. */
+/* #define HAVE_SYS_SOCKIO_H 1 */
+
+/* Define if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define if you have the <sys/time.h> header file. */
+#if defined(__MINGW32__)
+#define HAVE_SYS_TIME_H 1
+#endif
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have the <sys/utime.h> header file. */
+#define HAVE_SYS_UTIME_H 1
+
+/* Define if you have the <termio.h> header file. */
+/* #define HAVE_TERMIO_H 1 */
+
+/* Define if you have the <termios.h> header file. */
+/* #define HAVE_TERMIOS_H 1 */
+
+/* Define if you have the <unistd.h> header file. */
+#if defined(__MINGW32__)
+#define HAVE_UNISTD_H 1
+#endif
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#if defined(__MINGW32__)
+#define HAVE_LIBGEN_H 1
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                        OTHER HEADER INFO                         */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if bool is an available type. */
+#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || defined(__MINGW32__)
+#define HAVE_BOOL_T 1
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                             FUNCTIONS                            */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have the closesocket function. */
+#define HAVE_CLOSESOCKET 1
+
+/* Define if you have the ftruncate function. */
+#if defined(__MINGW32__)
+#define HAVE_FTRUNCATE 1
+#endif
+
+/* Define to 1 if you have the `getpeername' function. */
+#define HAVE_GETPEERNAME 1
+
+/* Define to 1 if you have the getsockname function. */
+#define HAVE_GETSOCKNAME 1
+
+/* Define if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define if you have the gettimeofday function. */
+#if defined(__MINGW32__)
+#define HAVE_GETTIMEOFDAY 1
+#endif
+
+/* Define if you have the ioctlsocket function. */
+#define HAVE_IOCTLSOCKET 1
+
+/* Define if you have a working ioctlsocket FIONBIO function. */
+#define HAVE_IOCTLSOCKET_FIONBIO 1
+
+/* Define if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define if you have the setlocale function. */
+#define HAVE_SETLOCALE 1
+
+/* Define if you have the setmode function. */
+#define HAVE_SETMODE 1
+
+/* Define if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define if you have the strcasecmp function. */
+#if defined(__MINGW32__)
+#define HAVE_STRCASECMP 1
+#endif
+
+/* Define if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define if you have the stricmp function. */
+#define HAVE_STRICMP 1
+
+/* Define if you have the strtoll function. */
+#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || defined(__MINGW32__)
+#define HAVE_STRTOLL 1
+#endif
+
+/* Define if you have the utime function. */
+#define HAVE_UTIME 1
+
+/* Define if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 SOCKET
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 SOCKET
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* Define to 1 if you have the snprintf function. */
+#if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || defined(__MINGW32__)
+#define HAVE_SNPRINTF 1
+#endif
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600  /* Vista */
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+#endif
+
+/* Define to 1 if you have the `basename' function. */
+#if defined(__MINGW32__)
+#define HAVE_BASENAME 1
+#endif
+
+/* Define to 1 if you have the strtok_r function. */
+#if defined(__MINGW32__)
+#define HAVE_STRTOK_R 1
+#endif
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* ---------------------------------------------------------------- */
+/*                       TYPEDEF REPLACEMENTS                       */
+/* ---------------------------------------------------------------- */
+
+/* Define if in_addr_t is not an available 'typedefed' type. */
+#define in_addr_t unsigned long
+
+/* Define if ssize_t is not an available 'typedefed' type. */
+#ifndef _SSIZE_T_DEFINED
+#  if defined(__MINGW32__)
+#  elif defined(_WIN64)
+#    define _SSIZE_T_DEFINED
+#    define ssize_t __int64
+#  else
+#    define _SSIZE_T_DEFINED
+#    define ssize_t int
+#  endif
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                            TYPE SIZES                            */
+/* ---------------------------------------------------------------- */
+
+/* Define to the size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* Define to the size of `long long', as computed by sizeof. */
+/* #define SIZEOF_LONG_LONG 8 */
+
+/* Define to the size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* Define to the size of `size_t', as computed by sizeof. */
+#if defined(_WIN64)
+#  define SIZEOF_SIZE_T 8
+#else
+#  define SIZEOF_SIZE_T 4
+#endif
+
+/* Define to the size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
+
+/* ---------------------------------------------------------------- */
+/*                        COMPILER SPECIFIC                         */
+/* ---------------------------------------------------------------- */
+
+/* Define to nothing if compiler does not support 'const' qualifier. */
+/* #define const */
+
+/* Define to nothing if compiler does not support 'volatile' qualifier. */
+/* #define volatile */
+
+/* Windows should not have HAVE_GMTIME_R defined */
+/* #undef HAVE_GMTIME_R */
+
+/* Define if the compiler supports the 'long long' data type. */
+#if (defined(_MSC_VER) && (_MSC_VER >= 1310)) || defined(__MINGW32__)
+#define HAVE_LONGLONG 1
+#endif
+
+/* Define to avoid VS2005 complaining about portable C functions. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define _CRT_SECURE_NO_DEPRECATE 1
+#define _CRT_NONSTDC_NO_DEPRECATE 1
+#endif
+
+/* mingw-w64 and visual studio >= 2005 (MSVCR80)
+   all default to 64-bit time_t unless _USE_32BIT_TIME_T is defined */
+#if (defined(_MSC_VER) && (_MSC_VER >= 1400)) || defined(__MINGW32__)
+#  ifndef _USE_32BIT_TIME_T
+#    define SIZEOF_TIME_T 8
+#  else
+#    define SIZEOF_TIME_T 4
+#  endif
+#endif
+
+/* Define some minimum and default build targets for Visual Studio */
+#if defined(_MSC_VER)
+   /* Officially, Microsoft's Windows SDK versions 6.X does not support Windows
+      2000 as a supported build target. VS2008 default installations provides
+      an embedded Windows SDK v6.0A along with the claim that Windows 2000 is a
+      valid build target for VS2008. Popular belief is that binaries built with
+      VS2008 using Windows SDK versions v6.X and Windows 2000 as a build target
+      are functional. */
+#  define VS2008_MIN_TARGET 0x0500
+
+   /* The minimum build target for VS2012 is Vista unless Update 1 is installed
+      and the v110_xp toolset is chosen. */
+#  if defined(_USING_V110_SDK71_)
+#    define VS2012_MIN_TARGET 0x0501
+#  else
+#    define VS2012_MIN_TARGET 0x0600
+#  endif
+
+   /* VS2008 default build target is Windows Vista. We override default target
+      to be Windows XP. */
+#  define VS2008_DEF_TARGET 0x0501
+
+   /* VS2012 default build target is Windows Vista unless Update 1 is installed
+      and the v110_xp toolset is chosen. */
+#  if defined(_USING_V110_SDK71_)
+#    define VS2012_DEF_TARGET 0x0501
+#  else
+#    define VS2012_DEF_TARGET 0x0600
+#  endif
+#endif
+
+/* VS2008 default target settings and minimum build target check. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (_MSC_VER <= 1600)
+#  ifndef _WIN32_WINNT
+#    define _WIN32_WINNT VS2008_DEF_TARGET
+#  endif
+#  ifndef WINVER
+#    define WINVER VS2008_DEF_TARGET
+#  endif
+#  if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET)
+#    error VS2008 does not support Windows build targets prior to Windows 2000
+#  endif
+#endif
+
+/* VS2012 default target settings and minimum build target check. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1700)
+#  ifndef _WIN32_WINNT
+#    define _WIN32_WINNT VS2012_DEF_TARGET
+#  endif
+#  ifndef WINVER
+#    define WINVER VS2012_DEF_TARGET
+#  endif
+#  if (_WIN32_WINNT < VS2012_MIN_TARGET) || (WINVER < VS2012_MIN_TARGET)
+#    if defined(_USING_V110_SDK71_)
+#      error VS2012 does not support Windows build targets prior to Windows XP
+#    else
+#      error VS2012 does not support Windows build targets prior to Windows \
+Vista
+#    endif
+#  endif
+#endif
+
+/* Windows XP is required for freeaddrinfo, getaddrinfo */
+#define HAVE_FREEADDRINFO           1
+#define HAVE_GETADDRINFO            1
+#define HAVE_GETADDRINFO_THREADSAFE 1
+
+/* ---------------------------------------------------------------- */
+/*                          STRUCT RELATED                          */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have struct sockaddr_storage. */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define if you have struct timeval. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define if struct sockaddr_in6 has the sin6_scope_id member. */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* ---------------------------------------------------------------- */
+/*                        LARGE FILE SUPPORT                        */
+/* ---------------------------------------------------------------- */
+
+#if defined(_MSC_VER) && !defined(_WIN32_WCE)
+#  if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+#    define USE_WIN32_LARGE_FILES
+#  else
+#    define USE_WIN32_SMALL_FILES
+#  endif
+#endif
+
+#if defined(__MINGW32__) && !defined(USE_WIN32_LARGE_FILES)
+#  define USE_WIN32_LARGE_FILES
+#endif
+
+#if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES)
+#  define USE_WIN32_SMALL_FILES
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#if defined(USE_WIN32_LARGE_FILES) && defined(__MINGW32__)
+#  ifndef _FILE_OFFSET_BITS
+#  define _FILE_OFFSET_BITS 64
+#  endif
+#endif
+
+#ifdef USE_WIN32_LARGE_FILES
+#define HAVE__FSEEKI64
+#endif
+
+/* Define to the size of `off_t', as computed by sizeof. */
+#if defined(__MINGW32__) && \
+  defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
+#  define SIZEOF_OFF_T 8
+#else
+#  define SIZEOF_OFF_T 4
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                       DNS RESOLVER SPECIALTY                     */
+/* ---------------------------------------------------------------- */
+
+/*
+ * Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS.
+ */
+
+/* Define to enable c-ares asynchronous DNS lookups. */
+/* #define USE_ARES 1 */
+
+/* Default define to enable threaded asynchronous DNS lookups. */
+#if !defined(USE_SYNC_DNS) && !defined(USE_ARES) && \
+    !defined(USE_THREADS_WIN32)
+#  define USE_THREADS_WIN32 1
+#endif
+
+#if defined(USE_ARES) && defined(USE_THREADS_WIN32)
+#  error "Only one DNS lookup specialty may be defined at most"
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                           LDAP SUPPORT                           */
+/* ---------------------------------------------------------------- */
+
+#if defined(CURL_HAS_NOVELL_LDAPSDK)
+#undef USE_WIN32_LDAP
+#define HAVE_LDAP_SSL_H 1
+#define HAVE_LDAP_URL_PARSE 1
+#elif defined(CURL_HAS_OPENLDAP_LDAPSDK)
+#undef USE_WIN32_LDAP
+#define HAVE_LDAP_URL_PARSE 1
+#else
+#undef HAVE_LDAP_URL_PARSE
+#define HAVE_LDAP_SSL 1
+#define USE_WIN32_LDAP 1
+#endif
+
+/* Define to use the Windows crypto library. */
+#if !defined(CURL_WINDOWS_APP)
+#define USE_WIN32_CRYPTO
+#endif
+
+/* Define to use Unix sockets. */
+#define USE_UNIX_SOCKETS
+
+/* ---------------------------------------------------------------- */
+/*                       ADDITIONAL DEFINITIONS                     */
+/* ---------------------------------------------------------------- */
+
+/* Define cpu-machine-OS */
+#ifndef OS
+#if defined(_M_IX86) || defined(__i386__) /* x86 (MSVC or gcc) */
+#define OS "i386-pc-win32"
+#elif defined(_M_X64) || defined(__x86_64__) /* x86_64 (MSVC >=2005 or gcc) */
+#define OS "x86_64-pc-win32"
+#elif defined(_M_IA64) || defined(__ia64__) /* Itanium */
+#define OS "ia64-pc-win32"
+#elif defined(_M_ARM_NT) || defined(__arm__) /* ARMv7-Thumb2 (Windows RT) */
+#define OS "thumbv7a-pc-win32"
+#elif defined(_M_ARM64) || defined(__aarch64__) /* ARM64 (Windows 10) */
+#define OS "aarch64-pc-win32"
+#else
+#define OS "unknown-pc-win32"
+#endif
+#endif
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* If you want to build curl with the built-in manual */
+#define USE_MANUAL 1
+
+#if defined(USE_IPV6)
+#  define ENABLE_IPV6 1
+#endif
+
+#endif /* HEADER_CURL_CONFIG_WIN32_H */
Index: trunk/src/libs/curl-8.7.1/lib/config-win32ce.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/config-win32ce.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/config-win32ce.h	(revision 104083)
@@ -0,0 +1,303 @@
+#ifndef HEADER_CURL_CONFIG_WIN32CE_H
+#define HEADER_CURL_CONFIG_WIN32CE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/*  lib/config-win32ce.h - Hand crafted config file for windows ce  */
+/* ================================================================ */
+
+/* ---------------------------------------------------------------- */
+/*                          HEADER FILES                            */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have the <arpa/inet.h> header file.  */
+/* #define HAVE_ARPA_INET_H 1 */
+
+/* Define if you have the <fcntl.h> header file.  */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <io.h> header file.  */
+#define HAVE_IO_H 1
+
+/* Define if you need the malloc.h header file even with stdlib.h  */
+#define NEED_MALLOC_H 1
+
+/* Define if you have the <netdb.h> header file.  */
+/* #define HAVE_NETDB_H 1 */
+
+/* Define if you have the <netinet/in.h> header file.  */
+/* #define HAVE_NETINET_IN_H 1 */
+
+/* Define if you have the <sys/param.h> header file.  */
+/* #define HAVE_SYS_PARAM_H 1 */
+
+/* Define if you have the <sys/select.h> header file.  */
+/* #define HAVE_SYS_SELECT_H 1 */
+
+/* Define if you have the <sys/socket.h> header file.  */
+/* #define HAVE_SYS_SOCKET_H 1 */
+
+/* Define if you have the <sys/sockio.h> header file.  */
+/* #define HAVE_SYS_SOCKIO_H 1 */
+
+/* Define if you have the <sys/stat.h> header file.  */
+#define HAVE_SYS_STAT_H 1
+
+/* Define if you have the <sys/time.h> header file */
+/* #define HAVE_SYS_TIME_H 1 */
+
+/* Define if you have the <sys/types.h> header file.  */
+/* #define HAVE_SYS_TYPES_H 1 */
+
+/* Define if you have the <sys/utime.h> header file */
+#define HAVE_SYS_UTIME_H 1
+
+/* Define if you have the <termio.h> header file.  */
+/* #define HAVE_TERMIO_H 1 */
+
+/* Define if you have the <termios.h> header file.  */
+/* #define HAVE_TERMIOS_H 1 */
+
+/* Define if you have the <unistd.h> header file.  */
+#if defined(__MINGW32__)
+#define HAVE_UNISTD_H 1
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                        OTHER HEADER INFO                         */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have the ANSI C header files.  */
+#define STDC_HEADERS 1
+
+/* ---------------------------------------------------------------- */
+/*                             FUNCTIONS                            */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have the closesocket function.  */
+#define HAVE_CLOSESOCKET 1
+
+/* Define if you have the gethostname function.  */
+#define HAVE_GETHOSTNAME 1
+
+/* Define if you have the gettimeofday function.  */
+/*  #define HAVE_GETTIMEOFDAY 1 */
+
+/* Define if you have the ioctlsocket function. */
+#define HAVE_IOCTLSOCKET 1
+
+/* Define if you have a working ioctlsocket FIONBIO function. */
+#define HAVE_IOCTLSOCKET_FIONBIO 1
+
+/* Define if you have the select function.  */
+#define HAVE_SELECT 1
+
+/* Define if you have the socket function.  */
+#define HAVE_SOCKET 1
+
+/* Define if you have the strcasecmp function.  */
+/* #define HAVE_STRCASECMP 1 */
+
+/* Define if you have the strdup function.  */
+/* #define HAVE_STRDUP 1 */
+
+/* Define if you have the stricmp function. */
+/* #define HAVE_STRICMP 1 */
+
+/* Define if you have the strtoll function.  */
+#if defined(__MINGW32__)
+#define HAVE_STRTOLL 1
+#endif
+
+/* Define if you have the utime function */
+#define HAVE_UTIME 1
+
+/* Define if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 SOCKET
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 SOCKET
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* ---------------------------------------------------------------- */
+/*                       TYPEDEF REPLACEMENTS                       */
+/* ---------------------------------------------------------------- */
+
+/* Define this if in_addr_t is not an available 'typedefed' type */
+#define in_addr_t unsigned long
+
+/* Define ssize_t if it is not an available 'typedefed' type */
+#if defined(_WIN64)
+#define ssize_t __int64
+#else
+#define ssize_t int
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                            TYPE SIZES                            */
+/* ---------------------------------------------------------------- */
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long long', as computed by sizeof. */
+/* #define SIZEOF_LONG_LONG 8 */
+
+/* Define to the size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `size_t', as computed by sizeof. */
+#if defined(_WIN64)
+#  define SIZEOF_SIZE_T 8
+#else
+#  define SIZEOF_SIZE_T 4
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                          STRUCT RELATED                          */
+/* ---------------------------------------------------------------- */
+
+/* Define this if you have struct sockaddr_storage */
+/* #define HAVE_STRUCT_SOCKADDR_STORAGE 1 */
+
+/* Define this if you have struct timeval */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define this if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* ---------------------------------------------------------------- */
+/*                        COMPILER SPECIFIC                         */
+/* ---------------------------------------------------------------- */
+
+/* Undef keyword 'const' if it does not work.  */
+/* #undef const */
+
+/* Define to avoid VS2005 complaining about portable C functions */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define _CRT_SECURE_NO_DEPRECATE 1
+#define _CRT_NONSTDC_NO_DEPRECATE 1
+#endif
+
+/* VS2005 and later default size for time_t is 64-bit, unless */
+/* _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#  ifndef _USE_32BIT_TIME_T
+#    define SIZEOF_TIME_T 8
+#  else
+#    define SIZEOF_TIME_T 4
+#  endif
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                        LARGE FILE SUPPORT                        */
+/* ---------------------------------------------------------------- */
+
+#if defined(_MSC_VER) && !defined(_WIN32_WCE)
+#  if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+#    define USE_WIN32_LARGE_FILES
+#  else
+#    define USE_WIN32_SMALL_FILES
+#  endif
+#endif
+
+#if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES)
+#  define USE_WIN32_SMALL_FILES
+#endif
+
+/* ---------------------------------------------------------------- */
+/*                           LDAP SUPPORT                           */
+/* ---------------------------------------------------------------- */
+
+#define USE_WIN32_LDAP 1
+#undef HAVE_LDAP_URL_PARSE
+
+/* ---------------------------------------------------------------- */
+/*                       ADDITIONAL DEFINITIONS                     */
+/* ---------------------------------------------------------------- */
+
+/* Define cpu-machine-OS */
+#ifndef OS
+#define OS "i386-pc-win32ce"
+#endif
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* ---------------------------------------------------------------- */
+/*                       WinCE                                      */
+/* ---------------------------------------------------------------- */
+
+#ifndef UNICODE
+#  define UNICODE
+#endif
+
+#ifndef _UNICODE
+#  define _UNICODE
+#endif
+
+#define CURL_DISABLE_FILE 1
+#define CURL_DISABLE_TELNET 1
+#define CURL_DISABLE_LDAP 1
+
+#define ENOSPC 1
+#define ENOMEM 2
+#define EAGAIN 3
+
+extern int stat(const char *path, struct stat *buffer);
+
+#endif /* HEADER_CURL_CONFIG_WIN32CE_H */
Index: trunk/src/libs/curl-8.7.1/lib/conncache.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/conncache.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/conncache.c	(revision 104083)
@@ -0,0 +1,582 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Linus Nielsen Feltzing, <linus@haxx.se>
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "url.h"
+#include "progress.h"
+#include "multiif.h"
+#include "sendf.h"
+#include "conncache.h"
+#include "share.h"
+#include "sigpipe.h"
+#include "connect.h"
+#include "strcase.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define HASHKEY_SIZE 128
+
+static CURLcode bundle_create(struct connectbundle **bundlep)
+{
+  DEBUGASSERT(*bundlep == NULL);
+  *bundlep = malloc(sizeof(struct connectbundle));
+  if(!*bundlep)
+    return CURLE_OUT_OF_MEMORY;
+
+  (*bundlep)->num_connections = 0;
+  (*bundlep)->multiuse = BUNDLE_UNKNOWN;
+
+  Curl_llist_init(&(*bundlep)->conn_list, NULL);
+  return CURLE_OK;
+}
+
+static void bundle_destroy(struct connectbundle *bundle)
+{
+  free(bundle);
+}
+
+/* Add a connection to a bundle */
+static void bundle_add_conn(struct connectbundle *bundle,
+                            struct connectdata *conn)
+{
+  Curl_llist_insert_next(&bundle->conn_list, bundle->conn_list.tail, conn,
+                         &conn->bundle_node);
+  conn->bundle = bundle;
+  bundle->num_connections++;
+}
+
+/* Remove a connection from a bundle */
+static int bundle_remove_conn(struct connectbundle *bundle,
+                              struct connectdata *conn)
+{
+  struct Curl_llist_element *curr;
+
+  curr = bundle->conn_list.head;
+  while(curr) {
+    if(curr->ptr == conn) {
+      Curl_llist_remove(&bundle->conn_list, curr, NULL);
+      bundle->num_connections--;
+      conn->bundle = NULL;
+      return 1; /* we removed a handle */
+    }
+    curr = curr->next;
+  }
+  DEBUGASSERT(0);
+  return 0;
+}
+
+static void free_bundle_hash_entry(void *freethis)
+{
+  struct connectbundle *b = (struct connectbundle *) freethis;
+
+  bundle_destroy(b);
+}
+
+int Curl_conncache_init(struct conncache *connc, int size)
+{
+  /* allocate a new easy handle to use when closing cached connections */
+  connc->closure_handle = curl_easy_init();
+  if(!connc->closure_handle)
+    return 1; /* bad */
+  connc->closure_handle->state.internal = true;
+
+  Curl_hash_init(&connc->hash, size, Curl_hash_str,
+                 Curl_str_key_compare, free_bundle_hash_entry);
+  connc->closure_handle->state.conn_cache = connc;
+
+  return 0; /* good */
+}
+
+void Curl_conncache_destroy(struct conncache *connc)
+{
+  if(connc)
+    Curl_hash_destroy(&connc->hash);
+}
+
+/* creates a key to find a bundle for this connection */
+static void hashkey(struct connectdata *conn, char *buf, size_t len)
+{
+  const char *hostname;
+  long port = conn->remote_port;
+  DEBUGASSERT(len >= HASHKEY_SIZE);
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
+    hostname = conn->http_proxy.host.name;
+    port = conn->primary.remote_port;
+  }
+  else
+#endif
+    if(conn->bits.conn_to_host)
+      hostname = conn->conn_to_host.name;
+  else
+    hostname = conn->host.name;
+
+  /* put the numbers first so that the hostname gets cut off if too long */
+#ifdef ENABLE_IPV6
+  msnprintf(buf, len, "%u/%ld/%s", conn->scope_id, port, hostname);
+#else
+  msnprintf(buf, len, "%ld/%s", port, hostname);
+#endif
+  Curl_strntolower(buf, buf, len);
+}
+
+/* Returns number of connections currently held in the connection cache.
+   Locks/unlocks the cache itself!
+*/
+size_t Curl_conncache_size(struct Curl_easy *data)
+{
+  size_t num;
+  CONNCACHE_LOCK(data);
+  num = data->state.conn_cache->num_conn;
+  CONNCACHE_UNLOCK(data);
+  return num;
+}
+
+/* Look up the bundle with all the connections to the same host this
+   connectdata struct is setup to use.
+
+   **NOTE**: When it returns, it holds the connection cache lock! */
+struct connectbundle *
+Curl_conncache_find_bundle(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           struct conncache *connc)
+{
+  struct connectbundle *bundle = NULL;
+  CONNCACHE_LOCK(data);
+  if(connc) {
+    char key[HASHKEY_SIZE];
+    hashkey(conn, key, sizeof(key));
+    bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
+  }
+
+  return bundle;
+}
+
+static void *conncache_add_bundle(struct conncache *connc,
+                                  char *key,
+                                  struct connectbundle *bundle)
+{
+  return Curl_hash_add(&connc->hash, key, strlen(key), bundle);
+}
+
+static void conncache_remove_bundle(struct conncache *connc,
+                                    struct connectbundle *bundle)
+{
+  struct Curl_hash_iterator iter;
+  struct Curl_hash_element *he;
+
+  if(!connc)
+    return;
+
+  Curl_hash_start_iterate(&connc->hash, &iter);
+
+  he = Curl_hash_next_element(&iter);
+  while(he) {
+    if(he->ptr == bundle) {
+      /* The bundle is destroyed by the hash destructor function,
+         free_bundle_hash_entry() */
+      Curl_hash_delete(&connc->hash, he->key, he->key_len);
+      return;
+    }
+
+    he = Curl_hash_next_element(&iter);
+  }
+}
+
+CURLcode Curl_conncache_add_conn(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct connectbundle *bundle = NULL;
+  struct connectdata *conn = data->conn;
+  struct conncache *connc = data->state.conn_cache;
+  DEBUGASSERT(conn);
+
+  /* *find_bundle() locks the connection cache */
+  bundle = Curl_conncache_find_bundle(data, conn, data->state.conn_cache);
+  if(!bundle) {
+    char key[HASHKEY_SIZE];
+
+    result = bundle_create(&bundle);
+    if(result) {
+      goto unlock;
+    }
+
+    hashkey(conn, key, sizeof(key));
+
+    if(!conncache_add_bundle(data->state.conn_cache, key, bundle)) {
+      bundle_destroy(bundle);
+      result = CURLE_OUT_OF_MEMORY;
+      goto unlock;
+    }
+  }
+
+  bundle_add_conn(bundle, conn);
+  conn->connection_id = connc->next_connection_id++;
+  connc->num_conn++;
+
+  DEBUGF(infof(data, "Added connection %" CURL_FORMAT_CURL_OFF_T ". "
+               "The cache now contains %zu members",
+               conn->connection_id, connc->num_conn));
+
+unlock:
+  CONNCACHE_UNLOCK(data);
+
+  return result;
+}
+
+/*
+ * Removes the connectdata object from the connection cache, but the transfer
+ * still owns this connection.
+ *
+ * Pass TRUE/FALSE in the 'lock' argument depending on if the parent function
+ * already holds the lock or not.
+ */
+void Curl_conncache_remove_conn(struct Curl_easy *data,
+                                struct connectdata *conn, bool lock)
+{
+  struct connectbundle *bundle = conn->bundle;
+  struct conncache *connc = data->state.conn_cache;
+
+  /* The bundle pointer can be NULL, since this function can be called
+     due to a failed connection attempt, before being added to a bundle */
+  if(bundle) {
+    if(lock) {
+      CONNCACHE_LOCK(data);
+    }
+    bundle_remove_conn(bundle, conn);
+    if(bundle->num_connections == 0)
+      conncache_remove_bundle(connc, bundle);
+    conn->bundle = NULL; /* removed from it */
+    if(connc) {
+      connc->num_conn--;
+      DEBUGF(infof(data, "The cache now contains %zu members",
+                   connc->num_conn));
+    }
+    if(lock) {
+      CONNCACHE_UNLOCK(data);
+    }
+  }
+}
+
+/* This function iterates the entire connection cache and calls the function
+   func() with the connection pointer as the first argument and the supplied
+   'param' argument as the other.
+
+   The conncache lock is still held when the callback is called. It needs it,
+   so that it can safely continue traversing the lists once the callback
+   returns.
+
+   Returns 1 if the loop was aborted due to the callback's return code.
+
+   Return 0 from func() to continue the loop, return 1 to abort it.
+ */
+bool Curl_conncache_foreach(struct Curl_easy *data,
+                            struct conncache *connc,
+                            void *param,
+                            int (*func)(struct Curl_easy *data,
+                                        struct connectdata *conn, void *param))
+{
+  struct Curl_hash_iterator iter;
+  struct Curl_llist_element *curr;
+  struct Curl_hash_element *he;
+
+  if(!connc)
+    return FALSE;
+
+  CONNCACHE_LOCK(data);
+  Curl_hash_start_iterate(&connc->hash, &iter);
+
+  he = Curl_hash_next_element(&iter);
+  while(he) {
+    struct connectbundle *bundle;
+
+    bundle = he->ptr;
+    he = Curl_hash_next_element(&iter);
+
+    curr = bundle->conn_list.head;
+    while(curr) {
+      /* Yes, we need to update curr before calling func(), because func()
+         might decide to remove the connection */
+      struct connectdata *conn = curr->ptr;
+      curr = curr->next;
+
+      if(1 == func(data, conn, param)) {
+        CONNCACHE_UNLOCK(data);
+        return TRUE;
+      }
+    }
+  }
+  CONNCACHE_UNLOCK(data);
+  return FALSE;
+}
+
+/* Return the first connection found in the cache. Used when closing all
+   connections.
+
+   NOTE: no locking is done here as this is presumably only done when cleaning
+   up a cache!
+*/
+static struct connectdata *
+conncache_find_first_connection(struct conncache *connc)
+{
+  struct Curl_hash_iterator iter;
+  struct Curl_hash_element *he;
+  struct connectbundle *bundle;
+
+  Curl_hash_start_iterate(&connc->hash, &iter);
+
+  he = Curl_hash_next_element(&iter);
+  while(he) {
+    struct Curl_llist_element *curr;
+    bundle = he->ptr;
+
+    curr = bundle->conn_list.head;
+    if(curr) {
+      return curr->ptr;
+    }
+
+    he = Curl_hash_next_element(&iter);
+  }
+
+  return NULL;
+}
+
+/*
+ * Give ownership of a connection back to the connection cache. Might
+ * disconnect the oldest existing in there to make space.
+ *
+ * Return TRUE if stored, FALSE if closed.
+ */
+bool Curl_conncache_return_conn(struct Curl_easy *data,
+                                struct connectdata *conn)
+{
+  unsigned int maxconnects = !data->multi->maxconnects ?
+    data->multi->num_easy * 4: data->multi->maxconnects;
+  struct connectdata *conn_candidate = NULL;
+
+  conn->lastused = Curl_now(); /* it was used up until now */
+  if(maxconnects && Curl_conncache_size(data) > maxconnects) {
+    infof(data, "Connection cache is full, closing the oldest one");
+
+    conn_candidate = Curl_conncache_extract_oldest(data);
+    if(conn_candidate) {
+      /* Use the closure handle for this disconnect so that anything that
+         happens during the disconnect is not stored and associated with the
+         'data' handle which already just finished a transfer and it is
+         important that details from this (unrelated) disconnect does not
+         taint meta-data in the data handle. */
+      struct conncache *connc = data->state.conn_cache;
+      Curl_disconnect(connc->closure_handle, conn_candidate,
+                      /* dead_connection */ FALSE);
+    }
+  }
+
+  return (conn_candidate == conn) ? FALSE : TRUE;
+
+}
+
+/*
+ * This function finds the connection in the connection bundle that has been
+ * unused for the longest time.
+ *
+ * Does not lock the connection cache!
+ *
+ * Returns the pointer to the oldest idle connection, or NULL if none was
+ * found.
+ */
+struct connectdata *
+Curl_conncache_extract_bundle(struct Curl_easy *data,
+                              struct connectbundle *bundle)
+{
+  struct Curl_llist_element *curr;
+  timediff_t highscore = -1;
+  timediff_t score;
+  struct curltime now;
+  struct connectdata *conn_candidate = NULL;
+  struct connectdata *conn;
+
+  (void)data;
+
+  now = Curl_now();
+
+  curr = bundle->conn_list.head;
+  while(curr) {
+    conn = curr->ptr;
+
+    if(!CONN_INUSE(conn)) {
+      /* Set higher score for the age passed since the connection was used */
+      score = Curl_timediff(now, conn->lastused);
+
+      if(score > highscore) {
+        highscore = score;
+        conn_candidate = conn;
+      }
+    }
+    curr = curr->next;
+  }
+  if(conn_candidate) {
+    /* remove it to prevent another thread from nicking it */
+    bundle_remove_conn(bundle, conn_candidate);
+    data->state.conn_cache->num_conn--;
+    DEBUGF(infof(data, "The cache now contains %zu members",
+                 data->state.conn_cache->num_conn));
+  }
+
+  return conn_candidate;
+}
+
+/*
+ * This function finds the connection in the connection cache that has been
+ * unused for the longest time and extracts that from the bundle.
+ *
+ * Returns the pointer to the connection, or NULL if none was found.
+ */
+struct connectdata *
+Curl_conncache_extract_oldest(struct Curl_easy *data)
+{
+  struct conncache *connc = data->state.conn_cache;
+  struct Curl_hash_iterator iter;
+  struct Curl_llist_element *curr;
+  struct Curl_hash_element *he;
+  timediff_t highscore =- 1;
+  timediff_t score;
+  struct curltime now;
+  struct connectdata *conn_candidate = NULL;
+  struct connectbundle *bundle;
+  struct connectbundle *bundle_candidate = NULL;
+
+  now = Curl_now();
+
+  CONNCACHE_LOCK(data);
+  Curl_hash_start_iterate(&connc->hash, &iter);
+
+  he = Curl_hash_next_element(&iter);
+  while(he) {
+    struct connectdata *conn;
+
+    bundle = he->ptr;
+
+    curr = bundle->conn_list.head;
+    while(curr) {
+      conn = curr->ptr;
+
+      if(!CONN_INUSE(conn) && !conn->bits.close &&
+         !conn->connect_only) {
+        /* Set higher score for the age passed since the connection was used */
+        score = Curl_timediff(now, conn->lastused);
+
+        if(score > highscore) {
+          highscore = score;
+          conn_candidate = conn;
+          bundle_candidate = bundle;
+        }
+      }
+      curr = curr->next;
+    }
+
+    he = Curl_hash_next_element(&iter);
+  }
+  if(conn_candidate) {
+    /* remove it to prevent another thread from nicking it */
+    bundle_remove_conn(bundle_candidate, conn_candidate);
+    connc->num_conn--;
+    DEBUGF(infof(data, "The cache now contains %zu members",
+                 connc->num_conn));
+  }
+  CONNCACHE_UNLOCK(data);
+
+  return conn_candidate;
+}
+
+void Curl_conncache_close_all_connections(struct conncache *connc)
+{
+  struct connectdata *conn;
+  SIGPIPE_VARIABLE(pipe_st);
+  if(!connc->closure_handle)
+    return;
+
+  conn = conncache_find_first_connection(connc);
+  while(conn) {
+    sigpipe_ignore(connc->closure_handle, &pipe_st);
+    /* This will remove the connection from the cache */
+    connclose(conn, "kill all");
+    Curl_conncache_remove_conn(connc->closure_handle, conn, TRUE);
+    Curl_disconnect(connc->closure_handle, conn, FALSE);
+    sigpipe_restore(&pipe_st);
+
+    conn = conncache_find_first_connection(connc);
+  }
+
+  sigpipe_ignore(connc->closure_handle, &pipe_st);
+
+  Curl_hostcache_clean(connc->closure_handle,
+                       connc->closure_handle->dns.hostcache);
+  Curl_close(&connc->closure_handle);
+  sigpipe_restore(&pipe_st);
+}
+
+#if 0
+/* Useful for debugging the connection cache */
+void Curl_conncache_print(struct conncache *connc)
+{
+  struct Curl_hash_iterator iter;
+  struct Curl_llist_element *curr;
+  struct Curl_hash_element *he;
+
+  if(!connc)
+    return;
+
+  fprintf(stderr, "=Bundle cache=\n");
+
+  Curl_hash_start_iterate(connc->hash, &iter);
+
+  he = Curl_hash_next_element(&iter);
+  while(he) {
+    struct connectbundle *bundle;
+    struct connectdata *conn;
+
+    bundle = he->ptr;
+
+    fprintf(stderr, "%s -", he->key);
+    curr = bundle->conn_list->head;
+    while(curr) {
+      conn = curr->ptr;
+
+      fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse);
+      curr = curr->next;
+    }
+    fprintf(stderr, "\n");
+
+    he = Curl_hash_next_element(&iter);
+  }
+}
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/conncache.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/conncache.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/conncache.h	(revision 104083)
@@ -0,0 +1,122 @@
+#ifndef HEADER_CURL_CONNCACHE_H
+#define HEADER_CURL_CONNCACHE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Linus Nielsen Feltzing, <linus@haxx.se>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * All accesses to struct fields and changing of data in the connection cache
+ * and connectbundles must be done with the conncache LOCKED. The cache might
+ * be shared.
+ */
+
+#include <curl/curl.h>
+#include "timeval.h"
+
+struct connectdata;
+
+struct conncache {
+  struct Curl_hash hash;
+  size_t num_conn;
+  curl_off_t next_connection_id;
+  curl_off_t next_easy_id;
+  struct curltime last_cleanup;
+  /* handle used for closing cached connections */
+  struct Curl_easy *closure_handle;
+};
+
+#define BUNDLE_NO_MULTIUSE -1
+#define BUNDLE_UNKNOWN     0  /* initial value */
+#define BUNDLE_MULTIPLEX   2
+
+#ifdef CURLDEBUG
+/* the debug versions of these macros make extra certain that the lock is
+   never doubly locked or unlocked */
+#define CONNCACHE_LOCK(x)                                               \
+  do {                                                                  \
+    if((x)->share) {                                                    \
+      Curl_share_lock((x), CURL_LOCK_DATA_CONNECT,                      \
+                      CURL_LOCK_ACCESS_SINGLE);                         \
+      DEBUGASSERT(!(x)->state.conncache_lock);                          \
+      (x)->state.conncache_lock = TRUE;                                 \
+    }                                                                   \
+  } while(0)
+
+#define CONNCACHE_UNLOCK(x)                                             \
+  do {                                                                  \
+    if((x)->share) {                                                    \
+      DEBUGASSERT((x)->state.conncache_lock);                           \
+      (x)->state.conncache_lock = FALSE;                                \
+      Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT);                   \
+    }                                                                   \
+  } while(0)
+#else
+#define CONNCACHE_LOCK(x) if((x)->share)                                \
+    Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE)
+#define CONNCACHE_UNLOCK(x) if((x)->share)              \
+    Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT)
+#endif
+
+struct connectbundle {
+  int multiuse;                 /* supports multi-use */
+  size_t num_connections;       /* Number of connections in the bundle */
+  struct Curl_llist conn_list;  /* The connectdata members of the bundle */
+};
+
+/* returns 1 on error, 0 is fine */
+int Curl_conncache_init(struct conncache *, int size);
+void Curl_conncache_destroy(struct conncache *connc);
+
+/* return the correct bundle, to a host or a proxy */
+struct connectbundle *Curl_conncache_find_bundle(struct Curl_easy *data,
+                                                 struct connectdata *conn,
+                                                 struct conncache *connc);
+/* returns number of connections currently held in the connection cache */
+size_t Curl_conncache_size(struct Curl_easy *data);
+
+bool Curl_conncache_return_conn(struct Curl_easy *data,
+                                struct connectdata *conn);
+CURLcode Curl_conncache_add_conn(struct Curl_easy *data) WARN_UNUSED_RESULT;
+void Curl_conncache_remove_conn(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                bool lock);
+bool Curl_conncache_foreach(struct Curl_easy *data,
+                            struct conncache *connc,
+                            void *param,
+                            int (*func)(struct Curl_easy *data,
+                                        struct connectdata *conn,
+                                        void *param));
+
+struct connectdata *
+Curl_conncache_find_first_connection(struct conncache *connc);
+
+struct connectdata *
+Curl_conncache_extract_bundle(struct Curl_easy *data,
+                              struct connectbundle *bundle);
+struct connectdata *
+Curl_conncache_extract_oldest(struct Curl_easy *data);
+void Curl_conncache_close_all_connections(struct conncache *connc);
+void Curl_conncache_print(struct conncache *connc);
+
+#endif /* HEADER_CURL_CONNCACHE_H */
Index: trunk/src/libs/curl-8.7.1/lib/connect.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/connect.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/connect.c	(revision 104083)
@@ -0,0 +1,1446 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h> /* <netinet/tcp.h> may need it */
+#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h> /* for sockaddr_un */
+#endif
+#ifdef HAVE_LINUX_TCP_H
+#include <linux/tcp.h>
+#elif defined(HAVE_NETINET_TCP_H)
+#include <netinet/tcp.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "if2ip.h"
+#include "strerror.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "cf-haproxy.h"
+#include "cf-https-connect.h"
+#include "cf-socket.h"
+#include "select.h"
+#include "url.h" /* for Curl_safefree() */
+#include "multiif.h"
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "inet_ntop.h"
+#include "inet_pton.h"
+#include "vtls/vtls.h" /* for vtsl cfilters */
+#include "progress.h"
+#include "warnless.h"
+#include "conncache.h"
+#include "multihandle.h"
+#include "share.h"
+#include "version_win32.h"
+#include "vquic/vquic.h" /* for quic cfilters */
+#include "http_proxy.h"
+#include "socks.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+/*
+ * Curl_timeleft() returns the amount of milliseconds left allowed for the
+ * transfer/connection. If the value is 0, there's no timeout (ie there's
+ * infinite time left). If the value is negative, the timeout time has already
+ * elapsed.
+ * @param data the transfer to check on
+ * @param nowp timestamp to use for calculation, NULL to use Curl_now()
+ * @param duringconnect TRUE iff connect timeout is also taken into account.
+ * @unittest: 1303
+ */
+timediff_t Curl_timeleft(struct Curl_easy *data,
+                         struct curltime *nowp,
+                         bool duringconnect)
+{
+  timediff_t timeleft_ms = 0;
+  timediff_t ctimeleft_ms = 0;
+  struct curltime now;
+
+  /* The duration of a connect and the total transfer are calculated from two
+     different time-stamps. It can end up with the total timeout being reached
+     before the connect timeout expires and we must acknowledge whichever
+     timeout that is reached first. The total timeout is set per entire
+     operation, while the connect timeout is set per connect. */
+  if(data->set.timeout <= 0 && !duringconnect)
+    return 0; /* no timeout in place or checked, return "no limit" */
+
+  if(!nowp) {
+    now = Curl_now();
+    nowp = &now;
+  }
+
+  if(data->set.timeout > 0) {
+    timeleft_ms = data->set.timeout -
+                  Curl_timediff(*nowp, data->progress.t_startop);
+    if(!timeleft_ms)
+      timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
+    if(!duringconnect)
+      return timeleft_ms; /* no connect check, this is it */
+  }
+
+  if(duringconnect) {
+    timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ?
+      data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
+    ctimeleft_ms = ctimeout_ms -
+                   Curl_timediff(*nowp, data->progress.t_startsingle);
+    if(!ctimeleft_ms)
+      ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
+    if(!timeleft_ms)
+      return ctimeleft_ms; /* no general timeout, this is it */
+  }
+  /* return minimal time left or max amount already expired */
+  return (ctimeleft_ms < timeleft_ms)? ctimeleft_ms : timeleft_ms;
+}
+
+/* Copies connection info into the transfer handle to make it available when
+   the transfer handle is no longer associated with the connection. */
+void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
+                          struct ip_quadruple *ip)
+{
+  if(ip)
+    data->info.primary = *ip;
+  else {
+    memset(&data->info.primary, 0, sizeof(data->info.primary));
+    data->info.primary.remote_port = -1;
+    data->info.primary.local_port = -1;
+  }
+  data->info.conn_scheme = conn->handler->scheme;
+  /* conn_protocol can only provide "old" protocols */
+  data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
+  data->info.conn_remote_port = conn->remote_port;
+  data->info.used_proxy =
+#ifdef CURL_DISABLE_PROXY
+    0
+#else
+    conn->bits.proxy
+#endif
+    ;
+}
+
+static const struct Curl_addrinfo *
+addr_first_match(const struct Curl_addrinfo *addr, int family)
+{
+  while(addr) {
+    if(addr->ai_family == family)
+      return addr;
+    addr = addr->ai_next;
+  }
+  return NULL;
+}
+
+static const struct Curl_addrinfo *
+addr_next_match(const struct Curl_addrinfo *addr, int family)
+{
+  while(addr && addr->ai_next) {
+    addr = addr->ai_next;
+    if(addr->ai_family == family)
+      return addr;
+  }
+  return NULL;
+}
+
+/* retrieves ip address and port from a sockaddr structure.
+   note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
+bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
+                      char *addr, int *port)
+{
+  struct sockaddr_in *si = NULL;
+#ifdef ENABLE_IPV6
+  struct sockaddr_in6 *si6 = NULL;
+#endif
+#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
+  struct sockaddr_un *su = NULL;
+#else
+  (void)salen;
+#endif
+
+  switch(sa->sa_family) {
+    case AF_INET:
+      si = (struct sockaddr_in *)(void *) sa;
+      if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
+                        addr, MAX_IPADR_LEN)) {
+        unsigned short us_port = ntohs(si->sin_port);
+        *port = us_port;
+        return TRUE;
+      }
+      break;
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+      si6 = (struct sockaddr_in6 *)(void *) sa;
+      if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
+                        addr, MAX_IPADR_LEN)) {
+        unsigned short us_port = ntohs(si6->sin6_port);
+        *port = us_port;
+        return TRUE;
+      }
+      break;
+#endif
+#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
+    case AF_UNIX:
+      if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
+        su = (struct sockaddr_un*)sa;
+        msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
+      }
+      else
+        addr[0] = 0; /* socket with no name */
+      *port = 0;
+      return TRUE;
+#endif
+    default:
+      break;
+  }
+
+  addr[0] = '\0';
+  *port = 0;
+  errno = EAFNOSUPPORT;
+  return FALSE;
+}
+
+struct connfind {
+  curl_off_t id_tofind;
+  struct connectdata *found;
+};
+
+static int conn_is_conn(struct Curl_easy *data,
+                        struct connectdata *conn, void *param)
+{
+  struct connfind *f = (struct connfind *)param;
+  (void)data;
+  if(conn->connection_id == f->id_tofind) {
+    f->found = conn;
+    return 1;
+  }
+  return 0;
+}
+
+/*
+ * Used to extract socket and connectdata struct for the most recent
+ * transfer on the given Curl_easy.
+ *
+ * The returned socket will be CURL_SOCKET_BAD in case of failure!
+ */
+curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
+                                  struct connectdata **connp)
+{
+  DEBUGASSERT(data);
+
+  /* this works for an easy handle:
+   * - that has been used for curl_easy_perform()
+   * - that is associated with a multi handle, and whose connection
+   *   was detached with CURLOPT_CONNECT_ONLY
+   */
+  if((data->state.lastconnect_id != -1) && (data->multi_easy || data->multi)) {
+    struct connectdata *c;
+    struct connfind find;
+    find.id_tofind = data->state.lastconnect_id;
+    find.found = NULL;
+
+    Curl_conncache_foreach(data,
+                           data->share && (data->share->specifier
+                           & (1<< CURL_LOCK_DATA_CONNECT))?
+                           &data->share->conn_cache:
+                           data->multi_easy?
+                           &data->multi_easy->conn_cache:
+                           &data->multi->conn_cache, &find, conn_is_conn);
+
+    if(!find.found) {
+      data->state.lastconnect_id = -1;
+      return CURL_SOCKET_BAD;
+    }
+
+    c = find.found;
+    if(connp)
+      /* only store this if the caller cares for it */
+      *connp = c;
+    return c->sock[FIRSTSOCKET];
+  }
+  return CURL_SOCKET_BAD;
+}
+
+/*
+ * Curl_conncontrol() marks streams or connection for closure.
+ */
+void Curl_conncontrol(struct connectdata *conn,
+                      int ctrl /* see defines in header */
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+                      , const char *reason
+#endif
+  )
+{
+  /* close if a connection, or a stream that isn't multiplexed. */
+  /* This function will be called both before and after this connection is
+     associated with a transfer. */
+  bool closeit, is_multiplex;
+  DEBUGASSERT(conn);
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void)reason; /* useful for debugging */
+#endif
+  is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
+  closeit = (ctrl == CONNCTRL_CONNECTION) ||
+    ((ctrl == CONNCTRL_STREAM) && !is_multiplex);
+  if((ctrl == CONNCTRL_STREAM) && is_multiplex)
+    ;  /* stream signal on multiplex conn never affects close state */
+  else if((bit)closeit != conn->bits.close) {
+    conn->bits.close = closeit; /* the only place in the source code that
+                                   should assign this bit */
+  }
+}
+
+/**
+ * job walking the matching addr infos, creating a sub-cfilter with the
+ * provided method `cf_create` and running setup/connect on it.
+ */
+struct eyeballer {
+  const char *name;
+  const struct Curl_addrinfo *first; /* complete address list, not owned */
+  const struct Curl_addrinfo *addr;  /* List of addresses to try, not owned */
+  int ai_family;                     /* matching address family only */
+  cf_ip_connect_create *cf_create;   /* for creating cf */
+  struct Curl_cfilter *cf;           /* current sub-cfilter connecting */
+  struct eyeballer *primary;         /* eyeballer this one is backup for */
+  timediff_t delay_ms;               /* delay until start */
+  struct curltime started;           /* start of current attempt */
+  timediff_t timeoutms;              /* timeout for current attempt */
+  expire_id timeout_id;              /* ID for Curl_expire() */
+  CURLcode result;
+  int error;
+  BIT(rewinded);                     /* if we rewinded the addr list */
+  BIT(has_started);                  /* attempts have started */
+  BIT(is_done);                      /* out of addresses/time */
+  BIT(connected);                    /* cf has connected */
+  BIT(inconclusive);                 /* connect was not a hard failure, we
+                                      * might talk to a restarting server */
+};
+
+
+typedef enum {
+  SCFST_INIT,
+  SCFST_WAITING,
+  SCFST_DONE
+} cf_connect_state;
+
+struct cf_he_ctx {
+  int transport;
+  cf_ip_connect_create *cf_create;
+  const struct Curl_dns_entry *remotehost;
+  cf_connect_state state;
+  struct eyeballer *baller[2];
+  struct eyeballer *winner;
+  struct curltime started;
+};
+
+/* when there are more than one IP address left to use, this macro returns how
+   much of the given timeout to spend on *this* attempt */
+#define TIMEOUT_LARGE 600
+#define USETIME(ms) ((ms > TIMEOUT_LARGE) ? (ms / 2) : ms)
+
+static CURLcode eyeballer_new(struct eyeballer **pballer,
+                              cf_ip_connect_create *cf_create,
+                              const struct Curl_addrinfo *addr,
+                              int ai_family,
+                              struct eyeballer *primary,
+                              timediff_t delay_ms,
+                              timediff_t timeout_ms,
+                              expire_id timeout_id)
+{
+  struct eyeballer *baller;
+
+  *pballer = NULL;
+  baller = calloc(1, sizeof(*baller));
+  if(!baller)
+    return CURLE_OUT_OF_MEMORY;
+
+  baller->name = ((ai_family == AF_INET)? "ipv4" : (
+#ifdef ENABLE_IPV6
+                  (ai_family == AF_INET6)? "ipv6" :
+#endif
+                  "ip"));
+  baller->cf_create = cf_create;
+  baller->first = baller->addr = addr;
+  baller->ai_family = ai_family;
+  baller->primary = primary;
+  baller->delay_ms = delay_ms;
+  baller->timeoutms = addr_next_match(baller->addr, baller->ai_family)?
+    USETIME(timeout_ms) : timeout_ms;
+  baller->timeout_id = timeout_id;
+  baller->result = CURLE_COULDNT_CONNECT;
+
+  *pballer = baller;
+  return CURLE_OK;
+}
+
+static void baller_close(struct eyeballer *baller,
+                          struct Curl_easy *data)
+{
+  if(baller && baller->cf) {
+    Curl_conn_cf_discard_chain(&baller->cf, data);
+  }
+}
+
+static void baller_free(struct eyeballer *baller,
+                         struct Curl_easy *data)
+{
+  if(baller) {
+    baller_close(baller, data);
+    free(baller);
+  }
+}
+
+static void baller_rewind(struct eyeballer *baller)
+{
+  baller->rewinded = TRUE;
+  baller->addr = baller->first;
+  baller->inconclusive = FALSE;
+}
+
+static void baller_next_addr(struct eyeballer *baller)
+{
+  baller->addr = addr_next_match(baller->addr, baller->ai_family);
+}
+
+/*
+ * Initiate a connect attempt walk.
+ *
+ * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
+ * CURL_SOCKET_BAD. Other errors will however return proper errors.
+ */
+static void baller_initiate(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            struct eyeballer *baller)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+  struct Curl_cfilter *cf_prev = baller->cf;
+  struct Curl_cfilter *wcf;
+  CURLcode result;
+
+
+  /* Don't close a previous cfilter yet to ensure that the next IP's
+     socket gets a different file descriptor, which can prevent bugs when
+     the curl_multi_socket_action interface is used with certain select()
+     replacements such as kqueue. */
+  result = baller->cf_create(&baller->cf, data, cf->conn, baller->addr,
+                             ctx->transport);
+  if(result)
+    goto out;
+
+  /* the new filter might have sub-filters */
+  for(wcf = baller->cf; wcf; wcf = wcf->next) {
+    wcf->conn = cf->conn;
+    wcf->sockindex = cf->sockindex;
+  }
+
+  if(addr_next_match(baller->addr, baller->ai_family)) {
+    Curl_expire(data, baller->timeoutms, baller->timeout_id);
+  }
+
+out:
+  if(result) {
+    CURL_TRC_CF(data, cf, "%s failed", baller->name);
+    baller_close(baller, data);
+  }
+  if(cf_prev)
+    Curl_conn_cf_discard_chain(&cf_prev, data);
+  baller->result = result;
+}
+
+/**
+ * Start a connection attempt on the current baller address.
+ * Will return CURLE_OK on the first address where a socket
+ * could be created and the non-blocking connect started.
+ * Returns error when all remaining addresses have been tried.
+ */
+static CURLcode baller_start(struct Curl_cfilter *cf,
+                             struct Curl_easy *data,
+                             struct eyeballer *baller,
+                             timediff_t timeoutms)
+{
+  baller->error = 0;
+  baller->connected = FALSE;
+  baller->has_started = TRUE;
+
+  while(baller->addr) {
+    baller->started = Curl_now();
+    baller->timeoutms = addr_next_match(baller->addr, baller->ai_family) ?
+      USETIME(timeoutms) : timeoutms;
+    baller_initiate(cf, data, baller);
+    if(!baller->result)
+      break;
+    baller_next_addr(baller);
+  }
+  if(!baller->addr) {
+    baller->is_done = TRUE;
+  }
+  return baller->result;
+}
+
+
+/* Used within the multi interface. Try next IP address, returns error if no
+   more address exists or error */
+static CURLcode baller_start_next(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  struct eyeballer *baller,
+                                  timediff_t timeoutms)
+{
+  if(cf->sockindex == FIRSTSOCKET) {
+    baller_next_addr(baller);
+    /* If we get inconclusive answers from the server(s), we make
+     * a second iteration over the address list */
+    if(!baller->addr && baller->inconclusive && !baller->rewinded)
+      baller_rewind(baller);
+    baller_start(cf, data, baller, timeoutms);
+  }
+  else {
+    baller->error = 0;
+    baller->connected = FALSE;
+    baller->has_started = TRUE;
+    baller->is_done = TRUE;
+    baller->result = CURLE_COULDNT_CONNECT;
+  }
+  return baller->result;
+}
+
+static CURLcode baller_connect(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               struct eyeballer *baller,
+                               struct curltime *now,
+                               bool *connected)
+{
+  (void)cf;
+  *connected = baller->connected;
+  if(!baller->result &&  !*connected) {
+    /* evaluate again */
+    baller->result = Curl_conn_cf_connect(baller->cf, data, 0, connected);
+
+    if(!baller->result) {
+      if(*connected) {
+        baller->connected = TRUE;
+        baller->is_done = TRUE;
+      }
+      else if(Curl_timediff(*now, baller->started) >= baller->timeoutms) {
+        infof(data, "%s connect timeout after %" CURL_FORMAT_TIMEDIFF_T
+              "ms, move on!", baller->name, baller->timeoutms);
+#if defined(ETIMEDOUT)
+        baller->error = ETIMEDOUT;
+#endif
+        baller->result = CURLE_OPERATION_TIMEDOUT;
+      }
+    }
+    else if(baller->result == CURLE_WEIRD_SERVER_REPLY)
+      baller->inconclusive = TRUE;
+  }
+  return baller->result;
+}
+
+/*
+ * is_connected() checks if the socket has connected.
+ */
+static CURLcode is_connected(struct Curl_cfilter *cf,
+                             struct Curl_easy *data,
+                             bool *connected)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+  struct connectdata *conn = cf->conn;
+  CURLcode result;
+  struct curltime now;
+  size_t i;
+  int ongoing, not_started;
+  const char *hostname;
+
+  /* Check if any of the conn->tempsock we use for establishing connections
+   * succeeded and, if so, close any ongoing other ones.
+   * Transfer the successful conn->tempsock to conn->sock[sockindex]
+   * and set conn->tempsock to CURL_SOCKET_BAD.
+   * If transport is QUIC, we need to shutdown the ongoing 'other'
+   * cot ballers in a QUIC appropriate way. */
+evaluate:
+  *connected = FALSE; /* a very negative world view is best */
+  now = Curl_now();
+  ongoing = not_started = 0;
+  for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
+    struct eyeballer *baller = ctx->baller[i];
+
+    if(!baller || baller->is_done)
+      continue;
+
+    if(!baller->has_started) {
+      ++not_started;
+      continue;
+    }
+    baller->result = baller_connect(cf, data, baller, &now, connected);
+    CURL_TRC_CF(data, cf, "%s connect -> %d, connected=%d",
+                baller->name, baller->result, *connected);
+
+    if(!baller->result) {
+      if(*connected) {
+        /* connected, declare the winner */
+        ctx->winner = baller;
+        ctx->baller[i] = NULL;
+        break;
+      }
+      else { /* still waiting */
+        ++ongoing;
+      }
+    }
+    else if(!baller->is_done) {
+      /* The baller failed to connect, start its next attempt */
+      if(baller->error) {
+        data->state.os_errno = baller->error;
+        SET_SOCKERRNO(baller->error);
+      }
+      baller_start_next(cf, data, baller, Curl_timeleft(data, &now, TRUE));
+      if(baller->is_done) {
+        CURL_TRC_CF(data, cf, "%s done", baller->name);
+      }
+      else {
+        /* next attempt was started */
+        CURL_TRC_CF(data, cf, "%s trying next", baller->name);
+        ++ongoing;
+        Curl_expire(data, 0, EXPIRE_RUN_NOW);
+      }
+    }
+  }
+
+  if(ctx->winner) {
+    *connected = TRUE;
+    return CURLE_OK;
+  }
+
+  /* Nothing connected, check the time before we might
+   * start new ballers or return ok. */
+  if((ongoing || not_started) && Curl_timeleft(data, &now, TRUE) < 0) {
+    failf(data, "Connection timeout after %" CURL_FORMAT_CURL_OFF_T " ms",
+          Curl_timediff(now, data->progress.t_startsingle));
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  /* Check if we have any waiting ballers to start now. */
+  if(not_started > 0) {
+    int added = 0;
+
+    for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
+      struct eyeballer *baller = ctx->baller[i];
+
+      if(!baller || baller->has_started)
+        continue;
+      /* We start its primary baller has failed to connect or if
+       * its start delay_ms have expired */
+      if((baller->primary && baller->primary->is_done) ||
+          Curl_timediff(now, ctx->started) >= baller->delay_ms) {
+        baller_start(cf, data, baller, Curl_timeleft(data, &now, TRUE));
+        if(baller->is_done) {
+          CURL_TRC_CF(data, cf, "%s done", baller->name);
+        }
+        else {
+          CURL_TRC_CF(data, cf, "%s starting (timeout=%"
+                      CURL_FORMAT_TIMEDIFF_T "ms)",
+                      baller->name, baller->timeoutms);
+          ++ongoing;
+          ++added;
+        }
+      }
+    }
+    if(added > 0)
+      goto evaluate;
+  }
+
+  if(ongoing > 0) {
+    /* We are still trying, return for more waiting */
+    *connected = FALSE;
+    return CURLE_OK;
+  }
+
+  /* all ballers have failed to connect. */
+  CURL_TRC_CF(data, cf, "all eyeballers failed");
+  result = CURLE_COULDNT_CONNECT;
+  for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
+    struct eyeballer *baller = ctx->baller[i];
+    if(!baller)
+      continue;
+    CURL_TRC_CF(data, cf, "%s assess started=%d, result=%d",
+                baller->name, baller->has_started, baller->result);
+    if(baller->has_started && baller->result) {
+      result = baller->result;
+      break;
+    }
+  }
+
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.socksproxy)
+    hostname = conn->socks_proxy.host.name;
+  else if(conn->bits.httpproxy)
+    hostname = conn->http_proxy.host.name;
+  else
+#endif
+    if(conn->bits.conn_to_host)
+      hostname = conn->conn_to_host.name;
+  else
+    hostname = conn->host.name;
+
+  failf(data, "Failed to connect to %s port %u after "
+        "%" CURL_FORMAT_TIMEDIFF_T " ms: %s",
+        hostname, conn->primary.remote_port,
+        Curl_timediff(now, data->progress.t_startsingle),
+        curl_easy_strerror(result));
+
+#ifdef WSAETIMEDOUT
+  if(WSAETIMEDOUT == data->state.os_errno)
+    result = CURLE_OPERATION_TIMEDOUT;
+#elif defined(ETIMEDOUT)
+  if(ETIMEDOUT == data->state.os_errno)
+    result = CURLE_OPERATION_TIMEDOUT;
+#endif
+
+  return result;
+}
+
+/*
+ * Connect to the given host with timeout, proxy or remote doesn't matter.
+ * There might be more than one IP address to try out.
+ */
+static CURLcode start_connect(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              const struct Curl_dns_entry *remotehost)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+  struct connectdata *conn = cf->conn;
+  CURLcode result = CURLE_COULDNT_CONNECT;
+  int ai_family0, ai_family1;
+  timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+  const struct Curl_addrinfo *addr0, *addr1;
+
+  if(timeout_ms < 0) {
+    /* a precaution, no need to continue if time already is up */
+    failf(data, "Connection time-out");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  ctx->started = Curl_now();
+
+  /* remotehost->addr is the list of addresses from the resolver, each
+   * with an address family. The list has at least one entry, possibly
+   * many more.
+   * We try at most 2 at a time, until we either get a connection or
+   * run out of addresses to try. Since likelihood of success is tied
+   * to the address family (e.g. IPV6 might not work at all ), we want
+   * the 2 connect attempt ballers to try different families, if possible.
+   *
+   */
+  if(conn->ip_version == CURL_IPRESOLVE_WHATEVER) {
+    /* any IP version is allowed */
+    ai_family0 = remotehost->addr?
+      remotehost->addr->ai_family : 0;
+#ifdef ENABLE_IPV6
+    ai_family1 = ai_family0 == AF_INET6 ?
+      AF_INET : AF_INET6;
+#else
+    ai_family1 = AF_UNSPEC;
+#endif
+  }
+  else {
+    /* only one IP version is allowed */
+    ai_family0 = (conn->ip_version == CURL_IPRESOLVE_V4) ?
+      AF_INET :
+#ifdef ENABLE_IPV6
+      AF_INET6;
+#else
+      AF_UNSPEC;
+#endif
+    ai_family1 = AF_UNSPEC;
+  }
+
+  /* Get the first address in the list that matches the family,
+   * this might give NULL, if we do not have any matches. */
+  addr0 = addr_first_match(remotehost->addr, ai_family0);
+  addr1 = addr_first_match(remotehost->addr, ai_family1);
+  if(!addr0 && addr1) {
+    /* switch around, so a single baller always uses addr0 */
+    addr0 = addr1;
+    ai_family0 = ai_family1;
+    addr1 = NULL;
+  }
+
+  /* We found no address that matches our criteria, we cannot connect */
+  if(!addr0) {
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  memset(ctx->baller, 0, sizeof(ctx->baller));
+  result = eyeballer_new(&ctx->baller[0], ctx->cf_create, addr0, ai_family0,
+                          NULL, 0, /* no primary/delay, start now */
+                          timeout_ms,  EXPIRE_DNS_PER_NAME);
+  if(result)
+    return result;
+  CURL_TRC_CF(data, cf, "created %s (timeout %"
+              CURL_FORMAT_TIMEDIFF_T "ms)",
+              ctx->baller[0]->name, ctx->baller[0]->timeoutms);
+  if(addr1) {
+    /* second one gets a delayed start */
+    result = eyeballer_new(&ctx->baller[1], ctx->cf_create, addr1, ai_family1,
+                            ctx->baller[0], /* wait on that to fail */
+                            /* or start this delayed */
+                            data->set.happy_eyeballs_timeout,
+                            timeout_ms,  EXPIRE_DNS_PER_NAME2);
+    if(result)
+      return result;
+    CURL_TRC_CF(data, cf, "created %s (timeout %"
+                CURL_FORMAT_TIMEDIFF_T "ms)",
+                ctx->baller[1]->name, ctx->baller[1]->timeoutms);
+    Curl_expire(data, data->set.happy_eyeballs_timeout,
+                EXPIRE_HAPPY_EYEBALLS);
+  }
+
+  return CURLE_OK;
+}
+
+static void cf_he_ctx_clear(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+  size_t i;
+
+  DEBUGASSERT(ctx);
+  DEBUGASSERT(data);
+  for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
+    baller_free(ctx->baller[i], data);
+    ctx->baller[i] = NULL;
+  }
+  baller_free(ctx->winner, data);
+  ctx->winner = NULL;
+}
+
+static void cf_he_adjust_pollset(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  struct easy_pollset *ps)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+  size_t i;
+
+  if(!cf->connected) {
+    for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
+      struct eyeballer *baller = ctx->baller[i];
+      if(!baller || !baller->cf)
+        continue;
+      Curl_conn_cf_adjust_pollset(baller->cf, data, ps);
+    }
+    CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
+  }
+}
+
+static CURLcode cf_he_connect(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              bool blocking, bool *done)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
+
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  (void)blocking; /* TODO: do we want to support this? */
+  DEBUGASSERT(ctx);
+  *done = FALSE;
+
+  switch(ctx->state) {
+    case SCFST_INIT:
+      DEBUGASSERT(CURL_SOCKET_BAD == Curl_conn_cf_get_socket(cf, data));
+      DEBUGASSERT(!cf->connected);
+      result = start_connect(cf, data, ctx->remotehost);
+      if(result)
+        return result;
+      ctx->state = SCFST_WAITING;
+      FALLTHROUGH();
+    case SCFST_WAITING:
+      result = is_connected(cf, data, done);
+      if(!result && *done) {
+        DEBUGASSERT(ctx->winner);
+        DEBUGASSERT(ctx->winner->cf);
+        DEBUGASSERT(ctx->winner->cf->connected);
+        /* we have a winner. Install and activate it.
+         * close/free all others. */
+        ctx->state = SCFST_DONE;
+        cf->connected = TRUE;
+        cf->next = ctx->winner->cf;
+        ctx->winner->cf = NULL;
+        cf_he_ctx_clear(cf, data);
+        Curl_conn_cf_cntrl(cf->next, data, TRUE,
+                           CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
+
+        if(cf->conn->handler->protocol & PROTO_FAMILY_SSH)
+          Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
+        Curl_verboseconnect(data, cf->conn, cf->sockindex);
+        data->info.numconnects++; /* to track the # of connections made */
+      }
+      break;
+    case SCFST_DONE:
+      *done = TRUE;
+      break;
+  }
+  return result;
+}
+
+static void cf_he_close(struct Curl_cfilter *cf,
+                        struct Curl_easy *data)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+
+  CURL_TRC_CF(data, cf, "close");
+  cf_he_ctx_clear(cf, data);
+  cf->connected = FALSE;
+  ctx->state = SCFST_INIT;
+
+  if(cf->next) {
+    cf->next->cft->do_close(cf->next, data);
+    Curl_conn_cf_discard_chain(&cf->next, data);
+  }
+}
+
+static bool cf_he_data_pending(struct Curl_cfilter *cf,
+                               const struct Curl_easy *data)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+  size_t i;
+
+  if(cf->connected)
+    return cf->next->cft->has_data_pending(cf->next, data);
+
+  for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
+    struct eyeballer *baller = ctx->baller[i];
+    if(!baller || !baller->cf)
+      continue;
+    if(baller->cf->cft->has_data_pending(baller->cf, data))
+      return TRUE;
+  }
+  return FALSE;
+}
+
+static struct curltime get_max_baller_time(struct Curl_cfilter *cf,
+                                          struct Curl_easy *data,
+                                          int query)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+  struct curltime t, tmax;
+  size_t i;
+
+  memset(&tmax, 0, sizeof(tmax));
+  for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
+    struct eyeballer *baller = ctx->baller[i];
+
+    memset(&t, 0, sizeof(t));
+    if(baller && baller->cf &&
+       !baller->cf->cft->query(baller->cf, data, query, NULL, &t)) {
+      if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+        tmax = t;
+    }
+  }
+  return tmax;
+}
+
+static CURLcode cf_he_query(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            int query, int *pres1, void *pres2)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+
+  if(!cf->connected) {
+    switch(query) {
+    case CF_QUERY_CONNECT_REPLY_MS: {
+      int reply_ms = -1;
+      size_t i;
+
+      for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
+        struct eyeballer *baller = ctx->baller[i];
+        int breply_ms;
+
+        if(baller && baller->cf &&
+           !baller->cf->cft->query(baller->cf, data, query,
+                                   &breply_ms, NULL)) {
+          if(breply_ms >= 0 && (reply_ms < 0 || breply_ms < reply_ms))
+            reply_ms = breply_ms;
+        }
+      }
+      *pres1 = reply_ms;
+      CURL_TRC_CF(data, cf, "query connect reply: %dms", *pres1);
+      return CURLE_OK;
+    }
+    case CF_QUERY_TIMER_CONNECT: {
+      struct curltime *when = pres2;
+      *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT);
+      return CURLE_OK;
+    }
+    case CF_QUERY_TIMER_APPCONNECT: {
+      struct curltime *when = pres2;
+      *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT);
+      return CURLE_OK;
+    }
+    default:
+      break;
+    }
+  }
+
+  return cf->next?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
+}
+
+static void cf_he_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+
+  CURL_TRC_CF(data, cf, "destroy");
+  if(ctx) {
+    cf_he_ctx_clear(cf, data);
+  }
+  /* release any resources held in state */
+  Curl_safefree(ctx);
+}
+
+struct Curl_cftype Curl_cft_happy_eyeballs = {
+  "HAPPY-EYEBALLS",
+  0,
+  CURL_LOG_LVL_NONE,
+  cf_he_destroy,
+  cf_he_connect,
+  cf_he_close,
+  Curl_cf_def_get_host,
+  cf_he_adjust_pollset,
+  cf_he_data_pending,
+  Curl_cf_def_send,
+  Curl_cf_def_recv,
+  Curl_cf_def_cntrl,
+  Curl_cf_def_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  cf_he_query,
+};
+
+/**
+ * Create a happy eyeball connection filter that uses the, once resolved,
+ * address information to connect on ip families based on connection
+ * configuration.
+ * @param pcf        output, the created cfilter
+ * @param data       easy handle used in creation
+ * @param conn       connection the filter is created for
+ * @param cf_create  method to create the sub-filters performing the
+ *                   actual connects.
+ */
+static CURLcode
+cf_happy_eyeballs_create(struct Curl_cfilter **pcf,
+                         struct Curl_easy *data,
+                         struct connectdata *conn,
+                         cf_ip_connect_create *cf_create,
+                         const struct Curl_dns_entry *remotehost,
+                         int transport)
+{
+  struct cf_he_ctx *ctx = NULL;
+  CURLcode result;
+
+  (void)data;
+  (void)conn;
+  *pcf = NULL;
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  ctx->transport = transport;
+  ctx->cf_create = cf_create;
+  ctx->remotehost = remotehost;
+
+  result = Curl_cf_create(pcf, &Curl_cft_happy_eyeballs, ctx);
+
+out:
+  if(result) {
+    Curl_safefree(*pcf);
+    Curl_safefree(ctx);
+  }
+  return result;
+}
+
+struct transport_provider {
+  int transport;
+  cf_ip_connect_create *cf_create;
+};
+
+static
+#ifndef DEBUGBUILD
+const
+#endif
+struct transport_provider transport_providers[] = {
+  { TRNSPRT_TCP, Curl_cf_tcp_create },
+#ifdef ENABLE_QUIC
+  { TRNSPRT_QUIC, Curl_cf_quic_create },
+#endif
+#ifndef CURL_DISABLE_TFTP
+  { TRNSPRT_UDP, Curl_cf_udp_create },
+#endif
+#ifdef USE_UNIX_SOCKETS
+  { TRNSPRT_UNIX, Curl_cf_unix_create },
+#endif
+};
+
+static cf_ip_connect_create *get_cf_create(int transport)
+{
+  size_t i;
+  for(i = 0; i < ARRAYSIZE(transport_providers); ++i) {
+    if(transport == transport_providers[i].transport)
+      return transport_providers[i].cf_create;
+  }
+  return NULL;
+}
+
+static CURLcode cf_he_insert_after(struct Curl_cfilter *cf_at,
+                                   struct Curl_easy *data,
+                                   const struct Curl_dns_entry *remotehost,
+                                   int transport)
+{
+  cf_ip_connect_create *cf_create;
+  struct Curl_cfilter *cf;
+  CURLcode result;
+
+  /* Need to be first */
+  DEBUGASSERT(cf_at);
+  cf_create = get_cf_create(transport);
+  if(!cf_create) {
+    CURL_TRC_CF(data, cf_at, "unsupported transport type %d", transport);
+    return CURLE_UNSUPPORTED_PROTOCOL;
+  }
+  result = cf_happy_eyeballs_create(&cf, data, cf_at->conn,
+                                    cf_create, remotehost,
+                                    transport);
+  if(result)
+    return result;
+
+  Curl_conn_cf_insert_after(cf_at, cf);
+  return CURLE_OK;
+}
+
+typedef enum {
+  CF_SETUP_INIT,
+  CF_SETUP_CNNCT_EYEBALLS,
+  CF_SETUP_CNNCT_SOCKS,
+  CF_SETUP_CNNCT_HTTP_PROXY,
+  CF_SETUP_CNNCT_HAPROXY,
+  CF_SETUP_CNNCT_SSL,
+  CF_SETUP_DONE
+} cf_setup_state;
+
+struct cf_setup_ctx {
+  cf_setup_state state;
+  const struct Curl_dns_entry *remotehost;
+  int ssl_mode;
+  int transport;
+};
+
+static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 bool blocking, bool *done)
+{
+  struct cf_setup_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
+
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  /* connect current sub-chain */
+connect_sub_chain:
+  if(cf->next && !cf->next->connected) {
+    result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+    if(result || !*done)
+      return result;
+  }
+
+  if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
+    result = cf_he_insert_after(cf, data, ctx->remotehost, ctx->transport);
+    if(result)
+      return result;
+    ctx->state = CF_SETUP_CNNCT_EYEBALLS;
+    if(!cf->next || !cf->next->connected)
+      goto connect_sub_chain;
+  }
+
+  /* sub-chain connected, do we need to add more? */
+#ifndef CURL_DISABLE_PROXY
+  if(ctx->state < CF_SETUP_CNNCT_SOCKS && cf->conn->bits.socksproxy) {
+    result = Curl_cf_socks_proxy_insert_after(cf, data);
+    if(result)
+      return result;
+    ctx->state = CF_SETUP_CNNCT_SOCKS;
+    if(!cf->next || !cf->next->connected)
+      goto connect_sub_chain;
+  }
+
+  if(ctx->state < CF_SETUP_CNNCT_HTTP_PROXY && cf->conn->bits.httpproxy) {
+#ifdef USE_SSL
+    if(IS_HTTPS_PROXY(cf->conn->http_proxy.proxytype)
+       && !Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
+      result = Curl_cf_ssl_proxy_insert_after(cf, data);
+      if(result)
+        return result;
+    }
+#endif /* USE_SSL */
+
+#if !defined(CURL_DISABLE_HTTP)
+    if(cf->conn->bits.tunnel_proxy) {
+      result = Curl_cf_http_proxy_insert_after(cf, data);
+      if(result)
+        return result;
+    }
+#endif /* !CURL_DISABLE_HTTP */
+    ctx->state = CF_SETUP_CNNCT_HTTP_PROXY;
+    if(!cf->next || !cf->next->connected)
+      goto connect_sub_chain;
+  }
+#endif /* !CURL_DISABLE_PROXY */
+
+  if(ctx->state < CF_SETUP_CNNCT_HAPROXY) {
+#if !defined(CURL_DISABLE_PROXY)
+    if(data->set.haproxyprotocol) {
+      if(Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
+        failf(data, "haproxy protocol not support with SSL "
+              "encryption in place (QUIC?)");
+        return CURLE_UNSUPPORTED_PROTOCOL;
+      }
+      result = Curl_cf_haproxy_insert_after(cf, data);
+      if(result)
+        return result;
+    }
+#endif /* !CURL_DISABLE_PROXY */
+    ctx->state = CF_SETUP_CNNCT_HAPROXY;
+    if(!cf->next || !cf->next->connected)
+      goto connect_sub_chain;
+  }
+
+  if(ctx->state < CF_SETUP_CNNCT_SSL) {
+#ifdef USE_SSL
+    if((ctx->ssl_mode == CURL_CF_SSL_ENABLE
+        || (ctx->ssl_mode != CURL_CF_SSL_DISABLE
+           && cf->conn->handler->flags & PROTOPT_SSL)) /* we want SSL */
+       && !Curl_conn_is_ssl(cf->conn, cf->sockindex)) { /* it is missing */
+      result = Curl_cf_ssl_insert_after(cf, data);
+      if(result)
+        return result;
+    }
+#endif /* USE_SSL */
+    ctx->state = CF_SETUP_CNNCT_SSL;
+    if(!cf->next || !cf->next->connected)
+      goto connect_sub_chain;
+  }
+
+  ctx->state = CF_SETUP_DONE;
+  cf->connected = TRUE;
+  *done = TRUE;
+  return CURLE_OK;
+}
+
+static void cf_setup_close(struct Curl_cfilter *cf,
+                           struct Curl_easy *data)
+{
+  struct cf_setup_ctx *ctx = cf->ctx;
+
+  CURL_TRC_CF(data, cf, "close");
+  cf->connected = FALSE;
+  ctx->state = CF_SETUP_INIT;
+
+  if(cf->next) {
+    cf->next->cft->do_close(cf->next, data);
+    Curl_conn_cf_discard_chain(&cf->next, data);
+  }
+}
+
+static void cf_setup_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_setup_ctx *ctx = cf->ctx;
+
+  (void)data;
+  CURL_TRC_CF(data, cf, "destroy");
+  Curl_safefree(ctx);
+}
+
+
+struct Curl_cftype Curl_cft_setup = {
+  "SETUP",
+  0,
+  CURL_LOG_LVL_NONE,
+  cf_setup_destroy,
+  cf_setup_connect,
+  cf_setup_close,
+  Curl_cf_def_get_host,
+  Curl_cf_def_adjust_pollset,
+  Curl_cf_def_data_pending,
+  Curl_cf_def_send,
+  Curl_cf_def_recv,
+  Curl_cf_def_cntrl,
+  Curl_cf_def_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  Curl_cf_def_query,
+};
+
+static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
+                                struct Curl_easy *data,
+                                const struct Curl_dns_entry *remotehost,
+                                int transport,
+                                int ssl_mode)
+{
+  struct Curl_cfilter *cf = NULL;
+  struct cf_setup_ctx *ctx;
+  CURLcode result = CURLE_OK;
+
+  (void)data;
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  ctx->state = CF_SETUP_INIT;
+  ctx->remotehost = remotehost;
+  ctx->ssl_mode = ssl_mode;
+  ctx->transport = transport;
+
+  result = Curl_cf_create(&cf, &Curl_cft_setup, ctx);
+  if(result)
+    goto out;
+  ctx = NULL;
+
+out:
+  *pcf = result? NULL : cf;
+  free(ctx);
+  return result;
+}
+
+static CURLcode cf_setup_add(struct Curl_easy *data,
+                             struct connectdata *conn,
+                             int sockindex,
+                             const struct Curl_dns_entry *remotehost,
+                             int transport,
+                             int ssl_mode)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(data);
+  result = cf_setup_create(&cf, data, remotehost, transport, ssl_mode);
+  if(result)
+    goto out;
+  Curl_conn_cf_add(data, conn, sockindex, cf);
+out:
+  return result;
+}
+
+#ifdef DEBUGBUILD
+/* used by unit2600.c */
+void Curl_debug_set_transport_provider(int transport,
+                                       cf_ip_connect_create *cf_create)
+{
+  size_t i;
+  for(i = 0; i < ARRAYSIZE(transport_providers); ++i) {
+    if(transport == transport_providers[i].transport) {
+      transport_providers[i].cf_create = cf_create;
+      return;
+    }
+  }
+}
+#endif /* DEBUGBUILD */
+
+CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
+                                    struct Curl_easy *data,
+                                    const struct Curl_dns_entry *remotehost,
+                                    int transport,
+                                    int ssl_mode)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result;
+
+  DEBUGASSERT(data);
+  result = cf_setup_create(&cf, data, remotehost, transport, ssl_mode);
+  if(result)
+    goto out;
+  Curl_conn_cf_insert_after(cf_at, cf);
+out:
+  return result;
+}
+
+CURLcode Curl_conn_setup(struct Curl_easy *data,
+                         struct connectdata *conn,
+                         int sockindex,
+                         const struct Curl_dns_entry *remotehost,
+                         int ssl_mode)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(conn->handler);
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+  if(!conn->cfilter[sockindex] &&
+     conn->handler->protocol == CURLPROTO_HTTPS) {
+    DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
+    result = Curl_cf_https_setup(data, conn, sockindex, remotehost);
+    if(result)
+      goto out;
+  }
+#endif /* !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) */
+
+  /* Still no cfilter set, apply default. */
+  if(!conn->cfilter[sockindex]) {
+    result = cf_setup_add(data, conn, sockindex, remotehost,
+                          conn->transport, ssl_mode);
+    if(result)
+      goto out;
+  }
+
+  DEBUGASSERT(conn->cfilter[sockindex]);
+out:
+  return result;
+}
Index: trunk/src/libs/curl-8.7.1/lib/connect.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/connect.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/connect.h	(revision 104083)
@@ -0,0 +1,133 @@
+#ifndef HEADER_CURL_CONNECT_H
+#define HEADER_CURL_CONNECT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */
+#include "sockaddr.h"
+#include "timeval.h"
+
+struct Curl_dns_entry;
+struct ip_quadruple;
+
+/* generic function that returns how much time there's left to run, according
+   to the timeouts set */
+timediff_t Curl_timeleft(struct Curl_easy *data,
+                         struct curltime *nowp,
+                         bool duringconnect);
+
+#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
+
+/*
+ * Used to extract socket and connectdata struct for the most recent
+ * transfer on the given Curl_easy.
+ *
+ * The returned socket will be CURL_SOCKET_BAD in case of failure!
+ */
+curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
+                                  struct connectdata **connp);
+
+bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
+                      char *addr, int *port);
+
+void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
+                          struct ip_quadruple *ip);
+
+/*
+ * Curl_conncontrol() marks the end of a connection/stream. The 'closeit'
+ * argument specifies if it is the end of a connection or a stream.
+ *
+ * For stream-based protocols (such as HTTP/2), a stream close will not cause
+ * a connection close. Other protocols will close the connection for both
+ * cases.
+ *
+ * It sets the bit.close bit to TRUE (with an explanation for debug builds),
+ * when the connection will close.
+ */
+
+#define CONNCTRL_KEEP 0 /* undo a marked closure */
+#define CONNCTRL_CONNECTION 1
+#define CONNCTRL_STREAM 2
+
+void Curl_conncontrol(struct connectdata *conn,
+                      int closeit
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+                      , const char *reason
+#endif
+  );
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM, y)
+#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y)
+#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP, y)
+#else /* if !DEBUGBUILD || CURL_DISABLE_VERBOSE_STRINGS */
+#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM)
+#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION)
+#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP)
+#endif
+
+/**
+ * Create a cfilter for making an "ip" connection to the
+ * given address, using parameters from `conn`. The "ip" connection
+ * can be a TCP socket, a UDP socket or even a QUIC connection.
+ *
+ * It MUST use only the supplied `ai` for its connection attempt.
+ *
+ * Such a filter may be used in "happy eyeball" scenarios, and its
+ * `connect` implementation needs to support non-blocking. Once connected,
+ * it MAY be installed in the connection filter chain to serve transfers.
+ */
+typedef CURLcode cf_ip_connect_create(struct Curl_cfilter **pcf,
+                                      struct Curl_easy *data,
+                                      struct connectdata *conn,
+                                      const struct Curl_addrinfo *ai,
+                                      int transport);
+
+CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
+                                    struct Curl_easy *data,
+                                    const struct Curl_dns_entry *remotehost,
+                                    int transport,
+                                    int ssl_mode);
+
+/**
+ * Setup the cfilters at `sockindex` in connection `conn`.
+ * If no filter chain is installed yet, inspects the configuration
+ * in `data` and `conn? to install a suitable filter chain.
+ */
+CURLcode Curl_conn_setup(struct Curl_easy *data,
+                         struct connectdata *conn,
+                         int sockindex,
+                         const struct Curl_dns_entry *remotehost,
+                         int ssl_mode);
+
+extern struct Curl_cftype Curl_cft_happy_eyeballs;
+extern struct Curl_cftype Curl_cft_setup;
+
+#ifdef DEBUGBUILD
+void Curl_debug_set_transport_provider(int transport,
+                                       cf_ip_connect_create *cf_create);
+#endif
+
+#endif /* HEADER_CURL_CONNECT_H */
Index: trunk/src/libs/curl-8.7.1/lib/content_encoding.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/content_encoding.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/content_encoding.c	(revision 104083)
@@ -0,0 +1,1052 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include <stddef.h>
+
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+#ifdef HAVE_BROTLI
+#if defined(__GNUC__)
+/* Ignore -Wvla warnings in brotli headers */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wvla"
+#endif
+#include <brotli/decode.h>
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+#endif
+
+#ifdef HAVE_ZSTD
+#include <zstd.h>
+#endif
+
+#include "sendf.h"
+#include "http.h"
+#include "content_encoding.h"
+#include "strdup.h"
+#include "strcase.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define CONTENT_ENCODING_DEFAULT  "identity"
+
+#ifndef CURL_DISABLE_HTTP
+
+/* allow no more than 5 "chained" compression steps */
+#define MAX_ENCODE_STACK 5
+
+#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
+
+
+#ifdef HAVE_LIBZ
+
+/* Comment this out if zlib is always going to be at least ver. 1.2.0.4
+   (doing so will reduce code size slightly). */
+#define OLD_ZLIB_SUPPORT 1
+
+#define GZIP_MAGIC_0 0x1f
+#define GZIP_MAGIC_1 0x8b
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define RESERVED     0xE0 /* bits 5..7: reserved */
+
+typedef enum {
+  ZLIB_UNINIT,               /* uninitialized */
+  ZLIB_INIT,                 /* initialized */
+  ZLIB_INFLATING,            /* inflating started. */
+  ZLIB_EXTERNAL_TRAILER,     /* reading external trailer */
+  ZLIB_GZIP_HEADER,          /* reading gzip header */
+  ZLIB_GZIP_INFLATING,       /* inflating gzip stream */
+  ZLIB_INIT_GZIP             /* initialized in transparent gzip mode */
+} zlibInitState;
+
+/* Deflate and gzip writer. */
+struct zlib_writer {
+  struct Curl_cwriter super;
+  zlibInitState zlib_init;   /* zlib init state */
+  uInt trailerlen;           /* Remaining trailer byte count. */
+  z_stream z;                /* State structure for zlib. */
+};
+
+
+static voidpf
+zalloc_cb(voidpf opaque, unsigned int items, unsigned int size)
+{
+  (void) opaque;
+  /* not a typo, keep it calloc() */
+  return (voidpf) calloc(items, size);
+}
+
+static void
+zfree_cb(voidpf opaque, voidpf ptr)
+{
+  (void) opaque;
+  free(ptr);
+}
+
+static CURLcode
+process_zlib_error(struct Curl_easy *data, z_stream *z)
+{
+  if(z->msg)
+    failf(data, "Error while processing content unencoding: %s",
+          z->msg);
+  else
+    failf(data, "Error while processing content unencoding: "
+          "Unknown failure within decompression software.");
+
+  return CURLE_BAD_CONTENT_ENCODING;
+}
+
+static CURLcode
+exit_zlib(struct Curl_easy *data,
+          z_stream *z, zlibInitState *zlib_init, CURLcode result)
+{
+  if(*zlib_init == ZLIB_GZIP_HEADER)
+    Curl_safefree(z->next_in);
+
+  if(*zlib_init != ZLIB_UNINIT) {
+    if(inflateEnd(z) != Z_OK && result == CURLE_OK)
+      result = process_zlib_error(data, z);
+    *zlib_init = ZLIB_UNINIT;
+  }
+
+  return result;
+}
+
+static CURLcode process_trailer(struct Curl_easy *data,
+                                struct zlib_writer *zp)
+{
+  z_stream *z = &zp->z;
+  CURLcode result = CURLE_OK;
+  uInt len = z->avail_in < zp->trailerlen? z->avail_in: zp->trailerlen;
+
+  /* Consume expected trailer bytes. Terminate stream if exhausted.
+     Issue an error if unexpected bytes follow. */
+
+  zp->trailerlen -= len;
+  z->avail_in -= len;
+  z->next_in += len;
+  if(z->avail_in)
+    result = CURLE_WRITE_ERROR;
+  if(result || !zp->trailerlen)
+    result = exit_zlib(data, z, &zp->zlib_init, result);
+  else {
+    /* Only occurs for gzip with zlib < 1.2.0.4 or raw deflate. */
+    zp->zlib_init = ZLIB_EXTERNAL_TRAILER;
+  }
+  return result;
+}
+
+static CURLcode inflate_stream(struct Curl_easy *data,
+                               struct Curl_cwriter *writer, int type,
+                               zlibInitState started)
+{
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
+  z_stream *z = &zp->z;         /* zlib state structure */
+  uInt nread = z->avail_in;
+  Bytef *orig_in = z->next_in;
+  bool done = FALSE;
+  CURLcode result = CURLE_OK;   /* Curl_client_write status */
+  char *decomp;                 /* Put the decompressed data here. */
+
+  /* Check state. */
+  if(zp->zlib_init != ZLIB_INIT &&
+     zp->zlib_init != ZLIB_INFLATING &&
+     zp->zlib_init != ZLIB_INIT_GZIP &&
+     zp->zlib_init != ZLIB_GZIP_INFLATING)
+    return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
+
+  /* Dynamically allocate a buffer for decompression because it's uncommonly
+     large to hold on the stack */
+  decomp = malloc(DSIZ);
+  if(!decomp)
+    return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
+
+  /* because the buffer size is fixed, iteratively decompress and transfer to
+     the client via next_write function. */
+  while(!done) {
+    int status;                   /* zlib status */
+    done = TRUE;
+
+    /* (re)set buffer for decompressed output for every iteration */
+    z->next_out = (Bytef *) decomp;
+    z->avail_out = DSIZ;
+
+#ifdef Z_BLOCK
+    /* Z_BLOCK is only available in zlib ver. >= 1.2.0.5 */
+    status = inflate(z, Z_BLOCK);
+#else
+    /* fallback for zlib ver. < 1.2.0.5 */
+    status = inflate(z, Z_SYNC_FLUSH);
+#endif
+
+    /* Flush output data if some. */
+    if(z->avail_out != DSIZ) {
+      if(status == Z_OK || status == Z_STREAM_END) {
+        zp->zlib_init = started;      /* Data started. */
+        result = Curl_cwriter_write(data, writer->next, type, decomp,
+                                     DSIZ - z->avail_out);
+        if(result) {
+          exit_zlib(data, z, &zp->zlib_init, result);
+          break;
+        }
+      }
+    }
+
+    /* Dispatch by inflate() status. */
+    switch(status) {
+    case Z_OK:
+      /* Always loop: there may be unflushed latched data in zlib state. */
+      done = FALSE;
+      break;
+    case Z_BUF_ERROR:
+      /* No more data to flush: just exit loop. */
+      break;
+    case Z_STREAM_END:
+      result = process_trailer(data, zp);
+      break;
+    case Z_DATA_ERROR:
+      /* some servers seem to not generate zlib headers, so this is an attempt
+         to fix and continue anyway */
+      if(zp->zlib_init == ZLIB_INIT) {
+        /* Do not use inflateReset2(): only available since zlib 1.2.3.4. */
+        (void) inflateEnd(z);     /* don't care about the return code */
+        if(inflateInit2(z, -MAX_WBITS) == Z_OK) {
+          z->next_in = orig_in;
+          z->avail_in = nread;
+          zp->zlib_init = ZLIB_INFLATING;
+          zp->trailerlen = 4; /* Tolerate up to 4 unknown trailer bytes. */
+          done = FALSE;
+          break;
+        }
+        zp->zlib_init = ZLIB_UNINIT;    /* inflateEnd() already called. */
+      }
+      result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
+      break;
+    default:
+      result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
+      break;
+    }
+  }
+  free(decomp);
+
+  /* We're about to leave this call so the `nread' data bytes won't be seen
+     again. If we are in a state that would wrongly allow restart in raw mode
+     at the next call, assume output has already started. */
+  if(nread && zp->zlib_init == ZLIB_INIT)
+    zp->zlib_init = started;      /* Cannot restart anymore. */
+
+  return result;
+}
+
+
+/* Deflate handler. */
+static CURLcode deflate_do_init(struct Curl_easy *data,
+                                    struct Curl_cwriter *writer)
+{
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
+  z_stream *z = &zp->z;     /* zlib state structure */
+
+  /* Initialize zlib */
+  z->zalloc = (alloc_func) zalloc_cb;
+  z->zfree = (free_func) zfree_cb;
+
+  if(inflateInit(z) != Z_OK)
+    return process_zlib_error(data, z);
+  zp->zlib_init = ZLIB_INIT;
+  return CURLE_OK;
+}
+
+static CURLcode deflate_do_write(struct Curl_easy *data,
+                                       struct Curl_cwriter *writer, int type,
+                                       const char *buf, size_t nbytes)
+{
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
+  z_stream *z = &zp->z;     /* zlib state structure */
+
+  if(!(type & CLIENTWRITE_BODY))
+    return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+
+  /* Set the compressed input when this function is called */
+  z->next_in = (Bytef *) buf;
+  z->avail_in = (uInt) nbytes;
+
+  if(zp->zlib_init == ZLIB_EXTERNAL_TRAILER)
+    return process_trailer(data, zp);
+
+  /* Now uncompress the data */
+  return inflate_stream(data, writer, type, ZLIB_INFLATING);
+}
+
+static void deflate_do_close(struct Curl_easy *data,
+                                 struct Curl_cwriter *writer)
+{
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
+  z_stream *z = &zp->z;     /* zlib state structure */
+
+  exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
+}
+
+static const struct Curl_cwtype deflate_encoding = {
+  "deflate",
+  NULL,
+  deflate_do_init,
+  deflate_do_write,
+  deflate_do_close,
+  sizeof(struct zlib_writer)
+};
+
+
+/* Gzip handler. */
+static CURLcode gzip_do_init(struct Curl_easy *data,
+                                 struct Curl_cwriter *writer)
+{
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
+  z_stream *z = &zp->z;     /* zlib state structure */
+
+  /* Initialize zlib */
+  z->zalloc = (alloc_func) zalloc_cb;
+  z->zfree = (free_func) zfree_cb;
+
+  if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
+    /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
+    if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
+      return process_zlib_error(data, z);
+    }
+    zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
+  }
+  else {
+    /* we must parse the gzip header and trailer ourselves */
+    if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
+      return process_zlib_error(data, z);
+    }
+    zp->trailerlen = 8; /* A CRC-32 and a 32-bit input size (RFC 1952, 2.2) */
+    zp->zlib_init = ZLIB_INIT; /* Initial call state */
+  }
+
+  return CURLE_OK;
+}
+
+#ifdef OLD_ZLIB_SUPPORT
+/* Skip over the gzip header */
+typedef enum {
+  GZIP_OK,
+  GZIP_BAD,
+  GZIP_UNDERFLOW
+} gzip_status;
+
+static gzip_status check_gzip_header(unsigned char const *data, ssize_t len,
+                                     ssize_t *headerlen)
+{
+  int method, flags;
+  const ssize_t totallen = len;
+
+  /* The shortest header is 10 bytes */
+  if(len < 10)
+    return GZIP_UNDERFLOW;
+
+  if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
+    return GZIP_BAD;
+
+  method = data[2];
+  flags = data[3];
+
+  if(method != Z_DEFLATED || (flags & RESERVED) != 0) {
+    /* Can't handle this compression method or unknown flag */
+    return GZIP_BAD;
+  }
+
+  /* Skip over time, xflags, OS code and all previous bytes */
+  len -= 10;
+  data += 10;
+
+  if(flags & EXTRA_FIELD) {
+    ssize_t extra_len;
+
+    if(len < 2)
+      return GZIP_UNDERFLOW;
+
+    extra_len = (data[1] << 8) | data[0];
+
+    if(len < (extra_len + 2))
+      return GZIP_UNDERFLOW;
+
+    len -= (extra_len + 2);
+    data += (extra_len + 2);
+  }
+
+  if(flags & ORIG_NAME) {
+    /* Skip over NUL-terminated file name */
+    while(len && *data) {
+      --len;
+      ++data;
+    }
+    if(!len || *data)
+      return GZIP_UNDERFLOW;
+
+    /* Skip over the NUL */
+    --len;
+    ++data;
+  }
+
+  if(flags & COMMENT) {
+    /* Skip over NUL-terminated comment */
+    while(len && *data) {
+      --len;
+      ++data;
+    }
+    if(!len || *data)
+      return GZIP_UNDERFLOW;
+
+    /* Skip over the NUL */
+    --len;
+  }
+
+  if(flags & HEAD_CRC) {
+    if(len < 2)
+      return GZIP_UNDERFLOW;
+
+    len -= 2;
+  }
+
+  *headerlen = totallen - len;
+  return GZIP_OK;
+}
+#endif
+
+static CURLcode gzip_do_write(struct Curl_easy *data,
+                                    struct Curl_cwriter *writer, int type,
+                                    const char *buf, size_t nbytes)
+{
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
+  z_stream *z = &zp->z;     /* zlib state structure */
+
+  if(!(type & CLIENTWRITE_BODY))
+    return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+
+  if(zp->zlib_init == ZLIB_INIT_GZIP) {
+    /* Let zlib handle the gzip decompression entirely */
+    z->next_in = (Bytef *) buf;
+    z->avail_in = (uInt) nbytes;
+    /* Now uncompress the data */
+    return inflate_stream(data, writer, type, ZLIB_INIT_GZIP);
+  }
+
+#ifndef OLD_ZLIB_SUPPORT
+  /* Support for old zlib versions is compiled away and we are running with
+     an old version, so return an error. */
+  return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
+
+#else
+  /* This next mess is to get around the potential case where there isn't
+   * enough data passed in to skip over the gzip header.  If that happens, we
+   * malloc a block and copy what we have then wait for the next call.  If
+   * there still isn't enough (this is definitely a worst-case scenario), we
+   * make the block bigger, copy the next part in and keep waiting.
+   *
+   * This is only required with zlib versions < 1.2.0.4 as newer versions
+   * can handle the gzip header themselves.
+   */
+
+  switch(zp->zlib_init) {
+  /* Skip over gzip header? */
+  case ZLIB_INIT:
+  {
+    /* Initial call state */
+    ssize_t hlen;
+
+    switch(check_gzip_header((unsigned char *) buf, nbytes, &hlen)) {
+    case GZIP_OK:
+      z->next_in = (Bytef *) buf + hlen;
+      z->avail_in = (uInt) (nbytes - hlen);
+      zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
+      break;
+
+    case GZIP_UNDERFLOW:
+      /* We need more data so we can find the end of the gzip header.  It's
+       * possible that the memory block we malloc here will never be freed if
+       * the transfer abruptly aborts after this point.  Since it's unlikely
+       * that circumstances will be right for this code path to be followed in
+       * the first place, and it's even more unlikely for a transfer to fail
+       * immediately afterwards, it should seldom be a problem.
+       */
+      z->avail_in = (uInt) nbytes;
+      z->next_in = malloc(z->avail_in);
+      if(!z->next_in) {
+        return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
+      }
+      memcpy(z->next_in, buf, z->avail_in);
+      zp->zlib_init = ZLIB_GZIP_HEADER;  /* Need more gzip header data state */
+      /* We don't have any data to inflate yet */
+      return CURLE_OK;
+
+    case GZIP_BAD:
+    default:
+      return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
+    }
+
+  }
+  break;
+
+  case ZLIB_GZIP_HEADER:
+  {
+    /* Need more gzip header data state */
+    ssize_t hlen;
+    z->avail_in += (uInt) nbytes;
+    z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
+    if(!z->next_in) {
+      return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
+    }
+    /* Append the new block of data to the previous one */
+    memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);
+
+    switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) {
+    case GZIP_OK:
+      /* This is the zlib stream data */
+      free(z->next_in);
+      /* Don't point into the malloced block since we just freed it */
+      z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in;
+      z->avail_in = (uInt) (z->avail_in - hlen);
+      zp->zlib_init = ZLIB_GZIP_INFLATING;   /* Inflating stream state */
+      break;
+
+    case GZIP_UNDERFLOW:
+      /* We still don't have any data to inflate! */
+      return CURLE_OK;
+
+    case GZIP_BAD:
+    default:
+      return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
+    }
+
+  }
+  break;
+
+  case ZLIB_EXTERNAL_TRAILER:
+    z->next_in = (Bytef *) buf;
+    z->avail_in = (uInt) nbytes;
+    return process_trailer(data, zp);
+
+  case ZLIB_GZIP_INFLATING:
+  default:
+    /* Inflating stream state */
+    z->next_in = (Bytef *) buf;
+    z->avail_in = (uInt) nbytes;
+    break;
+  }
+
+  if(z->avail_in == 0) {
+    /* We don't have any data to inflate; wait until next time */
+    return CURLE_OK;
+  }
+
+  /* We've parsed the header, now uncompress the data */
+  return inflate_stream(data, writer, type, ZLIB_GZIP_INFLATING);
+#endif
+}
+
+static void gzip_do_close(struct Curl_easy *data,
+                              struct Curl_cwriter *writer)
+{
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
+  z_stream *z = &zp->z;     /* zlib state structure */
+
+  exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
+}
+
+static const struct Curl_cwtype gzip_encoding = {
+  "gzip",
+  "x-gzip",
+  gzip_do_init,
+  gzip_do_write,
+  gzip_do_close,
+  sizeof(struct zlib_writer)
+};
+
+#endif /* HAVE_LIBZ */
+
+
+#ifdef HAVE_BROTLI
+/* Brotli writer. */
+struct brotli_writer {
+  struct Curl_cwriter super;
+  BrotliDecoderState *br;    /* State structure for brotli. */
+};
+
+static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
+{
+  switch(be) {
+  case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:
+  case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:
+  case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:
+  case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:
+  case BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:
+  case BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:
+  case BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:
+  case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:
+  case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:
+  case BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:
+  case BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:
+  case BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:
+  case BROTLI_DECODER_ERROR_FORMAT_PADDING_1:
+  case BROTLI_DECODER_ERROR_FORMAT_PADDING_2:
+#ifdef BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY
+  case BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY:
+#endif
+#ifdef BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET
+  case BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:
+#endif
+  case BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:
+    return CURLE_BAD_CONTENT_ENCODING;
+  case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:
+  case BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:
+  case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:
+  case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:
+  case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:
+  case BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:
+    return CURLE_OUT_OF_MEMORY;
+  default:
+    break;
+  }
+  return CURLE_WRITE_ERROR;
+}
+
+static CURLcode brotli_do_init(struct Curl_easy *data,
+                                   struct Curl_cwriter *writer)
+{
+  struct brotli_writer *bp = (struct brotli_writer *) writer;
+  (void) data;
+
+  bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL);
+  return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY;
+}
+
+static CURLcode brotli_do_write(struct Curl_easy *data,
+                                      struct Curl_cwriter *writer, int type,
+                                      const char *buf, size_t nbytes)
+{
+  struct brotli_writer *bp = (struct brotli_writer *) writer;
+  const uint8_t *src = (const uint8_t *) buf;
+  char *decomp;
+  uint8_t *dst;
+  size_t dstleft;
+  CURLcode result = CURLE_OK;
+  BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
+
+  if(!(type & CLIENTWRITE_BODY))
+    return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+
+  if(!bp->br)
+    return CURLE_WRITE_ERROR;  /* Stream already ended. */
+
+  decomp = malloc(DSIZ);
+  if(!decomp)
+    return CURLE_OUT_OF_MEMORY;
+
+  while((nbytes || r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) &&
+        result == CURLE_OK) {
+    dst = (uint8_t *) decomp;
+    dstleft = DSIZ;
+    r = BrotliDecoderDecompressStream(bp->br,
+                                      &nbytes, &src, &dstleft, &dst, NULL);
+    result = Curl_cwriter_write(data, writer->next, type,
+                                 decomp, DSIZ - dstleft);
+    if(result)
+      break;
+    switch(r) {
+    case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
+    case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
+      break;
+    case BROTLI_DECODER_RESULT_SUCCESS:
+      BrotliDecoderDestroyInstance(bp->br);
+      bp->br = NULL;
+      if(nbytes)
+        result = CURLE_WRITE_ERROR;
+      break;
+    default:
+      result = brotli_map_error(BrotliDecoderGetErrorCode(bp->br));
+      break;
+    }
+  }
+  free(decomp);
+  return result;
+}
+
+static void brotli_do_close(struct Curl_easy *data,
+                                struct Curl_cwriter *writer)
+{
+  struct brotli_writer *bp = (struct brotli_writer *) writer;
+
+  (void) data;
+
+  if(bp->br) {
+    BrotliDecoderDestroyInstance(bp->br);
+    bp->br = NULL;
+  }
+}
+
+static const struct Curl_cwtype brotli_encoding = {
+  "br",
+  NULL,
+  brotli_do_init,
+  brotli_do_write,
+  brotli_do_close,
+  sizeof(struct brotli_writer)
+};
+#endif
+
+
+#ifdef HAVE_ZSTD
+/* Zstd writer. */
+struct zstd_writer {
+  struct Curl_cwriter super;
+  ZSTD_DStream *zds;    /* State structure for zstd. */
+  void *decomp;
+};
+
+static CURLcode zstd_do_init(struct Curl_easy *data,
+                                 struct Curl_cwriter *writer)
+{
+  struct zstd_writer *zp = (struct zstd_writer *) writer;
+
+  (void)data;
+
+  zp->zds = ZSTD_createDStream();
+  zp->decomp = NULL;
+  return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
+}
+
+static CURLcode zstd_do_write(struct Curl_easy *data,
+                                    struct Curl_cwriter *writer, int type,
+                                    const char *buf, size_t nbytes)
+{
+  CURLcode result = CURLE_OK;
+  struct zstd_writer *zp = (struct zstd_writer *) writer;
+  ZSTD_inBuffer in;
+  ZSTD_outBuffer out;
+  size_t errorCode;
+
+  if(!(type & CLIENTWRITE_BODY))
+    return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+
+  if(!zp->decomp) {
+    zp->decomp = malloc(DSIZ);
+    if(!zp->decomp)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  in.pos = 0;
+  in.src = buf;
+  in.size = nbytes;
+
+  for(;;) {
+    out.pos = 0;
+    out.dst = zp->decomp;
+    out.size = DSIZ;
+
+    errorCode = ZSTD_decompressStream(zp->zds, &out, &in);
+    if(ZSTD_isError(errorCode)) {
+      return CURLE_BAD_CONTENT_ENCODING;
+    }
+    if(out.pos > 0) {
+      result = Curl_cwriter_write(data, writer->next, type,
+                                   zp->decomp, out.pos);
+      if(result)
+        break;
+    }
+    if((in.pos == nbytes) && (out.pos < out.size))
+      break;
+  }
+
+  return result;
+}
+
+static void zstd_do_close(struct Curl_easy *data,
+                              struct Curl_cwriter *writer)
+{
+  struct zstd_writer *zp = (struct zstd_writer *) writer;
+
+  (void)data;
+
+  if(zp->decomp) {
+    free(zp->decomp);
+    zp->decomp = NULL;
+  }
+  if(zp->zds) {
+    ZSTD_freeDStream(zp->zds);
+    zp->zds = NULL;
+  }
+}
+
+static const struct Curl_cwtype zstd_encoding = {
+  "zstd",
+  NULL,
+  zstd_do_init,
+  zstd_do_write,
+  zstd_do_close,
+  sizeof(struct zstd_writer)
+};
+#endif
+
+
+/* Identity handler. */
+static const struct Curl_cwtype identity_encoding = {
+  "identity",
+  "none",
+  Curl_cwriter_def_init,
+  Curl_cwriter_def_write,
+  Curl_cwriter_def_close,
+  sizeof(struct Curl_cwriter)
+};
+
+
+/* supported general content decoders. */
+static const struct Curl_cwtype * const general_unencoders[] = {
+  &identity_encoding,
+#ifdef HAVE_LIBZ
+  &deflate_encoding,
+  &gzip_encoding,
+#endif
+#ifdef HAVE_BROTLI
+  &brotli_encoding,
+#endif
+#ifdef HAVE_ZSTD
+  &zstd_encoding,
+#endif
+  NULL
+};
+
+/* supported content decoders only for transfer encodings */
+static const struct Curl_cwtype * const transfer_unencoders[] = {
+#ifndef CURL_DISABLE_HTTP
+  &Curl_httpchunk_unencoder,
+#endif
+  NULL
+};
+
+/* Provide a list of comma-separated names of supported encodings.
+*/
+void Curl_all_content_encodings(char *buf, size_t blen)
+{
+  size_t len = 0;
+  const struct Curl_cwtype * const *cep;
+  const struct Curl_cwtype *ce;
+
+  DEBUGASSERT(buf);
+  DEBUGASSERT(blen);
+  buf[0] = 0;
+
+  for(cep = general_unencoders; *cep; cep++) {
+    ce = *cep;
+    if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT))
+      len += strlen(ce->name) + 2;
+  }
+
+  if(!len) {
+    if(blen >= sizeof(CONTENT_ENCODING_DEFAULT))
+      strcpy(buf, CONTENT_ENCODING_DEFAULT);
+  }
+  else if(blen > len) {
+    char *p = buf;
+    for(cep = general_unencoders; *cep; cep++) {
+      ce = *cep;
+      if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) {
+        strcpy(p, ce->name);
+        p += strlen(p);
+        *p++ = ',';
+        *p++ = ' ';
+      }
+    }
+    p[-2] = '\0';
+  }
+}
+
+/* Deferred error dummy writer. */
+static CURLcode error_do_init(struct Curl_easy *data,
+                                  struct Curl_cwriter *writer)
+{
+  (void)data;
+  (void)writer;
+  return CURLE_OK;
+}
+
+static CURLcode error_do_write(struct Curl_easy *data,
+                                     struct Curl_cwriter *writer, int type,
+                                     const char *buf, size_t nbytes)
+{
+  char all[256];
+  (void)Curl_all_content_encodings(all, sizeof(all));
+
+  (void) writer;
+  (void) buf;
+  (void) nbytes;
+
+  if(!(type & CLIENTWRITE_BODY))
+    return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+
+  failf(data, "Unrecognized content encoding type. "
+        "libcurl understands %s content encodings.", all);
+  return CURLE_BAD_CONTENT_ENCODING;
+}
+
+static void error_do_close(struct Curl_easy *data,
+                               struct Curl_cwriter *writer)
+{
+  (void) data;
+  (void) writer;
+}
+
+static const struct Curl_cwtype error_writer = {
+  "ce-error",
+  NULL,
+  error_do_init,
+  error_do_write,
+  error_do_close,
+  sizeof(struct Curl_cwriter)
+};
+
+/* Find the content encoding by name. */
+static const struct Curl_cwtype *find_unencode_writer(const char *name,
+                                                      size_t len,
+                                                      Curl_cwriter_phase phase)
+{
+  const struct Curl_cwtype * const *cep;
+
+  if(phase == CURL_CW_TRANSFER_DECODE) {
+    for(cep = transfer_unencoders; *cep; cep++) {
+      const struct Curl_cwtype *ce = *cep;
+      if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
+         (ce->alias && strncasecompare(name, ce->alias, len)
+                    && !ce->alias[len]))
+        return ce;
+    }
+  }
+  /* look among the general decoders */
+  for(cep = general_unencoders; *cep; cep++) {
+    const struct Curl_cwtype *ce = *cep;
+    if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
+       (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
+      return ce;
+  }
+  return NULL;
+}
+
+/* Set-up the unencoding stack from the Content-Encoding header value.
+ * See RFC 7231 section 3.1.2.2. */
+CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
+                                     const char *enclist, int is_transfer)
+{
+  Curl_cwriter_phase phase = is_transfer?
+                             CURL_CW_TRANSFER_DECODE:CURL_CW_CONTENT_DECODE;
+  CURLcode result;
+
+  do {
+    const char *name;
+    size_t namelen;
+
+    /* Parse a single encoding name. */
+    while(ISBLANK(*enclist) || *enclist == ',')
+      enclist++;
+
+    name = enclist;
+
+    for(namelen = 0; *enclist && *enclist != ','; enclist++)
+      if(!ISSPACE(*enclist))
+        namelen = enclist - name + 1;
+
+    if(namelen) {
+      const struct Curl_cwtype *cwt;
+      struct Curl_cwriter *writer;
+
+      /* if we skip the decoding in this phase, do not look further.
+       * Exception is "chunked" transfer-encoding which always must happen */
+      if((is_transfer && !data->set.http_transfer_encoding &&
+          (namelen != 7 || !strncasecompare(name, "chunked", 7))) ||
+         (!is_transfer && data->set.http_ce_skip)) {
+        /* not requested, ignore */
+        return CURLE_OK;
+      }
+
+      if(Curl_cwriter_count(data, phase) + 1 >= MAX_ENCODE_STACK) {
+        failf(data, "Reject response due to more than %u content encodings",
+              MAX_ENCODE_STACK);
+        return CURLE_BAD_CONTENT_ENCODING;
+      }
+
+      cwt = find_unencode_writer(name, namelen, phase);
+      if(!cwt)
+        cwt = &error_writer;  /* Defer error at use. */
+
+      result = Curl_cwriter_create(&writer, data, cwt, phase);
+      if(result)
+        return result;
+
+      result = Curl_cwriter_add(data, writer);
+      if(result) {
+        Curl_cwriter_free(data, writer);
+        return result;
+      }
+    }
+  } while(*enclist);
+
+  return CURLE_OK;
+}
+
+#else
+/* Stubs for builds without HTTP. */
+CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
+                                     const char *enclist, int is_transfer)
+{
+  (void) data;
+  (void) enclist;
+  (void) is_transfer;
+  return CURLE_NOT_BUILT_IN;
+}
+
+void Curl_all_content_encodings(char *buf, size_t blen)
+{
+  DEBUGASSERT(buf);
+  DEBUGASSERT(blen);
+  if(blen < sizeof(CONTENT_ENCODING_DEFAULT))
+    buf[0] = 0;
+  else
+    strcpy(buf, CONTENT_ENCODING_DEFAULT);
+}
+
+
+#endif /* CURL_DISABLE_HTTP */
Index: trunk/src/libs/curl-8.7.1/lib/content_encoding.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/content_encoding.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/content_encoding.h	(revision 104083)
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_CONTENT_ENCODING_H
+#define HEADER_CURL_CONTENT_ENCODING_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+struct Curl_cwriter;
+
+void Curl_all_content_encodings(char *buf, size_t blen);
+
+CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
+                                     const char *enclist, int is_transfer);
+#endif /* HEADER_CURL_CONTENT_ENCODING_H */
Index: trunk/src/libs/curl-8.7.1/lib/cookie.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cookie.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cookie.c	(revision 104083)
@@ -0,0 +1,1770 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/***
+
+
+RECEIVING COOKIE INFORMATION
+============================
+
+struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+                    const char *file, struct CookieInfo *inc, bool newsession);
+
+        Inits a cookie struct to store data in a local file. This is always
+        called before any cookies are set.
+
+struct Cookie *Curl_cookie_add(struct Curl_easy *data,
+                 struct CookieInfo *c, bool httpheader, bool noexpire,
+                 char *lineptr, const char *domain, const char *path,
+                 bool secure);
+
+        The 'lineptr' parameter is a full "Set-cookie:" line as
+        received from a server.
+
+        The function need to replace previously stored lines that this new
+        line supersedes.
+
+        It may remove lines that are expired.
+
+        It should return an indication of success/error.
+
+
+SENDING COOKIE INFORMATION
+==========================
+
+struct Cookies *Curl_cookie_getlist(struct CookieInfo *cookie,
+                                    char *host, char *path, bool secure);
+
+        For a given host and path, return a linked list of cookies that
+        the client should send to the server if used now. The secure
+        boolean informs the cookie if a secure connection is achieved or
+        not.
+
+        It shall only return cookies that haven't expired.
+
+
+Example set of cookies:
+
+    Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
+    Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+    domain=.fidelity.com; path=/ftgw; secure
+    Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+    domain=.fidelity.com; path=/; secure
+    Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+    domain=.fidelity.com; path=/; secure
+    Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+    domain=.fidelity.com; path=/; secure
+    Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+    domain=.fidelity.com; path=/; secure
+    Set-cookie:
+    Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday,
+    13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
+****/
+
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+
+#include "urldata.h"
+#include "cookie.h"
+#include "psl.h"
+#include "strtok.h"
+#include "sendf.h"
+#include "slist.h"
+#include "share.h"
+#include "strtoofft.h"
+#include "strcase.h"
+#include "curl_get_line.h"
+#include "curl_memrchr.h"
+#include "parsedate.h"
+#include "rename.h"
+#include "fopen.h"
+#include "strdup.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+static void strstore(char **str, const char *newstr, size_t len);
+
+static void freecookie(struct Cookie *co)
+{
+  free(co->domain);
+  free(co->path);
+  free(co->spath);
+  free(co->name);
+  free(co->value);
+  free(co);
+}
+
+static bool cookie_tailmatch(const char *cookie_domain,
+                             size_t cookie_domain_len,
+                             const char *hostname)
+{
+  size_t hostname_len = strlen(hostname);
+
+  if(hostname_len < cookie_domain_len)
+    return FALSE;
+
+  if(!strncasecompare(cookie_domain,
+                      hostname + hostname_len-cookie_domain_len,
+                      cookie_domain_len))
+    return FALSE;
+
+  /*
+   * A lead char of cookie_domain is not '.'.
+   * RFC6265 4.1.2.3. The Domain Attribute says:
+   * For example, if the value of the Domain attribute is
+   * "example.com", the user agent will include the cookie in the Cookie
+   * header when making HTTP requests to example.com, www.example.com, and
+   * www.corp.example.com.
+   */
+  if(hostname_len == cookie_domain_len)
+    return TRUE;
+  if('.' == *(hostname + hostname_len - cookie_domain_len - 1))
+    return TRUE;
+  return FALSE;
+}
+
+/*
+ * matching cookie path and url path
+ * RFC6265 5.1.4 Paths and Path-Match
+ */
+static bool pathmatch(const char *cookie_path, const char *request_uri)
+{
+  size_t cookie_path_len;
+  size_t uri_path_len;
+  char *uri_path = NULL;
+  char *pos;
+  bool ret = FALSE;
+
+  /* cookie_path must not have last '/' separator. ex: /sample */
+  cookie_path_len = strlen(cookie_path);
+  if(1 == cookie_path_len) {
+    /* cookie_path must be '/' */
+    return TRUE;
+  }
+
+  uri_path = strdup(request_uri);
+  if(!uri_path)
+    return FALSE;
+  pos = strchr(uri_path, '?');
+  if(pos)
+    *pos = 0x0;
+
+  /* #-fragments are already cut off! */
+  if(0 == strlen(uri_path) || uri_path[0] != '/') {
+    strstore(&uri_path, "/", 1);
+    if(!uri_path)
+      return FALSE;
+  }
+
+  /*
+   * here, RFC6265 5.1.4 says
+   *  4. Output the characters of the uri-path from the first character up
+   *     to, but not including, the right-most %x2F ("/").
+   *  but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site
+   *  without redirect.
+   *  Ignore this algorithm because /hoge is uri path for this case
+   *  (uri path is not /).
+   */
+
+  uri_path_len = strlen(uri_path);
+
+  if(uri_path_len < cookie_path_len) {
+    ret = FALSE;
+    goto pathmatched;
+  }
+
+  /* not using checkprefix() because matching should be case-sensitive */
+  if(strncmp(cookie_path, uri_path, cookie_path_len)) {
+    ret = FALSE;
+    goto pathmatched;
+  }
+
+  /* The cookie-path and the uri-path are identical. */
+  if(cookie_path_len == uri_path_len) {
+    ret = TRUE;
+    goto pathmatched;
+  }
+
+  /* here, cookie_path_len < uri_path_len */
+  if(uri_path[cookie_path_len] == '/') {
+    ret = TRUE;
+    goto pathmatched;
+  }
+
+  ret = FALSE;
+
+pathmatched:
+  free(uri_path);
+  return ret;
+}
+
+/*
+ * Return the top-level domain, for optimal hashing.
+ */
+static const char *get_top_domain(const char * const domain, size_t *outlen)
+{
+  size_t len = 0;
+  const char *first = NULL, *last;
+
+  if(domain) {
+    len = strlen(domain);
+    last = memrchr(domain, '.', len);
+    if(last) {
+      first = memrchr(domain, '.', (last - domain));
+      if(first)
+        len -= (++first - domain);
+    }
+  }
+
+  if(outlen)
+    *outlen = len;
+
+  return first? first: domain;
+}
+
+/* Avoid C1001, an "internal error" with MSVC14 */
+#if defined(_MSC_VER) && (_MSC_VER == 1900)
+#pragma optimize("", off)
+#endif
+
+/*
+ * A case-insensitive hash for the cookie domains.
+ */
+static size_t cookie_hash_domain(const char *domain, const size_t len)
+{
+  const char *end = domain + len;
+  size_t h = 5381;
+
+  while(domain < end) {
+    h += h << 5;
+    h ^= Curl_raw_toupper(*domain++);
+  }
+
+  return (h % COOKIE_HASH_SIZE);
+}
+
+#if defined(_MSC_VER) && (_MSC_VER == 1900)
+#pragma optimize("", on)
+#endif
+
+/*
+ * Hash this domain.
+ */
+static size_t cookiehash(const char * const domain)
+{
+  const char *top;
+  size_t len;
+
+  if(!domain || Curl_host_is_ipnum(domain))
+    return 0;
+
+  top = get_top_domain(domain, &len);
+  return cookie_hash_domain(top, len);
+}
+
+/*
+ * cookie path sanitize
+ */
+static char *sanitize_cookie_path(const char *cookie_path)
+{
+  size_t len;
+  char *new_path = strdup(cookie_path);
+  if(!new_path)
+    return NULL;
+
+  /* some stupid site sends path attribute with '"'. */
+  len = strlen(new_path);
+  if(new_path[0] == '\"') {
+    memmove(new_path, new_path + 1, len);
+    len--;
+  }
+  if(len && (new_path[len - 1] == '\"')) {
+    new_path[--len] = 0x0;
+  }
+
+  /* RFC6265 5.2.4 The Path Attribute */
+  if(new_path[0] != '/') {
+    /* Let cookie-path be the default-path. */
+    strstore(&new_path, "/", 1);
+    return new_path;
+  }
+
+  /* convert /hoge/ to /hoge */
+  if(len && new_path[len - 1] == '/') {
+    new_path[len - 1] = 0x0;
+  }
+
+  return new_path;
+}
+
+/*
+ * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
+ *
+ * NOTE: OOM or cookie parsing failures are ignored.
+ */
+void Curl_cookie_loadfiles(struct Curl_easy *data)
+{
+  struct curl_slist *list = data->state.cookielist;
+  if(list) {
+    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+    while(list) {
+      struct CookieInfo *newcookies =
+        Curl_cookie_init(data, list->data, data->cookies,
+                         data->set.cookiesession);
+      if(!newcookies)
+        /*
+         * Failure may be due to OOM or a bad cookie; both are ignored
+         * but only the first should be
+         */
+        infof(data, "ignoring failed cookie_init for %s", list->data);
+      else
+        data->cookies = newcookies;
+      list = list->next;
+    }
+    Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+  }
+}
+
+/*
+ * strstore
+ *
+ * A thin wrapper around strdup which ensures that any memory allocated at
+ * *str will be freed before the string allocated by strdup is stored there.
+ * The intended usecase is repeated assignments to the same variable during
+ * parsing in a last-wins scenario. The caller is responsible for checking
+ * for OOM errors.
+ */
+static void strstore(char **str, const char *newstr, size_t len)
+{
+  DEBUGASSERT(newstr);
+  DEBUGASSERT(str);
+  free(*str);
+  *str = Curl_memdup0(newstr, len);
+}
+
+/*
+ * remove_expired
+ *
+ * Remove expired cookies from the hash by inspecting the expires timestamp on
+ * each cookie in the hash, freeing and deleting any where the timestamp is in
+ * the past.  If the cookiejar has recorded the next timestamp at which one or
+ * more cookies expire, then processing will exit early in case this timestamp
+ * is in the future.
+ */
+static void remove_expired(struct CookieInfo *cookies)
+{
+  struct Cookie *co, *nx;
+  curl_off_t now = (curl_off_t)time(NULL);
+  unsigned int i;
+
+  /*
+   * If the earliest expiration timestamp in the jar is in the future we can
+   * skip scanning the whole jar and instead exit early as there won't be any
+   * cookies to evict.  If we need to evict however, reset the next_expiration
+   * counter in order to track the next one. In case the recorded first
+   * expiration is the max offset, then perform the safe fallback of checking
+   * all cookies.
+   */
+  if(now < cookies->next_expiration &&
+      cookies->next_expiration != CURL_OFF_T_MAX)
+    return;
+  else
+    cookies->next_expiration = CURL_OFF_T_MAX;
+
+  for(i = 0; i < COOKIE_HASH_SIZE; i++) {
+    struct Cookie *pv = NULL;
+    co = cookies->cookies[i];
+    while(co) {
+      nx = co->next;
+      if(co->expires && co->expires < now) {
+        if(!pv) {
+          cookies->cookies[i] = co->next;
+        }
+        else {
+          pv->next = co->next;
+        }
+        cookies->numcookies--;
+        freecookie(co);
+      }
+      else {
+        /*
+         * If this cookie has an expiration timestamp earlier than what we've
+         * seen so far then record it for the next round of expirations.
+         */
+        if(co->expires && co->expires < cookies->next_expiration)
+          cookies->next_expiration = co->expires;
+        pv = co;
+      }
+      co = nx;
+    }
+  }
+}
+
+#ifndef USE_LIBPSL
+/* Make sure domain contains a dot or is localhost. */
+static bool bad_domain(const char *domain, size_t len)
+{
+  if((len == 9) && strncasecompare(domain, "localhost", 9))
+    return FALSE;
+  else {
+    /* there must be a dot present, but that dot must not be a trailing dot */
+    char *dot = memchr(domain, '.', len);
+    if(dot) {
+      size_t i = dot - domain;
+      if((len - i) > 1)
+        /* the dot is not the last byte */
+        return FALSE;
+    }
+  }
+  return TRUE;
+}
+#endif
+
+/*
+  RFC 6265 section 4.1.1 says a server should accept this range:
+
+  cookie-octet    = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
+
+  But Firefox and Chrome as of June 2022 accept space, comma and double-quotes
+  fine. The prime reason for filtering out control bytes is that some HTTP
+  servers return 400 for requests that contain such.
+*/
+static int invalid_octets(const char *p)
+{
+  /* Reject all bytes \x01 - \x1f (*except* \x09, TAB) + \x7f */
+  static const char badoctets[] = {
+    "\x01\x02\x03\x04\x05\x06\x07\x08\x0a"
+    "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
+    "\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f"
+  };
+  size_t len;
+  /* scan for all the octets that are *not* in cookie-octet */
+  len = strcspn(p, badoctets);
+  return (p[len] != '\0');
+}
+
+/*
+ * Curl_cookie_add
+ *
+ * Add a single cookie line to the cookie keeping object. Be aware that
+ * sometimes we get an IP-only host name, and that might also be a numerical
+ * IPv6 address.
+ *
+ * Returns NULL on out of memory or invalid cookie. This is suboptimal,
+ * as they should be treated separately.
+ */
+struct Cookie *
+Curl_cookie_add(struct Curl_easy *data,
+                struct CookieInfo *c,
+                bool httpheader, /* TRUE if HTTP header-style line */
+                bool noexpire, /* if TRUE, skip remove_expired() */
+                const char *lineptr,   /* first character of the line */
+                const char *domain, /* default domain */
+                const char *path,   /* full path used when this cookie is set,
+                                       used to get default path for the cookie
+                                       unless set */
+                bool secure)  /* TRUE if connection is over secure origin */
+{
+  struct Cookie *clist;
+  struct Cookie *co;
+  struct Cookie *lastc = NULL;
+  struct Cookie *replace_co = NULL;
+  struct Cookie *replace_clist = NULL;
+  time_t now = time(NULL);
+  bool replace_old = FALSE;
+  bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
+  size_t myhash;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(MAX_SET_COOKIE_AMOUNT <= 255); /* counter is an unsigned char */
+  if(data->req.setcookies >= MAX_SET_COOKIE_AMOUNT)
+    return NULL;
+
+  /* First, alloc and init a new struct for it */
+  co = calloc(1, sizeof(struct Cookie));
+  if(!co)
+    return NULL; /* bail out if we're this low on memory */
+
+  if(httpheader) {
+    /* This line was read off an HTTP-header */
+    const char *ptr;
+
+    size_t linelength = strlen(lineptr);
+    if(linelength > MAX_COOKIE_LINE) {
+      /* discard overly long lines at once */
+      free(co);
+      return NULL;
+    }
+
+    ptr = lineptr;
+    do {
+      size_t vlen;
+      size_t nlen;
+
+      while(*ptr && ISBLANK(*ptr))
+        ptr++;
+
+      /* we have a <name>=<value> pair or a stand-alone word here */
+      nlen = strcspn(ptr, ";\t\r\n=");
+      if(nlen) {
+        bool done = FALSE;
+        bool sep = FALSE;
+        const char *namep = ptr;
+        const char *valuep;
+
+        ptr += nlen;
+
+        /* trim trailing spaces and tabs after name */
+        while(nlen && ISBLANK(namep[nlen - 1]))
+          nlen--;
+
+        if(*ptr == '=') {
+          vlen = strcspn(++ptr, ";\r\n");
+          valuep = ptr;
+          sep = TRUE;
+          ptr = &valuep[vlen];
+
+          /* Strip off trailing whitespace from the value */
+          while(vlen && ISBLANK(valuep[vlen-1]))
+            vlen--;
+
+          /* Skip leading whitespace from the value */
+          while(vlen && ISBLANK(*valuep)) {
+            valuep++;
+            vlen--;
+          }
+
+          /* Reject cookies with a TAB inside the value */
+          if(memchr(valuep, '\t', vlen)) {
+            freecookie(co);
+            infof(data, "cookie contains TAB, dropping");
+            return NULL;
+          }
+        }
+        else {
+          valuep = NULL;
+          vlen = 0;
+        }
+
+        /*
+         * Check for too long individual name or contents, or too long
+         * combination of name + contents. Chrome and Firefox support 4095 or
+         * 4096 bytes combo
+         */
+        if(nlen >= (MAX_NAME-1) || vlen >= (MAX_NAME-1) ||
+           ((nlen + vlen) > MAX_NAME)) {
+          freecookie(co);
+          infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
+                nlen, vlen);
+          return NULL;
+        }
+
+        /*
+         * Check if we have a reserved prefix set before anything else, as we
+         * otherwise have to test for the prefix in both the cookie name and
+         * "the rest". Prefixes must start with '__' and end with a '-', so
+         * only test for names where that can possibly be true.
+         */
+        if(nlen >= 7 && namep[0] == '_' && namep[1] == '_') {
+          if(strncasecompare("__Secure-", namep, 9))
+            co->prefix |= COOKIE_PREFIX__SECURE;
+          else if(strncasecompare("__Host-", namep, 7))
+            co->prefix |= COOKIE_PREFIX__HOST;
+        }
+
+        /*
+         * Use strstore() below to properly deal with received cookie
+         * headers that have the same string property set more than once,
+         * and then we use the last one.
+         */
+
+        if(!co->name) {
+          /* The very first name/value pair is the actual cookie name */
+          if(!sep) {
+            /* Bad name/value pair. */
+            badcookie = TRUE;
+            break;
+          }
+          strstore(&co->name, namep, nlen);
+          strstore(&co->value, valuep, vlen);
+          done = TRUE;
+          if(!co->name || !co->value) {
+            badcookie = TRUE;
+            break;
+          }
+          if(invalid_octets(co->value) || invalid_octets(co->name)) {
+            infof(data, "invalid octets in name/value, cookie dropped");
+            badcookie = TRUE;
+            break;
+          }
+        }
+        else if(!vlen) {
+          /*
+           * this was a "<name>=" with no content, and we must allow
+           * 'secure' and 'httponly' specified this weirdly
+           */
+          done = TRUE;
+          /*
+           * secure cookies are only allowed to be set when the connection is
+           * using a secure protocol, or when the cookie is being set by
+           * reading from file
+           */
+          if((nlen == 6) && strncasecompare("secure", namep, 6)) {
+            if(secure || !c->running) {
+              co->secure = TRUE;
+            }
+            else {
+              badcookie = TRUE;
+              break;
+            }
+          }
+          else if((nlen == 8) && strncasecompare("httponly", namep, 8))
+            co->httponly = TRUE;
+          else if(sep)
+            /* there was a '=' so we're not done parsing this field */
+            done = FALSE;
+        }
+        if(done)
+          ;
+        else if((nlen == 4) && strncasecompare("path", namep, 4)) {
+          strstore(&co->path, valuep, vlen);
+          if(!co->path) {
+            badcookie = TRUE; /* out of memory bad */
+            break;
+          }
+          free(co->spath); /* if this is set again */
+          co->spath = sanitize_cookie_path(co->path);
+          if(!co->spath) {
+            badcookie = TRUE; /* out of memory bad */
+            break;
+          }
+        }
+        else if((nlen == 6) &&
+                strncasecompare("domain", namep, 6) && vlen) {
+          bool is_ip;
+
+          /*
+           * Now, we make sure that our host is within the given domain, or
+           * the given domain is not valid and thus cannot be set.
+           */
+
+          if('.' == valuep[0]) {
+            valuep++; /* ignore preceding dot */
+            vlen--;
+          }
+
+#ifndef USE_LIBPSL
+          /*
+           * Without PSL we don't know when the incoming cookie is set on a
+           * TLD or otherwise "protected" suffix. To reduce risk, we require a
+           * dot OR the exact host name being "localhost".
+           */
+          if(bad_domain(valuep, vlen))
+            domain = ":";
+#endif
+
+          is_ip = Curl_host_is_ipnum(domain ? domain : valuep);
+
+          if(!domain
+             || (is_ip && !strncmp(valuep, domain, vlen) &&
+                 (vlen == strlen(domain)))
+             || (!is_ip && cookie_tailmatch(valuep, vlen, domain))) {
+            strstore(&co->domain, valuep, vlen);
+            if(!co->domain) {
+              badcookie = TRUE;
+              break;
+            }
+            if(!is_ip)
+              co->tailmatch = TRUE; /* we always do that if the domain name was
+                                       given */
+          }
+          else {
+            /*
+             * We did not get a tailmatch and then the attempted set domain is
+             * not a domain to which the current host belongs. Mark as bad.
+             */
+            badcookie = TRUE;
+            infof(data, "skipped cookie with bad tailmatch domain: %s",
+                  valuep);
+          }
+        }
+        else if((nlen == 7) && strncasecompare("version", namep, 7)) {
+          /* just ignore */
+        }
+        else if((nlen == 7) && strncasecompare("max-age", namep, 7)) {
+          /*
+           * Defined in RFC2109:
+           *
+           * Optional.  The Max-Age attribute defines the lifetime of the
+           * cookie, in seconds.  The delta-seconds value is a decimal non-
+           * negative integer.  After delta-seconds seconds elapse, the
+           * client should discard the cookie.  A value of zero means the
+           * cookie should be discarded immediately.
+           */
+          CURLofft offt;
+          const char *maxage = valuep;
+          offt = curlx_strtoofft((*maxage == '\"')?
+                                 &maxage[1]:&maxage[0], NULL, 10,
+                                 &co->expires);
+          switch(offt) {
+          case CURL_OFFT_FLOW:
+            /* overflow, used max value */
+            co->expires = CURL_OFF_T_MAX;
+            break;
+          case CURL_OFFT_INVAL:
+            /* negative or otherwise bad, expire */
+            co->expires = 1;
+            break;
+          case CURL_OFFT_OK:
+            if(!co->expires)
+              /* already expired */
+              co->expires = 1;
+            else if(CURL_OFF_T_MAX - now < co->expires)
+              /* would overflow */
+              co->expires = CURL_OFF_T_MAX;
+            else
+              co->expires += now;
+            break;
+          }
+        }
+        else if((nlen == 7) && strncasecompare("expires", namep, 7)) {
+          char date[128];
+          if(!co->expires && (vlen < sizeof(date))) {
+            /* copy the date so that it can be null terminated */
+            memcpy(date, valuep, vlen);
+            date[vlen] = 0;
+            /*
+             * Let max-age have priority.
+             *
+             * If the date cannot get parsed for whatever reason, the cookie
+             * will be treated as a session cookie
+             */
+            co->expires = Curl_getdate_capped(date);
+
+            /*
+             * Session cookies have expires set to 0 so if we get that back
+             * from the date parser let's add a second to make it a
+             * non-session cookie
+             */
+            if(co->expires == 0)
+              co->expires = 1;
+            else if(co->expires < 0)
+              co->expires = 0;
+          }
+        }
+
+        /*
+         * Else, this is the second (or more) name we don't know about!
+         */
+      }
+      else {
+        /* this is an "illegal" <what>=<this> pair */
+      }
+
+      while(*ptr && ISBLANK(*ptr))
+        ptr++;
+      if(*ptr == ';')
+        ptr++;
+      else
+        break;
+    } while(1);
+
+    if(!badcookie && !co->domain) {
+      if(domain) {
+        /* no domain was given in the header line, set the default */
+        co->domain = strdup(domain);
+        if(!co->domain)
+          badcookie = TRUE;
+      }
+    }
+
+    if(!badcookie && !co->path && path) {
+      /*
+       * No path was given in the header line, set the default.  Note that the
+       * passed-in path to this function MAY have a '?' and following part that
+       * MUST NOT be stored as part of the path.
+       */
+      char *queryp = strchr(path, '?');
+
+      /*
+       * queryp is where the interesting part of the path ends, so now we
+       * want to the find the last
+       */
+      char *endslash;
+      if(!queryp)
+        endslash = strrchr(path, '/');
+      else
+        endslash = memrchr(path, '/', (queryp - path));
+      if(endslash) {
+        size_t pathlen = (endslash-path + 1); /* include end slash */
+        co->path = Curl_memdup0(path, pathlen);
+        if(co->path) {
+          co->spath = sanitize_cookie_path(co->path);
+          if(!co->spath)
+            badcookie = TRUE; /* out of memory bad */
+        }
+        else
+          badcookie = TRUE;
+      }
+    }
+
+    /*
+     * If we didn't get a cookie name, or a bad one, the this is an illegal
+     * line so bail out.
+     */
+    if(badcookie || !co->name) {
+      freecookie(co);
+      return NULL;
+    }
+    data->req.setcookies++;
+  }
+  else {
+    /*
+     * This line is NOT an HTTP header style line, we do offer support for
+     * reading the odd netscape cookies-file format here
+     */
+    char *ptr;
+    char *firstptr;
+    char *tok_buf = NULL;
+    int fields;
+
+    /*
+     * IE introduced HTTP-only cookies to prevent XSS attacks. Cookies marked
+     * with httpOnly after the domain name are not accessible from javascripts,
+     * but since curl does not operate at javascript level, we include them
+     * anyway. In Firefox's cookie files, these lines are preceded with
+     * #HttpOnly_ and then everything is as usual, so we skip 10 characters of
+     * the line..
+     */
+    if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
+      lineptr += 10;
+      co->httponly = TRUE;
+    }
+
+    if(lineptr[0]=='#') {
+      /* don't even try the comments */
+      free(co);
+      return NULL;
+    }
+    /* strip off the possible end-of-line characters */
+    ptr = strchr(lineptr, '\r');
+    if(ptr)
+      *ptr = 0; /* clear it */
+    ptr = strchr(lineptr, '\n');
+    if(ptr)
+      *ptr = 0; /* clear it */
+
+    firstptr = strtok_r((char *)lineptr, "\t", &tok_buf); /* tokenize on TAB */
+
+    /*
+     * Now loop through the fields and init the struct we already have
+     * allocated
+     */
+    for(ptr = firstptr, fields = 0; ptr && !badcookie;
+        ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
+      switch(fields) {
+      case 0:
+        if(ptr[0]=='.') /* skip preceding dots */
+          ptr++;
+        co->domain = strdup(ptr);
+        if(!co->domain)
+          badcookie = TRUE;
+        break;
+      case 1:
+        /*
+         * flag: A TRUE/FALSE value indicating if all machines within a given
+         * domain can access the variable. Set TRUE when the cookie says
+         * .domain.com and to false when the domain is complete www.domain.com
+         */
+        co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
+        break;
+      case 2:
+        /* The file format allows the path field to remain not filled in */
+        if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
+          /* only if the path doesn't look like a boolean option! */
+          co->path = strdup(ptr);
+          if(!co->path)
+            badcookie = TRUE;
+          else {
+            co->spath = sanitize_cookie_path(co->path);
+            if(!co->spath) {
+              badcookie = TRUE; /* out of memory bad */
+            }
+          }
+          break;
+        }
+        /* this doesn't look like a path, make one up! */
+        co->path = strdup("/");
+        if(!co->path)
+          badcookie = TRUE;
+        co->spath = strdup("/");
+        if(!co->spath)
+          badcookie = TRUE;
+        fields++; /* add a field and fall down to secure */
+        FALLTHROUGH();
+      case 3:
+        co->secure = FALSE;
+        if(strcasecompare(ptr, "TRUE")) {
+          if(secure || c->running)
+            co->secure = TRUE;
+          else
+            badcookie = TRUE;
+        }
+        break;
+      case 4:
+        if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
+          badcookie = TRUE;
+        break;
+      case 5:
+        co->name = strdup(ptr);
+        if(!co->name)
+          badcookie = TRUE;
+        else {
+          /* For Netscape file format cookies we check prefix on the name */
+          if(strncasecompare("__Secure-", co->name, 9))
+            co->prefix |= COOKIE_PREFIX__SECURE;
+          else if(strncasecompare("__Host-", co->name, 7))
+            co->prefix |= COOKIE_PREFIX__HOST;
+        }
+        break;
+      case 6:
+        co->value = strdup(ptr);
+        if(!co->value)
+          badcookie = TRUE;
+        break;
+      }
+    }
+    if(6 == fields) {
+      /* we got a cookie with blank contents, fix it */
+      co->value = strdup("");
+      if(!co->value)
+        badcookie = TRUE;
+      else
+        fields++;
+    }
+
+    if(!badcookie && (7 != fields))
+      /* we did not find the sufficient number of fields */
+      badcookie = TRUE;
+
+    if(badcookie) {
+      freecookie(co);
+      return NULL;
+    }
+
+  }
+
+  if(co->prefix & COOKIE_PREFIX__SECURE) {
+    /* The __Secure- prefix only requires that the cookie be set secure */
+    if(!co->secure) {
+      freecookie(co);
+      return NULL;
+    }
+  }
+  if(co->prefix & COOKIE_PREFIX__HOST) {
+    /*
+     * The __Host- prefix requires the cookie to be secure, have a "/" path
+     * and not have a domain set.
+     */
+    if(co->secure && co->path && strcmp(co->path, "/") == 0 && !co->tailmatch)
+      ;
+    else {
+      freecookie(co);
+      return NULL;
+    }
+  }
+
+  if(!c->running &&    /* read from a file */
+     c->newsession &&  /* clean session cookies */
+     !co->expires) {   /* this is a session cookie since it doesn't expire! */
+    freecookie(co);
+    return NULL;
+  }
+
+  co->livecookie = c->running;
+  co->creationtime = ++c->lastct;
+
+  /*
+   * Now we have parsed the incoming line, we must now check if this supersedes
+   * an already existing cookie, which it may if the previous have the same
+   * domain and path as this.
+   */
+
+  /* at first, remove expired cookies */
+  if(!noexpire)
+    remove_expired(c);
+
+#ifdef USE_LIBPSL
+  /*
+   * Check if the domain is a Public Suffix and if yes, ignore the cookie. We
+   * must also check that the data handle isn't NULL since the psl code will
+   * dereference it.
+   */
+  if(data && (domain && co->domain && !Curl_host_is_ipnum(co->domain))) {
+    bool acceptable = FALSE;
+    char lcase[256];
+    char lcookie[256];
+    size_t dlen = strlen(domain);
+    size_t clen = strlen(co->domain);
+    if((dlen < sizeof(lcase)) && (clen < sizeof(lcookie))) {
+      const psl_ctx_t *psl = Curl_psl_use(data);
+      if(psl) {
+        /* the PSL check requires lowercase domain name and pattern */
+        Curl_strntolower(lcase, domain, dlen + 1);
+        Curl_strntolower(lcookie, co->domain, clen + 1);
+        acceptable = psl_is_cookie_domain_acceptable(psl, lcase, lcookie);
+        Curl_psl_release(data);
+      }
+      else
+        infof(data, "libpsl problem, rejecting cookie for satety");
+    }
+
+    if(!acceptable) {
+      infof(data, "cookie '%s' dropped, domain '%s' must not "
+                  "set cookies for '%s'", co->name, domain, co->domain);
+      freecookie(co);
+      return NULL;
+    }
+  }
+#endif
+
+  /* A non-secure cookie may not overlay an existing secure cookie. */
+  myhash = cookiehash(co->domain);
+  clist = c->cookies[myhash];
+  while(clist) {
+    if(strcasecompare(clist->name, co->name)) {
+      /* the names are identical */
+      bool matching_domains = FALSE;
+
+      if(clist->domain && co->domain) {
+        if(strcasecompare(clist->domain, co->domain))
+          /* The domains are identical */
+          matching_domains = TRUE;
+      }
+      else if(!clist->domain && !co->domain)
+        matching_domains = TRUE;
+
+      if(matching_domains && /* the domains were identical */
+         clist->spath && co->spath && /* both have paths */
+         clist->secure && !co->secure && !secure) {
+        size_t cllen;
+        const char *sep;
+
+        /*
+         * A non-secure cookie may not overlay an existing secure cookie.
+         * For an existing cookie "a" with path "/login", refuse a new
+         * cookie "a" with for example path "/login/en", while the path
+         * "/loginhelper" is ok.
+         */
+
+        sep = strchr(clist->spath + 1, '/');
+
+        if(sep)
+          cllen = sep - clist->spath;
+        else
+          cllen = strlen(clist->spath);
+
+        if(strncasecompare(clist->spath, co->spath, cllen)) {
+          infof(data, "cookie '%s' for domain '%s' dropped, would "
+                "overlay an existing cookie", co->name, co->domain);
+          freecookie(co);
+          return NULL;
+        }
+      }
+    }
+
+    if(!replace_co && strcasecompare(clist->name, co->name)) {
+      /* the names are identical */
+
+      if(clist->domain && co->domain) {
+        if(strcasecompare(clist->domain, co->domain) &&
+          (clist->tailmatch == co->tailmatch))
+          /* The domains are identical */
+          replace_old = TRUE;
+      }
+      else if(!clist->domain && !co->domain)
+        replace_old = TRUE;
+
+      if(replace_old) {
+        /* the domains were identical */
+
+        if(clist->spath && co->spath &&
+           !strcasecompare(clist->spath, co->spath))
+          replace_old = FALSE;
+        else if(!clist->spath != !co->spath)
+          replace_old = FALSE;
+      }
+
+      if(replace_old && !co->livecookie && clist->livecookie) {
+        /*
+         * Both cookies matched fine, except that the already present cookie is
+         * "live", which means it was set from a header, while the new one was
+         * read from a file and thus isn't "live". "live" cookies are preferred
+         * so the new cookie is freed.
+         */
+        freecookie(co);
+        return NULL;
+      }
+      if(replace_old) {
+        replace_co = co;
+        replace_clist = clist;
+      }
+    }
+    lastc = clist;
+    clist = clist->next;
+  }
+  if(replace_co) {
+    co = replace_co;
+    clist = replace_clist;
+    co->next = clist->next; /* get the next-pointer first */
+
+    /* when replacing, creationtime is kept from old */
+    co->creationtime = clist->creationtime;
+
+    /* then free all the old pointers */
+    free(clist->name);
+    free(clist->value);
+    free(clist->domain);
+    free(clist->path);
+    free(clist->spath);
+
+    *clist = *co;  /* then store all the new data */
+
+    free(co);   /* free the newly allocated memory */
+    co = clist;
+  }
+
+  if(c->running)
+    /* Only show this when NOT reading the cookies from a file */
+    infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
+          "expire %" CURL_FORMAT_CURL_OFF_T,
+          replace_old?"Replaced":"Added", co->name, co->value,
+          co->domain, co->path, co->expires);
+
+  if(!replace_old) {
+    /* then make the last item point on this new one */
+    if(lastc)
+      lastc->next = co;
+    else
+      c->cookies[myhash] = co;
+    c->numcookies++; /* one more cookie in the jar */
+  }
+
+  /*
+   * Now that we've added a new cookie to the jar, update the expiration
+   * tracker in case it is the next one to expire.
+   */
+  if(co->expires && (co->expires < c->next_expiration))
+    c->next_expiration = co->expires;
+
+  return co;
+}
+
+
+/*
+ * Curl_cookie_init()
+ *
+ * Inits a cookie struct to read data from a local file. This is always
+ * called before any cookies are set. File may be NULL in which case only the
+ * struct is initialized. Is file is "-" then STDIN is read.
+ *
+ * If 'newsession' is TRUE, discard all "session cookies" on read from file.
+ *
+ * Note that 'data' might be called as NULL pointer. If data is NULL, 'file'
+ * will be ignored.
+ *
+ * Returns NULL on out of memory. Invalid cookies are ignored.
+ */
+struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+                                    const char *file,
+                                    struct CookieInfo *inc,
+                                    bool newsession)
+{
+  struct CookieInfo *c;
+  FILE *handle = NULL;
+
+  if(!inc) {
+    /* we didn't get a struct, create one */
+    c = calloc(1, sizeof(struct CookieInfo));
+    if(!c)
+      return NULL; /* failed to get memory */
+    /*
+     * Initialize the next_expiration time to signal that we don't have enough
+     * information yet.
+     */
+    c->next_expiration = CURL_OFF_T_MAX;
+  }
+  else {
+    /* we got an already existing one, use that */
+    c = inc;
+  }
+  c->newsession = newsession; /* new session? */
+
+  if(data) {
+    FILE *fp = NULL;
+    if(file && *file) {
+      if(!strcmp(file, "-"))
+        fp = stdin;
+      else {
+        fp = fopen(file, "rb");
+        if(!fp)
+          infof(data, "WARNING: failed to open cookie file \"%s\"", file);
+        else
+          handle = fp;
+      }
+    }
+
+    c->running = FALSE; /* this is not running, this is init */
+    if(fp) {
+      struct dynbuf buf;
+      Curl_dyn_init(&buf, MAX_COOKIE_LINE);
+      while(Curl_get_line(&buf, fp)) {
+        char *lineptr = Curl_dyn_ptr(&buf);
+        bool headerline = FALSE;
+        if(checkprefix("Set-Cookie:", lineptr)) {
+          /* This is a cookie line, get it! */
+          lineptr += 11;
+          headerline = TRUE;
+          while(*lineptr && ISBLANK(*lineptr))
+            lineptr++;
+        }
+
+        Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE);
+      }
+      Curl_dyn_free(&buf); /* free the line buffer */
+
+      /*
+       * Remove expired cookies from the hash. We must make sure to run this
+       * after reading the file, and not on every cookie.
+       */
+      remove_expired(c);
+
+      if(handle)
+        fclose(handle);
+    }
+    data->state.cookie_engine = TRUE;
+  }
+  c->running = TRUE;          /* now, we're running */
+
+  return c;
+}
+
+/*
+ * cookie_sort
+ *
+ * Helper function to sort cookies such that the longest path gets before the
+ * shorter path. Path, domain and name lengths are considered in that order,
+ * with the creationtime as the tiebreaker. The creationtime is guaranteed to
+ * be unique per cookie, so we know we will get an ordering at that point.
+ */
+static int cookie_sort(const void *p1, const void *p2)
+{
+  struct Cookie *c1 = *(struct Cookie **)p1;
+  struct Cookie *c2 = *(struct Cookie **)p2;
+  size_t l1, l2;
+
+  /* 1 - compare cookie path lengths */
+  l1 = c1->path ? strlen(c1->path) : 0;
+  l2 = c2->path ? strlen(c2->path) : 0;
+
+  if(l1 != l2)
+    return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */
+
+  /* 2 - compare cookie domain lengths */
+  l1 = c1->domain ? strlen(c1->domain) : 0;
+  l2 = c2->domain ? strlen(c2->domain) : 0;
+
+  if(l1 != l2)
+    return (l2 > l1) ? 1 : -1 ;  /* avoid size_t <=> int conversions */
+
+  /* 3 - compare cookie name lengths */
+  l1 = c1->name ? strlen(c1->name) : 0;
+  l2 = c2->name ? strlen(c2->name) : 0;
+
+  if(l1 != l2)
+    return (l2 > l1) ? 1 : -1;
+
+  /* 4 - compare cookie creation time */
+  return (c2->creationtime > c1->creationtime) ? 1 : -1;
+}
+
+/*
+ * cookie_sort_ct
+ *
+ * Helper function to sort cookies according to creation time.
+ */
+static int cookie_sort_ct(const void *p1, const void *p2)
+{
+  struct Cookie *c1 = *(struct Cookie **)p1;
+  struct Cookie *c2 = *(struct Cookie **)p2;
+
+  return (c2->creationtime > c1->creationtime) ? 1 : -1;
+}
+
+#define CLONE(field)                     \
+  do {                                   \
+    if(src->field) {                     \
+      d->field = strdup(src->field);     \
+      if(!d->field)                      \
+        goto fail;                       \
+    }                                    \
+  } while(0)
+
+static struct Cookie *dup_cookie(struct Cookie *src)
+{
+  struct Cookie *d = calloc(1, sizeof(struct Cookie));
+  if(d) {
+    CLONE(domain);
+    CLONE(path);
+    CLONE(spath);
+    CLONE(name);
+    CLONE(value);
+    d->expires = src->expires;
+    d->tailmatch = src->tailmatch;
+    d->secure = src->secure;
+    d->livecookie = src->livecookie;
+    d->httponly = src->httponly;
+    d->creationtime = src->creationtime;
+  }
+  return d;
+
+fail:
+  freecookie(d);
+  return NULL;
+}
+
+/*
+ * Curl_cookie_getlist
+ *
+ * For a given host and path, return a linked list of cookies that the client
+ * should send to the server if used now. The secure boolean informs the cookie
+ * if a secure connection is achieved or not.
+ *
+ * It shall only return cookies that haven't expired.
+ */
+struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
+                                   struct CookieInfo *c,
+                                   const char *host, const char *path,
+                                   bool secure)
+{
+  struct Cookie *newco;
+  struct Cookie *co;
+  struct Cookie *mainco = NULL;
+  size_t matches = 0;
+  bool is_ip;
+  const size_t myhash = cookiehash(host);
+
+  if(!c || !c->cookies[myhash])
+    return NULL; /* no cookie struct or no cookies in the struct */
+
+  /* at first, remove expired cookies */
+  remove_expired(c);
+
+  /* check if host is an IP(v4|v6) address */
+  is_ip = Curl_host_is_ipnum(host);
+
+  co = c->cookies[myhash];
+
+  while(co) {
+    /* if the cookie requires we're secure we must only continue if we are! */
+    if(co->secure?secure:TRUE) {
+
+      /* now check if the domain is correct */
+      if(!co->domain ||
+         (co->tailmatch && !is_ip &&
+          cookie_tailmatch(co->domain, strlen(co->domain), host)) ||
+         ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
+        /*
+         * the right part of the host matches the domain stuff in the
+         * cookie data
+         */
+
+        /*
+         * now check the left part of the path with the cookies path
+         * requirement
+         */
+        if(!co->spath || pathmatch(co->spath, path) ) {
+
+          /*
+           * and now, we know this is a match and we should create an
+           * entry for the return-linked-list
+           */
+
+          newco = dup_cookie(co);
+          if(newco) {
+            /* then modify our next */
+            newco->next = mainco;
+
+            /* point the main to us */
+            mainco = newco;
+
+            matches++;
+            if(matches >= MAX_COOKIE_SEND_AMOUNT) {
+              infof(data, "Included max number of cookies (%zu) in request!",
+                    matches);
+              break;
+            }
+          }
+          else
+            goto fail;
+        }
+      }
+    }
+    co = co->next;
+  }
+
+  if(matches) {
+    /*
+     * Now we need to make sure that if there is a name appearing more than
+     * once, the longest specified path version comes first. To make this
+     * the swiftest way, we just sort them all based on path length.
+     */
+    struct Cookie **array;
+    size_t i;
+
+    /* alloc an array and store all cookie pointers */
+    array = malloc(sizeof(struct Cookie *) * matches);
+    if(!array)
+      goto fail;
+
+    co = mainco;
+
+    for(i = 0; co; co = co->next)
+      array[i++] = co;
+
+    /* now sort the cookie pointers in path length order */
+    qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
+
+    /* remake the linked list order according to the new order */
+
+    mainco = array[0]; /* start here */
+    for(i = 0; i<matches-1; i++)
+      array[i]->next = array[i + 1];
+    array[matches-1]->next = NULL; /* terminate the list */
+
+    free(array); /* remove the temporary data again */
+  }
+
+  return mainco; /* return the new list */
+
+fail:
+  /* failure, clear up the allocated chain and return NULL */
+  Curl_cookie_freelist(mainco);
+  return NULL;
+}
+
+/*
+ * Curl_cookie_clearall
+ *
+ * Clear all existing cookies and reset the counter.
+ */
+void Curl_cookie_clearall(struct CookieInfo *cookies)
+{
+  if(cookies) {
+    unsigned int i;
+    for(i = 0; i < COOKIE_HASH_SIZE; i++) {
+      Curl_cookie_freelist(cookies->cookies[i]);
+      cookies->cookies[i] = NULL;
+    }
+    cookies->numcookies = 0;
+  }
+}
+
+/*
+ * Curl_cookie_freelist
+ *
+ * Free a list of cookies previously returned by Curl_cookie_getlist();
+ */
+void Curl_cookie_freelist(struct Cookie *co)
+{
+  struct Cookie *next;
+  while(co) {
+    next = co->next;
+    freecookie(co);
+    co = next;
+  }
+}
+
+/*
+ * Curl_cookie_clearsess
+ *
+ * Free all session cookies in the cookies list.
+ */
+void Curl_cookie_clearsess(struct CookieInfo *cookies)
+{
+  struct Cookie *first, *curr, *next, *prev = NULL;
+  unsigned int i;
+
+  if(!cookies)
+    return;
+
+  for(i = 0; i < COOKIE_HASH_SIZE; i++) {
+    if(!cookies->cookies[i])
+      continue;
+
+    first = curr = prev = cookies->cookies[i];
+
+    for(; curr; curr = next) {
+      next = curr->next;
+      if(!curr->expires) {
+        if(first == curr)
+          first = next;
+
+        if(prev == curr)
+          prev = next;
+        else
+          prev->next = next;
+
+        freecookie(curr);
+        cookies->numcookies--;
+      }
+      else
+        prev = curr;
+    }
+
+    cookies->cookies[i] = first;
+  }
+}
+
+/*
+ * Curl_cookie_cleanup()
+ *
+ * Free a "cookie object" previous created with Curl_cookie_init().
+ */
+void Curl_cookie_cleanup(struct CookieInfo *c)
+{
+  if(c) {
+    unsigned int i;
+    for(i = 0; i < COOKIE_HASH_SIZE; i++)
+      Curl_cookie_freelist(c->cookies[i]);
+    free(c); /* free the base struct as well */
+  }
+}
+
+/*
+ * get_netscape_format()
+ *
+ * Formats a string for Netscape output file, w/o a newline at the end.
+ * Function returns a char * to a formatted line. The caller is responsible
+ * for freeing the returned pointer.
+ */
+static char *get_netscape_format(const struct Cookie *co)
+{
+  return aprintf(
+    "%s"     /* httponly preamble */
+    "%s%s\t" /* domain */
+    "%s\t"   /* tailmatch */
+    "%s\t"   /* path */
+    "%s\t"   /* secure */
+    "%" CURL_FORMAT_CURL_OFF_T "\t"   /* expires */
+    "%s\t"   /* name */
+    "%s",    /* value */
+    co->httponly?"#HttpOnly_":"",
+    /*
+     * Make sure all domains are prefixed with a dot if they allow
+     * tailmatching. This is Mozilla-style.
+     */
+    (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
+    co->domain?co->domain:"unknown",
+    co->tailmatch?"TRUE":"FALSE",
+    co->path?co->path:"/",
+    co->secure?"TRUE":"FALSE",
+    co->expires,
+    co->name,
+    co->value?co->value:"");
+}
+
+/*
+ * cookie_output()
+ *
+ * Writes all internally known cookies to the specified file. Specify
+ * "-" as file name to write to stdout.
+ *
+ * The function returns non-zero on write failure.
+ */
+static CURLcode cookie_output(struct Curl_easy *data,
+                              struct CookieInfo *c, const char *filename)
+{
+  struct Cookie *co;
+  FILE *out = NULL;
+  bool use_stdout = FALSE;
+  char *tempstore = NULL;
+  CURLcode error = CURLE_OK;
+
+  if(!c)
+    /* no cookie engine alive */
+    return CURLE_OK;
+
+  /* at first, remove expired cookies */
+  remove_expired(c);
+
+  if(!strcmp("-", filename)) {
+    /* use stdout */
+    out = stdout;
+    use_stdout = TRUE;
+  }
+  else {
+    error = Curl_fopen(data, filename, &out, &tempstore);
+    if(error)
+      goto error;
+  }
+
+  fputs("# Netscape HTTP Cookie File\n"
+        "# https://curl.se/docs/http-cookies.html\n"
+        "# This file was generated by libcurl! Edit at your own risk.\n\n",
+        out);
+
+  if(c->numcookies) {
+    unsigned int i;
+    size_t nvalid = 0;
+    struct Cookie **array;
+
+    array = calloc(1, sizeof(struct Cookie *) * c->numcookies);
+    if(!array) {
+      error = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
+
+    /* only sort the cookies with a domain property */
+    for(i = 0; i < COOKIE_HASH_SIZE; i++) {
+      for(co = c->cookies[i]; co; co = co->next) {
+        if(!co->domain)
+          continue;
+        array[nvalid++] = co;
+      }
+    }
+
+    qsort(array, nvalid, sizeof(struct Cookie *), cookie_sort_ct);
+
+    for(i = 0; i < nvalid; i++) {
+      char *format_ptr = get_netscape_format(array[i]);
+      if(!format_ptr) {
+        free(array);
+        error = CURLE_OUT_OF_MEMORY;
+        goto error;
+      }
+      fprintf(out, "%s\n", format_ptr);
+      free(format_ptr);
+    }
+
+    free(array);
+  }
+
+  if(!use_stdout) {
+    fclose(out);
+    out = NULL;
+    if(tempstore && Curl_rename(tempstore, filename)) {
+      unlink(tempstore);
+      error = CURLE_WRITE_ERROR;
+      goto error;
+    }
+  }
+
+  /*
+   * If we reach here we have successfully written a cookie file so there is
+   * no need to inspect the error, any error case should have jumped into the
+   * error block below.
+   */
+  free(tempstore);
+  return CURLE_OK;
+
+error:
+  if(out && !use_stdout)
+    fclose(out);
+  free(tempstore);
+  return error;
+}
+
+static struct curl_slist *cookie_list(struct Curl_easy *data)
+{
+  struct curl_slist *list = NULL;
+  struct curl_slist *beg;
+  struct Cookie *c;
+  char *line;
+  unsigned int i;
+
+  if(!data->cookies || (data->cookies->numcookies == 0))
+    return NULL;
+
+  for(i = 0; i < COOKIE_HASH_SIZE; i++) {
+    for(c = data->cookies->cookies[i]; c; c = c->next) {
+      if(!c->domain)
+        continue;
+      line = get_netscape_format(c);
+      if(!line) {
+        curl_slist_free_all(list);
+        return NULL;
+      }
+      beg = Curl_slist_append_nodup(list, line);
+      if(!beg) {
+        free(line);
+        curl_slist_free_all(list);
+        return NULL;
+      }
+      list = beg;
+    }
+  }
+
+  return list;
+}
+
+struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
+{
+  struct curl_slist *list;
+  Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+  list = cookie_list(data);
+  Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+  return list;
+}
+
+void Curl_flush_cookies(struct Curl_easy *data, bool cleanup)
+{
+  CURLcode res;
+
+  if(data->set.str[STRING_COOKIEJAR]) {
+    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+
+    /* if we have a destination file for all the cookies to get dumped to */
+    res = cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR]);
+    if(res)
+      infof(data, "WARNING: failed to save cookies in %s: %s",
+            data->set.str[STRING_COOKIEJAR], curl_easy_strerror(res));
+  }
+  else {
+    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+  }
+
+  if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
+    Curl_cookie_cleanup(data->cookies);
+    data->cookies = NULL;
+  }
+  Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+}
+
+#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */
Index: trunk/src/libs/curl-8.7.1/lib/cookie.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/cookie.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/cookie.h	(revision 104083)
@@ -0,0 +1,138 @@
+#ifndef HEADER_CURL_COOKIE_H
+#define HEADER_CURL_COOKIE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+struct Cookie {
+  struct Cookie *next; /* next in the chain */
+  char *name;        /* <this> = value */
+  char *value;       /* name = <this> */
+  char *path;         /* path = <this> which is in Set-Cookie: */
+  char *spath;        /* sanitized cookie path */
+  char *domain;      /* domain = <this> */
+  curl_off_t expires;  /* expires = <this> */
+  bool tailmatch;    /* whether we do tail-matching of the domain name */
+  bool secure;       /* whether the 'secure' keyword was used */
+  bool livecookie;   /* updated from a server, not a stored file */
+  bool httponly;     /* true if the httponly directive is present */
+  int creationtime;  /* time when the cookie was written */
+  unsigned char prefix; /* bitmap fields indicating which prefix are set */
+};
+
+/*
+ * Available cookie prefixes, as defined in
+ * draft-ietf-httpbis-rfc6265bis-02
+ */
+#define COOKIE_PREFIX__SECURE (1<<0)
+#define COOKIE_PREFIX__HOST (1<<1)
+
+#define COOKIE_HASH_SIZE 63
+
+struct CookieInfo {
+  /* linked list of cookies we know of */
+  struct Cookie *cookies[COOKIE_HASH_SIZE];
+  curl_off_t next_expiration; /* the next time at which expiration happens */
+  int numcookies;  /* number of cookies in the "jar" */
+  int lastct;      /* last creation-time used in the jar */
+  bool running;    /* state info, for cookie adding information */
+  bool newsession; /* new session, discard session cookies on load */
+};
+
+/* The maximum sizes we accept for cookies. RFC 6265 section 6.1 says
+   "general-use user agents SHOULD provide each of the following minimum
+   capabilities":
+
+   - At least 4096 bytes per cookie (as measured by the sum of the length of
+     the cookie's name, value, and attributes).
+   In the 6265bis draft document section 5.4 it is phrased even stronger: "If
+   the sum of the lengths of the name string and the value string is more than
+   4096 octets, abort these steps and ignore the set-cookie-string entirely."
+*/
+
+/** Limits for INCOMING cookies **/
+
+/* The longest we allow a line to be when reading a cookie from a HTTP header
+   or from a cookie jar */
+#define MAX_COOKIE_LINE 5000
+
+/* Maximum length of an incoming cookie name or content we deal with. Longer
+   cookies are ignored. */
+#define MAX_NAME 4096
+
+/* Maximum number of Set-Cookie: lines accepted in a single response. If more
+   such header lines are received, they are ignored. This value must be less
+   than 256 since an unsigned char is used to count. */
+#define MAX_SET_COOKIE_AMOUNT 50
+
+/** Limits for OUTGOING cookies **/
+
+/* Maximum size for an outgoing cookie line libcurl will use in an http
+   request. This is the default maximum length used in some versions of Apache
+   httpd. */
+#define MAX_COOKIE_HEADER_LEN 8190
+
+/* Maximum number of cookies libcurl will send in a single request, even if
+   there might be more cookies that match. One reason to cap the number is to
+   keep the maximum HTTP request within the maximum allowed size. */
+#define MAX_COOKIE_SEND_AMOUNT 150
+
+struct Curl_easy;
+/*
+ * Add a cookie to the internal list of cookies. The domain and path arguments
+ * are only used if the header boolean is TRUE.
+ */
+
+struct Cookie *Curl_cookie_add(struct Curl_easy *data,
+                               struct CookieInfo *c, bool header,
+                               bool noexpiry, const char *lineptr,
+                               const char *domain, const char *path,
+                               bool secure);
+
+struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
+                                   struct CookieInfo *c, const char *host,
+                                   const char *path, bool secure);
+void Curl_cookie_freelist(struct Cookie *cookies);
+void Curl_cookie_clearall(struct CookieInfo *cookies);
+void Curl_cookie_clearsess(struct CookieInfo *cookies);
+
+#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES)
+#define Curl_cookie_list(x) NULL
+#define Curl_cookie_loadfiles(x) Curl_nop_stmt
+#define Curl_cookie_init(x,y,z,w) NULL
+#define Curl_cookie_cleanup(x) Curl_nop_stmt
+#define Curl_flush_cookies(x,y) Curl_nop_stmt
+#else
+void Curl_flush_cookies(struct Curl_easy *data, bool cleanup);
+void Curl_cookie_cleanup(struct CookieInfo *c);
+struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+                                    const char *file, struct CookieInfo *inc,
+                                    bool newsession);
+struct curl_slist *Curl_cookie_list(struct Curl_easy *data);
+void Curl_cookie_loadfiles(struct Curl_easy *data);
+#endif
+
+#endif /* HEADER_CURL_COOKIE_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_addrinfo.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_addrinfo.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_addrinfo.c	(revision 104083)
@@ -0,0 +1,592 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#ifdef HAVE_NETINET_IN_H
+#  include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#  include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETDB_H
+#  include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#  include <arpa/inet.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+#  include <sys/un.h>
+#endif
+
+#ifdef __VMS
+#  include <in.h>
+#  include <inet.h>
+#endif
+
+#include <stddef.h>
+
+#include "curl_addrinfo.h"
+#include "inet_pton.h"
+#include "warnless.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_freeaddrinfo()
+ *
+ * This is used to free a linked list of Curl_addrinfo structs along
+ * with all its associated allocated storage. This function should be
+ * called once for each successful call to Curl_getaddrinfo_ex() or to
+ * any function call which actually allocates a Curl_addrinfo struct.
+ */
+
+#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
+    defined(__OPTIMIZE__) && defined(__unix__) &&  defined(__i386__)
+  /* workaround icc 9.1 optimizer issue */
+# define vqualifier volatile
+#else
+# define vqualifier
+#endif
+
+void
+Curl_freeaddrinfo(struct Curl_addrinfo *cahead)
+{
+  struct Curl_addrinfo *vqualifier canext;
+  struct Curl_addrinfo *ca;
+
+  for(ca = cahead; ca; ca = canext) {
+    canext = ca->ai_next;
+    free(ca);
+  }
+}
+
+
+#ifdef HAVE_GETADDRINFO
+/*
+ * Curl_getaddrinfo_ex()
+ *
+ * This is a wrapper function around system's getaddrinfo(), with
+ * the only difference that instead of returning a linked list of
+ * addrinfo structs this one returns a linked list of Curl_addrinfo
+ * ones. The memory allocated by this function *MUST* be free'd with
+ * Curl_freeaddrinfo().  For each successful call to this function
+ * there must be an associated call later to Curl_freeaddrinfo().
+ *
+ * There should be no single call to system's getaddrinfo() in the
+ * whole library, any such call should be 'routed' through this one.
+ */
+
+int
+Curl_getaddrinfo_ex(const char *nodename,
+                    const char *servname,
+                    const struct addrinfo *hints,
+                    struct Curl_addrinfo **result)
+{
+  const struct addrinfo *ai;
+  struct addrinfo *aihead;
+  struct Curl_addrinfo *cafirst = NULL;
+  struct Curl_addrinfo *calast = NULL;
+  struct Curl_addrinfo *ca;
+  size_t ss_size;
+  int error;
+
+  *result = NULL; /* assume failure */
+
+  error = getaddrinfo(nodename, servname, hints, &aihead);
+  if(error)
+    return error;
+
+  /* traverse the addrinfo list */
+
+  for(ai = aihead; ai != NULL; ai = ai->ai_next) {
+    size_t namelen = ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0;
+    /* ignore elements with unsupported address family, */
+    /* settle family-specific sockaddr structure size.  */
+    if(ai->ai_family == AF_INET)
+      ss_size = sizeof(struct sockaddr_in);
+#ifdef ENABLE_IPV6
+    else if(ai->ai_family == AF_INET6)
+      ss_size = sizeof(struct sockaddr_in6);
+#endif
+    else
+      continue;
+
+    /* ignore elements without required address info */
+    if(!ai->ai_addr || !(ai->ai_addrlen > 0))
+      continue;
+
+    /* ignore elements with bogus address size */
+    if((size_t)ai->ai_addrlen < ss_size)
+      continue;
+
+    ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen);
+    if(!ca) {
+      error = EAI_MEMORY;
+      break;
+    }
+
+    /* copy each structure member individually, member ordering, */
+    /* size, or padding might be different for each platform.    */
+
+    ca->ai_flags     = ai->ai_flags;
+    ca->ai_family    = ai->ai_family;
+    ca->ai_socktype  = ai->ai_socktype;
+    ca->ai_protocol  = ai->ai_protocol;
+    ca->ai_addrlen   = (curl_socklen_t)ss_size;
+    ca->ai_addr      = NULL;
+    ca->ai_canonname = NULL;
+    ca->ai_next      = NULL;
+
+    ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
+    memcpy(ca->ai_addr, ai->ai_addr, ss_size);
+
+    if(namelen) {
+      ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
+      memcpy(ca->ai_canonname, ai->ai_canonname, namelen);
+    }
+
+    /* if the return list is empty, this becomes the first element */
+    if(!cafirst)
+      cafirst = ca;
+
+    /* add this element last in the return list */
+    if(calast)
+      calast->ai_next = ca;
+    calast = ca;
+
+  }
+
+  /* destroy the addrinfo list */
+  if(aihead)
+    freeaddrinfo(aihead);
+
+  /* if we failed, also destroy the Curl_addrinfo list */
+  if(error) {
+    Curl_freeaddrinfo(cafirst);
+    cafirst = NULL;
+  }
+  else if(!cafirst) {
+#ifdef EAI_NONAME
+    /* rfc3493 conformant */
+    error = EAI_NONAME;
+#else
+    /* rfc3493 obsoleted */
+    error = EAI_NODATA;
+#endif
+#ifdef USE_WINSOCK
+    SET_SOCKERRNO(error);
+#endif
+  }
+
+  *result = cafirst;
+
+  /* This is not a CURLcode */
+  return error;
+}
+#endif /* HAVE_GETADDRINFO */
+
+
+/*
+ * Curl_he2ai()
+ *
+ * This function returns a pointer to the first element of a newly allocated
+ * Curl_addrinfo struct linked list filled with the data of a given hostent.
+ * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6
+ * stack, but usable also for IPv4, all hosts and environments.
+ *
+ * The memory allocated by this function *MUST* be free'd later on calling
+ * Curl_freeaddrinfo().  For each successful call to this function there
+ * must be an associated call later to Curl_freeaddrinfo().
+ *
+ *   Curl_addrinfo defined in "lib/curl_addrinfo.h"
+ *
+ *     struct Curl_addrinfo {
+ *       int                   ai_flags;
+ *       int                   ai_family;
+ *       int                   ai_socktype;
+ *       int                   ai_protocol;
+ *       curl_socklen_t        ai_addrlen;   * Follow rfc3493 struct addrinfo *
+ *       char                 *ai_canonname;
+ *       struct sockaddr      *ai_addr;
+ *       struct Curl_addrinfo *ai_next;
+ *     };
+ *
+ *   hostent defined in <netdb.h>
+ *
+ *     struct hostent {
+ *       char    *h_name;
+ *       char    **h_aliases;
+ *       int     h_addrtype;
+ *       int     h_length;
+ *       char    **h_addr_list;
+ *     };
+ *
+ *   for backward compatibility:
+ *
+ *     #define h_addr  h_addr_list[0]
+ */
+
+struct Curl_addrinfo *
+Curl_he2ai(const struct hostent *he, int port)
+{
+  struct Curl_addrinfo *ai;
+  struct Curl_addrinfo *prevai = NULL;
+  struct Curl_addrinfo *firstai = NULL;
+  struct sockaddr_in *addr;
+#ifdef ENABLE_IPV6
+  struct sockaddr_in6 *addr6;
+#endif
+  CURLcode result = CURLE_OK;
+  int i;
+  char *curr;
+
+  if(!he)
+    /* no input == no output! */
+    return NULL;
+
+  DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
+
+  for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) {
+    size_t ss_size;
+    size_t namelen = strlen(he->h_name) + 1; /* include null-terminator */
+#ifdef ENABLE_IPV6
+    if(he->h_addrtype == AF_INET6)
+      ss_size = sizeof(struct sockaddr_in6);
+    else
+#endif
+      ss_size = sizeof(struct sockaddr_in);
+
+    /* allocate memory to hold the struct, the address and the name */
+    ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + namelen);
+    if(!ai) {
+      result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+    /* put the address after the struct */
+    ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
+    /* then put the name after the address */
+    ai->ai_canonname = (char *)ai->ai_addr + ss_size;
+    memcpy(ai->ai_canonname, he->h_name, namelen);
+
+    if(!firstai)
+      /* store the pointer we want to return from this function */
+      firstai = ai;
+
+    if(prevai)
+      /* make the previous entry point to this */
+      prevai->ai_next = ai;
+
+    ai->ai_family = he->h_addrtype;
+
+    /* we return all names as STREAM, so when using this address for TFTP
+       the type must be ignored and conn->socktype be used instead! */
+    ai->ai_socktype = SOCK_STREAM;
+
+    ai->ai_addrlen = (curl_socklen_t)ss_size;
+
+    /* leave the rest of the struct filled with zero */
+
+    switch(ai->ai_family) {
+    case AF_INET:
+      addr = (void *)ai->ai_addr; /* storage area for this info */
+
+      memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
+      addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
+      addr->sin_port = htons((unsigned short)port);
+      break;
+
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+      addr6 = (void *)ai->ai_addr; /* storage area for this info */
+
+      memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
+      addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
+      addr6->sin6_port = htons((unsigned short)port);
+      break;
+#endif
+    }
+
+    prevai = ai;
+  }
+
+  if(result) {
+    Curl_freeaddrinfo(firstai);
+    firstai = NULL;
+  }
+
+  return firstai;
+}
+
+
+struct namebuff {
+  struct hostent hostentry;
+  union {
+    struct in_addr  ina4;
+#ifdef ENABLE_IPV6
+    struct in6_addr ina6;
+#endif
+  } addrentry;
+  char *h_addr_list[2];
+};
+
+
+/*
+ * Curl_ip2addr()
+ *
+ * This function takes an internet address, in binary form, as input parameter
+ * along with its address family and the string version of the address, and it
+ * returns a Curl_addrinfo chain filled in correctly with information for the
+ * given address/host
+ */
+
+struct Curl_addrinfo *
+Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
+{
+  struct Curl_addrinfo *ai;
+
+#if defined(__VMS) && \
+    defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
+#pragma pointer_size save
+#pragma pointer_size short
+#pragma message disable PTRMISMATCH
+#endif
+
+  struct hostent  *h;
+  struct namebuff *buf;
+  char  *addrentry;
+  char  *hoststr;
+  size_t addrsize;
+
+  DEBUGASSERT(inaddr && hostname);
+
+  buf = malloc(sizeof(struct namebuff));
+  if(!buf)
+    return NULL;
+
+  hoststr = strdup(hostname);
+  if(!hoststr) {
+    free(buf);
+    return NULL;
+  }
+
+  switch(af) {
+  case AF_INET:
+    addrsize = sizeof(struct in_addr);
+    addrentry = (void *)&buf->addrentry.ina4;
+    memcpy(addrentry, inaddr, sizeof(struct in_addr));
+    break;
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    addrsize = sizeof(struct in6_addr);
+    addrentry = (void *)&buf->addrentry.ina6;
+    memcpy(addrentry, inaddr, sizeof(struct in6_addr));
+    break;
+#endif
+  default:
+    free(hoststr);
+    free(buf);
+    return NULL;
+  }
+
+  h = &buf->hostentry;
+  h->h_name = hoststr;
+  h->h_aliases = NULL;
+  h->h_addrtype = (short)af;
+  h->h_length = (short)addrsize;
+  h->h_addr_list = &buf->h_addr_list[0];
+  h->h_addr_list[0] = addrentry;
+  h->h_addr_list[1] = NULL; /* terminate list of entries */
+
+#if defined(__VMS) && \
+    defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
+#pragma pointer_size restore
+#pragma message enable PTRMISMATCH
+#endif
+
+  ai = Curl_he2ai(h, port);
+
+  free(hoststr);
+  free(buf);
+
+  return ai;
+}
+
+/*
+ * Given an IPv4 or IPv6 dotted string address, this converts it to a proper
+ * allocated Curl_addrinfo struct and returns it.
+ */
+struct Curl_addrinfo *Curl_str2addr(char *address, int port)
+{
+  struct in_addr in;
+  if(Curl_inet_pton(AF_INET, address, &in) > 0)
+    /* This is a dotted IP address 123.123.123.123-style */
+    return Curl_ip2addr(AF_INET, &in, address, port);
+#ifdef ENABLE_IPV6
+  {
+    struct in6_addr in6;
+    if(Curl_inet_pton(AF_INET6, address, &in6) > 0)
+      /* This is a dotted IPv6 address ::1-style */
+      return Curl_ip2addr(AF_INET6, &in6, address, port);
+  }
+#endif
+  return NULL; /* bad input format */
+}
+
+#ifdef USE_UNIX_SOCKETS
+/**
+ * Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo
+ * struct initialized with this path.
+ * Set '*longpath' to TRUE if the error is a too long path.
+ */
+struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
+                                     bool abstract)
+{
+  struct Curl_addrinfo *ai;
+  struct sockaddr_un *sa_un;
+  size_t path_len;
+
+  *longpath = FALSE;
+
+  ai = calloc(1, sizeof(struct Curl_addrinfo) + sizeof(struct sockaddr_un));
+  if(!ai)
+    return NULL;
+  ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
+
+  sa_un = (void *) ai->ai_addr;
+  sa_un->sun_family = AF_UNIX;
+
+  /* sun_path must be able to store the NUL-terminated path */
+  path_len = strlen(path) + 1;
+  if(path_len > sizeof(sa_un->sun_path)) {
+    free(ai);
+    *longpath = TRUE;
+    return NULL;
+  }
+
+  ai->ai_family = AF_UNIX;
+  ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */
+  ai->ai_addrlen = (curl_socklen_t)
+    ((offsetof(struct sockaddr_un, sun_path) + path_len) & 0x7FFFFFFF);
+
+  /* Abstract Unix domain socket have NULL prefix instead of suffix */
+  if(abstract)
+    memcpy(sa_un->sun_path + 1, path, path_len - 1);
+  else
+    memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */
+
+  return ai;
+}
+#endif
+
+#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) &&  \
+  defined(HAVE_FREEADDRINFO)
+/*
+ * curl_dbg_freeaddrinfo()
+ *
+ * This is strictly for memory tracing and are using the same style as the
+ * family otherwise present in memdebug.c. I put these ones here since they
+ * require a bunch of structs I didn't want to include in memdebug.c
+ */
+
+void
+curl_dbg_freeaddrinfo(struct addrinfo *freethis,
+                      int line, const char *source)
+{
+  curl_dbg_log("ADDR %s:%d freeaddrinfo(%p)\n",
+               source, line, (void *)freethis);
+#ifdef USE_LWIPSOCK
+  lwip_freeaddrinfo(freethis);
+#else
+  (freeaddrinfo)(freethis);
+#endif
+}
+#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
+
+
+#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
+/*
+ * curl_dbg_getaddrinfo()
+ *
+ * This is strictly for memory tracing and are using the same style as the
+ * family otherwise present in memdebug.c. I put these ones here since they
+ * require a bunch of structs I didn't want to include in memdebug.c
+ */
+
+int
+curl_dbg_getaddrinfo(const char *hostname,
+                    const char *service,
+                    const struct addrinfo *hints,
+                    struct addrinfo **result,
+                    int line, const char *source)
+{
+#ifdef USE_LWIPSOCK
+  int res = lwip_getaddrinfo(hostname, service, hints, result);
+#else
+  int res = (getaddrinfo)(hostname, service, hints, result);
+#endif
+  if(0 == res)
+    /* success */
+    curl_dbg_log("ADDR %s:%d getaddrinfo() = %p\n",
+                 source, line, (void *)*result);
+  else
+    curl_dbg_log("ADDR %s:%d getaddrinfo() failed\n",
+                 source, line);
+  return res;
+}
+#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
+
+#if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS)
+/*
+ * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X
+ * 10.11.5.
+ */
+void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)
+{
+  struct Curl_addrinfo *ca;
+  struct sockaddr_in *addr;
+#ifdef ENABLE_IPV6
+  struct sockaddr_in6 *addr6;
+#endif
+  for(ca = addrinfo; ca != NULL; ca = ca->ai_next) {
+    switch(ca->ai_family) {
+    case AF_INET:
+      addr = (void *)ca->ai_addr; /* storage area for this info */
+      addr->sin_port = htons((unsigned short)port);
+      break;
+
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+      addr6 = (void *)ca->ai_addr; /* storage area for this info */
+      addr6->sin6_port = htons((unsigned short)port);
+      break;
+#endif
+    }
+  }
+}
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/curl_addrinfo.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_addrinfo.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_addrinfo.h	(revision 104083)
@@ -0,0 +1,108 @@
+#ifndef HEADER_CURL_ADDRINFO_H
+#define HEADER_CURL_ADDRINFO_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#  include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#  include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#  include <arpa/inet.h>
+#endif
+
+#ifdef __VMS
+#  include <in.h>
+#  include <inet.h>
+#  include <stdlib.h>
+#endif
+
+/*
+ * Curl_addrinfo is our internal struct definition that we use to allow
+ * consistent internal handling of this data. We use this even when the
+ * system provides an addrinfo structure definition. And we use this for
+ * all sorts of IPv4 and IPV6 builds.
+ */
+
+struct Curl_addrinfo {
+  int                   ai_flags;
+  int                   ai_family;
+  int                   ai_socktype;
+  int                   ai_protocol;
+  curl_socklen_t        ai_addrlen;   /* Follow rfc3493 struct addrinfo */
+  char                 *ai_canonname;
+  struct sockaddr      *ai_addr;
+  struct Curl_addrinfo *ai_next;
+};
+
+void
+Curl_freeaddrinfo(struct Curl_addrinfo *cahead);
+
+#ifdef HAVE_GETADDRINFO
+int
+Curl_getaddrinfo_ex(const char *nodename,
+                    const char *servname,
+                    const struct addrinfo *hints,
+                    struct Curl_addrinfo **result);
+#endif
+
+struct Curl_addrinfo *
+Curl_he2ai(const struct hostent *he, int port);
+
+struct Curl_addrinfo *
+Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port);
+
+struct Curl_addrinfo *Curl_str2addr(char *dotted, int port);
+
+#ifdef USE_UNIX_SOCKETS
+struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
+                                     bool abstract);
+#endif
+
+#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \
+    defined(HAVE_FREEADDRINFO)
+void
+curl_dbg_freeaddrinfo(struct addrinfo *freethis, int line, const char *source);
+#endif
+
+#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
+int
+curl_dbg_getaddrinfo(const char *hostname, const char *service,
+                     const struct addrinfo *hints, struct addrinfo **result,
+                     int line, const char *source);
+#endif
+
+#ifdef HAVE_GETADDRINFO
+#ifdef USE_RESOLVE_ON_IPS
+void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port);
+#else
+#define Curl_addrinfo_set_port(x,y)
+#endif
+#endif
+
+#endif /* HEADER_CURL_ADDRINFO_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_base64.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_base64.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_base64.h	(revision 104083)
@@ -0,0 +1,41 @@
+#ifndef HEADER_CURL_BASE64_H
+#define HEADER_CURL_BASE64_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifndef BUILDING_LIBCURL
+/* this renames functions so that the tool code can use the same code
+   without getting symbol collisions */
+#define Curl_base64_encode(a,b,c,d) curlx_base64_encode(a,b,c,d)
+#define Curl_base64url_encode(a,b,c,d) curlx_base64url_encode(a,b,c,d)
+#define Curl_base64_decode(a,b,c) curlx_base64_decode(a,b,c)
+#endif
+
+CURLcode Curl_base64_encode(const char *inputbuff, size_t insize,
+                            char **outptr, size_t *outlen);
+CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize,
+                               char **outptr, size_t *outlen);
+CURLcode Curl_base64_decode(const char *src,
+                            unsigned char **outptr, size_t *outlen);
+#endif /* HEADER_CURL_BASE64_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_config.h.cmake
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_config.h.cmake	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_config.h.cmake	(revision 104083)
@@ -0,0 +1,798 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+/* lib/curl_config.h.in.  Generated somehow by cmake.  */
+
+/* Location of default ca bundle */
+#cmakedefine CURL_CA_BUNDLE "${CURL_CA_BUNDLE}"
+
+/* define "1" to use built-in ca store of TLS backend */
+#cmakedefine CURL_CA_FALLBACK 1
+
+/* Location of default ca path */
+#cmakedefine CURL_CA_PATH "${CURL_CA_PATH}"
+
+/* Default SSL backend */
+#cmakedefine CURL_DEFAULT_SSL_BACKEND "${CURL_DEFAULT_SSL_BACKEND}"
+
+/* disables alt-svc */
+#cmakedefine CURL_DISABLE_ALTSVC 1
+
+/* disables cookies support */
+#cmakedefine CURL_DISABLE_COOKIES 1
+
+/* disables Basic authentication */
+#cmakedefine CURL_DISABLE_BASIC_AUTH 1
+
+/* disables Bearer authentication */
+#cmakedefine CURL_DISABLE_BEARER_AUTH 1
+
+/* disables Digest authentication */
+#cmakedefine CURL_DISABLE_DIGEST_AUTH 1
+
+/* disables Kerberos authentication */
+#cmakedefine CURL_DISABLE_KERBEROS_AUTH 1
+
+/* disables negotiate authentication */
+#cmakedefine CURL_DISABLE_NEGOTIATE_AUTH 1
+
+/* disables AWS-SIG4 */
+#cmakedefine CURL_DISABLE_AWS 1
+
+/* disables DICT */
+#cmakedefine CURL_DISABLE_DICT 1
+
+/* disables DNS-over-HTTPS */
+#cmakedefine CURL_DISABLE_DOH 1
+
+/* disables FILE */
+#cmakedefine CURL_DISABLE_FILE 1
+
+/* disables form api */
+#cmakedefine CURL_DISABLE_FORM_API 1
+
+/* disables FTP */
+#cmakedefine CURL_DISABLE_FTP 1
+
+/* disables curl_easy_options API for existing options to curl_easy_setopt */
+#cmakedefine CURL_DISABLE_GETOPTIONS 1
+
+/* disables GOPHER */
+#cmakedefine CURL_DISABLE_GOPHER 1
+
+/* disables headers-api support */
+#cmakedefine CURL_DISABLE_HEADERS_API 1
+
+/* disables HSTS support */
+#cmakedefine CURL_DISABLE_HSTS 1
+
+/* disables HTTP */
+#cmakedefine CURL_DISABLE_HTTP 1
+
+/* disables IMAP */
+#cmakedefine CURL_DISABLE_IMAP 1
+
+/* disables LDAP */
+#cmakedefine CURL_DISABLE_LDAP 1
+
+/* disables LDAPS */
+#cmakedefine CURL_DISABLE_LDAPS 1
+
+/* disables --libcurl option from the curl tool */
+#cmakedefine CURL_DISABLE_LIBCURL_OPTION 1
+
+/* disables MIME support */
+#cmakedefine CURL_DISABLE_MIME 1
+
+/* disables local binding support */
+#cmakedefine CURL_DISABLE_BINDLOCAL 1
+
+/* disables MQTT */
+#cmakedefine CURL_DISABLE_MQTT 1
+
+/* disables netrc parser */
+#cmakedefine CURL_DISABLE_NETRC 1
+
+/* disables NTLM support */
+#cmakedefine CURL_DISABLE_NTLM 1
+
+/* disables date parsing */
+#cmakedefine CURL_DISABLE_PARSEDATE 1
+
+/* disables POP3 */
+#cmakedefine CURL_DISABLE_POP3 1
+
+/* disables built-in progress meter */
+#cmakedefine CURL_DISABLE_PROGRESS_METER 1
+
+/* disables proxies */
+#cmakedefine CURL_DISABLE_PROXY 1
+
+/* disables RTSP */
+#cmakedefine CURL_DISABLE_RTSP 1
+
+/* disables SMB */
+#cmakedefine CURL_DISABLE_SMB 1
+
+/* disables SMTP */
+#cmakedefine CURL_DISABLE_SMTP 1
+
+/* disables use of socketpair for curl_multi_poll */
+#cmakedefine CURL_DISABLE_SOCKETPAIR 1
+
+/* disables TELNET */
+#cmakedefine CURL_DISABLE_TELNET 1
+
+/* disables TFTP */
+#cmakedefine CURL_DISABLE_TFTP 1
+
+/* disables verbose strings */
+#cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1
+
+/* to make a symbol visible */
+#cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL}
+/* Ensure using CURL_EXTERN_SYMBOL is possible */
+#ifndef CURL_EXTERN_SYMBOL
+#define CURL_EXTERN_SYMBOL
+#endif
+
+/* Allow SMB to work on Windows */
+#cmakedefine USE_WIN32_CRYPTO 1
+
+/* Use Windows LDAP implementation */
+#cmakedefine USE_WIN32_LDAP 1
+
+/* Define if you want to enable IPv6 support */
+#cmakedefine ENABLE_IPV6 1
+
+/* Define to 1 if you have the alarm function. */
+#cmakedefine HAVE_ALARM 1
+
+/* Define to 1 if you have the arc4random function. */
+#cmakedefine HAVE_ARC4RANDOM 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#cmakedefine HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have _Atomic support. */
+#cmakedefine HAVE_ATOMIC 1
+
+/* Define to 1 if you have the `fnmatch' function. */
+#cmakedefine HAVE_FNMATCH 1
+
+/* Define to 1 if you have the `basename' function. */
+#cmakedefine HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#cmakedefine HAVE_BOOL_T 1
+
+/* Define to 1 if you have the __builtin_available function. */
+#cmakedefine HAVE_BUILTIN_AVAILABLE 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the clock_gettime function and raw monotonic timer.
+   */
+#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC_RAW 1
+
+/* Define to 1 if you have the `closesocket' function. */
+#cmakedefine HAVE_CLOSESOCKET 1
+
+/* Define to 1 if you have the fcntl function. */
+#cmakedefine HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#cmakedefine HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#cmakedefine HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#cmakedefine HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the fseeko function. */
+#cmakedefine HAVE_FSEEKO 1
+
+/* Define to 1 if you have the fseeko declaration. */
+#cmakedefine HAVE_DECL_FSEEKO 1
+
+/* Define to 1 if you have the _fseeki64 function. */
+#cmakedefine HAVE__FSEEKI64 1
+
+/* Define to 1 if you have the ftruncate function. */
+#cmakedefine HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#cmakedefine HAVE_GETADDRINFO 1
+
+/* Define to 1 if the getaddrinfo function is threadsafe. */
+#cmakedefine HAVE_GETADDRINFO_THREADSAFE 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#cmakedefine HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getppid' function. */
+#cmakedefine HAVE_GETPPID 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#cmakedefine HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+#cmakedefine HAVE_GETHOSTBYNAME_R_3 1
+
+/* gethostbyname_r() takes 5 args */
+#cmakedefine HAVE_GETHOSTBYNAME_R_5 1
+
+/* gethostbyname_r() takes 6 args */
+#cmakedefine HAVE_GETHOSTBYNAME_R_6 1
+
+/* Define to 1 if you have the gethostname function. */
+#cmakedefine HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+#cmakedefine HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+#cmakedefine HAVE_GETPASS_R 1
+
+/* Define to 1 if you have the `getpeername' function. */
+#cmakedefine HAVE_GETPEERNAME 1
+
+/* Define to 1 if you have the `getsockname' function. */
+#cmakedefine HAVE_GETSOCKNAME 1
+
+/* Define to 1 if you have the `if_nametoindex' function. */
+#cmakedefine HAVE_IF_NAMETOINDEX 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#cmakedefine HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getpwuid_r' function. */
+#cmakedefine HAVE_GETPWUID_R 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#cmakedefine HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#cmakedefine HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+#cmakedefine HAVE_GLIBC_STRERROR_R 1
+
+/* Define to 1 if you have a working gmtime_r function. */
+#cmakedefine HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+#cmakedefine HAVE_GSSAPI 1
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+#cmakedefine HAVE_GSSAPI_GSSAPI_GENERIC_H 1
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#cmakedefine HAVE_GSSAPI_GSSAPI_H 1
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+#cmakedefine HAVE_GSSAPI_GSSAPI_KRB5_H 1
+
+/* if you have the GNU gssapi libraries */
+#cmakedefine HAVE_GSSGNU 1
+
+/* Define to 1 if you have the `idna_strerror' function. */
+#cmakedefine HAVE_IDNA_STRERROR 1
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#cmakedefine HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#cmakedefine HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#cmakedefine HAVE_INET_PTON 1
+
+/* Define to 1 if symbol `sa_family_t' exists */
+#cmakedefine HAVE_SA_FAMILY_T 1
+
+/* Define to 1 if symbol `ADDRESS_FAMILY' exists */
+#cmakedefine HAVE_ADDRESS_FAMILY 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+#cmakedefine HAVE_IOCTLSOCKET 1
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+#cmakedefine HAVE_IOCTLSOCKET_CAMEL 1
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+#cmakedefine HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+#cmakedefine HAVE_IOCTLSOCKET_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#cmakedefine HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#cmakedefine HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+#cmakedefine HAVE_IO_H 1
+
+/* Define to 1 if you have the lber.h header file. */
+#cmakedefine HAVE_LBER_H 1
+
+/* Define to 1 if you have the ldap.h header file. */
+#cmakedefine HAVE_LDAP_H 1
+
+/* Use LDAPS implementation */
+#cmakedefine HAVE_LDAP_SSL 1
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+#cmakedefine HAVE_LDAP_SSL_H 1
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+#cmakedefine HAVE_LDAP_URL_PARSE 1
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#cmakedefine HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn2' library (-lidn2). */
+#cmakedefine HAVE_LIBIDN2 1
+
+/* Define to 1 if you have the idn2.h header file. */
+#cmakedefine HAVE_IDN2_H 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#cmakedefine HAVE_LIBSOCKET 1
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+#cmakedefine HAVE_LIBSSH2 1
+
+/* if zlib is available */
+#cmakedefine HAVE_LIBZ 1
+
+/* if brotli is available */
+#cmakedefine HAVE_BROTLI 1
+
+/* if zstd is available */
+#cmakedefine HAVE_ZSTD 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#cmakedefine HAVE_LOCALE_H 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#cmakedefine HAVE_LONGLONG 1
+
+/* Define to 1 if you have the 'suseconds_t' data type. */
+#cmakedefine HAVE_SUSECONDS_T 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#cmakedefine HAVE_MSG_NOSIGNAL 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#cmakedefine HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#cmakedefine HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#cmakedefine HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <netinet/udp.h> header file. */
+#cmakedefine HAVE_NETINET_UDP_H 1
+
+/* Define to 1 if you have the <linux/tcp.h> header file. */
+#cmakedefine HAVE_LINUX_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#cmakedefine HAVE_NET_IF_H 1
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */
+#cmakedefine HAVE_OLD_GSSMIT 1
+
+/* Define to 1 if you have the `pipe' function. */
+#cmakedefine HAVE_PIPE 1
+
+/* If you have a fine poll */
+#cmakedefine HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#cmakedefine HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#cmakedefine HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pthread.h> header file */
+#cmakedefine HAVE_PTHREAD_H 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#cmakedefine HAVE_PWD_H 1
+
+/* Define to 1 if OpenSSL has the `SSL_set0_wbio` function. */
+#cmakedefine HAVE_SSL_SET0_WBIO 1
+
+/* Define to 1 if you have the recv function. */
+#cmakedefine HAVE_RECV 1
+
+/* Define to 1 if you have the select function. */
+#cmakedefine HAVE_SELECT 1
+
+/* Define to 1 if you have the sched_yield function. */
+#cmakedefine HAVE_SCHED_YIELD 1
+
+/* Define to 1 if you have the send function. */
+#cmakedefine HAVE_SEND 1
+
+/* Define to 1 if you have the sendmsg function. */
+#cmakedefine HAVE_SENDMSG 1
+
+/* Define to 1 if you have the 'fsetxattr' function. */
+#cmakedefine HAVE_FSETXATTR 1
+
+/* fsetxattr() takes 5 args */
+#cmakedefine HAVE_FSETXATTR_5 1
+
+/* fsetxattr() takes 6 args */
+#cmakedefine HAVE_FSETXATTR_6 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#cmakedefine HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+#cmakedefine HAVE_SETMODE 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#cmakedefine HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+#cmakedefine HAVE_SETSOCKOPT_SO_NONBLOCK 1
+
+/* Define to 1 if you have the sigaction function. */
+#cmakedefine HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#cmakedefine HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#cmakedefine HAVE_SIGNAL 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#cmakedefine HAVE_SIGSETJMP 1
+
+/* Define to 1 if you have the `snprintf' function. */
+#cmakedefine HAVE_SNPRINTF 1
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#cmakedefine HAVE_SOCKET 1
+
+/* Define to 1 if you have the socketpair function. */
+#cmakedefine HAVE_SOCKETPAIR 1
+
+/* Define to 1 if you have the <stdatomic.h> header file. */
+#cmakedefine HAVE_STDATOMIC_H 1
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#cmakedefine HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#cmakedefine HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcmpi function. */
+#cmakedefine HAVE_STRCMPI 1
+
+/* Define to 1 if you have the strdup function. */
+#cmakedefine HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#cmakedefine HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+#cmakedefine HAVE_STRICMP 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#cmakedefine HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#cmakedefine HAVE_STROPTS_H 1
+
+/* Define to 1 if you have the strtok_r function. */
+#cmakedefine HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#cmakedefine HAVE_STRTOLL 1
+
+/* Define to 1 if you have the memrchr function. */
+#cmakedefine HAVE_MEMRCHR 1
+
+/* if struct sockaddr_storage is defined */
+#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#cmakedefine HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#cmakedefine HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#cmakedefine HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#cmakedefine HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#cmakedefine HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#cmakedefine HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#cmakedefine HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#cmakedefine HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#cmakedefine HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#cmakedefine HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#cmakedefine HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#cmakedefine HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#cmakedefine HAVE_SYS_UTIME_H 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#cmakedefine HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+#cmakedefine HAVE_TERMIO_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#cmakedefine HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+#cmakedefine HAVE_UTIMES 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#cmakedefine HAVE_UTIME_H 1
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#cmakedefine HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+#cmakedefine NEED_LBER_H 1
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+#cmakedefine NEED_MALLOC_H 1
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+#cmakedefine NEED_REENTRANT 1
+
+/* cpu-machine-OS */
+#cmakedefine OS ${OS}
+
+/* Name of package */
+#cmakedefine PACKAGE ${PACKAGE}
+
+/* Define to the address where bug reports for this package should be sent. */
+#cmakedefine PACKAGE_BUGREPORT ${PACKAGE_BUGREPORT}
+
+/* Define to the full name of this package. */
+#cmakedefine PACKAGE_NAME ${PACKAGE_NAME}
+
+/* Define to the full name and version of this package. */
+#cmakedefine PACKAGE_STRING ${PACKAGE_STRING}
+
+/* Define to the one symbol short name of this package. */
+#cmakedefine PACKAGE_TARNAME ${PACKAGE_TARNAME}
+
+/* Define to the version of this package. */
+#cmakedefine PACKAGE_VERSION ${PACKAGE_VERSION}
+
+/* a suitable file to read random data from */
+#cmakedefine RANDOM_FILE "${RANDOM_FILE}"
+
+/*
+ Note: SIZEOF_* variables are fetched with CMake through check_type_size().
+ As per CMake documentation on CheckTypeSize, C preprocessor code is
+ generated by CMake into SIZEOF_*_CODE. This is what we use in the
+ following statements.
+
+ Reference: https://cmake.org/cmake/help/latest/module/CheckTypeSize.html
+*/
+
+/* The size of `int', as computed by sizeof. */
+${SIZEOF_INT_CODE}
+
+/* The size of `long', as computed by sizeof. */
+${SIZEOF_LONG_CODE}
+
+/* The size of `long long', as computed by sizeof. */
+${SIZEOF_LONG_LONG_CODE}
+
+/* The size of `off_t', as computed by sizeof. */
+${SIZEOF_OFF_T_CODE}
+
+/* The size of `curl_off_t', as computed by sizeof. */
+${SIZEOF_CURL_OFF_T_CODE}
+
+/* The size of `curl_socket_t', as computed by sizeof. */
+${SIZEOF_CURL_SOCKET_T_CODE}
+
+/* The size of `size_t', as computed by sizeof. */
+${SIZEOF_SIZE_T_CODE}
+
+/* The size of `time_t', as computed by sizeof. */
+${SIZEOF_TIME_T_CODE}
+
+/* Define to 1 if you have the ANSI C header files. */
+#cmakedefine STDC_HEADERS 1
+
+/* Define if you want to enable c-ares support */
+#cmakedefine USE_ARES 1
+
+/* Define if you want to enable POSIX threaded DNS lookup */
+#cmakedefine USE_THREADS_POSIX 1
+
+/* Define if you want to enable WIN32 threaded DNS lookup */
+#cmakedefine USE_THREADS_WIN32 1
+
+/* if GnuTLS is enabled */
+#cmakedefine USE_GNUTLS 1
+
+/* if Secure Transport is enabled */
+#cmakedefine USE_SECTRANSP 1
+
+/* if mbedTLS is enabled */
+#cmakedefine USE_MBEDTLS 1
+
+/* if BearSSL is enabled */
+#cmakedefine USE_BEARSSL 1
+
+/* if WolfSSL is enabled */
+#cmakedefine USE_WOLFSSL 1
+
+/* if libSSH is in use */
+#cmakedefine USE_LIBSSH 1
+
+/* if libSSH2 is in use */
+#cmakedefine USE_LIBSSH2 1
+
+/* if libPSL is in use */
+#cmakedefine USE_LIBPSL 1
+
+/* if you want to use OpenLDAP code instead of legacy ldap implementation */
+#cmakedefine USE_OPENLDAP 1
+
+/* if OpenSSL is in use */
+#cmakedefine USE_OPENSSL 1
+
+/* Define to 1 if you don't want the OpenSSL configuration to be loaded
+   automatically */
+#cmakedefine CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG 1
+
+/* to enable NGHTTP2  */
+#cmakedefine USE_NGHTTP2 1
+
+/* to enable NGTCP2 */
+#cmakedefine USE_NGTCP2 1
+
+/* to enable NGHTTP3  */
+#cmakedefine USE_NGHTTP3 1
+
+/* to enable quiche */
+#cmakedefine USE_QUICHE 1
+
+/* to enable openssl + nghttp3 */
+#cmakedefine USE_OPENSSL_QUIC 1
+
+/* Define to 1 if you have the quiche_conn_set_qlog_fd function. */
+#cmakedefine HAVE_QUICHE_CONN_SET_QLOG_FD 1
+
+/* to enable msh3 */
+#cmakedefine USE_MSH3 1
+
+/* if Unix domain sockets are enabled  */
+#cmakedefine USE_UNIX_SOCKETS 1
+
+/* Define to 1 if you are building a Windows target with large file support. */
+#cmakedefine USE_WIN32_LARGE_FILES 1
+
+/* to enable SSPI support */
+#cmakedefine USE_WINDOWS_SSPI 1
+
+/* to enable Windows SSL  */
+#cmakedefine USE_SCHANNEL 1
+
+/* enable multiple SSL backends */
+#cmakedefine CURL_WITH_MULTI_SSL 1
+
+/* Version number of package */
+#cmakedefine VERSION ${VERSION}
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+#  undef _ALL_SOURCE
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
+
+/* Define for large files, on AIX-style hosts. */
+#cmakedefine _LARGE_FILES ${_LARGE_FILES}
+
+/* define this if you need it to compile thread-safe code */
+#cmakedefine _THREAD_SAFE ${_THREAD_SAFE}
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#cmakedefine const ${const}
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+#cmakedefine in_addr_t ${in_addr_t}
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#cmakedefine size_t ${size_t}
+
+/* the signed version of size_t */
+#cmakedefine ssize_t ${ssize_t}
+
+/* Define to 1 if you have the mach_absolute_time function. */
+#cmakedefine HAVE_MACH_ABSOLUTE_TIME 1
+
+/* to enable Windows IDN */
+#cmakedefine USE_WIN32_IDN 1
+
+/* Define to 1 to enable websocket support. */
+#cmakedefine USE_WEBSOCKETS 1
+
+/* Define to 1 if OpenSSL has the SSL_CTX_set_srp_username function. */
+#cmakedefine HAVE_OPENSSL_SRP 1
+
+/* Define to 1 if GnuTLS has the gnutls_srp_verifier function. */
+#cmakedefine HAVE_GNUTLS_SRP 1
+
+/* Define to 1 to enable TLS-SRP support. */
+#cmakedefine USE_TLS_SRP 1
Index: trunk/src/libs/curl-8.7.1/lib/curl_config.h.in
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_config.h.in	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_config.h.in	(revision 104083)
@@ -0,0 +1,995 @@
+/* lib/curl_config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* to enable curl debug memory tracking */
+#undef CURLDEBUG
+
+/* Location of default ca bundle */
+#undef CURL_CA_BUNDLE
+
+/* define "1" to use built in CA store of SSL library */
+#undef CURL_CA_FALLBACK
+
+/* Location of default ca path */
+#undef CURL_CA_PATH
+
+/* Default SSL backend */
+#undef CURL_DEFAULT_SSL_BACKEND
+
+/* disable alt-svc */
+#undef CURL_DISABLE_ALTSVC
+
+/* to disable AWS sig support */
+#undef CURL_DISABLE_AWS
+
+/* to disable basic authentication */
+#undef CURL_DISABLE_BASIC_AUTH
+
+/* to disable bearer authentication */
+#undef CURL_DISABLE_BEARER_AUTH
+
+/* disable local binding support */
+#undef CURL_DISABLE_BINDLOCAL
+
+/* to disable cookies support */
+#undef CURL_DISABLE_COOKIES
+
+/* to disable DICT */
+#undef CURL_DISABLE_DICT
+
+/* to disable digest authentication */
+#undef CURL_DISABLE_DIGEST_AUTH
+
+/* disable DoH */
+#undef CURL_DISABLE_DOH
+
+/* to disable FILE */
+#undef CURL_DISABLE_FILE
+
+/* disable form API */
+#undef CURL_DISABLE_FORM_API
+
+/* to disable FTP */
+#undef CURL_DISABLE_FTP
+
+/* to disable curl_easy_options */
+#undef CURL_DISABLE_GETOPTIONS
+
+/* to disable Gopher */
+#undef CURL_DISABLE_GOPHER
+
+/* disable headers-api */
+#undef CURL_DISABLE_HEADERS_API
+
+/* disable alt-svc */
+#undef CURL_DISABLE_HSTS
+
+/* to disable HTTP */
+#undef CURL_DISABLE_HTTP
+
+/* disable HTTP authentication */
+#undef CURL_DISABLE_HTTP_AUTH
+
+/* to disable IMAP */
+#undef CURL_DISABLE_IMAP
+
+/* to disable kerberos authentication */
+#undef CURL_DISABLE_KERBEROS_AUTH
+
+/* to disable LDAP */
+#undef CURL_DISABLE_LDAP
+
+/* to disable LDAPS */
+#undef CURL_DISABLE_LDAPS
+
+/* to disable --libcurl C code generation option */
+#undef CURL_DISABLE_LIBCURL_OPTION
+
+/* disable mime API */
+#undef CURL_DISABLE_MIME
+
+/* to disable MQTT */
+#undef CURL_DISABLE_MQTT
+
+/* to disable negotiate authentication */
+#undef CURL_DISABLE_NEGOTIATE_AUTH
+
+/* disable netrc parsing */
+#undef CURL_DISABLE_NETRC
+
+/* to disable NTLM support */
+#undef CURL_DISABLE_NTLM
+
+/* if the OpenSSL configuration won't be loaded automatically */
+#undef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG
+
+/* disable date parsing */
+#undef CURL_DISABLE_PARSEDATE
+
+/* to disable POP3 */
+#undef CURL_DISABLE_POP3
+
+/* disable progress-meter */
+#undef CURL_DISABLE_PROGRESS_METER
+
+/* to disable proxies */
+#undef CURL_DISABLE_PROXY
+
+/* to disable RTSP */
+#undef CURL_DISABLE_RTSP
+
+/* disable DNS shuffling */
+#undef CURL_DISABLE_SHUFFLE_DNS
+
+/* to disable SMB/CIFS */
+#undef CURL_DISABLE_SMB
+
+/* to disable SMTP */
+#undef CURL_DISABLE_SMTP
+
+/* to disable socketpair support */
+#undef CURL_DISABLE_SOCKETPAIR
+
+/* to disable TELNET */
+#undef CURL_DISABLE_TELNET
+
+/* to disable TFTP */
+#undef CURL_DISABLE_TFTP
+
+/* to disable verbose strings */
+#undef CURL_DISABLE_VERBOSE_STRINGS
+
+/* Definition to make a library symbol externally visible. */
+#undef CURL_EXTERN_SYMBOL
+
+/* IP address type in sockaddr */
+#undef CURL_SA_FAMILY_T
+
+/* built with multiple SSL backends */
+#undef CURL_WITH_MULTI_SSL
+
+/* enable debug build options */
+#undef DEBUGBUILD
+
+/* Define if you want to enable IPv6 support */
+#undef ENABLE_IPV6
+
+/* Define to the type of arg 2 for gethostname. */
+#undef GETHOSTNAME_TYPE_ARG2
+
+/* Define to 1 if you have the alarm function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have the `arc4random' function. */
+#undef HAVE_ARC4RANDOM
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have _Atomic support. */
+#undef HAVE_ATOMIC
+
+/* Define to 1 if you have the basename function. */
+#undef HAVE_BASENAME
+
+/* Define to 1 if bool is an available type. */
+#undef HAVE_BOOL_T
+
+/* if BROTLI is in use */
+#undef HAVE_BROTLI
+
+/* Define to 1 if you have the <brotli/decode.h> header file. */
+#undef HAVE_BROTLI_DECODE_H
+
+/* Define to 1 if you have the __builtin_available function. */
+#undef HAVE_BUILTIN_AVAILABLE
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#undef HAVE_CLOCK_GETTIME_MONOTONIC
+
+/* Define to 1 if you have the clock_gettime function and raw monotonic timer.
+   */
+#undef HAVE_CLOCK_GETTIME_MONOTONIC_RAW
+
+/* Define to 1 if you have the closesocket function. */
+#undef HAVE_CLOSESOCKET
+
+/* Define to 1 if you have the CloseSocket camel case function. */
+#undef HAVE_CLOSESOCKET_CAMEL
+
+/* Define to 1 if you have the <crypto.h> header file. */
+#undef HAVE_CRYPTO_H
+
+/* Define to 1 if you have the fseeko declaration */
+#undef HAVE_DECL_FSEEKO
+
+/* Define to 1 if you have the declaration of `getpwuid_r', and to 0 if you
+   don't. */
+#undef HAVE_DECL_GETPWUID_R
+
+/* "Set if getpwuid_r() declaration is missing" */
+#undef HAVE_DECL_GETPWUID_R_MISSING
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <err.h> header file. */
+#undef HAVE_ERR_H
+
+/* Define to 1 if you have the fcntl function. */
+#undef HAVE_FCNTL
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#undef HAVE_FCNTL_O_NONBLOCK
+
+/* Define to 1 if you have the `fnmatch' function. */
+#undef HAVE_FNMATCH
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#undef HAVE_FREEADDRINFO
+
+/* Define to 1 if you have the `fseeko' function. */
+#undef HAVE_FSEEKO
+
+/* Define to 1 if you have the fsetxattr function. */
+#undef HAVE_FSETXATTR
+
+/* fsetxattr() takes 5 args */
+#undef HAVE_FSETXATTR_5
+
+/* fsetxattr() takes 6 args */
+#undef HAVE_FSETXATTR_6
+
+/* Define to 1 if you have the ftruncate function. */
+#undef HAVE_FTRUNCATE
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if the getaddrinfo function is threadsafe. */
+#undef HAVE_GETADDRINFO_THREADSAFE
+
+/* Define to 1 if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define to 1 if you have the gethostbyname function. */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#undef HAVE_GETHOSTBYNAME_R
+
+/* gethostbyname_r() takes 3 args */
+#undef HAVE_GETHOSTBYNAME_R_3
+
+/* gethostbyname_r() takes 5 args */
+#undef HAVE_GETHOSTBYNAME_R_5
+
+/* gethostbyname_r() takes 6 args */
+#undef HAVE_GETHOSTBYNAME_R_6
+
+/* Define to 1 if you have the gethostname function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have a working getifaddrs function. */
+#undef HAVE_GETIFADDRS
+
+/* Define to 1 if you have the `getpass_r' function. */
+#undef HAVE_GETPASS_R
+
+/* Define to 1 if you have the getpeername function. */
+#undef HAVE_GETPEERNAME
+
+/* Define to 1 if you have the `getppid' function. */
+#undef HAVE_GETPPID
+
+/* Define to 1 if you have the `getpwuid' function. */
+#undef HAVE_GETPWUID
+
+/* Define to 1 if you have the `getpwuid_r' function. */
+#undef HAVE_GETPWUID_R
+
+/* Define to 1 if you have the `getrlimit' function. */
+#undef HAVE_GETRLIMIT
+
+/* Define to 1 if you have the getsockname function. */
+#undef HAVE_GETSOCKNAME
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+#undef HAVE_GLIBC_STRERROR_R
+
+/* Define to 1 if you have a working gmtime_r function. */
+#undef HAVE_GMTIME_R
+
+/* if you have the function gnutls_srp_verifier */
+#undef HAVE_GNUTLS_SRP
+
+/* if you have GSS-API libraries */
+#undef HAVE_GSSAPI
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_GENERIC_H
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_H
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_KRB5_H
+
+/* if you have GNU GSS */
+#undef HAVE_GSSGNU
+
+/* Define to 1 if you have the <hyper.h> header file. */
+#undef HAVE_HYPER_H
+
+/* Define to 1 if you have the <idn2.h> header file. */
+#undef HAVE_IDN2_H
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#undef HAVE_IFADDRS_H
+
+/* Define to 1 if you have the `if_nametoindex' function. */
+#undef HAVE_IF_NAMETOINDEX
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#undef HAVE_INET_PTON
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the ioctl function. */
+#undef HAVE_IOCTL
+
+/* Define to 1 if you have the ioctlsocket function. */
+#undef HAVE_IOCTLSOCKET
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+#undef HAVE_IOCTLSOCKET_CAMEL
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+#undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+#undef HAVE_IOCTLSOCKET_FIONBIO
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#undef HAVE_IOCTL_FIONBIO
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#undef HAVE_IOCTL_SIOCGIFADDR
+
+/* Define to 1 if you have the <io.h> header file. */
+#undef HAVE_IO_H
+
+/* Define to 1 if you have the lber.h header file. */
+#undef HAVE_LBER_H
+
+/* Define to 1 if you have the ldap.h header file. */
+#undef HAVE_LDAP_H
+
+/* Define to 1 if you have the `ldap_init_fd' function. */
+#undef HAVE_LDAP_INIT_FD
+
+/* Use LDAPS implementation */
+#undef HAVE_LDAP_SSL
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+#undef HAVE_LDAP_SSL_H
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+#undef HAVE_LDAP_URL_PARSE
+
+/* Define to 1 if you have the `brotlidec' library (-lbrotlidec). */
+#undef HAVE_LIBBROTLIDEC
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#undef HAVE_LIBGEN_H
+
+/* Define to 1 if you have the `idn2' library (-lidn2). */
+#undef HAVE_LIBIDN2
+
+/* Define to 1 if you have the <libpsl.h> header file. */
+#undef HAVE_LIBPSL_H
+
+/* Define to 1 if using libressl. */
+#undef HAVE_LIBRESSL
+
+/* Define to 1 if you have the <librtmp/rtmp.h> header file. */
+#undef HAVE_LIBRTMP_RTMP_H
+
+/* Define to 1 if you have the `ssh' library (-lssh). */
+#undef HAVE_LIBSSH
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+#undef HAVE_LIBSSH2
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#undef HAVE_LIBSSL
+
+/* Define to 1 if you have the `wolfssh' library (-lwolfssh). */
+#undef HAVE_LIBWOLFSSH
+
+/* if zlib is available */
+#undef HAVE_LIBZ
+
+/* Define to 1 if you have the `zstd' library (-lzstd). */
+#undef HAVE_LIBZSTD
+
+/* Define to 1 if you have the <linux/tcp.h> header file. */
+#undef HAVE_LINUX_TCP_H
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#undef HAVE_LONGLONG
+
+/* Define to 1 if you have the `mach_absolute_time' function. */
+#undef HAVE_MACH_ABSOLUTE_TIME
+
+/* Define to 1 if you have the memrchr function or macro. */
+#undef HAVE_MEMRCHR
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#undef HAVE_MSG_NOSIGNAL
+
+/* Define to 1 if you have the <msh3.h> header file. */
+#undef HAVE_MSH3_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+#undef HAVE_NETINET_IN6_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* Define to 1 if you have the <netinet/udp.h> header file. */
+#undef HAVE_NETINET_UDP_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define to 1 if you have the <nghttp2/nghttp2.h> header file. */
+#undef HAVE_NGHTTP2_NGHTTP2_H
+
+/* Define to 1 if you have the <nghttp3/nghttp3.h> header file. */
+#undef HAVE_NGHTTP3_NGHTTP3_H
+
+/* Define to 1 if you have the <ngtcp2/ngtcp2_crypto.h> header file. */
+#undef HAVE_NGTCP2_NGTCP2_CRYPTO_H
+
+/* Define to 1 if you have the <ngtcp2/ngtcp2.h> header file. */
+#undef HAVE_NGTCP2_NGTCP2_H
+
+/* if you have an old MIT Kerberos version, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+#undef HAVE_OLD_GSSMIT
+
+/* Define to 1 if using OpenSSL 3 or later. */
+#undef HAVE_OPENSSL3
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+#undef HAVE_OPENSSL_CRYPTO_H
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+#undef HAVE_OPENSSL_ERR_H
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+#undef HAVE_OPENSSL_PEM_H
+
+/* if you have the functions OSSL_QUIC_client_method */
+#undef HAVE_OPENSSL_QUIC
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+#undef HAVE_OPENSSL_RSA_H
+
+/* if you have the functions SSL_CTX_set_srp_username and
+   SSL_CTX_set_srp_password */
+#undef HAVE_OPENSSL_SRP
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+#undef HAVE_OPENSSL_SSL_H
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+#undef HAVE_OPENSSL_X509_H
+
+/* Define to 1 if you have the <pem.h> header file. */
+#undef HAVE_PEM_H
+
+/* Define to 1 if you have the `pipe' function. */
+#undef HAVE_PIPE
+
+/* If you have a fine poll */
+#undef HAVE_POLL_FINE
+
+/* Define to 1 if you have the <poll.h> header file. */
+#undef HAVE_POLL_H
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#undef HAVE_POSIX_STRERROR_R
+
+/* Define to 1 if you have the <proto/bsdsocket.h> header file. */
+#undef HAVE_PROTO_BSDSOCKET_H
+
+/* if you have <pthread.h> */
+#undef HAVE_PTHREAD_H
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* Define to 1 if you have the `quiche_conn_set_qlog_fd' function. */
+#undef HAVE_QUICHE_CONN_SET_QLOG_FD
+
+/* Define to 1 if you have the <quiche.h> header file. */
+#undef HAVE_QUICHE_H
+
+/* Define to 1 if you have the recv function. */
+#undef HAVE_RECV
+
+/* Define to 1 if you have the <rsa.h> header file. */
+#undef HAVE_RSA_H
+
+/* Define to 1 if you have the `sched_yield' function. */
+#undef HAVE_SCHED_YIELD
+
+/* Define to 1 if you have the select function. */
+#undef HAVE_SELECT
+
+/* Define to 1 if you have the send function. */
+#undef HAVE_SEND
+
+/* Define to 1 if you have the `sendmsg' function. */
+#undef HAVE_SENDMSG
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#undef HAVE_SETJMP_H
+
+/* Define to 1 if you have the `setlocale' function. */
+#undef HAVE_SETLOCALE
+
+/* Define to 1 if you have the `setmode' function. */
+#undef HAVE_SETMODE
+
+/* Define to 1 if you have the `setrlimit' function. */
+#undef HAVE_SETRLIMIT
+
+/* Define to 1 if you have the sigaction function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the siginterrupt function. */
+#undef HAVE_SIGINTERRUPT
+
+/* Define to 1 if you have the signal function. */
+#undef HAVE_SIGNAL
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#undef HAVE_SIGSETJMP
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#undef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+
+/* Define to 1 if you have the socket function. */
+#undef HAVE_SOCKET
+
+/* Define to 1 if you have the socketpair function. */
+#undef HAVE_SOCKETPAIR
+
+/* Define to 1 if you have the <socket.h> header file. */
+#undef HAVE_SOCKET_H
+
+/* Define to 1 if you have the `SSL_get_ech_status' function. */
+#undef HAVE_SSL_GET_ECH_STATUS
+
+/* Define to 1 if you have the <ssl.h> header file. */
+#undef HAVE_SSL_H
+
+/* Define to 1 if you have the `SSL_set0_wbio' function. */
+#undef HAVE_SSL_SET0_WBIO
+
+/* Define to 1 if you have the `SSL_set_quic_use_legacy_codepoint' function.
+   */
+#undef HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT
+
+/* Define to 1 if you have the <stdatomic.h> header file. */
+#undef HAVE_STDATOMIC_H
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the strcasecmp function. */
+#undef HAVE_STRCASECMP
+
+/* Define to 1 if you have the strcmpi function. */
+#undef HAVE_STRCMPI
+
+/* Define to 1 if you have the strdup function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the strerror_r function. */
+#undef HAVE_STRERROR_R
+
+/* Define to 1 if you have the stricmp function. */
+#undef HAVE_STRICMP
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#undef HAVE_STROPTS_H
+
+/* Define to 1 if you have the strtok_r function. */
+#undef HAVE_STRTOK_R
+
+/* Define to 1 if you have the strtoll function. */
+#undef HAVE_STRTOLL
+
+/* if struct sockaddr_storage is defined */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE
+
+/* Define to 1 if you have the timeval struct. */
+#undef HAVE_STRUCT_TIMEVAL
+
+/* Define to 1 if suseconds_t is an available type. */
+#undef HAVE_SUSECONDS_T
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#undef HAVE_SYS_POLL_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#undef HAVE_SYS_UTIME_H
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the <sys/xattr.h> header file. */
+#undef HAVE_SYS_XATTR_H
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define this if time_t is unsigned */
+#undef HAVE_TIME_T_UNSIGNED
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `utime' function. */
+#undef HAVE_UTIME
+
+/* Define to 1 if you have the `utimes' function. */
+#undef HAVE_UTIMES
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if you have the <wolfssh/ssh.h> header file. */
+#undef HAVE_WOLFSSH_SSH_H
+
+/* if you have wolfSSL_DES_ecb_encrypt */
+#undef HAVE_WOLFSSL_DES_ECB_ENCRYPT
+
+/* if you have wolfSSL_BIO_set_shutdown */
+#undef HAVE_WOLFSSL_FULL_BIO
+
+/* Define to 1 if you have the `wolfSSL_get_peer_certificate' function. */
+#undef HAVE_WOLFSSL_GET_PEER_CERTIFICATE
+
+/* Define to 1 if you have the `wolfSSL_UseALPN' function. */
+#undef HAVE_WOLFSSL_USEALPN
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#undef HAVE_WRITABLE_ARGV
+
+/* Define to 1 if you have the <x509.h> header file. */
+#undef HAVE_X509_H
+
+/* if libzstd is in use */
+#undef HAVE_ZSTD
+
+/* Define to 1 if you have the <zstd.h> header file. */
+#undef HAVE_ZSTD_H
+
+/* Define to 1 if you have the `_fseeki64' function. */
+#undef HAVE__FSEEKI64
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+#undef NEED_LBER_H
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+#undef NEED_REENTRANT
+
+/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
+#undef NEED_THREAD_SAFE
+
+/* Define to enable NTLM delegation to winbind's ntlm_auth helper. */
+#undef NTLM_WB_ENABLED
+
+/* Define absolute filename for winbind's ntlm_auth helper. */
+#undef NTLM_WB_FILE
+
+/* cpu-machine-OS */
+#undef OS
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* a suitable file to read random data from */
+#undef RANDOM_FILE
+
+/* Size of curl_off_t in number of bytes */
+#undef SIZEOF_CURL_OFF_T
+
+/* Size of curl_socket_t in number of bytes */
+#undef SIZEOF_CURL_SOCKET_T
+
+/* Size of int in number of bytes */
+#undef SIZEOF_INT
+
+/* Size of long in number of bytes */
+#undef SIZEOF_LONG
+
+/* Size of long long in number of bytes */
+#undef SIZEOF_LONG_LONG
+
+/* Size of off_t in number of bytes */
+#undef SIZEOF_OFF_T
+
+/* Size of size_t in number of bytes */
+#undef SIZEOF_SIZE_T
+
+/* Size of time_t in number of bytes */
+#undef SIZEOF_TIME_T
+
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+   required in a freestanding environment). This macro is provided for
+   backward compatibility; new code need not use it. */
+#undef STDC_HEADERS
+
+/* if AmiSSL is in use */
+#undef USE_AMISSL
+
+/* Define to enable c-ares support */
+#undef USE_ARES
+
+/* if BearSSL is enabled */
+#undef USE_BEARSSL
+
+/* if ECH support is available */
+#undef USE_ECH
+
+/* if GnuTLS is enabled */
+#undef USE_GNUTLS
+
+/* GSASL support enabled */
+#undef USE_GSASL
+
+/* if hyper is in use */
+#undef USE_HYPER
+
+/* if libpsl is in use */
+#undef USE_LIBPSL
+
+/* if librtmp is in use */
+#undef USE_LIBRTMP
+
+/* if libSSH is in use */
+#undef USE_LIBSSH
+
+/* if libSSH2 is in use */
+#undef USE_LIBSSH2
+
+/* If you want to build curl with the built-in manual */
+#undef USE_MANUAL
+
+/* if mbedTLS is enabled */
+#undef USE_MBEDTLS
+
+/* if msh3 is in use */
+#undef USE_MSH3
+
+/* if nghttp2 is in use */
+#undef USE_NGHTTP2
+
+/* if nghttp3 is in use */
+#undef USE_NGHTTP3
+
+/* if ngtcp2 is in use */
+#undef USE_NGTCP2
+
+/* if ngtcp2_crypto_boringssl is in use */
+#undef USE_NGTCP2_CRYPTO_BORINGSSL
+
+/* if ngtcp2_crypto_gnutls is in use */
+#undef USE_NGTCP2_CRYPTO_GNUTLS
+
+/* if ngtcp2_crypto_quictls is in use */
+#undef USE_NGTCP2_CRYPTO_QUICTLS
+
+/* if ngtcp2_crypto_wolfssl is in use */
+#undef USE_NGTCP2_CRYPTO_WOLFSSL
+
+/* if ngtcp2 + nghttp3 is in use */
+#undef USE_NGTCP2_H3
+
+/* Use OpenLDAP-specific code */
+#undef USE_OPENLDAP
+
+/* if OpenSSL is in use */
+#undef USE_OPENSSL
+
+/* if openssl quic + nghttp3 is in use */
+#undef USE_OPENSSL_H3
+
+/* if openssl QUIC is in use */
+#undef USE_OPENSSL_QUIC
+
+/* if quiche is in use */
+#undef USE_QUICHE
+
+/* if rustls is enabled */
+#undef USE_RUSTLS
+
+/* to enable Windows native SSL/TLS support */
+#undef USE_SCHANNEL
+
+/* enable Secure Transport */
+#undef USE_SECTRANSP
+
+/* if you want POSIX threaded DNS lookup */
+#undef USE_THREADS_POSIX
+
+/* if you want Win32 threaded DNS lookup */
+#undef USE_THREADS_WIN32
+
+/* Use TLS-SRP authentication */
+#undef USE_TLS_SRP
+
+/* Use Unix domain sockets */
+#undef USE_UNIX_SOCKETS
+
+/* enable websockets support */
+#undef USE_WEBSOCKETS
+
+/* Define to 1 if you are building a Windows target with crypto API support.
+   */
+#undef USE_WIN32_CRYPTO
+
+/* Define to 1 if you have the `normaliz' (WinIDN) library (-lnormaliz). */
+#undef USE_WIN32_IDN
+
+/* Define to 1 if you are building a Windows target with large file support.
+   */
+#undef USE_WIN32_LARGE_FILES
+
+/* Use Windows LDAP implementation */
+#undef USE_WIN32_LDAP
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+#undef USE_WIN32_SMALL_FILES
+
+/* to enable SSPI support */
+#undef USE_WINDOWS_SSPI
+
+/* if wolfSSH is in use */
+#undef USE_WOLFSSH
+
+/* if wolfSSL is enabled */
+#undef USE_WOLFSSL
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+#  undef _ALL_SOURCE
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+#undef in_addr_t
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* the signed version of size_t */
+#undef ssize_t
Index: trunk/src/libs/curl-8.7.1/lib/curl_ctype.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_ctype.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_ctype.h	(revision 104083)
@@ -0,0 +1,51 @@
+#ifndef HEADER_CURL_CTYPE_H
+#define HEADER_CURL_CTYPE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#define ISLOWHEXALHA(x) (((x) >= 'a') && ((x) <= 'f'))
+#define ISUPHEXALHA(x) (((x) >= 'A') && ((x) <= 'F'))
+
+#define ISLOWCNTRL(x) ((unsigned char)(x) <= 0x1f)
+#define IS7F(x) ((x) == 0x7f)
+
+#define ISLOWPRINT(x) (((x) >= 9) && ((x) <= 0x0d))
+
+#define ISPRINT(x)  (ISLOWPRINT(x) || (((x) >= ' ') && ((x) <= 0x7e)))
+#define ISGRAPH(x)  (ISLOWPRINT(x) || (((x) > ' ') && ((x) <= 0x7e)))
+#define ISCNTRL(x) (ISLOWCNTRL(x) || IS7F(x))
+#define ISALPHA(x) (ISLOWER(x) || ISUPPER(x))
+#define ISXDIGIT(x) (ISDIGIT(x) || ISLOWHEXALHA(x) || ISUPHEXALHA(x))
+#define ISALNUM(x)  (ISDIGIT(x) || ISLOWER(x) || ISUPPER(x))
+#define ISUPPER(x)  (((x) >= 'A') && ((x) <= 'Z'))
+#define ISLOWER(x)  (((x) >= 'a') && ((x) <= 'z'))
+#define ISDIGIT(x)  (((x) >= '0') && ((x) <= '9'))
+#define ISBLANK(x)  (((x) == ' ') || ((x) == '\t'))
+#define ISSPACE(x)  (ISBLANK(x) || (((x) >= 0xa) && ((x) <= 0x0d)))
+#define ISURLPUNTCS(x) (((x) == '-') || ((x) == '.') || ((x) == '_') || \
+                        ((x) == '~'))
+#define ISUNRESERVED(x) (ISALNUM(x) || ISURLPUNTCS(x))
+
+
+#endif /* HEADER_CURL_CTYPE_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_des.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_des.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_des.c	(revision 104083)
@@ -0,0 +1,69 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) &&     \
+  (defined(USE_GNUTLS) ||                                       \
+   defined(USE_SECTRANSP) ||                                    \
+   defined(USE_OS400CRYPTO) ||                                  \
+   defined(USE_WIN32_CRYPTO))
+
+#include "curl_des.h"
+
+/*
+ * Curl_des_set_odd_parity()
+ *
+ * This is used to apply odd parity to the given byte array. It is typically
+ * used by when a cryptography engine doesn't have its own version.
+ *
+ * The function is a port of the Java based oddParity() function over at:
+ *
+ * https://davenport.sourceforge.net/ntlm.html
+ *
+ * Parameters:
+ *
+ * bytes       [in/out] - The data whose parity bits are to be adjusted for
+ *                        odd parity.
+ * len         [out]    - The length of the data.
+ */
+void Curl_des_set_odd_parity(unsigned char *bytes, size_t len)
+{
+  size_t i;
+
+  for(i = 0; i < len; i++) {
+    unsigned char b = bytes[i];
+
+    bool needs_parity = (((b >> 7) ^ (b >> 6) ^ (b >> 5) ^
+                          (b >> 4) ^ (b >> 3) ^ (b >> 2) ^
+                          (b >> 1)) & 0x01) == 0;
+
+    if(needs_parity)
+      bytes[i] |= 0x01;
+    else
+      bytes[i] &= 0xfe;
+  }
+}
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/curl_des.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_des.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_des.h	(revision 104083)
@@ -0,0 +1,40 @@
+#ifndef HEADER_CURL_DES_H
+#define HEADER_CURL_DES_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) &&     \
+  (defined(USE_GNUTLS) ||                                       \
+   defined(USE_SECTRANSP) ||                                    \
+   defined(USE_OS400CRYPTO) ||                                  \
+   defined(USE_WIN32_CRYPTO))
+
+/* Applies odd parity to the given byte array */
+void Curl_des_set_odd_parity(unsigned char *bytes, size_t length);
+
+#endif
+
+#endif /* HEADER_CURL_DES_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_endian.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_endian.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_endian.c	(revision 104083)
@@ -0,0 +1,84 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "curl_endian.h"
+
+/*
+ * Curl_read16_le()
+ *
+ * This function converts a 16-bit integer from the little endian format, as
+ * used in the incoming package to whatever endian format we're using
+ * natively.
+ *
+ * Parameters:
+ *
+ * buf      [in]     - A pointer to a 2 byte buffer.
+ *
+ * Returns the integer.
+ */
+unsigned short Curl_read16_le(const unsigned char *buf)
+{
+  return (unsigned short)(((unsigned short)buf[0]) |
+                          ((unsigned short)buf[1] << 8));
+}
+
+/*
+ * Curl_read32_le()
+ *
+ * This function converts a 32-bit integer from the little endian format, as
+ * used in the incoming package to whatever endian format we're using
+ * natively.
+ *
+ * Parameters:
+ *
+ * buf      [in]     - A pointer to a 4 byte buffer.
+ *
+ * Returns the integer.
+ */
+unsigned int Curl_read32_le(const unsigned char *buf)
+{
+  return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
+         ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
+}
+
+/*
+ * Curl_read16_be()
+ *
+ * This function converts a 16-bit integer from the big endian format, as
+ * used in the incoming package to whatever endian format we're using
+ * natively.
+ *
+ * Parameters:
+ *
+ * buf      [in]     - A pointer to a 2 byte buffer.
+ *
+ * Returns the integer.
+ */
+unsigned short Curl_read16_be(const unsigned char *buf)
+{
+  return (unsigned short)(((unsigned short)buf[0] << 8) |
+                          ((unsigned short)buf[1]));
+}
Index: trunk/src/libs/curl-8.7.1/lib/curl_endian.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_endian.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_endian.h	(revision 104083)
@@ -0,0 +1,36 @@
+#ifndef HEADER_CURL_ENDIAN_H
+#define HEADER_CURL_ENDIAN_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* Converts a 16-bit integer from little endian */
+unsigned short Curl_read16_le(const unsigned char *buf);
+
+/* Converts a 32-bit integer from little endian */
+unsigned int Curl_read32_le(const unsigned char *buf);
+
+/* Converts a 16-bit integer from big endian */
+unsigned short Curl_read16_be(const unsigned char *buf);
+
+#endif /* HEADER_CURL_ENDIAN_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_fnmatch.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_fnmatch.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_fnmatch.c	(revision 104083)
@@ -0,0 +1,390 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#ifndef CURL_DISABLE_FTP
+#include <curl/curl.h>
+
+#include "curl_fnmatch.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef HAVE_FNMATCH
+
+#define CURLFNM_CHARSET_LEN (sizeof(char) * 256)
+#define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15)
+
+#define CURLFNM_NEGATE  CURLFNM_CHARSET_LEN
+
+#define CURLFNM_ALNUM   (CURLFNM_CHARSET_LEN + 1)
+#define CURLFNM_DIGIT   (CURLFNM_CHARSET_LEN + 2)
+#define CURLFNM_XDIGIT  (CURLFNM_CHARSET_LEN + 3)
+#define CURLFNM_ALPHA   (CURLFNM_CHARSET_LEN + 4)
+#define CURLFNM_PRINT   (CURLFNM_CHARSET_LEN + 5)
+#define CURLFNM_BLANK   (CURLFNM_CHARSET_LEN + 6)
+#define CURLFNM_LOWER   (CURLFNM_CHARSET_LEN + 7)
+#define CURLFNM_GRAPH   (CURLFNM_CHARSET_LEN + 8)
+#define CURLFNM_SPACE   (CURLFNM_CHARSET_LEN + 9)
+#define CURLFNM_UPPER   (CURLFNM_CHARSET_LEN + 10)
+
+typedef enum {
+  CURLFNM_SCHS_DEFAULT = 0,
+  CURLFNM_SCHS_RIGHTBR,
+  CURLFNM_SCHS_RIGHTBRLEFTBR
+} setcharset_state;
+
+typedef enum {
+  CURLFNM_PKW_INIT = 0,
+  CURLFNM_PKW_DDOT
+} parsekey_state;
+
+typedef enum {
+  CCLASS_OTHER = 0,
+  CCLASS_DIGIT,
+  CCLASS_UPPER,
+  CCLASS_LOWER
+} char_class;
+
+#define SETCHARSET_OK     1
+#define SETCHARSET_FAIL   0
+
+static int parsekeyword(unsigned char **pattern, unsigned char *charset)
+{
+  parsekey_state state = CURLFNM_PKW_INIT;
+#define KEYLEN 10
+  char keyword[KEYLEN] = { 0 };
+  int i;
+  unsigned char *p = *pattern;
+  bool found = FALSE;
+  for(i = 0; !found; i++) {
+    char c = *p++;
+    if(i >= KEYLEN)
+      return SETCHARSET_FAIL;
+    switch(state) {
+    case CURLFNM_PKW_INIT:
+      if(ISLOWER(c))
+        keyword[i] = c;
+      else if(c == ':')
+        state = CURLFNM_PKW_DDOT;
+      else
+        return SETCHARSET_FAIL;
+      break;
+    case CURLFNM_PKW_DDOT:
+      if(c == ']')
+        found = TRUE;
+      else
+        return SETCHARSET_FAIL;
+    }
+  }
+#undef KEYLEN
+
+  *pattern = p; /* move caller's pattern pointer */
+  if(strcmp(keyword, "digit") == 0)
+    charset[CURLFNM_DIGIT] = 1;
+  else if(strcmp(keyword, "alnum") == 0)
+    charset[CURLFNM_ALNUM] = 1;
+  else if(strcmp(keyword, "alpha") == 0)
+    charset[CURLFNM_ALPHA] = 1;
+  else if(strcmp(keyword, "xdigit") == 0)
+    charset[CURLFNM_XDIGIT] = 1;
+  else if(strcmp(keyword, "print") == 0)
+    charset[CURLFNM_PRINT] = 1;
+  else if(strcmp(keyword, "graph") == 0)
+    charset[CURLFNM_GRAPH] = 1;
+  else if(strcmp(keyword, "space") == 0)
+    charset[CURLFNM_SPACE] = 1;
+  else if(strcmp(keyword, "blank") == 0)
+    charset[CURLFNM_BLANK] = 1;
+  else if(strcmp(keyword, "upper") == 0)
+    charset[CURLFNM_UPPER] = 1;
+  else if(strcmp(keyword, "lower") == 0)
+    charset[CURLFNM_LOWER] = 1;
+  else
+    return SETCHARSET_FAIL;
+  return SETCHARSET_OK;
+}
+
+/* Return the character class. */
+static char_class charclass(unsigned char c)
+{
+  if(ISUPPER(c))
+    return CCLASS_UPPER;
+  if(ISLOWER(c))
+    return CCLASS_LOWER;
+  if(ISDIGIT(c))
+    return CCLASS_DIGIT;
+  return CCLASS_OTHER;
+}
+
+/* Include a character or a range in set. */
+static void setcharorrange(unsigned char **pp, unsigned char *charset)
+{
+  unsigned char *p = (*pp)++;
+  unsigned char c = *p++;
+
+  charset[c] = 1;
+  if(ISALNUM(c) && *p++ == '-') {
+    char_class cc = charclass(c);
+    unsigned char endrange = *p++;
+
+    if(endrange == '\\')
+      endrange = *p++;
+    if(endrange >= c && charclass(endrange) == cc) {
+      while(c++ != endrange)
+        if(charclass(c) == cc)  /* Chars in class may be not consecutive. */
+          charset[c] = 1;
+      *pp = p;
+    }
+  }
+}
+
+/* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
+static int setcharset(unsigned char **p, unsigned char *charset)
+{
+  setcharset_state state = CURLFNM_SCHS_DEFAULT;
+  bool something_found = FALSE;
+  unsigned char c;
+
+  memset(charset, 0, CURLFNM_CHSET_SIZE);
+  for(;;) {
+    c = **p;
+    if(!c)
+      return SETCHARSET_FAIL;
+
+    switch(state) {
+    case CURLFNM_SCHS_DEFAULT:
+      if(c == ']') {
+        if(something_found)
+          return SETCHARSET_OK;
+        something_found = TRUE;
+        state = CURLFNM_SCHS_RIGHTBR;
+        charset[c] = 1;
+        (*p)++;
+      }
+      else if(c == '[') {
+        unsigned char *pp = *p + 1;
+
+        if(*pp++ == ':' && parsekeyword(&pp, charset))
+          *p = pp;
+        else {
+          charset[c] = 1;
+          (*p)++;
+        }
+        something_found = TRUE;
+      }
+      else if(c == '^' || c == '!') {
+        if(!something_found) {
+          if(charset[CURLFNM_NEGATE]) {
+            charset[c] = 1;
+            something_found = TRUE;
+          }
+          else
+            charset[CURLFNM_NEGATE] = 1; /* negate charset */
+        }
+        else
+          charset[c] = 1;
+        (*p)++;
+      }
+      else if(c == '\\') {
+        c = *(++(*p));
+        if(c)
+          setcharorrange(p, charset);
+        else
+          charset['\\'] = 1;
+        something_found = TRUE;
+      }
+      else {
+        setcharorrange(p, charset);
+        something_found = TRUE;
+      }
+      break;
+    case CURLFNM_SCHS_RIGHTBR:
+      if(c == '[') {
+        state = CURLFNM_SCHS_RIGHTBRLEFTBR;
+        charset[c] = 1;
+        (*p)++;
+      }
+      else if(c == ']') {
+        return SETCHARSET_OK;
+      }
+      else if(ISPRINT(c)) {
+        charset[c] = 1;
+        (*p)++;
+        state = CURLFNM_SCHS_DEFAULT;
+      }
+      else
+        /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a
+         * nonsense warning 'statement not reached' at end of the fnc when
+         * compiling on Solaris */
+        goto fail;
+      break;
+    case CURLFNM_SCHS_RIGHTBRLEFTBR:
+      if(c == ']')
+        return SETCHARSET_OK;
+      state  = CURLFNM_SCHS_DEFAULT;
+      charset[c] = 1;
+      (*p)++;
+      break;
+    }
+  }
+fail:
+  return SETCHARSET_FAIL;
+}
+
+static int loop(const unsigned char *pattern, const unsigned char *string,
+                int maxstars)
+{
+  unsigned char *p = (unsigned char *)pattern;
+  unsigned char *s = (unsigned char *)string;
+  unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
+
+  for(;;) {
+    unsigned char *pp;
+
+    switch(*p) {
+    case '*':
+      if(!maxstars)
+        return CURL_FNMATCH_NOMATCH;
+      /* Regroup consecutive stars and question marks. This can be done because
+         '*?*?*' can be expressed as '??*'. */
+      for(;;) {
+        if(*++p == '\0')
+          return CURL_FNMATCH_MATCH;
+        if(*p == '?') {
+          if(!*s++)
+            return CURL_FNMATCH_NOMATCH;
+        }
+        else if(*p != '*')
+          break;
+      }
+      /* Skip string characters until we find a match with pattern suffix. */
+      for(maxstars--; *s; s++) {
+        if(loop(p, s, maxstars) == CURL_FNMATCH_MATCH)
+          return CURL_FNMATCH_MATCH;
+      }
+      return CURL_FNMATCH_NOMATCH;
+    case '?':
+      if(!*s)
+        return CURL_FNMATCH_NOMATCH;
+      s++;
+      p++;
+      break;
+    case '\0':
+      return *s? CURL_FNMATCH_NOMATCH: CURL_FNMATCH_MATCH;
+    case '\\':
+      if(p[1])
+        p++;
+      if(*s++ != *p++)
+        return CURL_FNMATCH_NOMATCH;
+      break;
+    case '[':
+      pp = p + 1; /* Copy in case of syntax error in set. */
+      if(setcharset(&pp, charset)) {
+        int found = FALSE;
+        if(!*s)
+          return CURL_FNMATCH_NOMATCH;
+        if(charset[(unsigned int)*s])
+          found = TRUE;
+        else if(charset[CURLFNM_ALNUM])
+          found = ISALNUM(*s);
+        else if(charset[CURLFNM_ALPHA])
+          found = ISALPHA(*s);
+        else if(charset[CURLFNM_DIGIT])
+          found = ISDIGIT(*s);
+        else if(charset[CURLFNM_XDIGIT])
+          found = ISXDIGIT(*s);
+        else if(charset[CURLFNM_PRINT])
+          found = ISPRINT(*s);
+        else if(charset[CURLFNM_SPACE])
+          found = ISSPACE(*s);
+        else if(charset[CURLFNM_UPPER])
+          found = ISUPPER(*s);
+        else if(charset[CURLFNM_LOWER])
+          found = ISLOWER(*s);
+        else if(charset[CURLFNM_BLANK])
+          found = ISBLANK(*s);
+        else if(charset[CURLFNM_GRAPH])
+          found = ISGRAPH(*s);
+
+        if(charset[CURLFNM_NEGATE])
+          found = !found;
+
+        if(!found)
+          return CURL_FNMATCH_NOMATCH;
+        p = pp + 1;
+        s++;
+        break;
+      }
+      /* Syntax error in set; mismatch! */
+      return CURL_FNMATCH_NOMATCH;
+
+    default:
+      if(*p++ != *s++)
+        return CURL_FNMATCH_NOMATCH;
+      break;
+    }
+  }
+}
+
+/*
+ * @unittest: 1307
+ */
+int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
+{
+  (void)ptr; /* the argument is specified by the curl_fnmatch_callback
+                prototype, but not used by Curl_fnmatch() */
+  if(!pattern || !string) {
+    return CURL_FNMATCH_FAIL;
+  }
+  return loop((unsigned char *)pattern, (unsigned char *)string, 2);
+}
+#else
+#include <fnmatch.h>
+/*
+ * @unittest: 1307
+ */
+int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
+{
+  (void)ptr; /* the argument is specified by the curl_fnmatch_callback
+                prototype, but not used by Curl_fnmatch() */
+  if(!pattern || !string) {
+    return CURL_FNMATCH_FAIL;
+  }
+
+  switch(fnmatch(pattern, string, 0)) {
+  case 0:
+    return CURL_FNMATCH_MATCH;
+  case FNM_NOMATCH:
+    return CURL_FNMATCH_NOMATCH;
+  default:
+    return CURL_FNMATCH_FAIL;
+  }
+  /* not reached */
+}
+
+#endif
+
+#endif /* if FTP is disabled */
Index: trunk/src/libs/curl-8.7.1/lib/curl_fnmatch.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_fnmatch.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_fnmatch.h	(revision 104083)
@@ -0,0 +1,46 @@
+#ifndef HEADER_CURL_FNMATCH_H
+#define HEADER_CURL_FNMATCH_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#define CURL_FNMATCH_MATCH    0
+#define CURL_FNMATCH_NOMATCH  1
+#define CURL_FNMATCH_FAIL     2
+
+/* default pattern matching function
+ * =================================
+ * Implemented with recursive backtracking, if you want to use Curl_fnmatch,
+ * please note that there is not implemented UTF/UNICODE support.
+ *
+ * Implemented features:
+ * '?' notation, does not match UTF characters
+ * '*' can also work with UTF string
+ * [a-zA-Z0-9] enumeration support
+ *
+ * keywords: alnum, digit, xdigit, alpha, print, blank, lower, graph, space
+ *           and upper (use as "[[:alnum:]]")
+ */
+int Curl_fnmatch(void *ptr, const char *pattern, const char *string);
+
+#endif /* HEADER_CURL_FNMATCH_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_get_line.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_get_line.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_get_line.c	(revision 104083)
@@ -0,0 +1,77 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) ||  \
+  !defined(CURL_DISABLE_HSTS) || !defined(CURL_DISABLE_NETRC)
+
+#include "curl_get_line.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Curl_get_line() makes sure to only return complete whole lines that end
+ * newlines.
+ */
+int Curl_get_line(struct dynbuf *buf, FILE *input)
+{
+  CURLcode result;
+  char buffer[128];
+  Curl_dyn_reset(buf);
+  while(1) {
+    char *b = fgets(buffer, sizeof(buffer), input);
+
+    if(b) {
+      size_t rlen = strlen(b);
+
+      if(!rlen)
+        break;
+
+      result = Curl_dyn_addn(buf, b, rlen);
+      if(result)
+        /* too long line or out of memory */
+        return 0; /* error */
+
+      else if(b[rlen-1] == '\n')
+        /* end of the line */
+        return 1; /* all good */
+
+      else if(feof(input)) {
+        /* append a newline */
+        result = Curl_dyn_addn(buf, "\n", 1);
+        if(result)
+          /* too long line or out of memory */
+          return 0; /* error */
+        return 1; /* all good */
+      }
+    }
+    else
+      break;
+  }
+  return 0;
+}
+
+#endif /* if not disabled */
Index: trunk/src/libs/curl-8.7.1/lib/curl_get_line.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_get_line.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_get_line.h	(revision 104083)
@@ -0,0 +1,32 @@
+#ifndef HEADER_CURL_GET_LINE_H
+#define HEADER_CURL_GET_LINE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "dynbuf.h"
+
+/* Curl_get_line() returns complete lines that end with a newline. */
+int Curl_get_line(struct dynbuf *buf, FILE *input);
+
+#endif /* HEADER_CURL_GET_LINE_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_gethostname.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_gethostname.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_gethostname.c	(revision 104083)
@@ -0,0 +1,102 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "curl_gethostname.h"
+
+/*
+ * Curl_gethostname() is a wrapper around gethostname() which allows
+ * overriding the host name that the function would normally return.
+ * This capability is used by the test suite to verify exact matching
+ * of NTLM authentication, which exercises libcurl's MD4 and DES code
+ * as well as by the SMTP module when a hostname is not provided.
+ *
+ * For libcurl debug enabled builds host name overriding takes place
+ * when environment variable CURL_GETHOSTNAME is set, using the value
+ * held by the variable to override returned host name.
+ *
+ * Note: The function always returns the un-qualified hostname rather
+ * than being provider dependent.
+ *
+ * For libcurl shared library release builds the test suite preloads
+ * another shared library named libhostname using the LD_PRELOAD
+ * mechanism which intercepts, and might override, the gethostname()
+ * function call. In this case a given platform must support the
+ * LD_PRELOAD mechanism and additionally have environment variable
+ * CURL_GETHOSTNAME set in order to override the returned host name.
+ *
+ * For libcurl static library release builds no overriding takes place.
+ */
+
+int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
+{
+#ifndef HAVE_GETHOSTNAME
+
+  /* Allow compilation and return failure when unavailable */
+  (void) name;
+  (void) namelen;
+  return -1;
+
+#else
+  int err;
+  char *dot;
+
+#ifdef DEBUGBUILD
+
+  /* Override host name when environment variable CURL_GETHOSTNAME is set */
+  const char *force_hostname = getenv("CURL_GETHOSTNAME");
+  if(force_hostname) {
+    strncpy(name, force_hostname, namelen);
+    err = 0;
+  }
+  else {
+    name[0] = '\0';
+    err = gethostname(name, namelen);
+  }
+
+#else /* DEBUGBUILD */
+
+  /* The call to system's gethostname() might get intercepted by the
+     libhostname library when libcurl is built as a non-debug shared
+     library when running the test suite. */
+  name[0] = '\0';
+  err = gethostname(name, namelen);
+
+#endif
+
+  name[namelen - 1] = '\0';
+
+  if(err)
+    return err;
+
+  /* Truncate domain, leave only machine name */
+  dot = strchr(name, '.');
+  if(dot)
+    *dot = '\0';
+
+  return 0;
+#endif
+
+}
Index: trunk/src/libs/curl-8.7.1/lib/curl_gethostname.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_gethostname.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_gethostname.h	(revision 104083)
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_GETHOSTNAME_H
+#define HEADER_CURL_GETHOSTNAME_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* Hostname buffer size */
+#define HOSTNAME_MAX 1024
+
+/* This returns the local machine's un-qualified hostname */
+int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen);
+
+#endif /* HEADER_CURL_GETHOSTNAME_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_gssapi.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_gssapi.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_gssapi.c	(revision 104083)
@@ -0,0 +1,152 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_GSSAPI
+
+#include "curl_gssapi.h"
+#include "sendf.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if defined(__GNUC__)
+#define CURL_ALIGN8   __attribute__ ((aligned(8)))
+#else
+#define CURL_ALIGN8
+#endif
+
+gss_OID_desc Curl_spnego_mech_oid CURL_ALIGN8 = {
+  6, (char *)"\x2b\x06\x01\x05\x05\x02"
+};
+gss_OID_desc Curl_krb5_mech_oid CURL_ALIGN8 = {
+  9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
+};
+
+OM_uint32 Curl_gss_init_sec_context(
+    struct Curl_easy *data,
+    OM_uint32 *minor_status,
+    gss_ctx_id_t *context,
+    gss_name_t target_name,
+    gss_OID mech_type,
+    gss_channel_bindings_t input_chan_bindings,
+    gss_buffer_t input_token,
+    gss_buffer_t output_token,
+    const bool mutual_auth,
+    OM_uint32 *ret_flags)
+{
+  OM_uint32 req_flags = GSS_C_REPLAY_FLAG;
+
+  if(mutual_auth)
+    req_flags |= GSS_C_MUTUAL_FLAG;
+
+  if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) {
+#ifdef GSS_C_DELEG_POLICY_FLAG
+    req_flags |= GSS_C_DELEG_POLICY_FLAG;
+#else
+    infof(data, "WARNING: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not "
+        "compiled in");
+#endif
+  }
+
+  if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG)
+    req_flags |= GSS_C_DELEG_FLAG;
+
+  return gss_init_sec_context(minor_status,
+                              GSS_C_NO_CREDENTIAL, /* cred_handle */
+                              context,
+                              target_name,
+                              mech_type,
+                              req_flags,
+                              0, /* time_req */
+                              input_chan_bindings,
+                              input_token,
+                              NULL, /* actual_mech_type */
+                              output_token,
+                              ret_flags,
+                              NULL /* time_rec */);
+}
+
+#define GSS_LOG_BUFFER_LEN 1024
+static size_t display_gss_error(OM_uint32 status, int type,
+                                char *buf, size_t len) {
+  OM_uint32 maj_stat;
+  OM_uint32 min_stat;
+  OM_uint32 msg_ctx = 0;
+  gss_buffer_desc status_string = GSS_C_EMPTY_BUFFER;
+
+  do {
+    maj_stat = gss_display_status(&min_stat,
+                                  status,
+                                  type,
+                                  GSS_C_NO_OID,
+                                  &msg_ctx,
+                                  &status_string);
+    if(maj_stat == GSS_S_COMPLETE && status_string.length > 0) {
+      if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) {
+        len += msnprintf(buf + len, GSS_LOG_BUFFER_LEN - len,
+                         "%.*s. ", (int)status_string.length,
+                         (char *)status_string.value);
+      }
+    }
+    gss_release_buffer(&min_stat, &status_string);
+  } while(!GSS_ERROR(maj_stat) && msg_ctx);
+
+  return len;
+}
+
+/*
+ * Curl_gss_log_error()
+ *
+ * This is used to log a GSS-API error status.
+ *
+ * Parameters:
+ *
+ * data    [in] - The session handle.
+ * prefix  [in] - The prefix of the log message.
+ * major   [in] - The major status code.
+ * minor   [in] - The minor status code.
+ */
+void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
+                        OM_uint32 major, OM_uint32 minor)
+{
+  char buf[GSS_LOG_BUFFER_LEN];
+  size_t len = 0;
+
+  if(major != GSS_S_FAILURE)
+    len = display_gss_error(major, GSS_C_GSS_CODE, buf, len);
+
+  display_gss_error(minor, GSS_C_MECH_CODE, buf, len);
+
+  infof(data, "%s%s", prefix, buf);
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)data;
+  (void)prefix;
+#endif
+}
+
+#endif /* HAVE_GSSAPI */
Index: trunk/src/libs/curl-8.7.1/lib/curl_gssapi.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_gssapi.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_gssapi.h	(revision 104083)
@@ -0,0 +1,63 @@
+#ifndef HEADER_CURL_GSSAPI_H
+#define HEADER_CURL_GSSAPI_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "urldata.h"
+
+#ifdef HAVE_GSSAPI
+extern gss_OID_desc Curl_spnego_mech_oid;
+extern gss_OID_desc Curl_krb5_mech_oid;
+
+/* Common method for using GSS-API */
+OM_uint32 Curl_gss_init_sec_context(
+    struct Curl_easy *data,
+    OM_uint32 *minor_status,
+    gss_ctx_id_t *context,
+    gss_name_t target_name,
+    gss_OID mech_type,
+    gss_channel_bindings_t input_chan_bindings,
+    gss_buffer_t input_token,
+    gss_buffer_t output_token,
+    const bool mutual_auth,
+    OM_uint32 *ret_flags);
+
+/* Helper to log a GSS-API error status */
+void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
+                        OM_uint32 major, OM_uint32 minor);
+
+/* Provide some definitions missing in old headers */
+#ifdef HAVE_OLD_GSSMIT
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#define NCOMPAT 1
+#endif
+
+/* Define our privacy and integrity protection values */
+#define GSSAUTH_P_NONE      1
+#define GSSAUTH_P_INTEGRITY 2
+#define GSSAUTH_P_PRIVACY   4
+
+#endif /* HAVE_GSSAPI */
+#endif /* HEADER_CURL_GSSAPI_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_hmac.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_hmac.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_hmac.h	(revision 104083)
@@ -0,0 +1,78 @@
+#ifndef HEADER_CURL_HMAC_H
+#define HEADER_CURL_HMAC_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI))         \
+  || !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH)   \
+  || defined(USE_LIBSSH2)
+
+#include <curl/curl.h>
+
+#define HMAC_MD5_LENGTH 16
+
+typedef CURLcode (* HMAC_hinit_func)(void *context);
+typedef void    (* HMAC_hupdate_func)(void *context,
+                                      const unsigned char *data,
+                                      unsigned int len);
+typedef void    (* HMAC_hfinal_func)(unsigned char *result, void *context);
+
+
+/* Per-hash function HMAC parameters. */
+struct HMAC_params {
+  HMAC_hinit_func
+  hmac_hinit;     /* Initialize context procedure. */
+  HMAC_hupdate_func     hmac_hupdate;   /* Update context with data. */
+  HMAC_hfinal_func      hmac_hfinal;    /* Get final result procedure. */
+  unsigned int          hmac_ctxtsize;  /* Context structure size. */
+  unsigned int          hmac_maxkeylen; /* Maximum key length (bytes). */
+  unsigned int          hmac_resultlen; /* Result length (bytes). */
+};
+
+
+/* HMAC computation context. */
+struct HMAC_context {
+  const struct HMAC_params *hmac_hash; /* Hash function definition. */
+  void *hmac_hashctxt1;         /* Hash function context 1. */
+  void *hmac_hashctxt2;         /* Hash function context 2. */
+};
+
+
+/* Prototypes. */
+struct HMAC_context *Curl_HMAC_init(const struct HMAC_params *hashparams,
+                                    const unsigned char *key,
+                                    unsigned int keylen);
+int Curl_HMAC_update(struct HMAC_context *context,
+                     const unsigned char *data,
+                     unsigned int len);
+int Curl_HMAC_final(struct HMAC_context *context, unsigned char *result);
+
+CURLcode Curl_hmacit(const struct HMAC_params *hashparams,
+                     const unsigned char *key, const size_t keylen,
+                     const unsigned char *data, const size_t datalen,
+                     unsigned char *output);
+
+#endif
+
+#endif /* HEADER_CURL_HMAC_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_krb5.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_krb5.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_krb5.h	(revision 104083)
@@ -0,0 +1,52 @@
+#ifndef HEADER_CURL_KRB5_H
+#define HEADER_CURL_KRB5_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+struct Curl_sec_client_mech {
+  const char *name;
+  size_t size;
+  int (*init)(void *);
+  int (*auth)(void *, struct Curl_easy *data, struct connectdata *);
+  void (*end)(void *);
+  int (*check_prot)(void *, int);
+  int (*encode)(void *, const void *, int, int, void **);
+  int (*decode)(void *, void *, int, int, struct connectdata *);
+};
+
+#define AUTH_OK         0
+#define AUTH_CONTINUE   1
+#define AUTH_ERROR      2
+
+#ifdef HAVE_GSSAPI
+int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, char *,
+                      enum protection_level);
+void Curl_sec_end(struct connectdata *);
+CURLcode Curl_sec_login(struct Curl_easy *, struct connectdata *);
+int Curl_sec_request_prot(struct connectdata *conn, const char *level);
+#else
+#define Curl_sec_end(x)
+#endif
+
+#endif /* HEADER_CURL_KRB5_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_ldap.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_ldap.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_ldap.h	(revision 104083)
@@ -0,0 +1,36 @@
+#ifndef HEADER_CURL_LDAP_H
+#define HEADER_CURL_LDAP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_LDAP
+extern const struct Curl_handler Curl_handler_ldap;
+
+#if !defined(CURL_DISABLE_LDAPS) && \
+    ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
+     (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
+extern const struct Curl_handler Curl_handler_ldaps;
+#endif
+
+#endif
+#endif /* HEADER_CURL_LDAP_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_md4.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_md4.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_md4.h	(revision 104083)
@@ -0,0 +1,39 @@
+#ifndef HEADER_CURL_MD4_H
+#define HEADER_CURL_MD4_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include <curl/curl.h>
+
+#if defined(USE_CURL_NTLM_CORE)
+
+#define MD4_DIGEST_LENGTH 16
+
+CURLcode Curl_md4it(unsigned char *output, const unsigned char *input,
+                    const size_t len);
+
+#endif /* defined(USE_CURL_NTLM_CORE) */
+
+#endif /* HEADER_CURL_MD4_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_md5.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_md5.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_md5.h	(revision 104083)
@@ -0,0 +1,67 @@
+#ifndef HEADER_CURL_MD5_H
+#define HEADER_CURL_MD5_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \
+    || !defined(CURL_DISABLE_DIGEST_AUTH)
+
+#include "curl_hmac.h"
+
+#define MD5_DIGEST_LEN  16
+
+typedef CURLcode (* Curl_MD5_init_func)(void *context);
+typedef void (* Curl_MD5_update_func)(void *context,
+                                      const unsigned char *data,
+                                      unsigned int len);
+typedef void (* Curl_MD5_final_func)(unsigned char *result, void *context);
+
+struct MD5_params {
+  Curl_MD5_init_func     md5_init_func;   /* Initialize context procedure */
+  Curl_MD5_update_func   md5_update_func; /* Update context with data */
+  Curl_MD5_final_func    md5_final_func;  /* Get final result procedure */
+  unsigned int           md5_ctxtsize;  /* Context structure size */
+  unsigned int           md5_resultlen; /* Result length (bytes) */
+};
+
+struct MD5_context {
+  const struct MD5_params *md5_hash;    /* Hash function definition */
+  void                  *md5_hashctx;   /* Hash function context */
+};
+
+extern const struct MD5_params Curl_DIGEST_MD5[1];
+extern const struct HMAC_params Curl_HMAC_MD5[1];
+
+CURLcode Curl_md5it(unsigned char *output, const unsigned char *input,
+                    const size_t len);
+
+struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params);
+CURLcode Curl_MD5_update(struct MD5_context *context,
+                         const unsigned char *data,
+                         unsigned int len);
+CURLcode Curl_MD5_final(struct MD5_context *context, unsigned char *result);
+
+#endif
+
+#endif /* HEADER_CURL_MD5_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_memory.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_memory.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_memory.h	(revision 104083)
@@ -0,0 +1,178 @@
+#ifndef HEADER_CURL_MEMORY_H
+#define HEADER_CURL_MEMORY_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Nasty internal details ahead...
+ *
+ * File curl_memory.h must be included by _all_ *.c source files
+ * that use memory related functions strdup, malloc, calloc, realloc
+ * or free, and given source file is used to build libcurl library.
+ * It should be included immediately before memdebug.h as the last files
+ * included to avoid undesired interaction with other memory function
+ * headers in dependent libraries.
+ *
+ * There is nearly no exception to above rule. All libcurl source
+ * files in 'lib' subdirectory as well as those living deep inside
+ * 'packages' subdirectories and linked together in order to build
+ * libcurl library shall follow it.
+ *
+ * File lib/strdup.c is an exception, given that it provides a strdup
+ * clone implementation while using malloc. Extra care needed inside
+ * this one.
+ *
+ * The need for curl_memory.h inclusion is due to libcurl's feature
+ * of allowing library user to provide memory replacement functions,
+ * memory callbacks, at runtime with curl_global_init_mem()
+ *
+ * Any *.c source file used to build libcurl library that does not
+ * include curl_memory.h and uses any memory function of the five
+ * mentioned above will compile without any indication, but it will
+ * trigger weird memory related issues at runtime.
+ *
+ */
+
+#ifdef HEADER_CURL_MEMDEBUG_H
+/* cleanup after memdebug.h */
+
+#ifdef MEMDEBUG_NODEFINES
+#ifdef CURLDEBUG
+
+#undef strdup
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+#undef send
+#undef recv
+
+#ifdef _WIN32
+#  ifdef UNICODE
+#    undef wcsdup
+#    undef _wcsdup
+#    undef _tcsdup
+#  else
+#    undef _tcsdup
+#  endif
+#endif
+
+#undef socket
+#undef accept
+#ifdef HAVE_SOCKETPAIR
+#undef socketpair
+#endif
+
+#ifdef HAVE_GETADDRINFO
+#if defined(getaddrinfo) && defined(__osf__)
+#undef ogetaddrinfo
+#else
+#undef getaddrinfo
+#endif
+#endif /* HAVE_GETADDRINFO */
+
+#ifdef HAVE_FREEADDRINFO
+#undef freeaddrinfo
+#endif /* HAVE_FREEADDRINFO */
+
+/* sclose is probably already defined, redefine it! */
+#undef sclose
+#undef fopen
+#undef fdopen
+#undef fclose
+
+#endif /* MEMDEBUG_NODEFINES */
+#endif /* CURLDEBUG */
+
+#undef HEADER_CURL_MEMDEBUG_H
+#endif /* HEADER_CURL_MEMDEBUG_H */
+
+/*
+** Following section applies even when CURLDEBUG is not defined.
+*/
+
+#undef fake_sclose
+
+#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */
+/*
+ * The following memory function replacement typedef's are COPIED from
+ * curl/curl.h and MUST match the originals. We copy them to avoid having to
+ * include curl/curl.h here. We avoid that include since it includes stdio.h
+ * and other headers that may get messed up with defines done here.
+ */
+typedef void *(*curl_malloc_callback)(size_t size);
+typedef void (*curl_free_callback)(void *ptr);
+typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
+typedef char *(*curl_strdup_callback)(const char *str);
+typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
+#define CURL_DID_MEMORY_FUNC_TYPEDEFS
+#endif
+
+extern curl_malloc_callback Curl_cmalloc;
+extern curl_free_callback Curl_cfree;
+extern curl_realloc_callback Curl_crealloc;
+extern curl_strdup_callback Curl_cstrdup;
+extern curl_calloc_callback Curl_ccalloc;
+#if defined(_WIN32) && defined(UNICODE)
+extern curl_wcsdup_callback Curl_cwcsdup;
+#endif
+
+#ifndef CURLDEBUG
+
+/*
+ * libcurl's 'memory tracking' system defines strdup, malloc, calloc,
+ * realloc and free, along with others, in memdebug.h in a different
+ * way although still using memory callbacks forward declared above.
+ * When using the 'memory tracking' system (CURLDEBUG defined) we do
+ * not define here the five memory functions given that definitions
+ * from memdebug.h are the ones that shall be used.
+ */
+
+#undef strdup
+#define strdup(ptr) Curl_cstrdup(ptr)
+#undef malloc
+#define malloc(size) Curl_cmalloc(size)
+#undef calloc
+#define calloc(nbelem,size) Curl_ccalloc(nbelem, size)
+#undef realloc
+#define realloc(ptr,size) Curl_crealloc(ptr, size)
+#undef free
+#define free(ptr) Curl_cfree(ptr)
+
+#ifdef _WIN32
+#  ifdef UNICODE
+#    undef wcsdup
+#    define wcsdup(ptr) Curl_cwcsdup(ptr)
+#    undef _wcsdup
+#    define _wcsdup(ptr) Curl_cwcsdup(ptr)
+#    undef _tcsdup
+#    define _tcsdup(ptr) Curl_cwcsdup(ptr)
+#  else
+#    undef _tcsdup
+#    define _tcsdup(ptr) Curl_cstrdup(ptr)
+#  endif
+#endif
+
+#endif /* CURLDEBUG */
+#endif /* HEADER_CURL_MEMORY_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_memrchr.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_memrchr.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_memrchr.c	(revision 104083)
@@ -0,0 +1,64 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "curl_memrchr.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef HAVE_MEMRCHR
+
+/*
+ * Curl_memrchr()
+ *
+ * Our memrchr() function clone for systems which lack this function. The
+ * memrchr() function is like the memchr() function, except that it searches
+ * backwards from the end of the n bytes pointed to by s instead of forward
+ * from the beginning.
+ */
+
+void *
+Curl_memrchr(const void *s, int c, size_t n)
+{
+  if(n > 0) {
+    const unsigned char *p = s;
+    const unsigned char *q = s;
+
+    p += n - 1;
+
+    while(p >= q) {
+      if(*p == (unsigned char)c)
+        return (void *)p;
+      p--;
+    }
+  }
+  return NULL;
+}
+
+#endif /* HAVE_MEMRCHR */
Index: trunk/src/libs/curl-8.7.1/lib/curl_memrchr.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_memrchr.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_memrchr.h	(revision 104083)
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_MEMRCHR_H
+#define HEADER_CURL_MEMRCHR_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_MEMRCHR
+
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#  include <strings.h>
+#endif
+
+#else /* HAVE_MEMRCHR */
+
+void *Curl_memrchr(const void *s, int c, size_t n);
+
+#define memrchr(x,y,z) Curl_memrchr((x),(y),(z))
+
+#endif /* HAVE_MEMRCHR */
+
+#endif /* HEADER_CURL_MEMRCHR_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_multibyte.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_multibyte.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_multibyte.c	(revision 104083)
@@ -0,0 +1,179 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * This file is 'mem-include-scan' clean, which means memdebug.h and
+ * curl_memory.h are purposely not included in this file. See test 1132.
+ *
+ * The functions in this file are curlx functions which are not tracked by the
+ * curl memory tracker memdebug.
+ */
+
+#include "curl_setup.h"
+
+#if defined(_WIN32)
+
+#include "curl_multibyte.h"
+
+/*
+ * MultiByte conversions using Windows kernel32 library.
+ */
+
+wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8)
+{
+  wchar_t *str_w = NULL;
+
+  if(str_utf8) {
+    int str_w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+                                        str_utf8, -1, NULL, 0);
+    if(str_w_len > 0) {
+      str_w = malloc(str_w_len * sizeof(wchar_t));
+      if(str_w) {
+        if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w,
+                               str_w_len) == 0) {
+          free(str_w);
+          return NULL;
+        }
+      }
+    }
+  }
+
+  return str_w;
+}
+
+char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
+{
+  char *str_utf8 = NULL;
+
+  if(str_w) {
+    int bytes = WideCharToMultiByte(CP_UTF8, 0, str_w, -1,
+                                    NULL, 0, NULL, NULL);
+    if(bytes > 0) {
+      str_utf8 = malloc(bytes);
+      if(str_utf8) {
+        if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, bytes,
+                               NULL, NULL) == 0) {
+          free(str_utf8);
+          return NULL;
+        }
+      }
+    }
+  }
+
+  return str_utf8;
+}
+
+#endif /* _WIN32 */
+
+#if defined(USE_WIN32_LARGE_FILES) || defined(USE_WIN32_SMALL_FILES)
+
+int curlx_win32_open(const char *filename, int oflag, ...)
+{
+  int pmode = 0;
+
+#ifdef _UNICODE
+  int result = -1;
+  wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
+#endif
+
+  va_list param;
+  va_start(param, oflag);
+  if(oflag & O_CREAT)
+    pmode = va_arg(param, int);
+  va_end(param);
+
+#ifdef _UNICODE
+  if(filename_w) {
+    result = _wopen(filename_w, oflag, pmode);
+    curlx_unicodefree(filename_w);
+  }
+  else
+    errno = EINVAL;
+  return result;
+#else
+  return (_open)(filename, oflag, pmode);
+#endif
+}
+
+FILE *curlx_win32_fopen(const char *filename, const char *mode)
+{
+#ifdef _UNICODE
+  FILE *result = NULL;
+  wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
+  wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode);
+  if(filename_w && mode_w)
+    result = _wfopen(filename_w, mode_w);
+  else
+    errno = EINVAL;
+  curlx_unicodefree(filename_w);
+  curlx_unicodefree(mode_w);
+  return result;
+#else
+  return (fopen)(filename, mode);
+#endif
+}
+
+int curlx_win32_stat(const char *path, struct_stat *buffer)
+{
+#ifdef _UNICODE
+  int result = -1;
+  wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
+  if(path_w) {
+#if defined(USE_WIN32_SMALL_FILES)
+    result = _wstat(path_w, buffer);
+#else
+    result = _wstati64(path_w, buffer);
+#endif
+    curlx_unicodefree(path_w);
+  }
+  else
+    errno = EINVAL;
+  return result;
+#else
+#if defined(USE_WIN32_SMALL_FILES)
+  return _stat(path, buffer);
+#else
+  return _stati64(path, buffer);
+#endif
+#endif
+}
+
+int curlx_win32_access(const char *path, int mode)
+{
+#if defined(_UNICODE)
+  int result = -1;
+  wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
+  if(path_w) {
+    result = _waccess(path_w, mode);
+    curlx_unicodefree(path_w);
+  }
+  else
+    errno = EINVAL;
+  return result;
+#else
+  return _access(path, mode);
+#endif
+}
+
+#endif /* USE_WIN32_LARGE_FILES || USE_WIN32_SMALL_FILES */
Index: trunk/src/libs/curl-8.7.1/lib/curl_multibyte.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_multibyte.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_multibyte.h	(revision 104083)
@@ -0,0 +1,91 @@
+#ifndef HEADER_CURL_MULTIBYTE_H
+#define HEADER_CURL_MULTIBYTE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(_WIN32)
+
+ /*
+  * MultiByte conversions using Windows kernel32 library.
+  */
+
+wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8);
+char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
+#endif /* _WIN32 */
+
+/*
+ * Macros curlx_convert_UTF8_to_tchar(), curlx_convert_tchar_to_UTF8()
+ * and curlx_unicodefree() main purpose is to minimize the number of
+ * preprocessor conditional directives needed by code using these
+ * to differentiate UNICODE from non-UNICODE builds.
+ *
+ * In the case of a non-UNICODE build the tchar strings are char strings that
+ * are duplicated via strdup and remain in whatever the passed in encoding is,
+ * which is assumed to be UTF-8 but may be other encoding. Therefore the
+ * significance of the conversion functions is primarily for UNICODE builds.
+ *
+ * Allocated memory should be free'd with curlx_unicodefree().
+ *
+ * Note: Because these are curlx functions their memory usage is not tracked
+ * by the curl memory tracker memdebug. You'll notice that curlx function-like
+ * macros call free and strdup in parentheses, eg (strdup)(ptr), and that's to
+ * ensure that the curl memdebug override macros do not replace them.
+ */
+
+#if defined(UNICODE) && defined(_WIN32)
+
+#define curlx_convert_UTF8_to_tchar(ptr) curlx_convert_UTF8_to_wchar((ptr))
+#define curlx_convert_tchar_to_UTF8(ptr) curlx_convert_wchar_to_UTF8((ptr))
+
+typedef union {
+  unsigned short       *tchar_ptr;
+  const unsigned short *const_tchar_ptr;
+  unsigned short       *tbyte_ptr;
+  const unsigned short *const_tbyte_ptr;
+} xcharp_u;
+
+#else
+
+#define curlx_convert_UTF8_to_tchar(ptr) (strdup)(ptr)
+#define curlx_convert_tchar_to_UTF8(ptr) (strdup)(ptr)
+
+typedef union {
+  char                *tchar_ptr;
+  const char          *const_tchar_ptr;
+  unsigned char       *tbyte_ptr;
+  const unsigned char *const_tbyte_ptr;
+} xcharp_u;
+
+#endif /* UNICODE && _WIN32 */
+
+#define curlx_unicodefree(ptr)                          \
+  do {                                                  \
+    if(ptr) {                                           \
+      (free)(ptr);                                      \
+      (ptr) = NULL;                                     \
+    }                                                   \
+  } while(0)
+
+#endif /* HEADER_CURL_MULTIBYTE_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_ntlm_core.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_ntlm_core.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_ntlm_core.c	(revision 104083)
@@ -0,0 +1,669 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_CURL_NTLM_CORE)
+
+/*
+ * NTLM details:
+ *
+ * https://davenport.sourceforge.net/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
+ */
+
+/* Please keep the SSL backend-specific #if branches in this order:
+
+   1. USE_OPENSSL
+   2. USE_WOLFSSL
+   3. USE_GNUTLS
+   4. -
+   5. USE_MBEDTLS
+   6. USE_SECTRANSP
+   7. USE_OS400CRYPTO
+   8. USE_WIN32_CRYPTO
+
+   This ensures that:
+   - the same SSL branch gets activated throughout this source
+     file even if multiple backends are enabled at the same time.
+   - OpenSSL has higher priority than Windows Crypt, due
+     to issues with the latter supporting NTLM2Session responses
+     in NTLM type-3 messages.
+ */
+
+#if defined(USE_OPENSSL)
+  #include <openssl/opensslconf.h>
+  #if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_DEPRECATED_3_0)
+    #define USE_OPENSSL_DES
+  #endif
+#endif
+
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
+
+#if defined(USE_OPENSSL)
+#  include <openssl/des.h>
+#  include <openssl/md5.h>
+#  include <openssl/ssl.h>
+#  include <openssl/rand.h>
+#else
+#  include <wolfssl/options.h>
+#  include <wolfssl/openssl/des.h>
+#  include <wolfssl/openssl/md5.h>
+#  include <wolfssl/openssl/ssl.h>
+#  include <wolfssl/openssl/rand.h>
+#endif
+
+#  if (defined(OPENSSL_VERSION_NUMBER) && \
+       (OPENSSL_VERSION_NUMBER < 0x00907001L)) && !defined(USE_WOLFSSL)
+#    define DES_key_schedule des_key_schedule
+#    define DES_cblock des_cblock
+#    define DES_set_odd_parity des_set_odd_parity
+#    define DES_set_key des_set_key
+#    define DES_ecb_encrypt des_ecb_encrypt
+#    define DESKEY(x) x
+#    define DESKEYARG(x) x
+#  elif defined(OPENSSL_IS_AWSLC)
+#    define DES_set_key_unchecked (void)DES_set_key
+#    define DESKEYARG(x) *x
+#    define DESKEY(x) &x
+#  else
+#    define DESKEYARG(x) *x
+#    define DESKEY(x) &x
+#  endif
+
+#elif defined(USE_GNUTLS)
+
+#  include <nettle/des.h>
+
+#elif defined(USE_MBEDTLS)
+
+#  include <mbedtls/des.h>
+
+#elif defined(USE_SECTRANSP)
+
+#  include <CommonCrypto/CommonCryptor.h>
+#  include <CommonCrypto/CommonDigest.h>
+
+#elif defined(USE_OS400CRYPTO)
+#  include "cipher.mih"  /* mih/cipher */
+#elif defined(USE_WIN32_CRYPTO)
+#  include <wincrypt.h>
+#else
+#  error "Can't compile NTLM support without a crypto library with DES."
+#  define CURL_NTLM_NOT_SUPPORTED
+#endif
+
+#include "urldata.h"
+#include "strcase.h"
+#include "curl_ntlm_core.h"
+#include "curl_md5.h"
+#include "curl_hmac.h"
+#include "warnless.h"
+#include "curl_endian.h"
+#include "curl_des.h"
+#include "curl_md4.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00"
+#define NTLMv2_BLOB_LEN       (44 -16 + ntlm->target_info_len + 4)
+
+#if !defined(CURL_NTLM_NOT_SUPPORTED)
+/*
+* Turns a 56-bit key into being 64-bit wide.
+*/
+static void extend_key_56_to_64(const unsigned char *key_56, char *key)
+{
+  key[0] = key_56[0];
+  key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
+  key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
+  key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
+  key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
+  key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
+  key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
+  key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
+}
+#endif
+
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
+/*
+ * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The
+ * key schedule ks is also set.
+ */
+static void setup_des_key(const unsigned char *key_56,
+                          DES_key_schedule DESKEYARG(ks))
+{
+  DES_cblock key;
+
+  /* Expand the 56-bit key to 64-bits */
+  extend_key_56_to_64(key_56, (char *) &key);
+
+  /* Set the key parity to odd */
+  DES_set_odd_parity(&key);
+
+  /* Set the key */
+  DES_set_key_unchecked(&key, ks);
+}
+
+#elif defined(USE_GNUTLS)
+
+static void setup_des_key(const unsigned char *key_56,
+                          struct des_ctx *des)
+{
+  char key[8];
+
+  /* Expand the 56-bit key to 64-bits */
+  extend_key_56_to_64(key_56, key);
+
+  /* Set the key parity to odd */
+  Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));
+
+  /* Set the key */
+  des_set_key(des, (const uint8_t *) key);
+}
+
+#elif defined(USE_MBEDTLS)
+
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+                        const unsigned char *key_56)
+{
+  mbedtls_des_context ctx;
+  char key[8];
+
+  /* Expand the 56-bit key to 64-bits */
+  extend_key_56_to_64(key_56, key);
+
+  /* Set the key parity to odd */
+  mbedtls_des_key_set_parity((unsigned char *) key);
+
+  /* Perform the encryption */
+  mbedtls_des_init(&ctx);
+  mbedtls_des_setkey_enc(&ctx, (unsigned char *) key);
+  return mbedtls_des_crypt_ecb(&ctx, in, out) == 0;
+}
+
+#elif defined(USE_SECTRANSP)
+
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+                        const unsigned char *key_56)
+{
+  char key[8];
+  size_t out_len;
+  CCCryptorStatus err;
+
+  /* Expand the 56-bit key to 64-bits */
+  extend_key_56_to_64(key_56, key);
+
+  /* Set the key parity to odd */
+  Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));
+
+  /* Perform the encryption */
+  err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key,
+                kCCKeySizeDES, NULL, in, 8 /* inbuflen */, out,
+                8 /* outbuflen */, &out_len);
+
+  return err == kCCSuccess;
+}
+
+#elif defined(USE_OS400CRYPTO)
+
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+                        const unsigned char *key_56)
+{
+  char key[8];
+  _CIPHER_Control_T ctl;
+
+  /* Setup the cipher control structure */
+  ctl.Func_ID = ENCRYPT_ONLY;
+  ctl.Data_Len = sizeof(key);
+
+  /* Expand the 56-bit key to 64-bits */
+  extend_key_56_to_64(key_56, ctl.Crypto_Key);
+
+  /* Set the key parity to odd */
+  Curl_des_set_odd_parity((unsigned char *) ctl.Crypto_Key, ctl.Data_Len);
+
+  /* Perform the encryption */
+  _CIPHER((_SPCPTR *) &out, &ctl, (_SPCPTR *) &in);
+
+  return TRUE;
+}
+
+#elif defined(USE_WIN32_CRYPTO)
+
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+                        const unsigned char *key_56)
+{
+  HCRYPTPROV hprov;
+  HCRYPTKEY hkey;
+  struct {
+    BLOBHEADER hdr;
+    unsigned int len;
+    char key[8];
+  } blob;
+  DWORD len = 8;
+
+  /* Acquire the crypto provider */
+  if(!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL,
+                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+    return FALSE;
+
+  /* Setup the key blob structure */
+  memset(&blob, 0, sizeof(blob));
+  blob.hdr.bType = PLAINTEXTKEYBLOB;
+  blob.hdr.bVersion = 2;
+  blob.hdr.aiKeyAlg = CALG_DES;
+  blob.len = sizeof(blob.key);
+
+  /* Expand the 56-bit key to 64-bits */
+  extend_key_56_to_64(key_56, blob.key);
+
+  /* Set the key parity to odd */
+  Curl_des_set_odd_parity((unsigned char *) blob.key, sizeof(blob.key));
+
+  /* Import the key */
+  if(!CryptImportKey(hprov, (BYTE *) &blob, sizeof(blob), 0, 0, &hkey)) {
+    CryptReleaseContext(hprov, 0);
+
+    return FALSE;
+  }
+
+  memcpy(out, in, 8);
+
+  /* Perform the encryption */
+  CryptEncrypt(hkey, 0, FALSE, 0, out, &len, len);
+
+  CryptDestroyKey(hkey);
+  CryptReleaseContext(hprov, 0);
+
+  return TRUE;
+}
+
+#endif /* defined(USE_WIN32_CRYPTO) */
+
+ /*
+  * takes a 21 byte array and treats it as 3 56-bit DES keys. The
+  * 8 byte plaintext is encrypted with each key and the resulting 24
+  * bytes are stored in the results array.
+  */
+void Curl_ntlm_core_lm_resp(const unsigned char *keys,
+                            const unsigned char *plaintext,
+                            unsigned char *results)
+{
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
+  DES_key_schedule ks;
+
+  setup_des_key(keys, DESKEY(ks));
+  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
+                  DESKEY(ks), DES_ENCRYPT);
+
+  setup_des_key(keys + 7, DESKEY(ks));
+  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8),
+                  DESKEY(ks), DES_ENCRYPT);
+
+  setup_des_key(keys + 14, DESKEY(ks));
+  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16),
+                  DESKEY(ks), DES_ENCRYPT);
+#elif defined(USE_GNUTLS)
+  struct des_ctx des;
+  setup_des_key(keys, &des);
+  des_encrypt(&des, 8, results, plaintext);
+  setup_des_key(keys + 7, &des);
+  des_encrypt(&des, 8, results + 8, plaintext);
+  setup_des_key(keys + 14, &des);
+  des_encrypt(&des, 8, results + 16, plaintext);
+#elif defined(USE_MBEDTLS) || defined(USE_SECTRANSP)            \
+  || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
+  encrypt_des(plaintext, results, keys);
+  encrypt_des(plaintext, results + 8, keys + 7);
+  encrypt_des(plaintext, results + 16, keys + 14);
+#else
+  (void)keys;
+  (void)plaintext;
+  (void)results;
+#endif
+}
+
+/*
+ * Set up lanmanager hashed password
+ */
+CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
+                                   unsigned char *lmbuffer /* 21 bytes */)
+{
+  unsigned char pw[14];
+#if !defined(CURL_NTLM_NOT_SUPPORTED)
+  static const unsigned char magic[] = {
+    0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
+  };
+#endif
+  size_t len = CURLMIN(strlen(password), 14);
+
+  Curl_strntoupper((char *)pw, password, len);
+  memset(&pw[len], 0, 14 - len);
+
+  {
+    /* Create LanManager hashed password. */
+
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
+    DES_key_schedule ks;
+
+    setup_des_key(pw, DESKEY(ks));
+    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
+                    DESKEY(ks), DES_ENCRYPT);
+
+    setup_des_key(pw + 7, DESKEY(ks));
+    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8),
+                    DESKEY(ks), DES_ENCRYPT);
+#elif defined(USE_GNUTLS)
+    struct des_ctx des;
+    setup_des_key(pw, &des);
+    des_encrypt(&des, 8, lmbuffer, magic);
+    setup_des_key(pw + 7, &des);
+    des_encrypt(&des, 8, lmbuffer + 8, magic);
+#elif defined(USE_MBEDTLS) || defined(USE_SECTRANSP)            \
+  || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
+    encrypt_des(magic, lmbuffer, pw);
+    encrypt_des(magic, lmbuffer + 8, pw + 7);
+#endif
+
+    memset(lmbuffer + 16, 0, 21 - 16);
+  }
+
+  return CURLE_OK;
+}
+
+static void ascii_to_unicode_le(unsigned char *dest, const char *src,
+                                size_t srclen)
+{
+  size_t i;
+  for(i = 0; i < srclen; i++) {
+    dest[2 * i] = (unsigned char)src[i];
+    dest[2 * i + 1] = '\0';
+  }
+}
+
+#if !defined(USE_WINDOWS_SSPI)
+
+static void ascii_uppercase_to_unicode_le(unsigned char *dest,
+                                          const char *src, size_t srclen)
+{
+  size_t i;
+  for(i = 0; i < srclen; i++) {
+    dest[2 * i] = (unsigned char)(Curl_raw_toupper(src[i]));
+    dest[2 * i + 1] = '\0';
+  }
+}
+
+#endif /* !USE_WINDOWS_SSPI */
+
+/*
+ * Set up nt hashed passwords
+ * @unittest: 1600
+ */
+CURLcode Curl_ntlm_core_mk_nt_hash(const char *password,
+                                   unsigned char *ntbuffer /* 21 bytes */)
+{
+  size_t len = strlen(password);
+  unsigned char *pw;
+  CURLcode result;
+  if(len > SIZE_T_MAX/2) /* avoid integer overflow */
+    return CURLE_OUT_OF_MEMORY;
+  pw = len ? malloc(len * 2) : (unsigned char *)strdup("");
+  if(!pw)
+    return CURLE_OUT_OF_MEMORY;
+
+  ascii_to_unicode_le(pw, password, len);
+
+  /* Create NT hashed password. */
+  result = Curl_md4it(ntbuffer, pw, 2 * len);
+  if(!result)
+    memset(ntbuffer + 16, 0, 21 - 16);
+
+  free(pw);
+
+  return result;
+}
+
+#if !defined(USE_WINDOWS_SSPI)
+
+/* Timestamp in tenths of a microsecond since January 1, 1601 00:00:00 UTC. */
+struct ms_filetime {
+  unsigned int dwLowDateTime;
+  unsigned int dwHighDateTime;
+};
+
+/* Convert a time_t to an MS FILETIME (MS-DTYP section 2.3.3). */
+static void time2filetime(struct ms_filetime *ft, time_t t)
+{
+#if SIZEOF_TIME_T > 4
+  t = (t + CURL_OFF_T_C(11644473600)) * 10000000;
+  ft->dwLowDateTime = (unsigned int) (t & 0xFFFFFFFF);
+  ft->dwHighDateTime = (unsigned int) (t >> 32);
+#else
+  unsigned int r, s;
+  unsigned int i;
+
+  ft->dwLowDateTime = t & 0xFFFFFFFF;
+  ft->dwHighDateTime = 0;
+
+# ifndef HAVE_TIME_T_UNSIGNED
+  /* Extend sign if needed. */
+  if(ft->dwLowDateTime & 0x80000000)
+    ft->dwHighDateTime = ~0;
+# endif
+
+  /* Bias seconds to Jan 1, 1601.
+     134774 days = 11644473600 seconds = 0x2B6109100 */
+  r = ft->dwLowDateTime;
+  ft->dwLowDateTime = (ft->dwLowDateTime + 0xB6109100U) & 0xFFFFFFFF;
+  ft->dwHighDateTime += ft->dwLowDateTime < r? 0x03: 0x02;
+
+  /* Convert to tenths of microseconds. */
+  ft->dwHighDateTime *= 10000000;
+  i = 32;
+  do {
+    i -= 8;
+    s = ((ft->dwLowDateTime >> i) & 0xFF) * (10000000 - 1);
+    r = (s << i) & 0xFFFFFFFF;
+    s >>= 1;   /* Split shift to avoid width overflow. */
+    s >>= 31 - i;
+    ft->dwLowDateTime = (ft->dwLowDateTime + r) & 0xFFFFFFFF;
+    if(ft->dwLowDateTime < r)
+      s++;
+    ft->dwHighDateTime += s;
+  } while(i);
+  ft->dwHighDateTime &= 0xFFFFFFFF;
+#endif
+}
+
+/* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode
+ * (uppercase UserName + Domain) as the data
+ */
+CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen,
+                                       const char *domain, size_t domlen,
+                                       unsigned char *ntlmhash,
+                                       unsigned char *ntlmv2hash)
+{
+  /* Unicode representation */
+  size_t identity_len;
+  unsigned char *identity;
+  CURLcode result = CURLE_OK;
+
+  if((userlen > CURL_MAX_INPUT_LENGTH) || (domlen > CURL_MAX_INPUT_LENGTH))
+    return CURLE_OUT_OF_MEMORY;
+
+  identity_len = (userlen + domlen) * 2;
+  identity = malloc(identity_len + 1);
+
+  if(!identity)
+    return CURLE_OUT_OF_MEMORY;
+
+  ascii_uppercase_to_unicode_le(identity, user, userlen);
+  ascii_to_unicode_le(identity + (userlen << 1), domain, domlen);
+
+  result = Curl_hmacit(Curl_HMAC_MD5, ntlmhash, 16, identity, identity_len,
+                       ntlmv2hash);
+  free(identity);
+
+  return result;
+}
+
+/*
+ * Curl_ntlm_core_mk_ntlmv2_resp()
+ *
+ * This creates the NTLMv2 response as set in the ntlm type-3 message.
+ *
+ * Parameters:
+ *
+ * ntlmv2hash       [in] - The ntlmv2 hash (16 bytes)
+ * challenge_client [in] - The client nonce (8 bytes)
+ * ntlm             [in] - The ntlm data struct being used to read TargetInfo
+                           and Server challenge received in the type-2 message
+ * ntresp          [out] - The address where a pointer to newly allocated
+ *                         memory holding the NTLMv2 response.
+ * ntresp_len      [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
+                                       unsigned char *challenge_client,
+                                       struct ntlmdata *ntlm,
+                                       unsigned char **ntresp,
+                                       unsigned int *ntresp_len)
+{
+/* NTLMv2 response structure :
+------------------------------------------------------------------------------
+0     HMAC MD5         16 bytes
+------BLOB--------------------------------------------------------------------
+16    Signature        0x01010000
+20    Reserved         long (0x00000000)
+24    Timestamp        LE, 64-bit signed value representing the number of
+                       tenths of a microsecond since January 1, 1601.
+32    Client Nonce     8 bytes
+40    Unknown          4 bytes
+44    Target Info      N bytes (from the type-2 message)
+44+N  Unknown          4 bytes
+------------------------------------------------------------------------------
+*/
+
+  unsigned int len = 0;
+  unsigned char *ptr = NULL;
+  unsigned char hmac_output[HMAC_MD5_LENGTH];
+  struct ms_filetime tw;
+
+  CURLcode result = CURLE_OK;
+
+  /* Calculate the timestamp */
+#ifdef DEBUGBUILD
+  char *force_timestamp = getenv("CURL_FORCETIME");
+  if(force_timestamp)
+    time2filetime(&tw, (time_t) 0);
+  else
+#endif
+    time2filetime(&tw, time(NULL));
+
+  /* Calculate the response len */
+  len = HMAC_MD5_LENGTH + NTLMv2_BLOB_LEN;
+
+  /* Allocate the response */
+  ptr = calloc(1, len);
+  if(!ptr)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Create the BLOB structure */
+  msnprintf((char *)ptr + HMAC_MD5_LENGTH, NTLMv2_BLOB_LEN,
+            "%c%c%c%c"           /* NTLMv2_BLOB_SIGNATURE */
+            "%c%c%c%c"           /* Reserved = 0 */
+            "%c%c%c%c%c%c%c%c",  /* Timestamp */
+            NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1],
+            NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3],
+            0, 0, 0, 0,
+            LONGQUARTET(tw.dwLowDateTime), LONGQUARTET(tw.dwHighDateTime));
+
+  memcpy(ptr + 32, challenge_client, 8);
+  if(ntlm->target_info_len)
+    memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len);
+
+  /* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */
+  memcpy(ptr + 8, &ntlm->nonce[0], 8);
+  result = Curl_hmacit(Curl_HMAC_MD5, ntlmv2hash, HMAC_MD5_LENGTH, ptr + 8,
+                    NTLMv2_BLOB_LEN + 8, hmac_output);
+  if(result) {
+    free(ptr);
+    return result;
+  }
+
+  /* Concatenate the HMAC MD5 output  with the BLOB */
+  memcpy(ptr, hmac_output, HMAC_MD5_LENGTH);
+
+  /* Return the response */
+  *ntresp = ptr;
+  *ntresp_len = len;
+
+  return result;
+}
+
+/*
+ * Curl_ntlm_core_mk_lmv2_resp()
+ *
+ * This creates the LMv2 response as used in the ntlm type-3 message.
+ *
+ * Parameters:
+ *
+ * ntlmv2hash        [in] - The ntlmv2 hash (16 bytes)
+ * challenge_client  [in] - The client nonce (8 bytes)
+ * challenge_client  [in] - The server challenge (8 bytes)
+ * lmresp           [out] - The LMv2 response (24 bytes)
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode  Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
+                                      unsigned char *challenge_client,
+                                      unsigned char *challenge_server,
+                                      unsigned char *lmresp)
+{
+  unsigned char data[16];
+  unsigned char hmac_output[16];
+  CURLcode result = CURLE_OK;
+
+  memcpy(&data[0], challenge_server, 8);
+  memcpy(&data[8], challenge_client, 8);
+
+  result = Curl_hmacit(Curl_HMAC_MD5, ntlmv2hash, 16, &data[0], 16,
+                       hmac_output);
+  if(result)
+    return result;
+
+  /* Concatenate the HMAC MD5 output  with the client nonce */
+  memcpy(lmresp, hmac_output, 16);
+  memcpy(lmresp + 16, challenge_client, 8);
+
+  return result;
+}
+
+#endif /* !USE_WINDOWS_SSPI */
+
+#endif /* USE_CURL_NTLM_CORE */
Index: trunk/src/libs/curl-8.7.1/lib/curl_ntlm_core.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_ntlm_core.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_ntlm_core.h	(revision 104083)
@@ -0,0 +1,79 @@
+#ifndef HEADER_CURL_NTLM_CORE_H
+#define HEADER_CURL_NTLM_CORE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_CURL_NTLM_CORE)
+
+#if defined(USE_OPENSSL)
+#  include <openssl/ssl.h>
+#elif defined(USE_WOLFSSL)
+#  include <wolfssl/options.h>
+#  include <wolfssl/openssl/ssl.h>
+#endif
+
+/* Helpers to generate function byte arguments in little endian order */
+#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
+#define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
+  ((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff))
+
+void Curl_ntlm_core_lm_resp(const unsigned char *keys,
+                            const unsigned char *plaintext,
+                            unsigned char *results);
+
+CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
+                                   unsigned char *lmbuffer /* 21 bytes */);
+
+CURLcode Curl_ntlm_core_mk_nt_hash(const char *password,
+                                   unsigned char *ntbuffer /* 21 bytes */);
+
+#if !defined(USE_WINDOWS_SSPI)
+
+CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen,
+                       const unsigned char *data, unsigned int datalen,
+                       unsigned char *output);
+
+CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen,
+                                       const char *domain, size_t domlen,
+                                       unsigned char *ntlmhash,
+                                       unsigned char *ntlmv2hash);
+
+CURLcode  Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
+                                        unsigned char *challenge_client,
+                                        struct ntlmdata *ntlm,
+                                        unsigned char **ntresp,
+                                        unsigned int *ntresp_len);
+
+CURLcode  Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
+                                      unsigned char *challenge_client,
+                                      unsigned char *challenge_server,
+                                      unsigned char *lmresp);
+
+#endif /* !USE_WINDOWS_SSPI */
+
+#endif /* USE_CURL_NTLM_CORE */
+
+#endif /* HEADER_CURL_NTLM_CORE_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_ntlm_wb.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_ntlm_wb.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_ntlm_wb.c	(revision 104083)
@@ -0,0 +1,500 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+    defined(NTLM_WB_ENABLED)
+
+/*
+ * NTLM details:
+ *
+ * https://davenport.sourceforge.net/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
+ */
+
+#define DEBUG_ME 0
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include <signal.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "select.h"
+#include "vauth/ntlm.h"
+#include "curl_ntlm_core.h"
+#include "curl_ntlm_wb.h"
+#include "url.h"
+#include "strerror.h"
+#include "strdup.h"
+#include "strcase.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if DEBUG_ME
+# define DEBUG_OUT(x) x
+#else
+# define DEBUG_OUT(x) Curl_nop_stmt
+#endif
+
+/* Portable 'sclose_nolog' used only in child process instead of 'sclose'
+   to avoid fooling the socket leak detector */
+#ifdef HAVE_PIPE
+#  define sclose_nolog(x)  close((x))
+#elif defined(HAVE_CLOSESOCKET)
+#  define sclose_nolog(x)  closesocket((x))
+#elif defined(HAVE_CLOSESOCKET_CAMEL)
+#  define sclose_nolog(x)  CloseSocket((x))
+#else
+#  define sclose_nolog(x)  close((x))
+#endif
+
+static void ntlm_wb_cleanup(struct ntlmdata *ntlm)
+{
+  if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) {
+    sclose(ntlm->ntlm_auth_hlpr_socket);
+    ntlm->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+  }
+
+  if(ntlm->ntlm_auth_hlpr_pid) {
+    int i;
+    for(i = 0; i < 4; i++) {
+      pid_t ret = waitpid(ntlm->ntlm_auth_hlpr_pid, NULL, WNOHANG);
+      if(ret == ntlm->ntlm_auth_hlpr_pid || errno == ECHILD)
+        break;
+      switch(i) {
+      case 0:
+        kill(ntlm->ntlm_auth_hlpr_pid, SIGTERM);
+        break;
+      case 1:
+        /* Give the process another moment to shut down cleanly before
+           bringing down the axe */
+        Curl_wait_ms(1);
+        break;
+      case 2:
+        kill(ntlm->ntlm_auth_hlpr_pid, SIGKILL);
+        break;
+      case 3:
+        break;
+      }
+    }
+    ntlm->ntlm_auth_hlpr_pid = 0;
+  }
+
+  Curl_safefree(ntlm->challenge);
+  Curl_safefree(ntlm->response);
+}
+
+static CURLcode ntlm_wb_init(struct Curl_easy *data, struct ntlmdata *ntlm,
+                             const char *userp)
+{
+  curl_socket_t sockfds[2];
+  pid_t child_pid;
+  const char *username;
+  char *slash, *domain = NULL;
+  const char *ntlm_auth = NULL;
+  char *ntlm_auth_alloc = NULL;
+#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
+  struct passwd pw, *pw_res;
+  char pwbuf[1024];
+#endif
+  char buffer[STRERROR_LEN];
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) data;
+#endif
+
+  /* Return if communication with ntlm_auth already set up */
+  if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
+     ntlm->ntlm_auth_hlpr_pid)
+    return CURLE_OK;
+
+  username = userp;
+  /* The real ntlm_auth really doesn't like being invoked with an
+     empty username. It won't make inferences for itself, and expects
+     the client to do so (mostly because it's really designed for
+     servers like squid to use for auth, and client support is an
+     afterthought for it). So try hard to provide a suitable username
+     if we don't already have one. But if we can't, provide the
+     empty one anyway. Perhaps they have an implementation of the
+     ntlm_auth helper which *doesn't* need it so we might as well try */
+  if(!username || !username[0]) {
+    username = getenv("NTLMUSER");
+    if(!username || !username[0])
+      username = getenv("LOGNAME");
+    if(!username || !username[0])
+      username = getenv("USER");
+#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
+    if((!username || !username[0]) &&
+       !getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) &&
+       pw_res) {
+      username = pw.pw_name;
+    }
+#endif
+    if(!username || !username[0])
+      username = userp;
+  }
+  slash = strpbrk(username, "\\/");
+  if(slash) {
+    domain = strdup(username);
+    if(!domain)
+      return CURLE_OUT_OF_MEMORY;
+    slash = domain + (slash - username);
+    *slash = '\0';
+    username = username + (slash - domain) + 1;
+  }
+
+  /* For testing purposes, when DEBUGBUILD is defined and environment
+     variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform
+     NTLM challenge/response which only accepts commands and output
+     strings pre-written in test case definitions */
+#ifdef DEBUGBUILD
+  ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE");
+  if(ntlm_auth_alloc)
+    ntlm_auth = ntlm_auth_alloc;
+  else
+#endif
+    ntlm_auth = NTLM_WB_FILE;
+
+  if(access(ntlm_auth, X_OK) != 0) {
+    failf(data, "Could not access ntlm_auth: %s errno %d: %s",
+          ntlm_auth, errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+    goto done;
+  }
+
+  if(wakeup_create(sockfds)) {
+    failf(data, "Could not open socket pair. errno %d: %s",
+          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+    goto done;
+  }
+
+  child_pid = fork();
+  if(child_pid == -1) {
+    wakeup_close(sockfds[0]);
+    wakeup_close(sockfds[1]);
+    failf(data, "Could not fork. errno %d: %s",
+          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+    goto done;
+  }
+  else if(!child_pid) {
+    /*
+     * child process
+     */
+
+    /* Don't use sclose in the child since it fools the socket leak detector */
+    sclose_nolog(sockfds[0]);
+    if(dup2(sockfds[1], STDIN_FILENO) == -1) {
+      failf(data, "Could not redirect child stdin. errno %d: %s",
+            errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+      exit(1);
+    }
+
+    if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
+      failf(data, "Could not redirect child stdout. errno %d: %s",
+            errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+      exit(1);
+    }
+
+    if(domain)
+      execl(ntlm_auth, ntlm_auth,
+            "--helper-protocol", "ntlmssp-client-1",
+            "--use-cached-creds",
+            "--username", username,
+            "--domain", domain,
+            NULL);
+    else
+      execl(ntlm_auth, ntlm_auth,
+            "--helper-protocol", "ntlmssp-client-1",
+            "--use-cached-creds",
+            "--username", username,
+            NULL);
+
+    sclose_nolog(sockfds[1]);
+    failf(data, "Could not execl(). errno %d: %s",
+          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+    exit(1);
+  }
+
+  sclose(sockfds[1]);
+  ntlm->ntlm_auth_hlpr_socket = sockfds[0];
+  ntlm->ntlm_auth_hlpr_pid = child_pid;
+  free(domain);
+  free(ntlm_auth_alloc);
+  return CURLE_OK;
+
+done:
+  free(domain);
+  free(ntlm_auth_alloc);
+  return CURLE_REMOTE_ACCESS_DENIED;
+}
+
+/* if larger than this, something is seriously wrong */
+#define MAX_NTLM_WB_RESPONSE 100000
+
+static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm,
+                                 const char *input, curlntlm state)
+{
+  size_t len_in = strlen(input), len_out = 0;
+  struct dynbuf b;
+  char *ptr = NULL;
+  unsigned char buf[1024];
+  Curl_dyn_init(&b, MAX_NTLM_WB_RESPONSE);
+
+  while(len_in > 0) {
+    ssize_t written = wakeup_write(ntlm->ntlm_auth_hlpr_socket, input, len_in);
+    if(written == -1) {
+      /* Interrupted by a signal, retry it */
+      if(errno == EINTR)
+        continue;
+      /* write failed if other errors happen */
+      goto done;
+    }
+    input += written;
+    len_in -= written;
+  }
+  /* Read one line */
+  while(1) {
+    ssize_t size =
+      wakeup_read(ntlm->ntlm_auth_hlpr_socket, buf, sizeof(buf));
+    if(size == -1) {
+      if(errno == EINTR)
+        continue;
+      goto done;
+    }
+    else if(size == 0)
+      goto done;
+
+    if(Curl_dyn_addn(&b, buf, size))
+      goto done;
+
+    len_out = Curl_dyn_len(&b);
+    ptr = Curl_dyn_ptr(&b);
+    if(len_out && ptr[len_out - 1] == '\n') {
+      ptr[len_out - 1] = '\0';
+      break; /* done! */
+    }
+    /* loop */
+  }
+
+  /* Samba/winbind installed but not configured */
+  if(state == NTLMSTATE_TYPE1 &&
+     len_out == 3 &&
+     ptr[0] == 'P' && ptr[1] == 'W')
+    goto done;
+  /* invalid response */
+  if(len_out < 4)
+    goto done;
+  if(state == NTLMSTATE_TYPE1 &&
+     (ptr[0]!='Y' || ptr[1]!='R' || ptr[2]!=' '))
+    goto done;
+  if(state == NTLMSTATE_TYPE2 &&
+     (ptr[0]!='K' || ptr[1]!='K' || ptr[2]!=' ') &&
+     (ptr[0]!='A' || ptr[1]!='F' || ptr[2]!=' '))
+    goto done;
+
+  ntlm->response = strdup(ptr + 3);
+  Curl_dyn_free(&b);
+  if(!ntlm->response)
+    return CURLE_OUT_OF_MEMORY;
+  return CURLE_OK;
+done:
+  Curl_dyn_free(&b);
+  return CURLE_REMOTE_ACCESS_DENIED;
+}
+
+CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
+                            struct connectdata *conn,
+                            bool proxy,
+                            const char *header)
+{
+  struct ntlmdata *ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
+  curlntlm *state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
+
+  (void) data;  /* In case it gets unused by nop log macros. */
+
+  if(!checkprefix("NTLM", header))
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  header += strlen("NTLM");
+  while(*header && ISSPACE(*header))
+    header++;
+
+  if(*header) {
+    ntlm->challenge = strdup(header);
+    if(!ntlm->challenge)
+      return CURLE_OUT_OF_MEMORY;
+
+    *state = NTLMSTATE_TYPE2; /* We got a type-2 message */
+  }
+  else {
+    if(*state == NTLMSTATE_LAST) {
+      infof(data, "NTLM auth restarted");
+      Curl_http_auth_cleanup_ntlm_wb(conn);
+    }
+    else if(*state == NTLMSTATE_TYPE3) {
+      infof(data, "NTLM handshake rejected");
+      Curl_http_auth_cleanup_ntlm_wb(conn);
+      *state = NTLMSTATE_NONE;
+      return CURLE_REMOTE_ACCESS_DENIED;
+    }
+    else if(*state >= NTLMSTATE_TYPE1) {
+      infof(data, "NTLM handshake failure (internal error)");
+      return CURLE_REMOTE_ACCESS_DENIED;
+    }
+
+    *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * This is for creating ntlm header output by delegating challenge/response
+ * to Samba's winbind daemon helper ntlm_auth.
+ */
+CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
+                             bool proxy)
+{
+  /* point to the address of the pointer that holds the string to send to the
+     server, which is for a plain host or for an HTTP proxy */
+  char **allocuserpwd;
+  /* point to the name and password for this */
+  const char *userp;
+  struct ntlmdata *ntlm;
+  curlntlm *state;
+  struct auth *authp;
+
+  CURLcode res = CURLE_OK;
+
+  DEBUGASSERT(conn);
+  DEBUGASSERT(data);
+
+  if(proxy) {
+#ifndef CURL_DISABLE_PROXY
+    allocuserpwd = &data->state.aptr.proxyuserpwd;
+    userp = conn->http_proxy.user;
+    ntlm = &conn->proxyntlm;
+    state = &conn->proxy_ntlm_state;
+    authp = &data->state.authproxy;
+#else
+    return CURLE_NOT_BUILT_IN;
+#endif
+  }
+  else {
+    allocuserpwd = &data->state.aptr.userpwd;
+    userp = conn->user;
+    ntlm = &conn->ntlm;
+    state = &conn->http_ntlm_state;
+    authp = &data->state.authhost;
+  }
+  authp->done = FALSE;
+
+  /* not set means empty */
+  if(!userp)
+    userp = "";
+
+  switch(*state) {
+  case NTLMSTATE_TYPE1:
+  default:
+    /* Use Samba's 'winbind' daemon to support NTLM authentication,
+     * by delegating the NTLM challenge/response protocol to a helper
+     * in ntlm_auth.
+     * https://web.archive.org/web/20190925164737
+     * /devel.squid-cache.org/ntlm/squid_helper_protocol.html
+     * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
+     * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
+     * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this
+     * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute
+     * filename of ntlm_auth helper.
+     * If NTLM authentication using winbind fails, go back to original
+     * request handling process.
+     */
+    /* Create communication with ntlm_auth */
+    res = ntlm_wb_init(data, ntlm, userp);
+    if(res)
+      return res;
+    res = ntlm_wb_response(data, ntlm, "YR\n", *state);
+    if(res)
+      return res;
+
+    free(*allocuserpwd);
+    *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+                            proxy ? "Proxy-" : "",
+                            ntlm->response);
+    DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
+    Curl_safefree(ntlm->response);
+    if(!*allocuserpwd)
+      return CURLE_OUT_OF_MEMORY;
+    break;
+
+  case NTLMSTATE_TYPE2: {
+    char *input = aprintf("TT %s\n", ntlm->challenge);
+    if(!input)
+      return CURLE_OUT_OF_MEMORY;
+    res = ntlm_wb_response(data, ntlm, input, *state);
+    free(input);
+    if(res)
+      return res;
+
+    free(*allocuserpwd);
+    *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+                            proxy ? "Proxy-" : "",
+                            ntlm->response);
+    DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
+    *state = NTLMSTATE_TYPE3; /* we sent a type-3 */
+    authp->done = TRUE;
+    Curl_http_auth_cleanup_ntlm_wb(conn);
+    if(!*allocuserpwd)
+      return CURLE_OUT_OF_MEMORY;
+    break;
+  }
+  case NTLMSTATE_TYPE3:
+    /* connection is already authenticated,
+     * don't send a header in future requests */
+    *state = NTLMSTATE_LAST;
+    FALLTHROUGH();
+  case NTLMSTATE_LAST:
+    Curl_safefree(*allocuserpwd);
+    authp->done = TRUE;
+    break;
+  }
+
+  return CURLE_OK;
+}
+
+void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn)
+{
+  ntlm_wb_cleanup(&conn->ntlm);
+  ntlm_wb_cleanup(&conn->proxyntlm);
+}
+
+#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */
Index: trunk/src/libs/curl-8.7.1/lib/curl_ntlm_wb.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_ntlm_wb.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_ntlm_wb.h	(revision 104083)
@@ -0,0 +1,45 @@
+#ifndef HEADER_CURL_NTLM_WB_H
+#define HEADER_CURL_NTLM_WB_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+    defined(NTLM_WB_ENABLED)
+
+/* this is for ntlm header input */
+CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
+                            struct connectdata *conn, bool proxy,
+                            const char *header);
+
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
+                             bool proxy);
+
+void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn);
+
+#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */
+
+#endif /* HEADER_CURL_NTLM_WB_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_path.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_path.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_path.c	(revision 104083)
@@ -0,0 +1,199 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl AND ISC
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_SSH)
+
+#include <curl/curl.h>
+#include "curl_memory.h"
+#include "curl_path.h"
+#include "escape.h"
+#include "memdebug.h"
+
+#define MAX_SSHPATH_LEN 100000 /* arbitrary */
+
+/* figure out the path to work with in this particular request */
+CURLcode Curl_getworkingpath(struct Curl_easy *data,
+                             char *homedir,  /* when SFTP is used */
+                             char **path) /* returns the  allocated
+                                             real path to work with */
+{
+  char *working_path;
+  size_t working_path_len;
+  struct dynbuf npath;
+  CURLcode result =
+    Curl_urldecode(data->state.up.path, 0, &working_path,
+                   &working_path_len, REJECT_ZERO);
+  if(result)
+    return result;
+
+  /* new path to switch to in case we need to */
+  Curl_dyn_init(&npath, MAX_SSHPATH_LEN);
+
+  /* Check for /~/, indicating relative to the user's home directory */
+  if((data->conn->handler->protocol & CURLPROTO_SCP) &&
+     (working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) {
+    /* It is referenced to the home directory, so strip the leading '/~/' */
+    if(Curl_dyn_addn(&npath, &working_path[3], working_path_len - 3)) {
+      free(working_path);
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  else if((data->conn->handler->protocol & CURLPROTO_SFTP) &&
+          (!strcmp("/~", working_path) ||
+           ((working_path_len > 2) && !memcmp(working_path, "/~/", 3)))) {
+    if(Curl_dyn_add(&npath, homedir)) {
+      free(working_path);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    if(working_path_len > 2) {
+      size_t len;
+      const char *p;
+      int copyfrom = 3;
+      /* Copy a separating '/' if homedir does not end with one */
+      len = Curl_dyn_len(&npath);
+      p = Curl_dyn_ptr(&npath);
+      if(len && (p[len-1] != '/'))
+        copyfrom = 2;
+
+      if(Curl_dyn_addn(&npath,
+                       &working_path[copyfrom], working_path_len - copyfrom)) {
+        free(working_path);
+        return CURLE_OUT_OF_MEMORY;
+      }
+    }
+  }
+
+  if(Curl_dyn_len(&npath)) {
+    free(working_path);
+
+    /* store the pointer for the caller to receive */
+    *path = Curl_dyn_ptr(&npath);
+  }
+  else
+    *path = working_path;
+
+  return CURLE_OK;
+}
+
+/* The get_pathname() function is being borrowed from OpenSSH sftp.c
+   version 4.6p1. */
+/*
+ * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
+{
+  const char *cp = *cpp, *end;
+  char quot;
+  unsigned int i, j;
+  size_t fullPathLength, pathLength;
+  bool relativePath = false;
+  static const char WHITESPACE[] = " \t\r\n";
+
+  DEBUGASSERT(homedir);
+  if(!*cp || !homedir) {
+    *cpp = NULL;
+    *path = NULL;
+    return CURLE_QUOTE_ERROR;
+  }
+  /* Ignore leading whitespace */
+  cp += strspn(cp, WHITESPACE);
+  /* Allocate enough space for home directory and filename + separator */
+  fullPathLength = strlen(cp) + strlen(homedir) + 2;
+  *path = malloc(fullPathLength);
+  if(!*path)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Check for quoted filenames */
+  if(*cp == '\"' || *cp == '\'') {
+    quot = *cp++;
+
+    /* Search for terminating quote, unescape some chars */
+    for(i = j = 0; i <= strlen(cp); i++) {
+      if(cp[i] == quot) {  /* Found quote */
+        i++;
+        (*path)[j] = '\0';
+        break;
+      }
+      if(cp[i] == '\0') {  /* End of string */
+        goto fail;
+      }
+      if(cp[i] == '\\') {  /* Escaped characters */
+        i++;
+        if(cp[i] != '\'' && cp[i] != '\"' &&
+            cp[i] != '\\') {
+          goto fail;
+        }
+      }
+      (*path)[j++] = cp[i];
+    }
+
+    if(j == 0) {
+      goto fail;
+    }
+    *cpp = cp + i + strspn(cp + i, WHITESPACE);
+  }
+  else {
+    /* Read to end of filename - either to whitespace or terminator */
+    end = strpbrk(cp, WHITESPACE);
+    if(!end)
+      end = strchr(cp, '\0');
+    /* return pointer to second parameter if it exists */
+    *cpp = end + strspn(end, WHITESPACE);
+    pathLength = 0;
+    relativePath = (cp[0] == '/' && cp[1] == '~' && cp[2] == '/');
+    /* Handling for relative path - prepend home directory */
+    if(relativePath) {
+      strcpy(*path, homedir);
+      pathLength = strlen(homedir);
+      (*path)[pathLength++] = '/';
+      (*path)[pathLength] = '\0';
+      cp += 3;
+    }
+    /* Copy path name up until first "whitespace" */
+    memcpy(&(*path)[pathLength], cp, (int)(end - cp));
+    pathLength += (int)(end - cp);
+    (*path)[pathLength] = '\0';
+  }
+  return CURLE_OK;
+
+fail:
+  Curl_safefree(*path);
+  return CURLE_QUOTE_ERROR;
+}
+
+#endif /* if SSH is used */
Index: trunk/src/libs/curl-8.7.1/lib/curl_path.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_path.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_path.h	(revision 104083)
@@ -0,0 +1,49 @@
+#ifndef HEADER_CURL_PATH_H
+#define HEADER_CURL_PATH_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include <curl/curl.h>
+#include "urldata.h"
+
+#ifdef _WIN32
+#  undef  PATH_MAX
+#  define PATH_MAX MAX_PATH
+#  ifndef R_OK
+#    define R_OK 4
+#  endif
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024 /* just an extra precaution since there are systems that
+                         have their definition hidden well */
+#endif
+
+CURLcode Curl_getworkingpath(struct Curl_easy *data,
+                             char *homedir,
+                             char **path);
+
+CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir);
+#endif /* HEADER_CURL_PATH_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_printf.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_printf.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_printf.h	(revision 104083)
@@ -0,0 +1,55 @@
+#ifndef HEADER_CURL_PRINTF_H
+#define HEADER_CURL_PRINTF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * This header should be included by ALL code in libcurl that uses any
+ * *rintf() functions.
+ */
+
+#include <curl/mprintf.h>
+
+#define MERR_OK        0
+#define MERR_MEM       1
+#define MERR_TOO_LARGE 2
+
+# undef printf
+# undef fprintf
+# undef msnprintf
+# undef vprintf
+# undef vfprintf
+# undef vsnprintf
+# undef mvsnprintf
+# undef aprintf
+# undef vaprintf
+# define printf curl_mprintf
+# define fprintf curl_mfprintf
+# define msnprintf curl_msnprintf
+# define vprintf curl_mvprintf
+# define vfprintf curl_mvfprintf
+# define mvsnprintf curl_mvsnprintf
+# define aprintf curl_maprintf
+# define vaprintf curl_mvaprintf
+#endif /* HEADER_CURL_PRINTF_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_range.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_range.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_range.c	(revision 104083)
@@ -0,0 +1,96 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include <curl/curl.h>
+#include "curl_range.h"
+#include "sendf.h"
+#include "strtoofft.h"
+
+/* Only include this function if one or more of FTP, FILE are enabled. */
+#if !defined(CURL_DISABLE_FTP) || !defined(CURL_DISABLE_FILE)
+
+ /*
+  Check if this is a range download, and if so, set the internal variables
+  properly.
+ */
+CURLcode Curl_range(struct Curl_easy *data)
+{
+  curl_off_t from, to;
+  char *ptr;
+  char *ptr2;
+
+  if(data->state.use_range && data->state.range) {
+    CURLofft from_t;
+    CURLofft to_t;
+    from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
+    if(from_t == CURL_OFFT_FLOW)
+      return CURLE_RANGE_ERROR;
+    while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
+      ptr++;
+    to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
+    if(to_t == CURL_OFFT_FLOW)
+      return CURLE_RANGE_ERROR;
+    if((to_t == CURL_OFFT_INVAL) && !from_t) {
+      /* X - */
+      data->state.resume_from = from;
+      DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file",
+                   from));
+    }
+    else if((from_t == CURL_OFFT_INVAL) && !to_t) {
+      /* -Y */
+      data->req.maxdownload = to;
+      data->state.resume_from = -to;
+      DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes",
+                   to));
+    }
+    else {
+      /* X-Y */
+      curl_off_t totalsize;
+
+      /* Ensure the range is sensible - to should follow from. */
+      if(from > to)
+        return CURLE_RANGE_ERROR;
+
+      totalsize = to - from;
+      if(totalsize == CURL_OFF_T_MAX)
+        return CURLE_RANGE_ERROR;
+
+      data->req.maxdownload = totalsize + 1; /* include last byte */
+      data->state.resume_from = from;
+      DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T
+                   " getting %" CURL_FORMAT_CURL_OFF_T " bytes",
+                   from, data->req.maxdownload));
+    }
+    DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T
+                 " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
+                 CURL_FORMAT_CURL_OFF_T " bytes",
+                 from, to, data->req.maxdownload));
+  }
+  else
+    data->req.maxdownload = -1;
+  return CURLE_OK;
+}
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/curl_range.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_range.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_range.h	(revision 104083)
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_RANGE_H
+#define HEADER_CURL_RANGE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "urldata.h"
+
+CURLcode Curl_range(struct Curl_easy *data);
+#endif /* HEADER_CURL_RANGE_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_rtmp.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_rtmp.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_rtmp.c	(revision 104083)
@@ -0,0 +1,338 @@
+/***************************************************************************
+ *                      _   _ ____  _
+ *  Project         ___| | | |  _ \| |
+ *                 / __| | | | |_) | |
+ *                | (__| |_| |  _ <| |___
+ *                 \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Howard Chu, <hyc@highlandsun.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_LIBRTMP
+
+#include "curl_rtmp.h"
+#include "urldata.h"
+#include "nonblock.h" /* for curlx_nonblock */
+#include "progress.h" /* for Curl_pgrsSetUploadSize */
+#include "transfer.h"
+#include "warnless.h"
+#include <curl/curl.h>
+#include <librtmp/rtmp.h>
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#if defined(_WIN32) && !defined(USE_LWIPSOCK)
+#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e)
+#define SET_RCVTIMEO(tv,s)   int tv = s*1000
+#elif defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD)
+#define SET_RCVTIMEO(tv,s)   int tv = s*1000
+#else
+#define SET_RCVTIMEO(tv,s)   struct timeval tv = {s,0}
+#endif
+
+#define DEF_BUFTIME    (2*60*60*1000)    /* 2 hours */
+
+static CURLcode rtmp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static CURLcode rtmp_do(struct Curl_easy *data, bool *done);
+static CURLcode rtmp_done(struct Curl_easy *data, CURLcode, bool premature);
+static CURLcode rtmp_connect(struct Curl_easy *data, bool *done);
+static CURLcode rtmp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
+
+static Curl_recv rtmp_recv;
+static Curl_send rtmp_send;
+
+/*
+ * RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu
+ */
+
+const struct Curl_handler Curl_handler_rtmp = {
+  "RTMP",                               /* scheme */
+  rtmp_setup_connection,                /* setup_connection */
+  rtmp_do,                              /* do_it */
+  rtmp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  rtmp_connect,                         /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  rtmp_disconnect,                      /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_RTMP,                            /* defport */
+  CURLPROTO_RTMP,                       /* protocol */
+  CURLPROTO_RTMP,                       /* family */
+  PROTOPT_NONE                          /* flags */
+};
+
+const struct Curl_handler Curl_handler_rtmpt = {
+  "RTMPT",                              /* scheme */
+  rtmp_setup_connection,                /* setup_connection */
+  rtmp_do,                              /* do_it */
+  rtmp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  rtmp_connect,                         /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  rtmp_disconnect,                      /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_RTMPT,                           /* defport */
+  CURLPROTO_RTMPT,                      /* protocol */
+  CURLPROTO_RTMPT,                      /* family */
+  PROTOPT_NONE                          /* flags */
+};
+
+const struct Curl_handler Curl_handler_rtmpe = {
+  "RTMPE",                              /* scheme */
+  rtmp_setup_connection,                /* setup_connection */
+  rtmp_do,                              /* do_it */
+  rtmp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  rtmp_connect,                         /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  rtmp_disconnect,                      /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_RTMP,                            /* defport */
+  CURLPROTO_RTMPE,                      /* protocol */
+  CURLPROTO_RTMPE,                      /* family */
+  PROTOPT_NONE                          /* flags */
+};
+
+const struct Curl_handler Curl_handler_rtmpte = {
+  "RTMPTE",                             /* scheme */
+  rtmp_setup_connection,                /* setup_connection */
+  rtmp_do,                              /* do_it */
+  rtmp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  rtmp_connect,                         /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  rtmp_disconnect,                      /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_RTMPT,                           /* defport */
+  CURLPROTO_RTMPTE,                     /* protocol */
+  CURLPROTO_RTMPTE,                     /* family */
+  PROTOPT_NONE                          /* flags */
+};
+
+const struct Curl_handler Curl_handler_rtmps = {
+  "RTMPS",                              /* scheme */
+  rtmp_setup_connection,                /* setup_connection */
+  rtmp_do,                              /* do_it */
+  rtmp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  rtmp_connect,                         /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  rtmp_disconnect,                      /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_RTMPS,                           /* defport */
+  CURLPROTO_RTMPS,                      /* protocol */
+  CURLPROTO_RTMP,                       /* family */
+  PROTOPT_NONE                          /* flags */
+};
+
+const struct Curl_handler Curl_handler_rtmpts = {
+  "RTMPTS",                             /* scheme */
+  rtmp_setup_connection,                /* setup_connection */
+  rtmp_do,                              /* do_it */
+  rtmp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  rtmp_connect,                         /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  rtmp_disconnect,                      /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_RTMPS,                           /* defport */
+  CURLPROTO_RTMPTS,                     /* protocol */
+  CURLPROTO_RTMPT,                      /* family */
+  PROTOPT_NONE                          /* flags */
+};
+
+static CURLcode rtmp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  RTMP *r = RTMP_Alloc();
+  if(!r)
+    return CURLE_OUT_OF_MEMORY;
+
+  RTMP_Init(r);
+  RTMP_SetBufferMS(r, DEF_BUFTIME);
+  if(!RTMP_SetupURL(r, data->state.url)) {
+    RTMP_Free(r);
+    return CURLE_URL_MALFORMAT;
+  }
+  conn->proto.rtmp = r;
+  return CURLE_OK;
+}
+
+static CURLcode rtmp_connect(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  RTMP *r = conn->proto.rtmp;
+  SET_RCVTIMEO(tv, 10);
+
+  r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET];
+
+  /* We have to know if it's a write before we send the
+   * connect request packet
+   */
+  if(data->state.upload)
+    r->Link.protocol |= RTMP_FEATURE_WRITE;
+
+  /* For plain streams, use the buffer toggle trick to keep data flowing */
+  if(!(r->Link.lFlags & RTMP_LF_LIVE) &&
+     !(r->Link.protocol & RTMP_FEATURE_HTTP))
+    r->Link.lFlags |= RTMP_LF_BUFX;
+
+  (void)curlx_nonblock(r->m_sb.sb_socket, FALSE);
+  setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO,
+             (char *)&tv, sizeof(tv));
+
+  if(!RTMP_Connect1(r, NULL))
+    return CURLE_FAILED_INIT;
+
+  /* Clients must send a periodic BytesReceived report to the server */
+  r->m_bSendCounter = true;
+
+  *done = TRUE;
+  conn->recv[FIRSTSOCKET] = rtmp_recv;
+  conn->send[FIRSTSOCKET] = rtmp_send;
+  return CURLE_OK;
+}
+
+static CURLcode rtmp_do(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  RTMP *r = conn->proto.rtmp;
+
+  if(!RTMP_ConnectStream(r, 0))
+    return CURLE_FAILED_INIT;
+
+  if(data->state.upload) {
+    Curl_pgrsSetUploadSize(data, data->state.infilesize);
+    Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
+  }
+  else
+    Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
+  *done = TRUE;
+  return CURLE_OK;
+}
+
+static CURLcode rtmp_done(struct Curl_easy *data, CURLcode status,
+                          bool premature)
+{
+  (void)data; /* unused */
+  (void)status; /* unused */
+  (void)premature; /* unused */
+
+  return CURLE_OK;
+}
+
+static CURLcode rtmp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                bool dead_connection)
+{
+  RTMP *r = conn->proto.rtmp;
+  (void)data;
+  (void)dead_connection;
+  if(r) {
+    conn->proto.rtmp = NULL;
+    RTMP_Close(r);
+    RTMP_Free(r);
+  }
+  return CURLE_OK;
+}
+
+static ssize_t rtmp_recv(struct Curl_easy *data, int sockindex, char *buf,
+                         size_t len, CURLcode *err)
+{
+  struct connectdata *conn = data->conn;
+  RTMP *r = conn->proto.rtmp;
+  ssize_t nread;
+
+  (void)sockindex; /* unused */
+
+  nread = RTMP_Read(r, buf, curlx_uztosi(len));
+  if(nread < 0) {
+    if(r->m_read.status == RTMP_READ_COMPLETE ||
+       r->m_read.status == RTMP_READ_EOF) {
+      data->req.size = data->req.bytecount;
+      nread = 0;
+    }
+    else
+      *err = CURLE_RECV_ERROR;
+  }
+  return nread;
+}
+
+static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
+                         const void *buf, size_t len, CURLcode *err)
+{
+  struct connectdata *conn = data->conn;
+  RTMP *r = conn->proto.rtmp;
+  ssize_t num;
+
+  (void)sockindex; /* unused */
+
+  num = RTMP_Write(r, (char *)buf, curlx_uztosi(len));
+  if(num < 0)
+    *err = CURLE_SEND_ERROR;
+
+  return num;
+}
+#endif  /* USE_LIBRTMP */
Index: trunk/src/libs/curl-8.7.1/lib/curl_rtmp.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_rtmp.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_rtmp.h	(revision 104083)
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_RTMP_H
+#define HEADER_CURL_RTMP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Howard Chu, <hyc@highlandsun.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#ifdef USE_LIBRTMP
+extern const struct Curl_handler Curl_handler_rtmp;
+extern const struct Curl_handler Curl_handler_rtmpt;
+extern const struct Curl_handler Curl_handler_rtmpe;
+extern const struct Curl_handler Curl_handler_rtmpte;
+extern const struct Curl_handler Curl_handler_rtmps;
+extern const struct Curl_handler Curl_handler_rtmpts;
+#endif
+
+#endif /* HEADER_CURL_RTMP_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_sasl.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_sasl.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_sasl.c	(revision 104083)
@@ -0,0 +1,760 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC2195 CRAM-MD5 authentication
+ * RFC2617 Basic and Digest Access Authentication
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC4422 Simple Authentication and Security Layer (SASL)
+ * RFC4616 PLAIN authentication
+ * RFC5802 SCRAM-SHA-1 authentication
+ * RFC7677 SCRAM-SHA-256 authentication
+ * RFC6749 OAuth 2.0 Authorization Framework
+ * RFC7628 A Set of SASL Mechanisms for OAuth
+ * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \
+  !defined(CURL_DISABLE_POP3) || \
+  (!defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP))
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#include "curl_base64.h"
+#include "curl_md5.h"
+#include "vauth/vauth.h"
+#include "cfilters.h"
+#include "vtls/vtls.h"
+#include "curl_hmac.h"
+#include "curl_sasl.h"
+#include "warnless.h"
+#include "strtok.h"
+#include "sendf.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Supported mechanisms */
+static const struct {
+  const char    *name;  /* Name */
+  size_t         len;   /* Name length */
+  unsigned short bit;   /* Flag bit */
+} mechtable[] = {
+  { "LOGIN",        5,  SASL_MECH_LOGIN },
+  { "PLAIN",        5,  SASL_MECH_PLAIN },
+  { "CRAM-MD5",     8,  SASL_MECH_CRAM_MD5 },
+  { "DIGEST-MD5",   10, SASL_MECH_DIGEST_MD5 },
+  { "GSSAPI",       6,  SASL_MECH_GSSAPI },
+  { "EXTERNAL",     8,  SASL_MECH_EXTERNAL },
+  { "NTLM",         4,  SASL_MECH_NTLM },
+  { "XOAUTH2",      7,  SASL_MECH_XOAUTH2 },
+  { "OAUTHBEARER",  11, SASL_MECH_OAUTHBEARER },
+  { "SCRAM-SHA-1",  11, SASL_MECH_SCRAM_SHA_1 },
+  { "SCRAM-SHA-256",13, SASL_MECH_SCRAM_SHA_256 },
+  { ZERO_NULL,      0,  0 }
+};
+
+/*
+ * Curl_sasl_cleanup()
+ *
+ * This is used to cleanup any libraries or curl modules used by the sasl
+ * functions.
+ *
+ * Parameters:
+ *
+ * conn     [in]     - The connection data.
+ * authused [in]     - The authentication mechanism used.
+ */
+void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused)
+{
+  (void)conn;
+  (void)authused;
+
+#if defined(USE_KERBEROS5)
+  /* Cleanup the gssapi structure */
+  if(authused == SASL_MECH_GSSAPI) {
+    Curl_auth_cleanup_gssapi(&conn->krb5);
+  }
+#endif
+
+#if defined(USE_GSASL)
+  /* Cleanup the GSASL structure */
+  if(authused & (SASL_MECH_SCRAM_SHA_1 | SASL_MECH_SCRAM_SHA_256)) {
+    Curl_auth_gsasl_cleanup(&conn->gsasl);
+  }
+#endif
+
+#if defined(USE_NTLM)
+  /* Cleanup the NTLM structure */
+  if(authused == SASL_MECH_NTLM) {
+    Curl_auth_cleanup_ntlm(&conn->ntlm);
+  }
+#endif
+}
+
+/*
+ * Curl_sasl_decode_mech()
+ *
+ * Convert a SASL mechanism name into a token.
+ *
+ * Parameters:
+ *
+ * ptr    [in]     - The mechanism string.
+ * maxlen [in]     - Maximum mechanism string length.
+ * len    [out]    - If not NULL, effective name length.
+ *
+ * Returns the SASL mechanism token or 0 if no match.
+ */
+unsigned short Curl_sasl_decode_mech(const char *ptr, size_t maxlen,
+                                     size_t *len)
+{
+  unsigned int i;
+  char c;
+
+  for(i = 0; mechtable[i].name; i++) {
+    if(maxlen >= mechtable[i].len &&
+       !memcmp(ptr, mechtable[i].name, mechtable[i].len)) {
+      if(len)
+        *len = mechtable[i].len;
+
+      if(maxlen == mechtable[i].len)
+        return mechtable[i].bit;
+
+      c = ptr[mechtable[i].len];
+      if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_')
+        return mechtable[i].bit;
+    }
+  }
+
+  return 0;
+}
+
+/*
+ * Curl_sasl_parse_url_auth_option()
+ *
+ * Parse the URL login options.
+ */
+CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
+                                         const char *value, size_t len)
+{
+  CURLcode result = CURLE_OK;
+  size_t mechlen;
+
+  if(!len)
+    return CURLE_URL_MALFORMAT;
+
+  if(sasl->resetprefs) {
+    sasl->resetprefs = FALSE;
+    sasl->prefmech = SASL_AUTH_NONE;
+  }
+
+  if(!strncmp(value, "*", len))
+    sasl->prefmech = SASL_AUTH_DEFAULT;
+  else {
+    unsigned short mechbit = Curl_sasl_decode_mech(value, len, &mechlen);
+    if(mechbit && mechlen == len)
+      sasl->prefmech |= mechbit;
+    else
+      result = CURLE_URL_MALFORMAT;
+  }
+
+  return result;
+}
+
+/*
+ * Curl_sasl_init()
+ *
+ * Initializes the SASL structure.
+ */
+void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
+                    const struct SASLproto *params)
+{
+  unsigned long auth = data->set.httpauth;
+
+  sasl->params = params;           /* Set protocol dependent parameters */
+  sasl->state = SASL_STOP;         /* Not yet running */
+  sasl->curmech = NULL;            /* No mechanism yet. */
+  sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
+  sasl->prefmech = params->defmechs; /* Default preferred mechanisms */
+  sasl->authused = SASL_AUTH_NONE; /* The authentication mechanism used */
+  sasl->resetprefs = TRUE;         /* Reset prefmech upon AUTH parsing. */
+  sasl->mutual_auth = FALSE;       /* No mutual authentication (GSSAPI only) */
+  sasl->force_ir = FALSE;          /* Respect external option */
+
+  if(auth != CURLAUTH_BASIC) {
+    unsigned short mechs = SASL_AUTH_NONE;
+
+    /* If some usable http authentication options have been set, determine
+       new defaults from them. */
+    if(auth & CURLAUTH_BASIC)
+      mechs |= SASL_MECH_PLAIN | SASL_MECH_LOGIN;
+    if(auth & CURLAUTH_DIGEST)
+      mechs |= SASL_MECH_DIGEST_MD5;
+    if(auth & CURLAUTH_NTLM)
+      mechs |= SASL_MECH_NTLM;
+    if(auth & CURLAUTH_BEARER)
+      mechs |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2;
+    if(auth & CURLAUTH_GSSAPI)
+      mechs |= SASL_MECH_GSSAPI;
+
+    if(mechs != SASL_AUTH_NONE)
+      sasl->prefmech = mechs;
+  }
+}
+
+/*
+ * sasl_state()
+ *
+ * This is the ONLY way to change SASL state!
+ */
+static void sasl_state(struct SASL *sasl, struct Curl_easy *data,
+                       saslstate newstate)
+{
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[]={
+    "STOP",
+    "PLAIN",
+    "LOGIN",
+    "LOGIN_PASSWD",
+    "EXTERNAL",
+    "CRAMMD5",
+    "DIGESTMD5",
+    "DIGESTMD5_RESP",
+    "NTLM",
+    "NTLM_TYPE2MSG",
+    "GSSAPI",
+    "GSSAPI_TOKEN",
+    "GSSAPI_NO_DATA",
+    "OAUTH2",
+    "OAUTH2_RESP",
+    "GSASL",
+    "CANCEL",
+    "FINAL",
+    /* LAST */
+  };
+
+  if(sasl->state != newstate)
+    infof(data, "SASL %p state change from %s to %s",
+          (void *)sasl, names[sasl->state], names[newstate]);
+#else
+  (void) data;
+#endif
+
+  sasl->state = newstate;
+}
+
+#if defined(USE_NTLM) || defined(USE_GSASL) || defined(USE_KERBEROS5) || \
+  !defined(CURL_DISABLE_DIGEST_AUTH)
+/* Get the SASL server message and convert it to binary. */
+static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
+                                   struct bufref *out)
+{
+  CURLcode result = CURLE_OK;
+
+  result = sasl->params->getmessage(data, out);
+  if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) {
+    unsigned char *msg;
+    size_t msglen;
+    const char *serverdata = (const char *) Curl_bufref_ptr(out);
+
+    if(!*serverdata || *serverdata == '=')
+      Curl_bufref_set(out, NULL, 0, NULL);
+    else {
+      result = Curl_base64_decode(serverdata, &msg, &msglen);
+      if(!result)
+        Curl_bufref_set(out, msg, msglen, curl_free);
+    }
+  }
+  return result;
+}
+#endif
+
+/* Encode the outgoing SASL message. */
+static CURLcode build_message(struct SASL *sasl, struct bufref *msg)
+{
+  CURLcode result = CURLE_OK;
+
+  if(sasl->params->flags & SASL_FLAG_BASE64) {
+    if(!Curl_bufref_ptr(msg))                   /* Empty message. */
+      Curl_bufref_set(msg, "", 0, NULL);
+    else if(!Curl_bufref_len(msg))              /* Explicit empty response. */
+      Curl_bufref_set(msg, "=", 1, NULL);
+    else {
+      char *base64;
+      size_t base64len;
+
+      result = Curl_base64_encode((const char *) Curl_bufref_ptr(msg),
+                                  Curl_bufref_len(msg), &base64, &base64len);
+      if(!result)
+        Curl_bufref_set(msg, base64, base64len, curl_free);
+    }
+  }
+
+  return result;
+}
+
+/*
+ * Curl_sasl_can_authenticate()
+ *
+ * Check if we have enough auth data and capabilities to authenticate.
+ */
+bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
+{
+  /* Have credentials been provided? */
+  if(data->state.aptr.user)
+    return TRUE;
+
+  /* EXTERNAL can authenticate without a user name and/or password */
+  if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
+    return TRUE;
+
+  return FALSE;
+}
+
+/*
+ * Curl_sasl_start()
+ *
+ * Calculate the required login details for SASL authentication.
+ */
+CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
+                         bool force_ir, saslprogress *progress)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  unsigned short enabledmechs;
+  const char *mech = NULL;
+  struct bufref resp;
+  saslstate state1 = SASL_STOP;
+  saslstate state2 = SASL_FINAL;
+  const char *hostname, *disp_hostname;
+  int port;
+#if defined(USE_KERBEROS5) || defined(USE_NTLM)
+  const char *service = data->set.str[STRING_SERVICE_NAME] ?
+    data->set.str[STRING_SERVICE_NAME] :
+    sasl->params->service;
+#endif
+  const char *oauth_bearer = data->set.str[STRING_BEARER];
+  struct bufref nullmsg;
+
+  Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
+  Curl_bufref_init(&nullmsg);
+  Curl_bufref_init(&resp);
+  sasl->force_ir = force_ir;    /* Latch for future use */
+  sasl->authused = 0;           /* No mechanism used yet */
+  enabledmechs = sasl->authmechs & sasl->prefmech;
+  *progress = SASL_IDLE;
+
+  /* Calculate the supported authentication mechanism, by decreasing order of
+     security, as well as the initial response where appropriate */
+  if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) {
+    mech = SASL_MECH_STRING_EXTERNAL;
+    state1 = SASL_EXTERNAL;
+    sasl->authused = SASL_MECH_EXTERNAL;
+
+    if(force_ir || data->set.sasl_ir)
+      result = Curl_auth_create_external_message(conn->user, &resp);
+  }
+  else if(data->state.aptr.user) {
+#if defined(USE_KERBEROS5)
+    if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() &&
+       Curl_auth_user_contains_domain(conn->user)) {
+      sasl->mutual_auth = FALSE;
+      mech = SASL_MECH_STRING_GSSAPI;
+      state1 = SASL_GSSAPI;
+      state2 = SASL_GSSAPI_TOKEN;
+      sasl->authused = SASL_MECH_GSSAPI;
+
+      if(force_ir || data->set.sasl_ir)
+        result = Curl_auth_create_gssapi_user_message(data, conn->user,
+                                                      conn->passwd,
+                                                      service,
+                                                      conn->host.name,
+                                                      sasl->mutual_auth,
+                                                      NULL, &conn->krb5,
+                                                      &resp);
+    }
+    else
+#endif
+#ifdef USE_GSASL
+    if((enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
+       Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
+                                    &conn->gsasl)) {
+      mech = SASL_MECH_STRING_SCRAM_SHA_256;
+      sasl->authused = SASL_MECH_SCRAM_SHA_256;
+      state1 = SASL_GSASL;
+      state2 = SASL_GSASL;
+
+      result = Curl_auth_gsasl_start(data, conn->user,
+                                     conn->passwd, &conn->gsasl);
+      if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
+        result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
+    }
+    else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
+            Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
+                                         &conn->gsasl)) {
+      mech = SASL_MECH_STRING_SCRAM_SHA_1;
+      sasl->authused = SASL_MECH_SCRAM_SHA_1;
+      state1 = SASL_GSASL;
+      state2 = SASL_GSASL;
+
+      result = Curl_auth_gsasl_start(data, conn->user,
+                                     conn->passwd, &conn->gsasl);
+      if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
+        result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
+    }
+    else
+#endif
+#ifndef CURL_DISABLE_DIGEST_AUTH
+    if((enabledmechs & SASL_MECH_DIGEST_MD5) &&
+       Curl_auth_is_digest_supported()) {
+      mech = SASL_MECH_STRING_DIGEST_MD5;
+      state1 = SASL_DIGESTMD5;
+      sasl->authused = SASL_MECH_DIGEST_MD5;
+    }
+    else if(enabledmechs & SASL_MECH_CRAM_MD5) {
+      mech = SASL_MECH_STRING_CRAM_MD5;
+      state1 = SASL_CRAMMD5;
+      sasl->authused = SASL_MECH_CRAM_MD5;
+    }
+    else
+#endif
+#ifdef USE_NTLM
+    if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) {
+      mech = SASL_MECH_STRING_NTLM;
+      state1 = SASL_NTLM;
+      state2 = SASL_NTLM_TYPE2MSG;
+      sasl->authused = SASL_MECH_NTLM;
+
+      if(force_ir || data->set.sasl_ir)
+        result = Curl_auth_create_ntlm_type1_message(data,
+                                                     conn->user, conn->passwd,
+                                                     service,
+                                                     hostname,
+                                                     &conn->ntlm, &resp);
+      }
+    else
+#endif
+    if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) {
+      mech = SASL_MECH_STRING_OAUTHBEARER;
+      state1 = SASL_OAUTH2;
+      state2 = SASL_OAUTH2_RESP;
+      sasl->authused = SASL_MECH_OAUTHBEARER;
+
+      if(force_ir || data->set.sasl_ir)
+        result = Curl_auth_create_oauth_bearer_message(conn->user,
+                                                       hostname,
+                                                       port,
+                                                       oauth_bearer,
+                                                       &resp);
+    }
+    else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) {
+      mech = SASL_MECH_STRING_XOAUTH2;
+      state1 = SASL_OAUTH2;
+      sasl->authused = SASL_MECH_XOAUTH2;
+
+      if(force_ir || data->set.sasl_ir)
+        result = Curl_auth_create_xoauth_bearer_message(conn->user,
+                                                        oauth_bearer,
+                                                        &resp);
+    }
+    else if(enabledmechs & SASL_MECH_PLAIN) {
+      mech = SASL_MECH_STRING_PLAIN;
+      state1 = SASL_PLAIN;
+      sasl->authused = SASL_MECH_PLAIN;
+
+      if(force_ir || data->set.sasl_ir)
+        result = Curl_auth_create_plain_message(conn->sasl_authzid,
+                                                conn->user, conn->passwd,
+                                                &resp);
+    }
+    else if(enabledmechs & SASL_MECH_LOGIN) {
+      mech = SASL_MECH_STRING_LOGIN;
+      state1 = SASL_LOGIN;
+      state2 = SASL_LOGIN_PASSWD;
+      sasl->authused = SASL_MECH_LOGIN;
+
+      if(force_ir || data->set.sasl_ir)
+        result = Curl_auth_create_login_message(conn->user, &resp);
+    }
+  }
+
+  if(!result && mech) {
+    sasl->curmech = mech;
+    if(Curl_bufref_ptr(&resp))
+      result = build_message(sasl, &resp);
+
+    if(sasl->params->maxirlen &&
+       strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
+      Curl_bufref_free(&resp);
+
+    if(!result)
+      result = sasl->params->sendauth(data, mech, &resp);
+
+    if(!result) {
+      *progress = SASL_INPROGRESS;
+      sasl_state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1);
+    }
+  }
+
+  Curl_bufref_free(&resp);
+  return result;
+}
+
+/*
+ * Curl_sasl_continue()
+ *
+ * Continue the authentication.
+ */
+CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
+                            int code, saslprogress *progress)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  saslstate newstate = SASL_FINAL;
+  struct bufref resp;
+  const char *hostname, *disp_hostname;
+  int port;
+#if defined(USE_KERBEROS5) || defined(USE_NTLM) \
+    || !defined(CURL_DISABLE_DIGEST_AUTH)
+  const char *service = data->set.str[STRING_SERVICE_NAME] ?
+    data->set.str[STRING_SERVICE_NAME] :
+    sasl->params->service;
+#endif
+  const char *oauth_bearer = data->set.str[STRING_BEARER];
+  struct bufref serverdata;
+
+  Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
+  Curl_bufref_init(&serverdata);
+  Curl_bufref_init(&resp);
+  *progress = SASL_INPROGRESS;
+
+  if(sasl->state == SASL_FINAL) {
+    if(code != sasl->params->finalcode)
+      result = CURLE_LOGIN_DENIED;
+    *progress = SASL_DONE;
+    sasl_state(sasl, data, SASL_STOP);
+    return result;
+  }
+
+  if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
+     code != sasl->params->contcode) {
+    *progress = SASL_DONE;
+    sasl_state(sasl, data, SASL_STOP);
+    return CURLE_LOGIN_DENIED;
+  }
+
+  switch(sasl->state) {
+  case SASL_STOP:
+    *progress = SASL_DONE;
+    return result;
+  case SASL_PLAIN:
+    result = Curl_auth_create_plain_message(conn->sasl_authzid,
+                                            conn->user, conn->passwd, &resp);
+    break;
+  case SASL_LOGIN:
+    result = Curl_auth_create_login_message(conn->user, &resp);
+    newstate = SASL_LOGIN_PASSWD;
+    break;
+  case SASL_LOGIN_PASSWD:
+    result = Curl_auth_create_login_message(conn->passwd, &resp);
+    break;
+  case SASL_EXTERNAL:
+    result = Curl_auth_create_external_message(conn->user, &resp);
+    break;
+#ifdef USE_GSASL
+  case SASL_GSASL:
+    result = get_server_message(sasl, data, &serverdata);
+    if(!result)
+      result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp);
+    if(!result && Curl_bufref_len(&resp) > 0)
+      newstate = SASL_GSASL;
+    break;
+#endif
+#ifndef CURL_DISABLE_DIGEST_AUTH
+  case SASL_CRAMMD5:
+    result = get_server_message(sasl, data, &serverdata);
+    if(!result)
+      result = Curl_auth_create_cram_md5_message(&serverdata, conn->user,
+                                                 conn->passwd, &resp);
+    break;
+  case SASL_DIGESTMD5:
+    result = get_server_message(sasl, data, &serverdata);
+    if(!result)
+      result = Curl_auth_create_digest_md5_message(data, &serverdata,
+                                                   conn->user, conn->passwd,
+                                                   service, &resp);
+    if(!result && (sasl->params->flags & SASL_FLAG_BASE64))
+      newstate = SASL_DIGESTMD5_RESP;
+    break;
+  case SASL_DIGESTMD5_RESP:
+    /* Keep response NULL to output an empty line. */
+    break;
+#endif
+
+#ifdef USE_NTLM
+  case SASL_NTLM:
+    /* Create the type-1 message */
+    result = Curl_auth_create_ntlm_type1_message(data,
+                                                 conn->user, conn->passwd,
+                                                 service, hostname,
+                                                 &conn->ntlm, &resp);
+    newstate = SASL_NTLM_TYPE2MSG;
+    break;
+  case SASL_NTLM_TYPE2MSG:
+    /* Decode the type-2 message */
+    result = get_server_message(sasl, data, &serverdata);
+    if(!result)
+      result = Curl_auth_decode_ntlm_type2_message(data, &serverdata,
+                                                   &conn->ntlm);
+    if(!result)
+      result = Curl_auth_create_ntlm_type3_message(data, conn->user,
+                                                   conn->passwd, &conn->ntlm,
+                                                   &resp);
+    break;
+#endif
+
+#if defined(USE_KERBEROS5)
+  case SASL_GSSAPI:
+    result = Curl_auth_create_gssapi_user_message(data, conn->user,
+                                                  conn->passwd,
+                                                  service,
+                                                  conn->host.name,
+                                                  sasl->mutual_auth, NULL,
+                                                  &conn->krb5,
+                                                  &resp);
+    newstate = SASL_GSSAPI_TOKEN;
+    break;
+  case SASL_GSSAPI_TOKEN:
+    result = get_server_message(sasl, data, &serverdata);
+    if(!result) {
+      if(sasl->mutual_auth) {
+        /* Decode the user token challenge and create the optional response
+           message */
+        result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
+                                                      NULL, NULL,
+                                                      sasl->mutual_auth,
+                                                      &serverdata,
+                                                      &conn->krb5,
+                                                      &resp);
+        newstate = SASL_GSSAPI_NO_DATA;
+      }
+      else
+        /* Decode the security challenge and create the response message */
+        result = Curl_auth_create_gssapi_security_message(data,
+                                                          conn->sasl_authzid,
+                                                          &serverdata,
+                                                          &conn->krb5,
+                                                          &resp);
+    }
+    break;
+  case SASL_GSSAPI_NO_DATA:
+    /* Decode the security challenge and create the response message */
+    result = get_server_message(sasl, data, &serverdata);
+    if(!result)
+      result = Curl_auth_create_gssapi_security_message(data,
+                                                        conn->sasl_authzid,
+                                                        &serverdata,
+                                                        &conn->krb5,
+                                                        &resp);
+    break;
+#endif
+
+  case SASL_OAUTH2:
+    /* Create the authorization message */
+    if(sasl->authused == SASL_MECH_OAUTHBEARER) {
+      result = Curl_auth_create_oauth_bearer_message(conn->user,
+                                                     hostname,
+                                                     port,
+                                                     oauth_bearer,
+                                                     &resp);
+
+      /* Failures maybe sent by the server as continuations for OAUTHBEARER */
+      newstate = SASL_OAUTH2_RESP;
+    }
+    else
+      result = Curl_auth_create_xoauth_bearer_message(conn->user,
+                                                      oauth_bearer,
+                                                      &resp);
+    break;
+
+  case SASL_OAUTH2_RESP:
+    /* The continuation is optional so check the response code */
+    if(code == sasl->params->finalcode) {
+      /* Final response was received so we are done */
+      *progress = SASL_DONE;
+      sasl_state(sasl, data, SASL_STOP);
+      return result;
+    }
+    else if(code == sasl->params->contcode) {
+      /* Acknowledge the continuation by sending a 0x01 response. */
+      Curl_bufref_set(&resp, "\x01", 1, NULL);
+      break;
+    }
+    else {
+      *progress = SASL_DONE;
+      sasl_state(sasl, data, SASL_STOP);
+      return CURLE_LOGIN_DENIED;
+    }
+
+  case SASL_CANCEL:
+    /* Remove the offending mechanism from the supported list */
+    sasl->authmechs ^= sasl->authused;
+
+    /* Start an alternative SASL authentication */
+    return Curl_sasl_start(sasl, data, sasl->force_ir, progress);
+  default:
+    failf(data, "Unsupported SASL authentication mechanism");
+    result = CURLE_UNSUPPORTED_PROTOCOL;  /* Should not happen */
+    break;
+  }
+
+  Curl_bufref_free(&serverdata);
+
+  switch(result) {
+  case CURLE_BAD_CONTENT_ENCODING:
+    /* Cancel dialog */
+    result = sasl->params->cancelauth(data, sasl->curmech);
+    newstate = SASL_CANCEL;
+    break;
+  case CURLE_OK:
+    result = build_message(sasl, &resp);
+    if(!result)
+      result = sasl->params->contauth(data, sasl->curmech, &resp);
+    break;
+  default:
+    newstate = SASL_STOP;    /* Stop on error */
+    *progress = SASL_DONE;
+    break;
+  }
+
+  Curl_bufref_free(&resp);
+
+  sasl_state(sasl, data, newstate);
+
+  return result;
+}
+#endif /* protocols are enabled that use SASL */
Index: trunk/src/libs/curl-8.7.1/lib/curl_sasl.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_sasl.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_sasl.h	(revision 104083)
@@ -0,0 +1,165 @@
+#ifndef HEADER_CURL_SASL_H
+#define HEADER_CURL_SASL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+#include "bufref.h"
+
+struct Curl_easy;
+struct connectdata;
+
+/* Authentication mechanism flags */
+#define SASL_MECH_LOGIN             (1 << 0)
+#define SASL_MECH_PLAIN             (1 << 1)
+#define SASL_MECH_CRAM_MD5          (1 << 2)
+#define SASL_MECH_DIGEST_MD5        (1 << 3)
+#define SASL_MECH_GSSAPI            (1 << 4)
+#define SASL_MECH_EXTERNAL          (1 << 5)
+#define SASL_MECH_NTLM              (1 << 6)
+#define SASL_MECH_XOAUTH2           (1 << 7)
+#define SASL_MECH_OAUTHBEARER       (1 << 8)
+#define SASL_MECH_SCRAM_SHA_1       (1 << 9)
+#define SASL_MECH_SCRAM_SHA_256     (1 << 10)
+
+/* Authentication mechanism values */
+#define SASL_AUTH_NONE          0
+#define SASL_AUTH_ANY           0xffff
+#define SASL_AUTH_DEFAULT       (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
+
+/* Authentication mechanism strings */
+#define SASL_MECH_STRING_LOGIN          "LOGIN"
+#define SASL_MECH_STRING_PLAIN          "PLAIN"
+#define SASL_MECH_STRING_CRAM_MD5       "CRAM-MD5"
+#define SASL_MECH_STRING_DIGEST_MD5     "DIGEST-MD5"
+#define SASL_MECH_STRING_GSSAPI         "GSSAPI"
+#define SASL_MECH_STRING_EXTERNAL       "EXTERNAL"
+#define SASL_MECH_STRING_NTLM           "NTLM"
+#define SASL_MECH_STRING_XOAUTH2        "XOAUTH2"
+#define SASL_MECH_STRING_OAUTHBEARER    "OAUTHBEARER"
+#define SASL_MECH_STRING_SCRAM_SHA_1    "SCRAM-SHA-1"
+#define SASL_MECH_STRING_SCRAM_SHA_256  "SCRAM-SHA-256"
+
+/* SASL flags */
+#define SASL_FLAG_BASE64        0x0001  /* Messages are base64-encoded */
+
+/* SASL machine states */
+typedef enum {
+  SASL_STOP,
+  SASL_PLAIN,
+  SASL_LOGIN,
+  SASL_LOGIN_PASSWD,
+  SASL_EXTERNAL,
+  SASL_CRAMMD5,
+  SASL_DIGESTMD5,
+  SASL_DIGESTMD5_RESP,
+  SASL_NTLM,
+  SASL_NTLM_TYPE2MSG,
+  SASL_GSSAPI,
+  SASL_GSSAPI_TOKEN,
+  SASL_GSSAPI_NO_DATA,
+  SASL_OAUTH2,
+  SASL_OAUTH2_RESP,
+  SASL_GSASL,
+  SASL_CANCEL,
+  SASL_FINAL
+} saslstate;
+
+/* Progress indicator */
+typedef enum {
+  SASL_IDLE,
+  SASL_INPROGRESS,
+  SASL_DONE
+} saslprogress;
+
+/* Protocol dependent SASL parameters */
+struct SASLproto {
+  const char *service;     /* The service name */
+  CURLcode (*sendauth)(struct Curl_easy *data, const char *mech,
+                       const struct bufref *ir);
+                           /* Send authentication command */
+  CURLcode (*contauth)(struct Curl_easy *data, const char *mech,
+                       const struct bufref *contauth);
+                           /* Send authentication continuation */
+  CURLcode (*cancelauth)(struct Curl_easy *data, const char *mech);
+                           /* Cancel authentication. */
+  CURLcode (*getmessage)(struct Curl_easy *data, struct bufref *out);
+                           /* Get SASL response message */
+  size_t maxirlen;         /* Maximum initial response + mechanism length,
+                              or zero if no max. This is normally the max
+                              command length - other characters count.
+                              This has to be zero for non-base64 protocols. */
+  int contcode;            /* Code to receive when continuation is expected */
+  int finalcode;           /* Code to receive upon authentication success */
+  unsigned short defmechs; /* Mechanisms enabled by default */
+  unsigned short flags;    /* Configuration flags. */
+};
+
+/* Per-connection parameters */
+struct SASL {
+  const struct SASLproto *params; /* Protocol dependent parameters */
+  saslstate state;           /* Current machine state */
+  const char *curmech;       /* Current mechanism id. */
+  unsigned short authmechs;  /* Accepted authentication mechanisms */
+  unsigned short prefmech;   /* Preferred authentication mechanism */
+  unsigned short authused;   /* Auth mechanism used for the connection */
+  BIT(resetprefs);           /* For URL auth option parsing. */
+  BIT(mutual_auth);          /* Mutual authentication enabled (GSSAPI only) */
+  BIT(force_ir);             /* Protocol always supports initial response */
+};
+
+/* This is used to test whether the line starts with the given mechanism */
+#define sasl_mech_equal(line, wordlen, mech) \
+  (wordlen == (sizeof(mech) - 1) / sizeof(char) && \
+   !memcmp(line, mech, wordlen))
+
+/* This is used to cleanup any libraries or curl modules used by the sasl
+   functions */
+void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused);
+
+/* Convert a mechanism name to a token */
+unsigned short Curl_sasl_decode_mech(const char *ptr,
+                                     size_t maxlen, size_t *len);
+
+/* Parse the URL login options */
+CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
+                                         const char *value, size_t len);
+
+/* Initializes an SASL structure */
+void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
+                    const struct SASLproto *params);
+
+/* Check if we have enough auth data and capabilities to authenticate */
+bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data);
+
+/* Calculate the required login details for SASL authentication  */
+CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
+                         bool force_ir, saslprogress *progress);
+
+/* Continue an SASL authentication  */
+CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
+                            int code, saslprogress *progress);
+
+#endif /* HEADER_CURL_SASL_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_setup.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_setup.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_setup.h	(revision 104083)
@@ -0,0 +1,895 @@
+#ifndef HEADER_CURL_SETUP_H
+#define HEADER_CURL_SETUP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#if defined(BUILDING_LIBCURL) && !defined(CURL_NO_OLDIES)
+#define CURL_NO_OLDIES
+#endif
+
+/* FIXME: Delete this once the warnings have been fixed. */
+#if !defined(CURL_WARN_SIGN_CONVERSION)
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wsign-conversion"
+#endif
+#endif
+
+/* Set default _WIN32_WINNT */
+#ifdef __MINGW32__
+#include <_mingw.h>
+#endif
+
+/*
+ * Disable Visual Studio warnings:
+ * 4127 "conditional expression is constant"
+ */
+#ifdef _MSC_VER
+#pragma warning(disable:4127)
+#endif
+
+#ifdef _WIN32
+/*
+ * Don't include unneeded stuff in Windows headers to avoid compiler
+ * warnings and macro clashes.
+ * Make sure to define this macro before including any Windows headers.
+ */
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN
+#  endif
+#  ifndef NOGDI
+#    define NOGDI
+#  endif
+/* Detect Windows App environment which has a restricted access
+ * to the Win32 APIs. */
+# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \
+  defined(WINAPI_FAMILY)
+#  include <winapifamily.h>
+#  if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) &&  \
+     !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#    define CURL_WINDOWS_APP
+#  endif
+# endif
+#endif
+
+/*
+ * Include configuration script results or hand-crafted
+ * configuration file for platforms which lack config tool.
+ */
+
+#ifdef HAVE_CONFIG_H
+
+#include "curl_config.h"
+
+# ifdef VBOX
+#  ifdef WIN32
+     /* Fixing an issue with following #if (SIZEOF_CURL_OFF_T < 8) */
+     /* Define to the size of `curl_off_t', as computed by sizeof. */
+#    undef SIZEOF_CURL_OFF_T
+#    define SIZEOF_CURL_OFF_T 8
+#  endif
+# endif
+
+#else /* HAVE_CONFIG_H */
+
+#ifdef _WIN32_WCE
+#  include "config-win32ce.h"
+#else
+#  ifdef _WIN32
+#    include "config-win32.h"
+#  endif
+#endif
+
+#ifdef macintosh
+#  include "config-mac.h"
+#endif
+
+#ifdef __riscos__
+#  include "config-riscos.h"
+#endif
+
+#ifdef __AMIGA__
+#  include "config-amigaos.h"
+#endif
+
+#ifdef __OS400__
+#  include "config-os400.h"
+#endif
+
+#ifdef __PLAN9__
+#  include "config-plan9.h"
+#endif
+
+#ifdef MSDOS
+#  include "config-dos.h"
+#endif
+
+#endif /* HAVE_CONFIG_H */
+
+/* ================================================================ */
+/* Definition of preprocessor macros/symbols which modify compiler  */
+/* behavior or generated code characteristics must be done here,   */
+/* as appropriate, before any system header file is included. It is */
+/* also possible to have them defined in the config file included   */
+/* before this point. As a result of all this we frown inclusion of */
+/* system header files in our config files, avoid this at any cost. */
+/* ================================================================ */
+
+/*
+ * AIX 4.3 and newer needs _THREAD_SAFE defined to build
+ * proper reentrant code. Others may also need it.
+ */
+
+#ifdef NEED_THREAD_SAFE
+#  ifndef _THREAD_SAFE
+#    define _THREAD_SAFE
+#  endif
+#endif
+
+/*
+ * Tru64 needs _REENTRANT set for a few function prototypes and
+ * things to appear in the system header files. Unixware needs it
+ * to build proper reentrant code. Others may also need it.
+ */
+
+#ifdef NEED_REENTRANT
+#  ifndef _REENTRANT
+#    define _REENTRANT
+#  endif
+#endif
+
+/* Solaris needs this to get a POSIX-conformant getpwuid_r */
+#if defined(sun) || defined(__sun)
+#  ifndef _POSIX_PTHREAD_SEMANTICS
+#    define _POSIX_PTHREAD_SEMANTICS 1
+#  endif
+#endif
+
+/* ================================================================ */
+/*  If you need to include a system header file for your platform,  */
+/*  please, do it beyond the point further indicated in this file.  */
+/* ================================================================ */
+
+/*
+ * Disable other protocols when http is the only one desired.
+ */
+
+#ifdef HTTP_ONLY
+#  ifndef CURL_DISABLE_DICT
+#    define CURL_DISABLE_DICT
+#  endif
+#  ifndef CURL_DISABLE_FILE
+#    define CURL_DISABLE_FILE
+#  endif
+#  ifndef CURL_DISABLE_FTP
+#    define CURL_DISABLE_FTP
+#  endif
+#  ifndef CURL_DISABLE_GOPHER
+#    define CURL_DISABLE_GOPHER
+#  endif
+#  ifndef CURL_DISABLE_IMAP
+#    define CURL_DISABLE_IMAP
+#  endif
+#  ifndef CURL_DISABLE_LDAP
+#    define CURL_DISABLE_LDAP
+#  endif
+#  ifndef CURL_DISABLE_LDAPS
+#    define CURL_DISABLE_LDAPS
+#  endif
+#  ifndef CURL_DISABLE_MQTT
+#    define CURL_DISABLE_MQTT
+#  endif
+#  ifndef CURL_DISABLE_POP3
+#    define CURL_DISABLE_POP3
+#  endif
+#  ifndef CURL_DISABLE_RTSP
+#    define CURL_DISABLE_RTSP
+#  endif
+#  ifndef CURL_DISABLE_SMB
+#    define CURL_DISABLE_SMB
+#  endif
+#  ifndef CURL_DISABLE_SMTP
+#    define CURL_DISABLE_SMTP
+#  endif
+#  ifndef CURL_DISABLE_TELNET
+#    define CURL_DISABLE_TELNET
+#  endif
+#  ifndef CURL_DISABLE_TFTP
+#    define CURL_DISABLE_TFTP
+#  endif
+#endif
+
+/*
+ * When http is disabled rtsp is not supported.
+ */
+
+#if defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_RTSP)
+#  define CURL_DISABLE_RTSP
+#endif
+
+/*
+ * When HTTP is disabled, disable HTTP-only features
+ */
+
+#if defined(CURL_DISABLE_HTTP)
+#  define CURL_DISABLE_ALTSVC 1
+#  define CURL_DISABLE_COOKIES 1
+#  define CURL_DISABLE_BASIC_AUTH 1
+#  define CURL_DISABLE_BEARER_AUTH 1
+#  define CURL_DISABLE_AWS 1
+#  define CURL_DISABLE_DOH 1
+#  define CURL_DISABLE_FORM_API 1
+#  define CURL_DISABLE_HEADERS_API 1
+#  define CURL_DISABLE_HSTS 1
+#  define CURL_DISABLE_HTTP_AUTH 1
+#endif
+
+/* ================================================================ */
+/* No system header file shall be included in this file before this */
+/* point.                                                           */
+/* ================================================================ */
+
+/*
+ * OS/400 setup file includes some system headers.
+ */
+
+#ifdef __OS400__
+#  include "setup-os400.h"
+#endif
+
+/*
+ * VMS setup file includes some system headers.
+ */
+
+#ifdef __VMS
+#  include "setup-vms.h"
+#endif
+
+/*
+ * Windows setup file includes some system headers.
+ */
+
+#ifdef _WIN32
+#  include "setup-win32.h"
+#endif
+
+#include <curl/system.h>
+
+/* Helper macro to expand and concatenate two macros.
+ * Direct macros concatenation does not work because macros
+ * are not expanded before direct concatenation.
+ */
+#define CURL_CONC_MACROS_(A,B) A ## B
+#define CURL_CONC_MACROS(A,B) CURL_CONC_MACROS_(A,B)
+
+/* curl uses its own printf() function internally. It understands the GNU
+ * format. Use this format, so that is matches the GNU format attribute we
+ * use with the mingw compiler, allowing it to verify them at compile-time.
+ */
+#ifdef  __MINGW32__
+#  undef CURL_FORMAT_CURL_OFF_T
+#  undef CURL_FORMAT_CURL_OFF_TU
+#  define CURL_FORMAT_CURL_OFF_T   "lld"
+#  define CURL_FORMAT_CURL_OFF_TU  "llu"
+#endif
+
+/* based on logic in "curl/mprintf.h" */
+
+#if (defined(__GNUC__) || defined(__clang__)) &&                        \
+  defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) &&         \
+  !defined(CURL_NO_FMT_CHECKS)
+#if defined(__MINGW32__) && !defined(__clang__)
+#define CURL_PRINTF(fmt, arg) \
+  __attribute__((format(gnu_printf, fmt, arg)))
+#else
+#define CURL_PRINTF(fmt, arg) \
+  __attribute__((format(__printf__, fmt, arg)))
+#endif
+#else
+#define CURL_PRINTF(fmt, arg)
+#endif
+
+/*
+ * Use getaddrinfo to resolve the IPv4 address literal. If the current network
+ * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64,
+ * performing this task will result in a synthesized IPv6 address.
+ */
+#if defined(__APPLE__) && !defined(USE_ARES)
+#include <TargetConditionals.h>
+#define USE_RESOLVE_ON_IPS 1
+#  if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && \
+     defined(ENABLE_IPV6)
+#    define CURL_MACOS_CALL_COPYPROXIES 1
+#  endif
+#endif
+
+#ifdef USE_LWIPSOCK
+#  include <lwip/init.h>
+#  include <lwip/sockets.h>
+#  include <lwip/netdb.h>
+#endif
+
+#ifdef HAVE_EXTRA_STRICMP_H
+#  include <extra/stricmp.h>
+#endif
+
+#ifdef HAVE_EXTRA_STRDUP_H
+#  include <extra/strdup.h>
+#endif
+
+#ifdef __AMIGA__
+#  ifdef __amigaos4__
+#    define __USE_INLINE__
+     /* use our own resolver which uses runtime feature detection */
+#    define CURLRES_AMIGA
+     /* getaddrinfo() currently crashes bsdsocket.library, so disable */
+#    undef HAVE_GETADDRINFO
+#    if !(defined(__NEWLIB__) || \
+          (defined(__CLIB2__) && defined(__THREAD_SAFE)))
+       /* disable threaded resolver with clib2 - requires newlib or clib-ts */
+#      undef USE_THREADS_POSIX
+#    endif
+#  endif
+#  include <exec/types.h>
+#  include <exec/execbase.h>
+#  include <proto/exec.h>
+#  include <proto/dos.h>
+#  include <unistd.h>
+#  if defined(HAVE_PROTO_BSDSOCKET_H) && \
+    (!defined(__amigaos4__) || defined(USE_AMISSL))
+     /* use bsdsocket.library directly, instead of libc networking functions */
+#    define _SYS_MBUF_H /* m_len define clashes with curl */
+#    include <proto/bsdsocket.h>
+#    ifdef __amigaos4__
+       int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds,
+                             fd_set *errorfds, struct timeval *timeout);
+#      define select(a,b,c,d,e) Curl_amiga_select(a,b,c,d,e)
+#    else
+#      define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0)
+#    endif
+     /* must not use libc's fcntl() on bsdsocket.library sockfds! */
+#    undef HAVE_FCNTL
+#    undef HAVE_FCNTL_O_NONBLOCK
+#  else
+     /* use libc networking and hence close() and fnctl() */
+#    undef HAVE_CLOSESOCKET_CAMEL
+#    undef HAVE_IOCTLSOCKET_CAMEL
+#  endif
+/*
+ * In clib2 arpa/inet.h warns that some prototypes may clash
+ * with bsdsocket.library. This avoids the definition of those.
+ */
+#  define __NO_NET_API
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+
+#ifdef __TANDEM /* for ns*-tandem-nsk systems */
+# if ! defined __LP64
+#  include <floss.h> /* FLOSS is only used for 32-bit builds. */
+# endif
+#endif
+
+#ifndef STDC_HEADERS /* no standard C headers! */
+#include <curl/stdcheaders.h>
+#endif
+
+/*
+ * Large file (>2Gb) support using WIN32 functions.
+ */
+
+#ifdef USE_WIN32_LARGE_FILES
+#  include <io.h>
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  undef  lseek
+#  define lseek(fdes,offset,whence)  _lseeki64(fdes, offset, whence)
+#  undef  fstat
+#  define fstat(fdes,stp)            _fstati64(fdes, stp)
+#  undef  stat
+#  define stat(fname,stp)            curlx_win32_stat(fname, stp)
+#  define struct_stat                struct _stati64
+#  define LSEEK_ERROR                (__int64)-1
+#  define open                       curlx_win32_open
+#  define fopen(fname,mode)          curlx_win32_fopen(fname, mode)
+#  define access(fname,mode)         curlx_win32_access(fname, mode)
+   int curlx_win32_open(const char *filename, int oflag, ...);
+   int curlx_win32_stat(const char *path, struct_stat *buffer);
+   FILE *curlx_win32_fopen(const char *filename, const char *mode);
+   int curlx_win32_access(const char *path, int mode);
+#endif
+
+/*
+ * Small file (<2Gb) support using WIN32 functions.
+ */
+
+#ifdef USE_WIN32_SMALL_FILES
+#  include <io.h>
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  ifndef _WIN32_WCE
+#    undef  lseek
+#    define lseek(fdes,offset,whence)  _lseek(fdes, (long)offset, whence)
+#    define fstat(fdes,stp)            _fstat(fdes, stp)
+#    define stat(fname,stp)            curlx_win32_stat(fname, stp)
+#    define struct_stat                struct _stat
+#    define open                       curlx_win32_open
+#    define fopen(fname,mode)          curlx_win32_fopen(fname, mode)
+#    define access(fname,mode)         curlx_win32_access(fname, mode)
+     int curlx_win32_stat(const char *path, struct_stat *buffer);
+     int curlx_win32_open(const char *filename, int oflag, ...);
+     FILE *curlx_win32_fopen(const char *filename, const char *mode);
+     int curlx_win32_access(const char *path, int mode);
+#  endif
+#  define LSEEK_ERROR                (long)-1
+#endif
+
+#ifndef struct_stat
+#  define struct_stat struct stat
+#endif
+
+#ifndef LSEEK_ERROR
+#  define LSEEK_ERROR (off_t)-1
+#endif
+
+#ifndef SIZEOF_TIME_T
+/* assume default size of time_t to be 32 bit */
+#define SIZEOF_TIME_T 4
+#endif
+
+#ifndef SIZEOF_CURL_SOCKET_T
+/* configure and cmake check and set the define */
+#  ifdef _WIN64
+#    define SIZEOF_CURL_SOCKET_T 8
+#  else
+/* default guess */
+#    define SIZEOF_CURL_SOCKET_T 4
+#  endif
+#endif
+
+#if SIZEOF_CURL_SOCKET_T < 8
+#  define CURL_FORMAT_SOCKET_T "d"
+#elif defined(__MINGW32__)
+#  define CURL_FORMAT_SOCKET_T "zd"
+#else
+#  define CURL_FORMAT_SOCKET_T "qd"
+#endif
+
+/*
+ * Default sizeof(off_t) in case it hasn't been defined in config file.
+ */
+
+#ifndef SIZEOF_OFF_T
+#  if defined(__VMS) && !defined(__VAX)
+#    if defined(_LARGEFILE)
+#      define SIZEOF_OFF_T 8
+#    endif
+#  elif defined(__OS400__) && defined(__ILEC400__)
+#    if defined(_LARGE_FILES)
+#      define SIZEOF_OFF_T 8
+#    endif
+#  elif defined(__MVS__) && defined(__IBMC__)
+#    if defined(_LP64) || defined(_LARGE_FILES)
+#      define SIZEOF_OFF_T 8
+#    endif
+#  elif defined(__370__) && defined(__IBMC__)
+#    if defined(_LP64) || defined(_LARGE_FILES)
+#      define SIZEOF_OFF_T 8
+#    endif
+#  endif
+#  ifndef SIZEOF_OFF_T
+#    define SIZEOF_OFF_T 4
+#  endif
+#endif
+
+#if (SIZEOF_CURL_OFF_T < 8)
+#error "too small curl_off_t"
+#else
+   /* assume SIZEOF_CURL_OFF_T == 8 */
+#  define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
+#endif
+#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1))
+
+#if (SIZEOF_CURL_OFF_T != 8)
+#  error "curl_off_t must be exactly 64 bits"
+#else
+  typedef unsigned CURL_TYPEOF_CURL_OFF_T curl_uint64_t;
+#  ifndef CURL_SUFFIX_CURL_OFF_TU
+#    error "CURL_SUFFIX_CURL_OFF_TU must be defined"
+#  endif
+#  define CURL_UINT64_SUFFIX  CURL_SUFFIX_CURL_OFF_TU
+#  define CURL_UINT64_C(val)  CURL_CONC_MACROS(val,CURL_UINT64_SUFFIX)
+#endif
+
+#if (SIZEOF_TIME_T == 4)
+#  ifdef HAVE_TIME_T_UNSIGNED
+#  define TIME_T_MAX UINT_MAX
+#  define TIME_T_MIN 0
+#  else
+#  define TIME_T_MAX INT_MAX
+#  define TIME_T_MIN INT_MIN
+#  endif
+#else
+#  ifdef HAVE_TIME_T_UNSIGNED
+#  define TIME_T_MAX 0xFFFFFFFFFFFFFFFF
+#  define TIME_T_MIN 0
+#  else
+#  define TIME_T_MAX 0x7FFFFFFFFFFFFFFF
+#  define TIME_T_MIN (-TIME_T_MAX - 1)
+#  endif
+#endif
+
+#ifndef SIZE_T_MAX
+/* some limits.h headers have this defined, some don't */
+#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
+#define SIZE_T_MAX 18446744073709551615U
+#else
+#define SIZE_T_MAX 4294967295U
+#endif
+#endif
+
+#ifndef SSIZE_T_MAX
+/* some limits.h headers have this defined, some don't */
+#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
+#define SSIZE_T_MAX 9223372036854775807
+#else
+#define SSIZE_T_MAX 2147483647
+#endif
+#endif
+
+/*
+ * Arg 2 type for gethostname in case it hasn't been defined in config file.
+ */
+
+#ifndef GETHOSTNAME_TYPE_ARG2
+#  ifdef USE_WINSOCK
+#    define GETHOSTNAME_TYPE_ARG2 int
+#  else
+#    define GETHOSTNAME_TYPE_ARG2 size_t
+#  endif
+#endif
+
+/* Below we define some functions. They should
+
+   4. set the SIGALRM signal timeout
+   5. set dir/file naming defines
+   */
+
+#ifdef _WIN32
+
+#  define DIR_CHAR      "\\"
+
+#else /* _WIN32 */
+
+#  ifdef MSDOS  /* Watt-32 */
+
+#    include <sys/ioctl.h>
+#    define select(n,r,w,x,t) select_s(n,r,w,x,t)
+#    define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z))
+#    include <tcp.h>
+#    ifdef word
+#      undef word
+#    endif
+#    ifdef byte
+#      undef byte
+#    endif
+
+#  endif /* MSDOS */
+
+#  ifdef __minix
+     /* Minix 3 versions up to at least 3.1.3 are missing these prototypes */
+     extern char *strtok_r(char *s, const char *delim, char **last);
+     extern struct tm *gmtime_r(const time_t * const timep, struct tm *tmp);
+#  endif
+
+#  define DIR_CHAR      "/"
+
+#endif /* _WIN32 */
+
+/* ---------------------------------------------------------------- */
+/*             resolver specialty compile-time defines              */
+/*         CURLRES_* defines to use in the host*.c sources          */
+/* ---------------------------------------------------------------- */
+
+/*
+ * MSVC threads support requires a multi-threaded runtime library.
+ * _beginthreadex() is not available in single-threaded ones.
+ */
+
+#if defined(_MSC_VER) && !defined(_MT)
+#  undef USE_THREADS_POSIX
+#  undef USE_THREADS_WIN32
+#endif
+
+/*
+ * Mutually exclusive CURLRES_* definitions.
+ */
+
+#if defined(ENABLE_IPV6) && defined(HAVE_GETADDRINFO)
+#  define CURLRES_IPV6
+#elif defined(ENABLE_IPV6) && (defined(_WIN32) || defined(__CYGWIN__))
+/* assume on Windows that IPv6 without getaddrinfo is a broken build */
+#  error "Unexpected build: IPv6 is enabled but getaddrinfo was not found."
+#else
+#  define CURLRES_IPV4
+#endif
+
+#ifdef USE_ARES
+#  define CURLRES_ASYNCH
+#  define CURLRES_ARES
+/* now undef the stock libc functions just to avoid them being used */
+#  undef HAVE_GETADDRINFO
+#  undef HAVE_FREEADDRINFO
+#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+#  define CURLRES_ASYNCH
+#  define CURLRES_THREADED
+#else
+#  define CURLRES_SYNCH
+#endif
+
+/* ---------------------------------------------------------------- */
+
+#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && !defined(USE_WIN32_IDN)
+/* The lib and header are present */
+#define USE_LIBIDN2
+#endif
+
+#if defined(USE_LIBIDN2) && defined(USE_WIN32_IDN)
+#error "Both libidn2 and WinIDN are enabled, choose one."
+#endif
+
+#define LIBIDN_REQUIRED_VERSION "0.4.1"
+
+#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \
+  defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
+  defined(USE_BEARSSL) || defined(USE_RUSTLS)
+#define USE_SSL    /* SSL support has been enabled */
+#endif
+
+/* Single point where USE_SPNEGO definition might be defined */
+#if !defined(CURL_DISABLE_NEGOTIATE_AUTH) && \
+    (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI))
+#define USE_SPNEGO
+#endif
+
+/* Single point where USE_KERBEROS5 definition might be defined */
+#if !defined(CURL_DISABLE_KERBEROS_AUTH) && \
+    (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI))
+#define USE_KERBEROS5
+#endif
+
+/* Single point where USE_NTLM definition might be defined */
+#if !defined(CURL_DISABLE_NTLM)
+#  if defined(USE_OPENSSL) || defined(USE_MBEDTLS) ||                   \
+  defined(USE_GNUTLS) || defined(USE_SECTRANSP) ||                      \
+  defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) ||              \
+  (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT))
+#    define USE_CURL_NTLM_CORE
+#  endif
+#  if defined(USE_CURL_NTLM_CORE) || defined(USE_WINDOWS_SSPI)
+#    define USE_NTLM
+#  endif
+#endif
+
+#ifdef CURL_WANTS_CA_BUNDLE_ENV
+#error "No longer supported. Set CURLOPT_CAINFO at runtime instead."
+#endif
+
+#if defined(USE_LIBSSH2) || defined(USE_LIBSSH) || defined(USE_WOLFSSH)
+#define USE_SSH
+#endif
+
+/*
+ * Provide a mechanism to silence picky compilers, such as gcc 4.6+.
+ * Parameters should of course normally not be unused, but for example when
+ * we have multiple implementations of the same interface it may happen.
+ */
+
+#if defined(__GNUC__) && ((__GNUC__ >= 3) || \
+  ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7)))
+#  define UNUSED_PARAM __attribute__((__unused__))
+#  define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#  define UNUSED_PARAM /* NOTHING */
+#  define WARN_UNUSED_RESULT
+#endif
+
+/* noreturn attribute */
+
+#if !defined(CURL_NORETURN)
+#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__)
+#  define CURL_NORETURN  __attribute__((__noreturn__))
+#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
+#  define CURL_NORETURN  __declspec(noreturn)
+#else
+#  define CURL_NORETURN
+#endif
+#endif
+
+/* fallthrough attribute */
+
+#if !defined(FALLTHROUGH)
+#if (defined(__GNUC__) && __GNUC__ >= 7) || \
+    (defined(__clang__) && __clang_major__ >= 10)
+#  define FALLTHROUGH()  __attribute__((fallthrough))
+#else
+#  define FALLTHROUGH()  do {} while (0)
+#endif
+#endif
+
+/*
+ * Include macros and defines that should only be processed once.
+ */
+
+#ifndef HEADER_CURL_SETUP_ONCE_H
+#include "curl_setup_once.h"
+#endif
+
+/*
+ * Definition of our NOP statement Object-like macro
+ */
+
+#ifndef Curl_nop_stmt
+#  define Curl_nop_stmt do { } while(0)
+#endif
+
+/*
+ * Ensure that Winsock and lwIP TCP/IP stacks are not mixed.
+ */
+
+#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)
+#  if defined(SOCKET) || defined(USE_WINSOCK)
+#    error "WinSock and lwIP TCP/IP stack definitions shall not coexist!"
+#  endif
+#endif
+
+/*
+ * shutdown() flags for systems that don't define them
+ */
+
+#ifndef SHUT_RD
+#define SHUT_RD 0x00
+#endif
+
+#ifndef SHUT_WR
+#define SHUT_WR 0x01
+#endif
+
+#ifndef SHUT_RDWR
+#define SHUT_RDWR 0x02
+#endif
+
+/* Define S_ISREG if not defined by system headers, e.g. MSVC */
+#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+/* Define S_ISDIR if not defined by system headers, e.g. MSVC */
+#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+/* In Windows the default file mode is text but an application can override it.
+Therefore we specify it explicitly. https://github.com/curl/curl/pull/258
+*/
+#if defined(_WIN32) || defined(MSDOS)
+#define FOPEN_READTEXT "rt"
+#define FOPEN_WRITETEXT "wt"
+#define FOPEN_APPENDTEXT "at"
+#elif defined(__CYGWIN__)
+/* Cygwin has specific behavior we need to address when WIN32 is not defined.
+https://cygwin.com/cygwin-ug-net/using-textbinary.html
+For write we want our output to have line endings of LF and be compatible with
+other Cygwin utilities. For read we want to handle input that may have line
+endings either CRLF or LF so 't' is appropriate.
+*/
+#define FOPEN_READTEXT "rt"
+#define FOPEN_WRITETEXT "w"
+#define FOPEN_APPENDTEXT "a"
+#else
+#define FOPEN_READTEXT "r"
+#define FOPEN_WRITETEXT "w"
+#define FOPEN_APPENDTEXT "a"
+#endif
+
+/* for systems that don't detect this in configure */
+#ifndef CURL_SA_FAMILY_T
+#  if defined(HAVE_SA_FAMILY_T)
+#    define CURL_SA_FAMILY_T sa_family_t
+#  elif defined(HAVE_ADDRESS_FAMILY)
+#    define CURL_SA_FAMILY_T ADDRESS_FAMILY
+#  else
+/* use a sensible default */
+#    define CURL_SA_FAMILY_T unsigned short
+#  endif
+#endif
+
+/* Some convenience macros to get the larger/smaller value out of two given.
+   We prefix with CURL to prevent name collisions. */
+#define CURLMAX(x,y) ((x)>(y)?(x):(y))
+#define CURLMIN(x,y) ((x)<(y)?(x):(y))
+
+/* A convenience macro to provide both the string literal and the length of
+   the string literal in one go, useful for functions that take "string,len"
+   as their argument */
+#define STRCONST(x) x,sizeof(x)-1
+
+/* Some versions of the Android SDK is missing the declaration */
+#if defined(HAVE_GETPWUID_R) && defined(HAVE_DECL_GETPWUID_R_MISSING)
+struct passwd;
+int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
+               size_t buflen, struct passwd **result);
+#endif
+
+#ifdef DEBUGBUILD
+#define UNITTEST
+#else
+#define UNITTEST static
+#endif
+
+/* Hyper supports HTTP2 also, but Curl's integration with Hyper does not */
+#if defined(USE_NGHTTP2)
+#define USE_HTTP2
+#endif
+
+#if (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \
+    (defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)) || \
+    defined(USE_QUICHE) || defined(USE_MSH3)
+
+#ifdef CURL_WITH_MULTI_SSL
+#error "Multi-SSL combined with QUIC is not supported"
+#endif
+
+#define ENABLE_QUIC
+#define USE_HTTP3
+#endif
+
+/* Certain Windows implementations are not aligned with what curl expects,
+   so always use the local one on this platform. E.g. the mingw-w64
+   implementation can return wrong results for non-ASCII inputs. */
+#if defined(HAVE_BASENAME) && defined(_WIN32)
+#undef HAVE_BASENAME
+#endif
+
+#if defined(USE_UNIX_SOCKETS) && defined(_WIN32)
+#  if !defined(UNIX_PATH_MAX)
+     /* Replicating logic present in afunix.h
+        (distributed with newer Windows 10 SDK versions only) */
+#    define UNIX_PATH_MAX 108
+     /* !checksrc! disable TYPEDEFSTRUCT 1 */
+     typedef struct sockaddr_un {
+       ADDRESS_FAMILY sun_family;
+       char sun_path[UNIX_PATH_MAX];
+     } SOCKADDR_UN, *PSOCKADDR_UN;
+#    define WIN32_SOCKADDR_UN
+#  endif
+#endif
+
+/* OpenSSLv3 marks DES, MD5 and ENGINE functions deprecated but we have no
+   replacements (yet) so tell the compiler to not warn for them. */
+#ifdef USE_OPENSSL
+#define OPENSSL_SUPPRESS_DEPRECATED
+#endif
+
+#endif /* HEADER_CURL_SETUP_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_setup_once.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_setup_once.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_setup_once.h	(revision 104083)
@@ -0,0 +1,423 @@
+#ifndef HEADER_CURL_SETUP_ONCE_H
+#define HEADER_CURL_SETUP_ONCE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+
+/*
+ * Inclusion of common header files.
+ */
+
+#ifdef VBOX
+# include <iprt/types.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef NEED_MALLOC_H
+#include <malloc.h>
+#endif
+
+#ifdef NEED_MEMORY_H
+#include <memory.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if defined(HAVE_STDBOOL_H) && defined(HAVE_BOOL_T)
+#include <stdbool.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef USE_WOLFSSL
+#include <stdint.h>
+#endif
+
+#ifdef USE_SCHANNEL
+/* Must set this before <schannel.h> is included directly or indirectly by
+   another Windows header. */
+#  define SCHANNEL_USE_BLACKLISTS 1
+#endif
+
+#ifdef __hpux
+#  if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
+#    ifdef _APP32_64BIT_OFF_T
+#      define OLD_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T
+#      undef _APP32_64BIT_OFF_T
+#    else
+#      undef OLD_APP32_64BIT_OFF_T
+#    endif
+#  endif
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#include "functypes.h"
+
+#ifdef __hpux
+#  if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
+#    ifdef OLD_APP32_64BIT_OFF_T
+#      define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T
+#      undef OLD_APP32_64BIT_OFF_T
+#    endif
+#  endif
+#endif
+
+/*
+ * Definition of timeval struct for platforms that don't have it.
+ */
+
+#ifndef HAVE_STRUCT_TIMEVAL
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+#endif
+
+
+/*
+ * If we have the MSG_NOSIGNAL define, make sure we use
+ * it as the fourth argument of function send()
+ */
+
+#ifdef HAVE_MSG_NOSIGNAL
+#define SEND_4TH_ARG MSG_NOSIGNAL
+#else
+#define SEND_4TH_ARG 0
+#endif
+
+
+#if defined(__minix)
+/* Minix doesn't support recv on TCP sockets */
+#define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \
+                                   (RECV_TYPE_ARG2)(y), \
+                                   (RECV_TYPE_ARG3)(z))
+
+#elif defined(HAVE_RECV)
+/*
+ * The definitions for the return type and arguments types
+ * of functions recv() and send() belong and come from the
+ * configuration file. Do not define them in any other place.
+ *
+ * HAVE_RECV is defined if you have a function named recv()
+ * which is used to read incoming data from sockets. If your
+ * function has another name then don't define HAVE_RECV.
+ *
+ * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2,
+ * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also
+ * be defined.
+ *
+ * HAVE_SEND is defined if you have a function named send()
+ * which is used to write outgoing data on a connected socket.
+ * If yours has another name then don't define HAVE_SEND.
+ *
+ * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2,
+ * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and
+ * SEND_TYPE_RETV must also be defined.
+ */
+
+#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \
+                                   (RECV_TYPE_ARG2)(y), \
+                                   (RECV_TYPE_ARG3)(z), \
+                                   (RECV_TYPE_ARG4)(0))
+#else /* HAVE_RECV */
+#ifndef sread
+  /* */
+  Error Missing_definition_of_macro_sread
+  /* */
+#endif
+#endif /* HAVE_RECV */
+
+
+#if defined(__minix)
+/* Minix doesn't support send on TCP sockets */
+#define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \
+                                    (SEND_TYPE_ARG2)(y), \
+                                    (SEND_TYPE_ARG3)(z))
+
+#elif defined(HAVE_SEND)
+#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \
+                                    (SEND_QUAL_ARG2 SEND_TYPE_ARG2)(y), \
+                                    (SEND_TYPE_ARG3)(z), \
+                                    (SEND_TYPE_ARG4)(SEND_4TH_ARG))
+#else /* HAVE_SEND */
+#ifndef swrite
+  /* */
+  Error Missing_definition_of_macro_swrite
+  /* */
+#endif
+#endif /* HAVE_SEND */
+
+
+/*
+ * Function-like macro definition used to close a socket.
+ */
+
+#if defined(HAVE_CLOSESOCKET)
+#  define sclose(x)  closesocket((x))
+#elif defined(HAVE_CLOSESOCKET_CAMEL)
+#  define sclose(x)  CloseSocket((x))
+#elif defined(HAVE_CLOSE_S)
+#  define sclose(x)  close_s((x))
+#elif defined(USE_LWIPSOCK)
+#  define sclose(x)  lwip_close((x))
+#else
+#  define sclose(x)  close((x))
+#endif
+
+/*
+ * Stack-independent version of fcntl() on sockets:
+ */
+#if defined(USE_LWIPSOCK)
+#  define sfcntl  lwip_fcntl
+#else
+#  define sfcntl  fcntl
+#endif
+
+/*
+ * 'bool' stuff compatible with HP-UX headers.
+ */
+
+#if defined(__hpux) && !defined(HAVE_BOOL_T)
+   typedef int bool;
+#  define false 0
+#  define true 1
+#  define HAVE_BOOL_T
+#endif
+
+
+/*
+ * 'bool' exists on platforms with <stdbool.h>, i.e. C99 platforms.
+ * On non-C99 platforms there's no bool, so define an enum for that.
+ * On C99 platforms 'false' and 'true' also exist. Enum uses a
+ * global namespace though, so use bool_false and bool_true.
+ */
+
+#ifndef VBOX /* VirtualBox */
+#ifndef HAVE_BOOL_T
+  typedef enum {
+      bool_false = 0,
+      bool_true  = 1
+  } bool;
+
+/*
+ * Use a define to let 'true' and 'false' use those enums.  There
+ * are currently no use of true and false in libcurl proper, but
+ * there are some in the examples. This will cater for any later
+ * code happening to use true and false.
+ */
+#  define false bool_false
+#  define true  bool_true
+#  define HAVE_BOOL_T
+#endif
+#endif
+
+/* the type we use for storing a single boolean bit */
+#ifdef _MSC_VER
+typedef bool bit;
+#define BIT(x) bool x
+#else
+typedef unsigned int bit;
+#define BIT(x) bit x:1
+#endif
+
+/*
+ * Redefine TRUE and FALSE too, to catch current use. With this
+ * change, 'bool found = 1' will give a warning on MIPSPro, but
+ * 'bool found = TRUE' will not. Change tested on IRIX/MIPSPro,
+ * AIX 5.1/Xlc, Tru64 5.1/cc, w/make test too.
+ */
+
+#ifndef TRUE
+#define TRUE true
+#endif
+#ifndef FALSE
+#define FALSE false
+#endif
+
+#include "curl_ctype.h"
+
+
+/*
+ * Macro used to include code only in debug builds.
+ */
+
+#ifdef DEBUGBUILD
+#define DEBUGF(x) x
+#else
+#define DEBUGF(x) do { } while(0)
+#endif
+
+
+/*
+ * Macro used to include assertion code only in debug builds.
+ */
+
+#undef DEBUGASSERT
+#if defined(DEBUGBUILD)
+#define DEBUGASSERT(x) assert(x)
+#else
+#define DEBUGASSERT(x) do { } while(0)
+#endif
+
+
+/*
+ * Macro SOCKERRNO / SET_SOCKERRNO() returns / sets the *socket-related* errno
+ * (or equivalent) on this platform to hide platform details to code using it.
+ */
+
+#ifdef USE_WINSOCK
+#define SOCKERRNO         ((int)WSAGetLastError())
+#define SET_SOCKERRNO(x)  (WSASetLastError((int)(x)))
+#else
+#define SOCKERRNO         (errno)
+#define SET_SOCKERRNO(x)  (errno = (x))
+#endif
+
+
+/*
+ * Portable error number symbolic names defined to Winsock error codes.
+ */
+
+#ifdef USE_WINSOCK
+#undef  EBADF            /* override definition in errno.h */
+#define EBADF            WSAEBADF
+#undef  EINTR            /* override definition in errno.h */
+#define EINTR            WSAEINTR
+#undef  EINVAL           /* override definition in errno.h */
+#define EINVAL           WSAEINVAL
+#undef  EWOULDBLOCK      /* override definition in errno.h */
+#define EWOULDBLOCK      WSAEWOULDBLOCK
+#undef  EINPROGRESS      /* override definition in errno.h */
+#define EINPROGRESS      WSAEINPROGRESS
+#undef  EALREADY         /* override definition in errno.h */
+#define EALREADY         WSAEALREADY
+#undef  ENOTSOCK         /* override definition in errno.h */
+#define ENOTSOCK         WSAENOTSOCK
+#undef  EDESTADDRREQ     /* override definition in errno.h */
+#define EDESTADDRREQ     WSAEDESTADDRREQ
+#undef  EMSGSIZE         /* override definition in errno.h */
+#define EMSGSIZE         WSAEMSGSIZE
+#undef  EPROTOTYPE       /* override definition in errno.h */
+#define EPROTOTYPE       WSAEPROTOTYPE
+#undef  ENOPROTOOPT      /* override definition in errno.h */
+#define ENOPROTOOPT      WSAENOPROTOOPT
+#undef  EPROTONOSUPPORT  /* override definition in errno.h */
+#define EPROTONOSUPPORT  WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT  WSAESOCKTNOSUPPORT
+#undef  EOPNOTSUPP       /* override definition in errno.h */
+#define EOPNOTSUPP       WSAEOPNOTSUPP
+#define EPFNOSUPPORT     WSAEPFNOSUPPORT
+#undef  EAFNOSUPPORT     /* override definition in errno.h */
+#define EAFNOSUPPORT     WSAEAFNOSUPPORT
+#undef  EADDRINUSE       /* override definition in errno.h */
+#define EADDRINUSE       WSAEADDRINUSE
+#undef  EADDRNOTAVAIL    /* override definition in errno.h */
+#define EADDRNOTAVAIL    WSAEADDRNOTAVAIL
+#undef  ENETDOWN         /* override definition in errno.h */
+#define ENETDOWN         WSAENETDOWN
+#undef  ENETUNREACH      /* override definition in errno.h */
+#define ENETUNREACH      WSAENETUNREACH
+#undef  ENETRESET        /* override definition in errno.h */
+#define ENETRESET        WSAENETRESET
+#undef  ECONNABORTED     /* override definition in errno.h */
+#define ECONNABORTED     WSAECONNABORTED
+#undef  ECONNRESET       /* override definition in errno.h */
+#define ECONNRESET       WSAECONNRESET
+#undef  ENOBUFS          /* override definition in errno.h */
+#define ENOBUFS          WSAENOBUFS
+#undef  EISCONN          /* override definition in errno.h */
+#define EISCONN          WSAEISCONN
+#undef  ENOTCONN         /* override definition in errno.h */
+#define ENOTCONN         WSAENOTCONN
+#define ESHUTDOWN        WSAESHUTDOWN
+#define ETOOMANYREFS     WSAETOOMANYREFS
+#undef  ETIMEDOUT        /* override definition in errno.h */
+#define ETIMEDOUT        WSAETIMEDOUT
+#undef  ECONNREFUSED     /* override definition in errno.h */
+#define ECONNREFUSED     WSAECONNREFUSED
+#undef  ELOOP            /* override definition in errno.h */
+#define ELOOP            WSAELOOP
+#ifndef ENAMETOOLONG     /* possible previous definition in errno.h */
+#define ENAMETOOLONG     WSAENAMETOOLONG
+#endif
+#define EHOSTDOWN        WSAEHOSTDOWN
+#undef  EHOSTUNREACH     /* override definition in errno.h */
+#define EHOSTUNREACH     WSAEHOSTUNREACH
+#ifndef ENOTEMPTY        /* possible previous definition in errno.h */
+#define ENOTEMPTY        WSAENOTEMPTY
+#endif
+#define EPROCLIM         WSAEPROCLIM
+#define EUSERS           WSAEUSERS
+#define EDQUOT           WSAEDQUOT
+#define ESTALE           WSAESTALE
+#define EREMOTE          WSAEREMOTE
+#endif
+
+/*
+ * Macro argv_item_t hides platform details to code using it.
+ */
+
+#ifdef __VMS
+#define argv_item_t  __char_ptr32
+#elif defined(_UNICODE)
+#define argv_item_t wchar_t *
+#else
+#define argv_item_t  char *
+#endif
+
+
+/*
+ * We use this ZERO_NULL to avoid picky compiler warnings,
+ * when assigning a NULL pointer to a function pointer var.
+ */
+
+#define ZERO_NULL 0
+
+
+#endif /* HEADER_CURL_SETUP_ONCE_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_sha256.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_sha256.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_sha256.h	(revision 104083)
@@ -0,0 +1,50 @@
+#ifndef HEADER_CURL_SHA256_H
+#define HEADER_CURL_SHA256_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Florin Petriuc, <petriuc.florin@gmail.com>
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) \
+    || defined(USE_LIBSSH2)
+
+#include <curl/curl.h>
+#include "curl_hmac.h"
+
+extern const struct HMAC_params Curl_HMAC_SHA256[1];
+
+#ifdef USE_WOLFSSL
+/* SHA256_DIGEST_LENGTH is an enum value in wolfSSL. Need to import it from
+ * sha.h */
+#include <wolfssl/options.h>
+#include <wolfssl/openssl/sha.h>
+#else
+#define SHA256_DIGEST_LENGTH 32
+#endif
+
+CURLcode Curl_sha256it(unsigned char *outbuffer, const unsigned char *input,
+                       const size_t len);
+
+#endif
+
+#endif /* HEADER_CURL_SHA256_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_sspi.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_sspi.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_sspi.c	(revision 104083)
@@ -0,0 +1,239 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_WINDOWS_SSPI
+
+#include <curl/curl.h>
+#include "curl_sspi.h"
+#include "curl_multibyte.h"
+#include "system_win32.h"
+#include "version_win32.h"
+#include "warnless.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* We use our own typedef here since some headers might lack these */
+typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID);
+
+/* See definition of SECURITY_ENTRYPOINT in sspi.h */
+#ifdef UNICODE
+#  ifdef _WIN32_WCE
+#    define SECURITYENTRYPOINT L"InitSecurityInterfaceW"
+#  else
+#    define SECURITYENTRYPOINT "InitSecurityInterfaceW"
+#  endif
+#else
+#  define SECURITYENTRYPOINT "InitSecurityInterfaceA"
+#endif
+
+/* Handle of security.dll or secur32.dll, depending on Windows version */
+HMODULE s_hSecDll = NULL;
+
+/* Pointer to SSPI dispatch table */
+PSecurityFunctionTable s_pSecFn = NULL;
+
+/*
+ * Curl_sspi_global_init()
+ *
+ * This is used to load the Security Service Provider Interface (SSPI)
+ * dynamic link library portably across all Windows versions, without
+ * the need to directly link libcurl, nor the application using it, at
+ * build time.
+ *
+ * Once this function has been executed, Windows SSPI functions can be
+ * called through the Security Service Provider Interface dispatch table.
+ *
+ * Parameters:
+ *
+ * None.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_sspi_global_init(void)
+{
+  INITSECURITYINTERFACE_FN pInitSecurityInterface;
+
+  /* If security interface is not yet initialized try to do this */
+  if(!s_hSecDll) {
+    /* Security Service Provider Interface (SSPI) functions are located in
+     * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
+     * have both these DLLs (security.dll forwards calls to secur32.dll) */
+
+    /* Load SSPI dll into the address space of the calling process */
+    if(curlx_verify_windows_version(4, 0, 0, PLATFORM_WINNT, VERSION_EQUAL))
+      s_hSecDll = Curl_load_library(TEXT("security.dll"));
+    else
+      s_hSecDll = Curl_load_library(TEXT("secur32.dll"));
+    if(!s_hSecDll)
+      return CURLE_FAILED_INIT;
+
+    /* Get address of the InitSecurityInterfaceA function from the SSPI dll */
+    pInitSecurityInterface =
+      CURLX_FUNCTION_CAST(INITSECURITYINTERFACE_FN,
+                          (GetProcAddress(s_hSecDll, SECURITYENTRYPOINT)));
+    if(!pInitSecurityInterface)
+      return CURLE_FAILED_INIT;
+
+    /* Get pointer to Security Service Provider Interface dispatch table */
+    s_pSecFn = pInitSecurityInterface();
+    if(!s_pSecFn)
+      return CURLE_FAILED_INIT;
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_sspi_global_cleanup()
+ *
+ * This deinitializes the Security Service Provider Interface from libcurl.
+ *
+ * Parameters:
+ *
+ * None.
+ */
+void Curl_sspi_global_cleanup(void)
+{
+  if(s_hSecDll) {
+    FreeLibrary(s_hSecDll);
+    s_hSecDll = NULL;
+    s_pSecFn = NULL;
+  }
+}
+
+/*
+ * Curl_create_sspi_identity()
+ *
+ * This is used to populate a SSPI identity structure based on the supplied
+ * username and password.
+ *
+ * Parameters:
+ *
+ * userp    [in]     - The user name in the format User or Domain\User.
+ * passwdp  [in]     - The user's password.
+ * identity [in/out] - The identity structure.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
+                                   SEC_WINNT_AUTH_IDENTITY *identity)
+{
+  xcharp_u useranddomain;
+  xcharp_u user, dup_user;
+  xcharp_u domain, dup_domain;
+  xcharp_u passwd, dup_passwd;
+  size_t domlen = 0;
+
+  domain.const_tchar_ptr = TEXT("");
+
+  /* Initialize the identity */
+  memset(identity, 0, sizeof(*identity));
+
+  useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)userp);
+  if(!useranddomain.tchar_ptr)
+    return CURLE_OUT_OF_MEMORY;
+
+  user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\'));
+  if(!user.const_tchar_ptr)
+    user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/'));
+
+  if(user.tchar_ptr) {
+    domain.tchar_ptr = useranddomain.tchar_ptr;
+    domlen = user.tchar_ptr - useranddomain.tchar_ptr;
+    user.tchar_ptr++;
+  }
+  else {
+    user.tchar_ptr = useranddomain.tchar_ptr;
+    domain.const_tchar_ptr = TEXT("");
+    domlen = 0;
+  }
+
+  /* Setup the identity's user and length */
+  dup_user.tchar_ptr = _tcsdup(user.tchar_ptr);
+  if(!dup_user.tchar_ptr) {
+    curlx_unicodefree(useranddomain.tchar_ptr);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  identity->User = dup_user.tbyte_ptr;
+  identity->UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr));
+  dup_user.tchar_ptr = NULL;
+
+  /* Setup the identity's domain and length */
+  dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1));
+  if(!dup_domain.tchar_ptr) {
+    curlx_unicodefree(useranddomain.tchar_ptr);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen);
+  *(dup_domain.tchar_ptr + domlen) = TEXT('\0');
+  identity->Domain = dup_domain.tbyte_ptr;
+  identity->DomainLength = curlx_uztoul(domlen);
+  dup_domain.tchar_ptr = NULL;
+
+  curlx_unicodefree(useranddomain.tchar_ptr);
+
+  /* Setup the identity's password and length */
+  passwd.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)passwdp);
+  if(!passwd.tchar_ptr)
+    return CURLE_OUT_OF_MEMORY;
+  dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr);
+  if(!dup_passwd.tchar_ptr) {
+    curlx_unicodefree(passwd.tchar_ptr);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  identity->Password = dup_passwd.tbyte_ptr;
+  identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr));
+  dup_passwd.tchar_ptr = NULL;
+
+  curlx_unicodefree(passwd.tchar_ptr);
+
+  /* Setup the identity's flags */
+  identity->Flags = SECFLAG_WINNT_AUTH_IDENTITY;
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_sspi_free_identity()
+ *
+ * This is used to free the contents of a SSPI identifier structure.
+ *
+ * Parameters:
+ *
+ * identity [in/out] - The identity structure.
+ */
+void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity)
+{
+  if(identity) {
+    Curl_safefree(identity->User);
+    Curl_safefree(identity->Password);
+    Curl_safefree(identity->Domain);
+  }
+}
+
+#endif /* USE_WINDOWS_SSPI */
Index: trunk/src/libs/curl-8.7.1/lib/curl_sspi.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_sspi.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_sspi.h	(revision 104083)
@@ -0,0 +1,123 @@
+#ifndef HEADER_CURL_SSPI_H
+#define HEADER_CURL_SSPI_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_WINDOWS_SSPI
+
+#include <curl/curl.h>
+
+/*
+ * When including the following three headers, it is mandatory to define either
+ * SECURITY_WIN32 or SECURITY_KERNEL, indicating who is compiling the code.
+ */
+
+#undef SECURITY_WIN32
+#undef SECURITY_KERNEL
+#define SECURITY_WIN32 1
+#include <security.h>
+#include <sspi.h>
+#include <rpc.h>
+
+CURLcode Curl_sspi_global_init(void);
+void Curl_sspi_global_cleanup(void);
+
+/* This is used to populate the domain in a SSPI identity structure */
+CURLcode Curl_override_sspi_http_realm(const char *chlg,
+                                       SEC_WINNT_AUTH_IDENTITY *identity);
+
+/* This is used to generate an SSPI identity structure */
+CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
+                                   SEC_WINNT_AUTH_IDENTITY *identity);
+
+/* This is used to free an SSPI identity structure */
+void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity);
+
+/* Forward-declaration of global variables defined in curl_sspi.c */
+extern HMODULE s_hSecDll;
+extern PSecurityFunctionTable s_pSecFn;
+
+/* Provide some definitions missing in old headers */
+#define SP_NAME_DIGEST              "WDigest"
+#define SP_NAME_NTLM                "NTLM"
+#define SP_NAME_NEGOTIATE           "Negotiate"
+#define SP_NAME_KERBEROS            "Kerberos"
+
+#ifndef ISC_REQ_USE_HTTP_STYLE
+#define ISC_REQ_USE_HTTP_STYLE                0x01000000
+#endif
+
+#ifndef SEC_E_INVALID_PARAMETER
+# define SEC_E_INVALID_PARAMETER              ((HRESULT)0x8009035DL)
+#endif
+#ifndef SEC_E_DELEGATION_POLICY
+# define SEC_E_DELEGATION_POLICY              ((HRESULT)0x8009035EL)
+#endif
+#ifndef SEC_E_POLICY_NLTM_ONLY
+# define SEC_E_POLICY_NLTM_ONLY               ((HRESULT)0x8009035FL)
+#endif
+
+#ifndef SEC_I_SIGNATURE_NEEDED
+# define SEC_I_SIGNATURE_NEEDED               ((HRESULT)0x0009035CL)
+#endif
+
+#ifndef CRYPT_E_REVOKED
+# define CRYPT_E_REVOKED                      ((HRESULT)0x80092010L)
+#endif
+
+#ifndef CRYPT_E_NO_REVOCATION_DLL
+# define CRYPT_E_NO_REVOCATION_DLL            ((HRESULT)0x80092011L)
+#endif
+
+#ifndef CRYPT_E_NO_REVOCATION_CHECK
+# define CRYPT_E_NO_REVOCATION_CHECK          ((HRESULT)0x80092012L)
+#endif
+
+#ifndef CRYPT_E_REVOCATION_OFFLINE
+# define CRYPT_E_REVOCATION_OFFLINE           ((HRESULT)0x80092013L)
+#endif
+
+#ifndef CRYPT_E_NOT_IN_REVOCATION_DATABASE
+# define CRYPT_E_NOT_IN_REVOCATION_DATABASE   ((HRESULT)0x80092014L)
+#endif
+
+#ifdef UNICODE
+#  define SECFLAG_WINNT_AUTH_IDENTITY \
+     (unsigned long)SEC_WINNT_AUTH_IDENTITY_UNICODE
+#else
+#  define SECFLAG_WINNT_AUTH_IDENTITY \
+     (unsigned long)SEC_WINNT_AUTH_IDENTITY_ANSI
+#endif
+
+/*
+ * Definitions required from ntsecapi.h are directly provided below this point
+ * to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h
+ */
+#define KERB_WRAP_NO_ENCRYPT 0x80000001
+
+#endif /* USE_WINDOWS_SSPI */
+
+#endif /* HEADER_CURL_SSPI_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_threads.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_threads.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_threads.c	(revision 104083)
@@ -0,0 +1,153 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#if defined(USE_THREADS_POSIX)
+#  ifdef HAVE_PTHREAD_H
+#    include <pthread.h>
+#  endif
+#elif defined(USE_THREADS_WIN32)
+#  include <process.h>
+#endif
+
+#include "curl_threads.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#if defined(USE_THREADS_POSIX)
+
+struct Curl_actual_call {
+  unsigned int (*func)(void *);
+  void *arg;
+};
+
+static void *curl_thread_create_thunk(void *arg)
+{
+  struct Curl_actual_call *ac = arg;
+  unsigned int (*func)(void *) = ac->func;
+  void *real_arg = ac->arg;
+
+  free(ac);
+
+  (*func)(real_arg);
+
+  return 0;
+}
+
+curl_thread_t Curl_thread_create(unsigned int (*func) (void *), void *arg)
+{
+  curl_thread_t t = malloc(sizeof(pthread_t));
+  struct Curl_actual_call *ac = malloc(sizeof(struct Curl_actual_call));
+  if(!(ac && t))
+    goto err;
+
+  ac->func = func;
+  ac->arg = arg;
+
+  if(pthread_create(t, NULL, curl_thread_create_thunk, ac) != 0)
+    goto err;
+
+  return t;
+
+err:
+  free(t);
+  free(ac);
+  return curl_thread_t_null;
+}
+
+void Curl_thread_destroy(curl_thread_t hnd)
+{
+  if(hnd != curl_thread_t_null) {
+    pthread_detach(*hnd);
+    free(hnd);
+  }
+}
+
+int Curl_thread_join(curl_thread_t *hnd)
+{
+  int ret = (pthread_join(**hnd, NULL) == 0);
+
+  free(*hnd);
+  *hnd = curl_thread_t_null;
+
+  return ret;
+}
+
+#elif defined(USE_THREADS_WIN32)
+
+/* !checksrc! disable SPACEBEFOREPAREN 1 */
+curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
+                                 void *arg)
+{
+#ifdef _WIN32_WCE
+  typedef HANDLE curl_win_thread_handle_t;
+#else
+  typedef uintptr_t curl_win_thread_handle_t;
+#endif
+  curl_thread_t t;
+  curl_win_thread_handle_t thread_handle;
+#ifdef _WIN32_WCE
+  thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL);
+#else
+  thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);
+#endif
+  t = (curl_thread_t)thread_handle;
+  if((t == 0) || (t == LongToHandle(-1L))) {
+#ifdef _WIN32_WCE
+    DWORD gle = GetLastError();
+    errno = ((gle == ERROR_ACCESS_DENIED ||
+              gle == ERROR_NOT_ENOUGH_MEMORY) ?
+             EACCES : EINVAL);
+#endif
+    return curl_thread_t_null;
+  }
+  return t;
+}
+
+void Curl_thread_destroy(curl_thread_t hnd)
+{
+  CloseHandle(hnd);
+}
+
+int Curl_thread_join(curl_thread_t *hnd)
+{
+#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
+    (_WIN32_WINNT < _WIN32_WINNT_VISTA)
+  int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0);
+#else
+  int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0);
+#endif
+
+  Curl_thread_destroy(*hnd);
+
+  *hnd = curl_thread_t_null;
+
+  return ret;
+}
+
+#endif /* USE_THREADS_* */
Index: trunk/src/libs/curl-8.7.1/lib/curl_threads.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_threads.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_threads.h	(revision 104083)
@@ -0,0 +1,65 @@
+#ifndef HEADER_CURL_THREADS_H
+#define HEADER_CURL_THREADS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(USE_THREADS_POSIX)
+#  define CURL_STDCALL
+#  define curl_mutex_t           pthread_mutex_t
+#  define curl_thread_t          pthread_t *
+#  define curl_thread_t_null     (pthread_t *)0
+#  define Curl_mutex_init(m)     pthread_mutex_init(m, NULL)
+#  define Curl_mutex_acquire(m)  pthread_mutex_lock(m)
+#  define Curl_mutex_release(m)  pthread_mutex_unlock(m)
+#  define Curl_mutex_destroy(m)  pthread_mutex_destroy(m)
+#elif defined(USE_THREADS_WIN32)
+#  define CURL_STDCALL           __stdcall
+#  define curl_mutex_t           CRITICAL_SECTION
+#  define curl_thread_t          HANDLE
+#  define curl_thread_t_null     (HANDLE)0
+#  if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
+      (_WIN32_WINNT < _WIN32_WINNT_VISTA)
+#    define Curl_mutex_init(m)   InitializeCriticalSection(m)
+#  else
+#    define Curl_mutex_init(m)   InitializeCriticalSectionEx(m, 0, 1)
+#  endif
+#  define Curl_mutex_acquire(m)  EnterCriticalSection(m)
+#  define Curl_mutex_release(m)  LeaveCriticalSection(m)
+#  define Curl_mutex_destroy(m)  DeleteCriticalSection(m)
+#endif
+
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+
+/* !checksrc! disable SPACEBEFOREPAREN 1 */
+curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
+                                 void *arg);
+
+void Curl_thread_destroy(curl_thread_t hnd);
+
+int Curl_thread_join(curl_thread_t *hnd);
+
+#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
+
+#endif /* HEADER_CURL_THREADS_H */
Index: trunk/src/libs/curl-8.7.1/lib/curl_trc.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_trc.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_trc.c	(revision 104083)
@@ -0,0 +1,268 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "curl_trc.h"
+#include "urldata.h"
+#include "easyif.h"
+#include "cfilters.h"
+#include "timeval.h"
+#include "multiif.h"
+#include "strcase.h"
+
+#include "cf-socket.h"
+#include "connect.h"
+#include "doh.h"
+#include "http2.h"
+#include "http_proxy.h"
+#include "cf-h1-proxy.h"
+#include "cf-h2-proxy.h"
+#include "cf-haproxy.h"
+#include "cf-https-connect.h"
+#include "socks.h"
+#include "strtok.h"
+#include "vtls/vtls.h"
+#include "vquic/vquic.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+void Curl_debug(struct Curl_easy *data, curl_infotype type,
+                char *ptr, size_t size)
+{
+  if(data->set.verbose) {
+    static const char s_infotype[CURLINFO_END][3] = {
+      "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
+    if(data->set.fdebug) {
+      bool inCallback = Curl_is_in_callback(data);
+      Curl_set_in_callback(data, true);
+      (void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
+      Curl_set_in_callback(data, inCallback);
+    }
+    else {
+      switch(type) {
+      case CURLINFO_TEXT:
+      case CURLINFO_HEADER_OUT:
+      case CURLINFO_HEADER_IN:
+        fwrite(s_infotype[type], 2, 1, data->set.err);
+        fwrite(ptr, size, 1, data->set.err);
+        break;
+      default: /* nada */
+        break;
+      }
+    }
+  }
+}
+
+
+/* Curl_failf() is for messages stating why we failed.
+ * The message SHALL NOT include any LF or CR.
+ */
+void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
+{
+  DEBUGASSERT(!strchr(fmt, '\n'));
+  if(data->set.verbose || data->set.errorbuffer) {
+    va_list ap;
+    int len;
+    char error[CURL_ERROR_SIZE + 2];
+    va_start(ap, fmt);
+    len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
+
+    if(data->set.errorbuffer && !data->state.errorbuf) {
+      strcpy(data->set.errorbuffer, error);
+      data->state.errorbuf = TRUE; /* wrote error string */
+    }
+    error[len++] = '\n';
+    error[len] = '\0';
+    Curl_debug(data, CURLINFO_TEXT, error, len);
+    va_end(ap);
+  }
+}
+
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+
+/* Curl_infof() is for info message along the way */
+#define MAXINFO 2048
+
+void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
+{
+  DEBUGASSERT(!strchr(fmt, '\n'));
+  if(Curl_trc_is_verbose(data)) {
+    va_list ap;
+    int len = 0;
+    char buffer[MAXINFO + 2];
+    if(data->state.feat)
+      len = msnprintf(buffer, MAXINFO, "[%s] ", data->state.feat->name);
+    va_start(ap, fmt);
+    len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
+    va_end(ap);
+    buffer[len++] = '\n';
+    buffer[len] = '\0';
+    Curl_debug(data, CURLINFO_TEXT, buffer, len);
+  }
+}
+
+void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
+                       const char *fmt, ...)
+{
+  DEBUGASSERT(cf);
+  if(Curl_trc_cf_is_verbose(cf, data)) {
+    va_list ap;
+    int len = 0;
+    char buffer[MAXINFO + 2];
+    if(data->state.feat)
+      len += msnprintf(buffer + len, MAXINFO - len, "[%s] ",
+                       data->state.feat->name);
+    if(cf->sockindex)
+      len += msnprintf(buffer + len, MAXINFO - len, "[%s-%d] ",
+                      cf->cft->name, cf->sockindex);
+    else
+      len += msnprintf(buffer + len, MAXINFO - len, "[%s] ", cf->cft->name);
+    va_start(ap, fmt);
+    len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
+    va_end(ap);
+    buffer[len++] = '\n';
+    buffer[len] = '\0';
+    Curl_debug(data, CURLINFO_TEXT, buffer, len);
+  }
+}
+
+static struct curl_trc_feat *trc_feats[] = {
+#ifndef CURL_DISABLE_DOH
+  &Curl_doh_trc,
+#endif
+  NULL,
+};
+
+static struct Curl_cftype *cf_types[] = {
+  &Curl_cft_tcp,
+  &Curl_cft_udp,
+  &Curl_cft_unix,
+  &Curl_cft_tcp_accept,
+  &Curl_cft_happy_eyeballs,
+  &Curl_cft_setup,
+#ifdef USE_NGHTTP2
+  &Curl_cft_nghttp2,
+#endif
+#ifdef USE_SSL
+  &Curl_cft_ssl,
+#ifndef CURL_DISABLE_PROXY
+  &Curl_cft_ssl_proxy,
+#endif
+#endif
+#if !defined(CURL_DISABLE_PROXY)
+#if !defined(CURL_DISABLE_HTTP)
+  &Curl_cft_h1_proxy,
+#ifdef USE_NGHTTP2
+  &Curl_cft_h2_proxy,
+#endif
+  &Curl_cft_http_proxy,
+#endif /* !CURL_DISABLE_HTTP */
+  &Curl_cft_haproxy,
+  &Curl_cft_socks_proxy,
+#endif /* !CURL_DISABLE_PROXY */
+#ifdef ENABLE_QUIC
+  &Curl_cft_http3,
+#endif
+#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+  &Curl_cft_http_connect,
+#endif
+  NULL,
+};
+
+CURLcode Curl_trc_opt(const char *config)
+{
+  char *token, *tok_buf, *tmp;
+  size_t i;
+  int lvl;
+
+  tmp = strdup(config);
+  if(!tmp)
+    return CURLE_OUT_OF_MEMORY;
+
+  token = strtok_r(tmp, ", ", &tok_buf);
+  while(token) {
+    switch(*token) {
+      case '-':
+        lvl = CURL_LOG_LVL_NONE;
+        ++token;
+        break;
+      case '+':
+        lvl = CURL_LOG_LVL_INFO;
+        ++token;
+        break;
+      default:
+        lvl = CURL_LOG_LVL_INFO;
+        break;
+    }
+    for(i = 0; cf_types[i]; ++i) {
+      if(strcasecompare(token, "all")) {
+        cf_types[i]->log_level = lvl;
+      }
+      else if(strcasecompare(token, cf_types[i]->name)) {
+        cf_types[i]->log_level = lvl;
+        break;
+      }
+    }
+    for(i = 0; trc_feats[i]; ++i) {
+      if(strcasecompare(token, "all")) {
+        trc_feats[i]->log_level = lvl;
+      }
+      else if(strcasecompare(token, trc_feats[i]->name)) {
+        trc_feats[i]->log_level = lvl;
+        break;
+      }
+    }
+    token = strtok_r(NULL, ", ", &tok_buf);
+  }
+  free(tmp);
+  return CURLE_OK;
+}
+
+CURLcode Curl_trc_init(void)
+{
+#ifdef DEBUGBUILD
+  /* WIP: we use the auto-init from an env var only in DEBUG builds for
+   * convenience. */
+  const char *config = getenv("CURL_DEBUG");
+  if(config) {
+    return Curl_trc_opt(config);
+  }
+#endif /* DEBUGBUILD */
+  return CURLE_OK;
+}
+#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
+
+CURLcode Curl_trc_init(void)
+{
+  return CURLE_OK;
+}
+
+#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
Index: trunk/src/libs/curl-8.7.1/lib/curl_trc.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curl_trc.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curl_trc.h	(revision 104083)
@@ -0,0 +1,139 @@
+#ifndef HEADER_CURL_TRC_H
+#define HEADER_CURL_TRC_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+struct Curl_easy;
+struct Curl_cfilter;
+
+/**
+ * Init logging, return != 0 on failure.
+ */
+CURLcode Curl_trc_init(void);
+
+/**
+ * Configure tracing. May be called several times during global
+ * initialization. Later calls may not take effect.
+ *
+ * Configuration format supported:
+ * - comma-separated list of component names to enable logging on.
+ *   E.g. 'http/2,ssl'. Unknown names are ignored. Names are compared
+ *   case-insensitive.
+ * - component 'all' applies to all known log components
+ * - prefixing a component with '+' or '-' will en-/disable logging for
+ *   that component
+ * Example: 'all,-ssl' would enable logging for all components but the
+ * SSL filters.
+ *
+ * @param config configuration string
+ */
+CURLcode Curl_trc_opt(const char *config);
+
+/* the function used to output verbose information */
+void Curl_debug(struct Curl_easy *data, curl_infotype type,
+                char *ptr, size_t size);
+
+/**
+ * Output a failure message on registered callbacks for transfer.
+ */
+void Curl_failf(struct Curl_easy *data,
+                const char *fmt, ...) CURL_PRINTF(2, 3);
+
+#define failf Curl_failf
+
+#define CURL_LOG_LVL_NONE  0
+#define CURL_LOG_LVL_INFO  1
+
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define CURL_HAVE_C99
+#endif
+
+#ifdef CURL_HAVE_C99
+#define infof(data, ...) \
+  do { if(Curl_trc_is_verbose(data)) \
+         Curl_infof(data, __VA_ARGS__); } while(0)
+#define CURL_TRC_CF(data, cf, ...) \
+  do { if(Curl_trc_cf_is_verbose(cf, data)) \
+         Curl_trc_cf_infof(data, cf, __VA_ARGS__); } while(0)
+
+#else
+#define infof Curl_infof
+#define CURL_TRC_CF Curl_trc_cf_infof
+#endif
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+/* informational messages enabled */
+
+struct curl_trc_feat {
+  const char *name;
+  int log_level;
+};
+
+#define Curl_trc_is_verbose(data) \
+            ((data) && (data)->set.verbose && \
+            (!(data)->state.feat || \
+             ((data)->state.feat->log_level >= CURL_LOG_LVL_INFO)))
+#define Curl_trc_cf_is_verbose(cf, data) \
+            (Curl_trc_is_verbose(data) && \
+            (cf) && (cf)->cft->log_level >= CURL_LOG_LVL_INFO)
+#define Curl_trc_ft_is_verbose(data, ft) \
+                            (Curl_trc_is_verbose(data) && \
+                            (ft)->log_level >= CURL_LOG_LVL_INFO)
+
+/**
+ * Output an informational message when transfer's verbose logging is enabled.
+ */
+void Curl_infof(struct Curl_easy *data,
+                const char *fmt, ...) CURL_PRINTF(2, 3);
+
+/**
+ * Output an informational message when both transfer's verbose logging
+ * and connection filters verbose logging are enabled.
+ */
+void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
+                       const char *fmt, ...) CURL_PRINTF(3, 4);
+
+#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
+/* All informational messages are not compiled in for size savings */
+
+#define Curl_trc_is_verbose(d)        ((void)(d), FALSE)
+#define Curl_trc_cf_is_verbose(x,y)   ((void)(x), (void)(y), FALSE)
+#define Curl_trc_ft_is_verbose(x,y)   ((void)(x), (void)(y), FALSE)
+
+static void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data; (void)fmt;
+}
+
+static void Curl_trc_cf_infof(struct Curl_easy *data,
+                              struct Curl_cfilter *cf,
+                              const char *fmt, ...)
+{
+  (void)data; (void)cf; (void)fmt;
+}
+
+#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
+
+#endif /* HEADER_CURL_TRC_H */
Index: trunk/src/libs/curl-8.7.1/lib/curlx.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/curlx.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/curlx.h	(revision 104083)
@@ -0,0 +1,118 @@
+#ifndef HEADER_CURL_CURLX_H
+#define HEADER_CURL_CURLX_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Defines protos and includes all header files that provide the curlx_*
+ * functions. The curlx_* functions are not part of the libcurl API, but are
+ * stand-alone functions whose sources can be built and linked by apps if need
+ * be.
+ */
+
+#include <curl/mprintf.h>
+/* this is still a public header file that provides the curl_mprintf()
+   functions while they still are offered publicly. They will be made library-
+   private one day */
+
+#include "strcase.h"
+/* "strcase.h" provides the strcasecompare protos */
+
+#include "strtoofft.h"
+/* "strtoofft.h" provides this function: curlx_strtoofft(), returns a
+   curl_off_t number from a given string.
+*/
+
+#include "nonblock.h"
+/* "nonblock.h" provides curlx_nonblock() */
+
+#include "warnless.h"
+/* "warnless.h" provides functions:
+
+  curlx_ultous()
+  curlx_ultouc()
+  curlx_uztosi()
+*/
+
+#include "curl_multibyte.h"
+/* "curl_multibyte.h" provides these functions and macros:
+
+  curlx_convert_UTF8_to_wchar()
+  curlx_convert_wchar_to_UTF8()
+  curlx_convert_UTF8_to_tchar()
+  curlx_convert_tchar_to_UTF8()
+  curlx_unicodefree()
+*/
+
+#include "version_win32.h"
+/* "version_win32.h" provides curlx_verify_windows_version() */
+
+/* Now setup curlx_ * names for the functions that are to become curlx_ and
+   be removed from a future libcurl official API:
+   curlx_getenv
+   curlx_mprintf (and its variations)
+   curlx_strcasecompare
+   curlx_strncasecompare
+
+*/
+
+#define curlx_getenv curl_getenv
+#define curlx_mvsnprintf curl_mvsnprintf
+#define curlx_msnprintf curl_msnprintf
+#define curlx_maprintf curl_maprintf
+#define curlx_mvaprintf curl_mvaprintf
+#define curlx_msprintf curl_msprintf
+#define curlx_mprintf curl_mprintf
+#define curlx_mfprintf curl_mfprintf
+#define curlx_mvsprintf curl_mvsprintf
+#define curlx_mvprintf curl_mvprintf
+#define curlx_mvfprintf curl_mvfprintf
+
+#ifdef ENABLE_CURLX_PRINTF
+/* If this define is set, we define all "standard" printf() functions to use
+   the curlx_* version instead. It makes the source code transparent and
+   easier to understand/patch. Undefine them first. */
+# undef printf
+# undef fprintf
+# undef sprintf
+# undef msnprintf
+# undef vprintf
+# undef vfprintf
+# undef vsprintf
+# undef mvsnprintf
+# undef aprintf
+# undef vaprintf
+
+# define printf curlx_mprintf
+# define fprintf curlx_mfprintf
+# define sprintf curlx_msprintf
+# define msnprintf curlx_msnprintf
+# define vprintf curlx_mvprintf
+# define vfprintf curlx_mvfprintf
+# define mvsnprintf curlx_mvsnprintf
+# define aprintf curlx_maprintf
+# define vaprintf curlx_mvaprintf
+#endif /* ENABLE_CURLX_PRINTF */
+
+#endif /* HEADER_CURL_CURLX_H */
Index: trunk/src/libs/curl-8.7.1/lib/dict.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/dict.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/dict.c	(revision 104083)
@@ -0,0 +1,320 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_DICT
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#elif defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "escape.h"
+#include "progress.h"
+#include "dict.h"
+#include "curl_printf.h"
+#include "strcase.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Forward declarations.
+ */
+
+static CURLcode dict_do(struct Curl_easy *data, bool *done);
+
+/*
+ * DICT protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_dict = {
+  "DICT",                               /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  dict_do,                              /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_DICT,                            /* defport */
+  CURLPROTO_DICT,                       /* protocol */
+  CURLPROTO_DICT,                       /* family */
+  PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
+};
+
+#define DYN_DICT_WORD 10000
+static char *unescape_word(const char *input)
+{
+  struct dynbuf out;
+  const char *ptr;
+  CURLcode result = CURLE_OK;
+  Curl_dyn_init(&out, DYN_DICT_WORD);
+
+  /* According to RFC2229 section 2.2, these letters need to be escaped with
+     \[letter] */
+  for(ptr = input; *ptr; ptr++) {
+    char ch = *ptr;
+    if((ch <= 32) || (ch == 127) ||
+       (ch == '\'') || (ch == '\"') || (ch == '\\'))
+      result = Curl_dyn_addn(&out, "\\", 1);
+    if(!result)
+      result = Curl_dyn_addn(&out, ptr, 1);
+    if(result)
+      return NULL;
+  }
+  return Curl_dyn_ptr(&out);
+}
+
+/* sendf() sends formatted data to the server */
+static CURLcode sendf(struct Curl_easy *data,
+                      const char *fmt, ...) CURL_PRINTF(2, 3);
+
+static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...)
+{
+  size_t bytes_written;
+  size_t write_len;
+  CURLcode result = CURLE_OK;
+  char *s;
+  char *sptr;
+  va_list ap;
+  va_start(ap, fmt);
+  s = vaprintf(fmt, ap); /* returns an allocated string */
+  va_end(ap);
+  if(!s)
+    return CURLE_OUT_OF_MEMORY; /* failure */
+
+  bytes_written = 0;
+  write_len = strlen(s);
+  sptr = s;
+
+  for(;;) {
+    /* Write the buffer to the socket */
+    result = Curl_xfer_send(data, sptr, write_len, &bytes_written);
+
+    if(result)
+      break;
+
+    Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written);
+
+    if((size_t)bytes_written != write_len) {
+      /* if not all was written at once, we must advance the pointer, decrease
+         the size left and try again! */
+      write_len -= bytes_written;
+      sptr += bytes_written;
+    }
+    else
+      break;
+  }
+
+  free(s); /* free the output string */
+
+  return result;
+}
+
+static CURLcode dict_do(struct Curl_easy *data, bool *done)
+{
+  char *word;
+  char *eword = NULL;
+  char *ppath;
+  char *database = NULL;
+  char *strategy = NULL;
+  char *nthdef = NULL; /* This is not part of the protocol, but required
+                          by RFC 2229 */
+  CURLcode result;
+
+  char *path;
+
+  *done = TRUE; /* unconditionally */
+
+  /* url-decode path before further evaluation */
+  result = Curl_urldecode(data->state.up.path, 0, &path, NULL, REJECT_CTRL);
+  if(result)
+    return result;
+
+  if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
+     strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
+     strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
+
+    word = strchr(path, ':');
+    if(word) {
+      word++;
+      database = strchr(word, ':');
+      if(database) {
+        *database++ = (char)0;
+        strategy = strchr(database, ':');
+        if(strategy) {
+          *strategy++ = (char)0;
+          nthdef = strchr(strategy, ':');
+          if(nthdef) {
+            *nthdef = (char)0;
+          }
+        }
+      }
+    }
+
+    if(!word || (*word == (char)0)) {
+      infof(data, "lookup word is missing");
+      word = (char *)"default";
+    }
+    if(!database || (*database == (char)0)) {
+      database = (char *)"!";
+    }
+    if(!strategy || (*strategy == (char)0)) {
+      strategy = (char *)".";
+    }
+
+    eword = unescape_word(word);
+    if(!eword) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
+
+    result = sendf(data,
+                   "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+                   "MATCH "
+                   "%s "    /* database */
+                   "%s "    /* strategy */
+                   "%s\r\n" /* word */
+                   "QUIT\r\n",
+                   database,
+                   strategy,
+                   eword);
+
+    if(result) {
+      failf(data, "Failed sending DICT request");
+      goto error;
+    }
+    Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */
+  }
+  else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
+          strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
+          strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
+
+    word = strchr(path, ':');
+    if(word) {
+      word++;
+      database = strchr(word, ':');
+      if(database) {
+        *database++ = (char)0;
+        nthdef = strchr(database, ':');
+        if(nthdef) {
+          *nthdef = (char)0;
+        }
+      }
+    }
+
+    if(!word || (*word == (char)0)) {
+      infof(data, "lookup word is missing");
+      word = (char *)"default";
+    }
+    if(!database || (*database == (char)0)) {
+      database = (char *)"!";
+    }
+
+    eword = unescape_word(word);
+    if(!eword) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
+
+    result = sendf(data,
+                   "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+                   "DEFINE "
+                   "%s "     /* database */
+                   "%s\r\n"  /* word */
+                   "QUIT\r\n",
+                   database,
+                   eword);
+
+    if(result) {
+      failf(data, "Failed sending DICT request");
+      goto error;
+    }
+    Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
+  }
+  else {
+
+    ppath = strchr(path, '/');
+    if(ppath) {
+      int i;
+
+      ppath++;
+      for(i = 0; ppath[i]; i++) {
+        if(ppath[i] == ':')
+          ppath[i] = ' ';
+      }
+      result = sendf(data,
+                     "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+                     "%s\r\n"
+                     "QUIT\r\n", ppath);
+      if(result) {
+        failf(data, "Failed sending DICT request");
+        goto error;
+      }
+
+      Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
+    }
+  }
+
+error:
+  free(eword);
+  free(path);
+  return result;
+}
+#endif /* CURL_DISABLE_DICT */
Index: trunk/src/libs/curl-8.7.1/lib/dict.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/dict.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/dict.h	(revision 104083)
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_DICT_H
+#define HEADER_CURL_DICT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_DICT
+extern const struct Curl_handler Curl_handler_dict;
+#endif
+
+#endif /* HEADER_CURL_DICT_H */
Index: trunk/src/libs/curl-8.7.1/lib/doh.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/doh.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/doh.c	(revision 104083)
@@ -0,0 +1,1006 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_DOH
+
+#include "urldata.h"
+#include "curl_addrinfo.h"
+#include "doh.h"
+
+#include "sendf.h"
+#include "multiif.h"
+#include "url.h"
+#include "share.h"
+#include "curl_base64.h"
+#include "connect.h"
+#include "strdup.h"
+#include "dynbuf.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define DNS_CLASS_IN 0x01
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static const char * const errors[]={
+  "",
+  "Bad label",
+  "Out of range",
+  "Label loop",
+  "Too small",
+  "Out of memory",
+  "RDATA length",
+  "Malformat",
+  "Bad RCODE",
+  "Unexpected TYPE",
+  "Unexpected CLASS",
+  "No content",
+  "Bad ID",
+  "Name too long"
+};
+
+static const char *doh_strerror(DOHcode code)
+{
+  if((code >= DOH_OK) && (code <= DOH_DNS_NAME_TOO_LONG))
+    return errors[code];
+  return "bad error code";
+}
+
+struct curl_trc_feat Curl_doh_trc = {
+  "DoH",
+  CURL_LOG_LVL_NONE,
+};
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+
+/* @unittest 1655
+ */
+UNITTEST DOHcode doh_encode(const char *host,
+                            DNStype dnstype,
+                            unsigned char *dnsp, /* buffer */
+                            size_t len,  /* buffer size */
+                            size_t *olen) /* output length */
+{
+  const size_t hostlen = strlen(host);
+  unsigned char *orig = dnsp;
+  const char *hostp = host;
+
+  /* The expected output length is 16 bytes more than the length of
+   * the QNAME-encoding of the host name.
+   *
+   * A valid DNS name may not contain a zero-length label, except at
+   * the end.  For this reason, a name beginning with a dot, or
+   * containing a sequence of two or more consecutive dots, is invalid
+   * and cannot be encoded as a QNAME.
+   *
+   * If the host name ends with a trailing dot, the corresponding
+   * QNAME-encoding is one byte longer than the host name. If (as is
+   * also valid) the hostname is shortened by the omission of the
+   * trailing dot, then its QNAME-encoding will be two bytes longer
+   * than the host name.
+   *
+   * Each [ label, dot ] pair is encoded as [ length, label ],
+   * preserving overall length.  A final [ label ] without a dot is
+   * also encoded as [ length, label ], increasing overall length
+   * by one. The encoding is completed by appending a zero byte,
+   * representing the zero-length root label, again increasing
+   * the overall length by one.
+   */
+
+  size_t expected_len;
+  DEBUGASSERT(hostlen);
+  expected_len = 12 + 1 + hostlen + 4;
+  if(host[hostlen-1]!='.')
+    expected_len++;
+
+  if(expected_len > (256 + 16)) /* RFCs 1034, 1035 */
+    return DOH_DNS_NAME_TOO_LONG;
+
+  if(len < expected_len)
+    return DOH_TOO_SMALL_BUFFER;
+
+  *dnsp++ = 0; /* 16 bit id */
+  *dnsp++ = 0;
+  *dnsp++ = 0x01; /* |QR|   Opcode  |AA|TC|RD| Set the RD bit */
+  *dnsp++ = '\0'; /* |RA|   Z    |   RCODE   |                */
+  *dnsp++ = '\0';
+  *dnsp++ = 1;    /* QDCOUNT (number of entries in the question section) */
+  *dnsp++ = '\0';
+  *dnsp++ = '\0'; /* ANCOUNT */
+  *dnsp++ = '\0';
+  *dnsp++ = '\0'; /* NSCOUNT */
+  *dnsp++ = '\0';
+  *dnsp++ = '\0'; /* ARCOUNT */
+
+  /* encode each label and store it in the QNAME */
+  while(*hostp) {
+    size_t labellen;
+    char *dot = strchr(hostp, '.');
+    if(dot)
+      labellen = dot - hostp;
+    else
+      labellen = strlen(hostp);
+    if((labellen > 63) || (!labellen)) {
+      /* label is too long or too short, error out */
+      *olen = 0;
+      return DOH_DNS_BAD_LABEL;
+    }
+    /* label is non-empty, process it */
+    *dnsp++ = (unsigned char)labellen;
+    memcpy(dnsp, hostp, labellen);
+    dnsp += labellen;
+    hostp += labellen;
+    /* advance past dot, but only if there is one */
+    if(dot)
+      hostp++;
+  } /* next label */
+
+  *dnsp++ = 0; /* append zero-length label for root */
+
+  /* There are assigned TYPE codes beyond 255: use range [1..65535]  */
+  *dnsp++ = (unsigned char)(255 & (dnstype>>8)); /* upper 8 bit TYPE */
+  *dnsp++ = (unsigned char)(255 & dnstype);      /* lower 8 bit TYPE */
+
+  *dnsp++ = '\0'; /* upper 8 bit CLASS */
+  *dnsp++ = DNS_CLASS_IN; /* IN - "the Internet" */
+
+  *olen = dnsp - orig;
+
+  /* verify that our estimation of length is valid, since
+   * this has led to buffer overflows in this function */
+  DEBUGASSERT(*olen == expected_len);
+  return DOH_OK;
+}
+
+static size_t
+doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
+{
+  size_t realsize = size * nmemb;
+  struct dynbuf *mem = (struct dynbuf *)userp;
+
+  if(Curl_dyn_addn(mem, contents, realsize))
+    return 0;
+
+  return realsize;
+}
+
+/* called from multi.c when this DoH transfer is complete */
+static int doh_done(struct Curl_easy *doh, CURLcode result)
+{
+  struct Curl_easy *data = doh->set.dohfor;
+  struct dohdata *dohp = data->req.doh;
+  /* so one of the DoH request done for the 'data' transfer is now complete! */
+  dohp->pending--;
+  infof(doh, "a DoH request is completed, %u to go", dohp->pending);
+  if(result)
+    infof(doh, "DoH request %s", curl_easy_strerror(result));
+
+  if(!dohp->pending) {
+    /* DoH completed */
+    curl_slist_free_all(dohp->headers);
+    dohp->headers = NULL;
+    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+  }
+  return 0;
+}
+
+#define ERROR_CHECK_SETOPT(x,y) \
+do {                                          \
+  result = curl_easy_setopt(doh, x, y);       \
+  if(result &&                                \
+     result != CURLE_NOT_BUILT_IN &&          \
+     result != CURLE_UNKNOWN_OPTION)          \
+    goto error;                               \
+} while(0)
+
+static CURLcode dohprobe(struct Curl_easy *data,
+                         struct dnsprobe *p, DNStype dnstype,
+                         const char *host,
+                         const char *url, CURLM *multi,
+                         struct curl_slist *headers)
+{
+  struct Curl_easy *doh = NULL;
+  CURLcode result = CURLE_OK;
+  timediff_t timeout_ms;
+  DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer),
+                         &p->dohlen);
+  if(d) {
+    failf(data, "Failed to encode DoH packet [%d]", d);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  p->dnstype = dnstype;
+  Curl_dyn_init(&p->serverdoh, DYN_DOH_RESPONSE);
+
+  timeout_ms = Curl_timeleft(data, NULL, TRUE);
+  if(timeout_ms <= 0) {
+    result = CURLE_OPERATION_TIMEDOUT;
+    goto error;
+  }
+  /* Curl_open() is the internal version of curl_easy_init() */
+  result = Curl_open(&doh);
+  if(!result) {
+    /* pass in the struct pointer via a local variable to please coverity and
+       the gcc typecheck helpers */
+    struct dynbuf *resp = &p->serverdoh;
+    doh->state.internal = true;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+    doh->state.feat = &Curl_doh_trc;
+#endif
+    ERROR_CHECK_SETOPT(CURLOPT_URL, url);
+    ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https");
+    ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
+    ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp);
+    ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
+    ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
+    ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
+#ifdef USE_HTTP2
+    ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
+    ERROR_CHECK_SETOPT(CURLOPT_PIPEWAIT, 1L);
+#endif
+#ifndef CURLDEBUG
+    /* enforce HTTPS if not debug */
+    ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
+#else
+    /* in debug mode, also allow http */
+    ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
+#endif
+    ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
+    ERROR_CHECK_SETOPT(CURLOPT_SHARE, data->share);
+    if(data->set.err && data->set.err != stderr)
+      ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err);
+    if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc))
+      ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
+    if(data->set.no_signal)
+      ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
+
+    ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST,
+      data->set.doh_verifyhost ? 2L : 0L);
+    ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER,
+      data->set.doh_verifypeer ? 1L : 0L);
+    ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS,
+      data->set.doh_verifystatus ? 1L : 0L);
+
+    /* Inherit *some* SSL options from the user's transfer. This is a
+       best-guess as to which options are needed for compatibility. #3661
+
+       Note DoH does not inherit the user's proxy server so proxy SSL settings
+       have no effect and are not inherited. If that changes then two new
+       options should be added to check doh proxy insecure separately,
+       CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER.
+       */
+    if(data->set.ssl.falsestart)
+      ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
+    if(data->set.str[STRING_SSL_CAFILE]) {
+      ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
+                         data->set.str[STRING_SSL_CAFILE]);
+    }
+    if(data->set.blobs[BLOB_CAINFO]) {
+      ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB,
+                         data->set.blobs[BLOB_CAINFO]);
+    }
+    if(data->set.str[STRING_SSL_CAPATH]) {
+      ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
+                         data->set.str[STRING_SSL_CAPATH]);
+    }
+    if(data->set.str[STRING_SSL_CRLFILE]) {
+      ERROR_CHECK_SETOPT(CURLOPT_CRLFILE,
+                         data->set.str[STRING_SSL_CRLFILE]);
+    }
+    if(data->set.ssl.certinfo)
+      ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L);
+    if(data->set.ssl.fsslctx)
+      ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
+    if(data->set.ssl.fsslctxp)
+      ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp);
+    if(data->set.fdebug)
+      ERROR_CHECK_SETOPT(CURLOPT_DEBUGFUNCTION, data->set.fdebug);
+    if(data->set.debugdata)
+      ERROR_CHECK_SETOPT(CURLOPT_DEBUGDATA, data->set.debugdata);
+    if(data->set.str[STRING_SSL_EC_CURVES]) {
+      ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES,
+                         data->set.str[STRING_SSL_EC_CURVES]);
+    }
+
+    {
+      long mask =
+        (data->set.ssl.enable_beast ?
+         CURLSSLOPT_ALLOW_BEAST : 0) |
+        (data->set.ssl.no_revoke ?
+         CURLSSLOPT_NO_REVOKE : 0) |
+        (data->set.ssl.no_partialchain ?
+         CURLSSLOPT_NO_PARTIALCHAIN : 0) |
+        (data->set.ssl.revoke_best_effort ?
+         CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
+        (data->set.ssl.native_ca_store ?
+         CURLSSLOPT_NATIVE_CA : 0) |
+        (data->set.ssl.auto_client_cert ?
+         CURLSSLOPT_AUTO_CLIENT_CERT : 0);
+
+      (void)curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask);
+    }
+
+    doh->set.fmultidone = doh_done;
+    doh->set.dohfor = data; /* identify for which transfer this is done */
+    p->easy = doh;
+
+    /* DoH handles must not inherit private_data. The handles may be passed to
+       the user via callbacks and the user will be able to identify them as
+       internal handles because private data is not set. The user can then set
+       private_data via CURLOPT_PRIVATE if they so choose. */
+    DEBUGASSERT(!doh->set.private_data);
+
+    if(curl_multi_add_handle(multi, doh))
+      goto error;
+  }
+  else
+    goto error;
+  return CURLE_OK;
+
+error:
+  Curl_close(&doh);
+  return result;
+}
+
+/*
+ * Curl_doh() resolves a name using DoH. It resolves a name and returns a
+ * 'Curl_addrinfo *' with the address information.
+ */
+
+struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
+                               const char *hostname,
+                               int port,
+                               int *waitp)
+{
+  CURLcode result = CURLE_OK;
+  int slot;
+  struct dohdata *dohp;
+  struct connectdata *conn = data->conn;
+  *waitp = FALSE;
+  (void)hostname;
+  (void)port;
+
+  DEBUGASSERT(!data->req.doh);
+  DEBUGASSERT(conn);
+
+  /* start clean, consider allocating this struct on demand */
+  dohp = data->req.doh = calloc(1, sizeof(struct dohdata));
+  if(!dohp)
+    return NULL;
+
+  conn->bits.doh = TRUE;
+  dohp->host = hostname;
+  dohp->port = port;
+  dohp->headers =
+    curl_slist_append(NULL,
+                      "Content-Type: application/dns-message");
+  if(!dohp->headers)
+    goto error;
+
+  /* create IPv4 DoH request */
+  result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
+                    DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
+                    data->multi, dohp->headers);
+  if(result)
+    goto error;
+  dohp->pending++;
+
+#ifdef ENABLE_IPV6
+  if((conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
+    /* create IPv6 DoH request */
+    result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
+                      DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
+                      data->multi, dohp->headers);
+    if(result)
+      goto error;
+    dohp->pending++;
+  }
+#endif
+  *waitp = TRUE; /* this never returns synchronously */
+  return NULL;
+
+error:
+  curl_slist_free_all(dohp->headers);
+  data->req.doh->headers = NULL;
+  for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
+    (void)curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
+    Curl_close(&dohp->probe[slot].easy);
+  }
+  Curl_safefree(data->req.doh);
+  return NULL;
+}
+
+static DOHcode skipqname(const unsigned char *doh, size_t dohlen,
+                         unsigned int *indexp)
+{
+  unsigned char length;
+  do {
+    if(dohlen < (*indexp + 1))
+      return DOH_DNS_OUT_OF_RANGE;
+    length = doh[*indexp];
+    if((length & 0xc0) == 0xc0) {
+      /* name pointer, advance over it and be done */
+      if(dohlen < (*indexp + 2))
+        return DOH_DNS_OUT_OF_RANGE;
+      *indexp += 2;
+      break;
+    }
+    if(length & 0xc0)
+      return DOH_DNS_BAD_LABEL;
+    if(dohlen < (*indexp + 1 + length))
+      return DOH_DNS_OUT_OF_RANGE;
+    *indexp += (unsigned int)(1 + length);
+  } while(length);
+  return DOH_OK;
+}
+
+static unsigned short get16bit(const unsigned char *doh, int index)
+{
+  return (unsigned short)((doh[index] << 8) | doh[index + 1]);
+}
+
+static unsigned int get32bit(const unsigned char *doh, int index)
+{
+  /* make clang and gcc optimize this to bswap by incrementing
+     the pointer first. */
+  doh += index;
+
+  /* avoid undefined behavior by casting to unsigned before shifting
+     24 bits, possibly into the sign bit. codegen is same, but
+     ub sanitizer won't be upset */
+  return ((unsigned)doh[0] << 24) | ((unsigned)doh[1] << 16) |
+         ((unsigned)doh[2] << 8) | doh[3];
+}
+
+static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d)
+{
+  /* silently ignore addresses over the limit */
+  if(d->numaddr < DOH_MAX_ADDR) {
+    struct dohaddr *a = &d->addr[d->numaddr];
+    a->type = DNS_TYPE_A;
+    memcpy(&a->ip.v4, &doh[index], 4);
+    d->numaddr++;
+  }
+  return DOH_OK;
+}
+
+static DOHcode store_aaaa(const unsigned char *doh,
+                          int index,
+                          struct dohentry *d)
+{
+  /* silently ignore addresses over the limit */
+  if(d->numaddr < DOH_MAX_ADDR) {
+    struct dohaddr *a = &d->addr[d->numaddr];
+    a->type = DNS_TYPE_AAAA;
+    memcpy(&a->ip.v6, &doh[index], 16);
+    d->numaddr++;
+  }
+  return DOH_OK;
+}
+
+static DOHcode store_cname(const unsigned char *doh,
+                           size_t dohlen,
+                           unsigned int index,
+                           struct dohentry *d)
+{
+  struct dynbuf *c;
+  unsigned int loop = 128; /* a valid DNS name can never loop this much */
+  unsigned char length;
+
+  if(d->numcname == DOH_MAX_CNAME)
+    return DOH_OK; /* skip! */
+
+  c = &d->cname[d->numcname++];
+  do {
+    if(index >= dohlen)
+      return DOH_DNS_OUT_OF_RANGE;
+    length = doh[index];
+    if((length & 0xc0) == 0xc0) {
+      int newpos;
+      /* name pointer, get the new offset (14 bits) */
+      if((index + 1) >= dohlen)
+        return DOH_DNS_OUT_OF_RANGE;
+
+      /* move to the new index */
+      newpos = (length & 0x3f) << 8 | doh[index + 1];
+      index = newpos;
+      continue;
+    }
+    else if(length & 0xc0)
+      return DOH_DNS_BAD_LABEL; /* bad input */
+    else
+      index++;
+
+    if(length) {
+      if(Curl_dyn_len(c)) {
+        if(Curl_dyn_addn(c, STRCONST(".")))
+          return DOH_OUT_OF_MEM;
+      }
+      if((index + length) > dohlen)
+        return DOH_DNS_BAD_LABEL;
+
+      if(Curl_dyn_addn(c, &doh[index], length))
+        return DOH_OUT_OF_MEM;
+      index += length;
+    }
+  } while(length && --loop);
+
+  if(!loop)
+    return DOH_DNS_LABEL_LOOP;
+  return DOH_OK;
+}
+
+static DOHcode rdata(const unsigned char *doh,
+                     size_t dohlen,
+                     unsigned short rdlength,
+                     unsigned short type,
+                     int index,
+                     struct dohentry *d)
+{
+  /* RDATA
+     - A (TYPE 1):  4 bytes
+     - AAAA (TYPE 28): 16 bytes
+     - NS (TYPE 2): N bytes */
+  DOHcode rc;
+
+  switch(type) {
+  case DNS_TYPE_A:
+    if(rdlength != 4)
+      return DOH_DNS_RDATA_LEN;
+    rc = store_a(doh, index, d);
+    if(rc)
+      return rc;
+    break;
+  case DNS_TYPE_AAAA:
+    if(rdlength != 16)
+      return DOH_DNS_RDATA_LEN;
+    rc = store_aaaa(doh, index, d);
+    if(rc)
+      return rc;
+    break;
+  case DNS_TYPE_CNAME:
+    rc = store_cname(doh, dohlen, index, d);
+    if(rc)
+      return rc;
+    break;
+  case DNS_TYPE_DNAME:
+    /* explicit for clarity; just skip; rely on synthesized CNAME  */
+    break;
+  default:
+    /* unsupported type, just skip it */
+    break;
+  }
+  return DOH_OK;
+}
+
+UNITTEST void de_init(struct dohentry *de)
+{
+  int i;
+  memset(de, 0, sizeof(*de));
+  de->ttl = INT_MAX;
+  for(i = 0; i < DOH_MAX_CNAME; i++)
+    Curl_dyn_init(&de->cname[i], DYN_DOH_CNAME);
+}
+
+
+UNITTEST DOHcode doh_decode(const unsigned char *doh,
+                            size_t dohlen,
+                            DNStype dnstype,
+                            struct dohentry *d)
+{
+  unsigned char rcode;
+  unsigned short qdcount;
+  unsigned short ancount;
+  unsigned short type = 0;
+  unsigned short rdlength;
+  unsigned short nscount;
+  unsigned short arcount;
+  unsigned int index = 12;
+  DOHcode rc;
+
+  if(dohlen < 12)
+    return DOH_TOO_SMALL_BUFFER; /* too small */
+  if(!doh || doh[0] || doh[1])
+    return DOH_DNS_BAD_ID; /* bad ID */
+  rcode = doh[3] & 0x0f;
+  if(rcode)
+    return DOH_DNS_BAD_RCODE; /* bad rcode */
+
+  qdcount = get16bit(doh, 4);
+  while(qdcount) {
+    rc = skipqname(doh, dohlen, &index);
+    if(rc)
+      return rc; /* bad qname */
+    if(dohlen < (index + 4))
+      return DOH_DNS_OUT_OF_RANGE;
+    index += 4; /* skip question's type and class */
+    qdcount--;
+  }
+
+  ancount = get16bit(doh, 6);
+  while(ancount) {
+    unsigned short class;
+    unsigned int ttl;
+
+    rc = skipqname(doh, dohlen, &index);
+    if(rc)
+      return rc; /* bad qname */
+
+    if(dohlen < (index + 2))
+      return DOH_DNS_OUT_OF_RANGE;
+
+    type = get16bit(doh, index);
+    if((type != DNS_TYPE_CNAME)    /* may be synthesized from DNAME */
+       && (type != DNS_TYPE_DNAME) /* if present, accept and ignore */
+       && (type != dnstype))
+      /* Not the same type as was asked for nor CNAME nor DNAME */
+      return DOH_DNS_UNEXPECTED_TYPE;
+    index += 2;
+
+    if(dohlen < (index + 2))
+      return DOH_DNS_OUT_OF_RANGE;
+    class = get16bit(doh, index);
+    if(DNS_CLASS_IN != class)
+      return DOH_DNS_UNEXPECTED_CLASS; /* unsupported */
+    index += 2;
+
+    if(dohlen < (index + 4))
+      return DOH_DNS_OUT_OF_RANGE;
+
+    ttl = get32bit(doh, index);
+    if(ttl < d->ttl)
+      d->ttl = ttl;
+    index += 4;
+
+    if(dohlen < (index + 2))
+      return DOH_DNS_OUT_OF_RANGE;
+
+    rdlength = get16bit(doh, index);
+    index += 2;
+    if(dohlen < (index + rdlength))
+      return DOH_DNS_OUT_OF_RANGE;
+
+    rc = rdata(doh, dohlen, rdlength, type, index, d);
+    if(rc)
+      return rc; /* bad rdata */
+    index += rdlength;
+    ancount--;
+  }
+
+  nscount = get16bit(doh, 8);
+  while(nscount) {
+    rc = skipqname(doh, dohlen, &index);
+    if(rc)
+      return rc; /* bad qname */
+
+    if(dohlen < (index + 8))
+      return DOH_DNS_OUT_OF_RANGE;
+
+    index += 2 + 2 + 4; /* type, class and ttl */
+
+    if(dohlen < (index + 2))
+      return DOH_DNS_OUT_OF_RANGE;
+
+    rdlength = get16bit(doh, index);
+    index += 2;
+    if(dohlen < (index + rdlength))
+      return DOH_DNS_OUT_OF_RANGE;
+    index += rdlength;
+    nscount--;
+  }
+
+  arcount = get16bit(doh, 10);
+  while(arcount) {
+    rc = skipqname(doh, dohlen, &index);
+    if(rc)
+      return rc; /* bad qname */
+
+    if(dohlen < (index + 8))
+      return DOH_DNS_OUT_OF_RANGE;
+
+    index += 2 + 2 + 4; /* type, class and ttl */
+
+    if(dohlen < (index + 2))
+      return DOH_DNS_OUT_OF_RANGE;
+
+    rdlength = get16bit(doh, index);
+    index += 2;
+    if(dohlen < (index + rdlength))
+      return DOH_DNS_OUT_OF_RANGE;
+    index += rdlength;
+    arcount--;
+  }
+
+  if(index != dohlen)
+    return DOH_DNS_MALFORMAT; /* something is wrong */
+
+  if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr)
+    /* nothing stored! */
+    return DOH_NO_CONTENT;
+
+  return DOH_OK; /* ok */
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void showdoh(struct Curl_easy *data,
+                    const struct dohentry *d)
+{
+  int i;
+  infof(data, "[DoH] TTL: %u seconds", d->ttl);
+  for(i = 0; i < d->numaddr; i++) {
+    const struct dohaddr *a = &d->addr[i];
+    if(a->type == DNS_TYPE_A) {
+      infof(data, "[DoH] A: %u.%u.%u.%u",
+            a->ip.v4[0], a->ip.v4[1],
+            a->ip.v4[2], a->ip.v4[3]);
+    }
+    else if(a->type == DNS_TYPE_AAAA) {
+      int j;
+      char buffer[128];
+      char *ptr;
+      size_t len;
+      len = msnprintf(buffer, 128, "[DoH] AAAA: ");
+      ptr = &buffer[len];
+      len = sizeof(buffer) - len;
+      for(j = 0; j < 16; j += 2) {
+        size_t l;
+        msnprintf(ptr, len, "%s%02x%02x", j?":":"", d->addr[i].ip.v6[j],
+                  d->addr[i].ip.v6[j + 1]);
+        l = strlen(ptr);
+        len -= l;
+        ptr += l;
+      }
+      infof(data, "%s", buffer);
+    }
+  }
+  for(i = 0; i < d->numcname; i++) {
+    infof(data, "CNAME: %s", Curl_dyn_ptr(&d->cname[i]));
+  }
+}
+#else
+#define showdoh(x,y)
+#endif
+
+/*
+ * doh2ai()
+ *
+ * This function returns a pointer to the first element of a newly allocated
+ * Curl_addrinfo struct linked list filled with the data from a set of DoH
+ * lookups.  Curl_addrinfo is meant to work like the addrinfo struct does for
+ * a IPv6 stack, but usable also for IPv4, all hosts and environments.
+ *
+ * The memory allocated by this function *MUST* be free'd later on calling
+ * Curl_freeaddrinfo().  For each successful call to this function there
+ * must be an associated call later to Curl_freeaddrinfo().
+ */
+
+static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
+                       int port, struct Curl_addrinfo **aip)
+{
+  struct Curl_addrinfo *ai;
+  struct Curl_addrinfo *prevai = NULL;
+  struct Curl_addrinfo *firstai = NULL;
+  struct sockaddr_in *addr;
+#ifdef ENABLE_IPV6
+  struct sockaddr_in6 *addr6;
+#endif
+  CURLcode result = CURLE_OK;
+  int i;
+  size_t hostlen = strlen(hostname) + 1; /* include null-terminator */
+
+  DEBUGASSERT(de);
+
+  if(!de->numaddr)
+    return CURLE_COULDNT_RESOLVE_HOST;
+
+  for(i = 0; i < de->numaddr; i++) {
+    size_t ss_size;
+    CURL_SA_FAMILY_T addrtype;
+    if(de->addr[i].type == DNS_TYPE_AAAA) {
+#ifndef ENABLE_IPV6
+      /* we can't handle IPv6 addresses */
+      continue;
+#else
+      ss_size = sizeof(struct sockaddr_in6);
+      addrtype = AF_INET6;
+#endif
+    }
+    else {
+      ss_size = sizeof(struct sockaddr_in);
+      addrtype = AF_INET;
+    }
+
+    ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen);
+    if(!ai) {
+      result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+    ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
+    ai->ai_canonname = (void *)((char *)ai->ai_addr + ss_size);
+    memcpy(ai->ai_canonname, hostname, hostlen);
+
+    if(!firstai)
+      /* store the pointer we want to return from this function */
+      firstai = ai;
+
+    if(prevai)
+      /* make the previous entry point to this */
+      prevai->ai_next = ai;
+
+    ai->ai_family = addrtype;
+
+    /* we return all names as STREAM, so when using this address for TFTP
+       the type must be ignored and conn->socktype be used instead! */
+    ai->ai_socktype = SOCK_STREAM;
+
+    ai->ai_addrlen = (curl_socklen_t)ss_size;
+
+    /* leave the rest of the struct filled with zero */
+
+    switch(ai->ai_family) {
+    case AF_INET:
+      addr = (void *)ai->ai_addr; /* storage area for this info */
+      DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
+      memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
+      addr->sin_family = addrtype;
+      addr->sin_port = htons((unsigned short)port);
+      break;
+
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+      addr6 = (void *)ai->ai_addr; /* storage area for this info */
+      DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
+      memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
+      addr6->sin6_family = addrtype;
+      addr6->sin6_port = htons((unsigned short)port);
+      break;
+#endif
+    }
+
+    prevai = ai;
+  }
+
+  if(result) {
+    Curl_freeaddrinfo(firstai);
+    firstai = NULL;
+  }
+  *aip = firstai;
+
+  return result;
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static const char *type2name(DNStype dnstype)
+{
+  return (dnstype == DNS_TYPE_A)?"A":"AAAA";
+}
+#endif
+
+UNITTEST void de_cleanup(struct dohentry *d)
+{
+  int i = 0;
+  for(i = 0; i < d->numcname; i++) {
+    Curl_dyn_free(&d->cname[i]);
+  }
+}
+
+CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
+                              struct Curl_dns_entry **dnsp)
+{
+  CURLcode result;
+  struct dohdata *dohp = data->req.doh;
+  *dnsp = NULL; /* defaults to no response */
+  if(!dohp)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
+     !dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
+    failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
+    return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY:
+      CURLE_COULDNT_RESOLVE_HOST;
+  }
+  else if(!dohp->pending) {
+    DOHcode rc[DOH_PROBE_SLOTS] = {
+      DOH_OK, DOH_OK
+    };
+    struct dohentry de;
+    int slot;
+    /* remove DoH handles from multi handle and close them */
+    for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
+      curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
+      Curl_close(&dohp->probe[slot].easy);
+    }
+    /* parse the responses, create the struct and return it! */
+    de_init(&de);
+    for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
+      struct dnsprobe *p = &dohp->probe[slot];
+      if(!p->dnstype)
+        continue;
+      rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh),
+                            Curl_dyn_len(&p->serverdoh),
+                            p->dnstype,
+                            &de);
+      Curl_dyn_free(&p->serverdoh);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+      if(rc[slot]) {
+        infof(data, "DoH: %s type %s for %s", doh_strerror(rc[slot]),
+              type2name(p->dnstype), dohp->host);
+      }
+#endif
+    } /* next slot */
+
+    result = CURLE_COULDNT_RESOLVE_HOST; /* until we know better */
+    if(!rc[DOH_PROBE_SLOT_IPADDR_V4] || !rc[DOH_PROBE_SLOT_IPADDR_V6]) {
+      /* we have an address, of one kind or other */
+      struct Curl_dns_entry *dns;
+      struct Curl_addrinfo *ai;
+
+
+      if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc)) {
+        infof(data, "[DoH] Host name: %s", dohp->host);
+        showdoh(data, &de);
+      }
+
+      result = doh2ai(&de, dohp->host, dohp->port, &ai);
+      if(result) {
+        de_cleanup(&de);
+        return result;
+      }
+
+      if(data->share)
+        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+      /* we got a response, store it in the cache */
+      dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port);
+
+      if(data->share)
+        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+      if(!dns) {
+        /* returned failure, bail out nicely */
+        Curl_freeaddrinfo(ai);
+      }
+      else {
+        data->state.async.dns = dns;
+        *dnsp = dns;
+        result = CURLE_OK;      /* address resolution OK */
+      }
+    } /* address processing done */
+
+    /* Now process any build-specific attributes retrieved from DNS */
+
+    /* All done */
+    de_cleanup(&de);
+    Curl_safefree(data->req.doh);
+    return result;
+
+  } /* !dohp->pending */
+
+  /* else wait for pending DoH transactions to complete */
+  return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_DOH */
Index: trunk/src/libs/curl-8.7.1/lib/doh.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/doh.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/doh.h	(revision 104083)
@@ -0,0 +1,130 @@
+#ifndef HEADER_CURL_DOH_H
+#define HEADER_CURL_DOH_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "urldata.h"
+#include "curl_addrinfo.h"
+
+#ifndef CURL_DISABLE_DOH
+
+typedef enum {
+  DOH_OK,
+  DOH_DNS_BAD_LABEL,    /* 1 */
+  DOH_DNS_OUT_OF_RANGE, /* 2 */
+  DOH_DNS_LABEL_LOOP,   /* 3 */
+  DOH_TOO_SMALL_BUFFER, /* 4 */
+  DOH_OUT_OF_MEM,       /* 5 */
+  DOH_DNS_RDATA_LEN,    /* 6 */
+  DOH_DNS_MALFORMAT,    /* 7 */
+  DOH_DNS_BAD_RCODE,    /* 8 - no such name */
+  DOH_DNS_UNEXPECTED_TYPE,  /* 9 */
+  DOH_DNS_UNEXPECTED_CLASS, /* 10 */
+  DOH_NO_CONTENT,           /* 11 */
+  DOH_DNS_BAD_ID,           /* 12 */
+  DOH_DNS_NAME_TOO_LONG     /* 13 */
+} DOHcode;
+
+typedef enum {
+  DNS_TYPE_A = 1,
+  DNS_TYPE_NS = 2,
+  DNS_TYPE_CNAME = 5,
+  DNS_TYPE_AAAA = 28,
+  DNS_TYPE_DNAME = 39           /* RFC6672 */
+} DNStype;
+
+/* one of these for each DoH request */
+struct dnsprobe {
+  CURL *easy;
+  DNStype dnstype;
+  unsigned char dohbuffer[512];
+  size_t dohlen;
+  struct dynbuf serverdoh;
+};
+
+struct dohdata {
+  struct curl_slist *headers;
+  struct dnsprobe probe[DOH_PROBE_SLOTS];
+  unsigned int pending; /* still outstanding requests */
+  int port;
+  const char *host;
+};
+
+/*
+ * Curl_doh() resolve a name using DoH (DNS-over-HTTPS). It resolves a name
+ * and returns a 'Curl_addrinfo *' with the address information.
+ */
+
+struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
+                               const char *hostname,
+                               int port,
+                               int *waitp);
+
+CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
+                              struct Curl_dns_entry **dns);
+
+int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks);
+
+#define DOH_MAX_ADDR 24
+#define DOH_MAX_CNAME 4
+
+struct dohaddr {
+  int type;
+  union {
+    unsigned char v4[4]; /* network byte order */
+    unsigned char v6[16];
+  } ip;
+};
+
+struct dohentry {
+  struct dynbuf cname[DOH_MAX_CNAME];
+  struct dohaddr addr[DOH_MAX_ADDR];
+  int numaddr;
+  unsigned int ttl;
+  int numcname;
+};
+
+
+#ifdef DEBUGBUILD
+DOHcode doh_encode(const char *host,
+                   DNStype dnstype,
+                   unsigned char *dnsp, /* buffer */
+                   size_t len,  /* buffer size */
+                   size_t *olen); /* output length */
+DOHcode doh_decode(const unsigned char *doh,
+                   size_t dohlen,
+                   DNStype dnstype,
+                   struct dohentry *d);
+void de_init(struct dohentry *d);
+void de_cleanup(struct dohentry *d);
+#endif
+
+extern struct curl_trc_feat Curl_doh_trc;
+
+#else /* if DoH is disabled */
+#define Curl_doh(a,b,c,d) NULL
+#define Curl_doh_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
+#endif
+
+#endif /* HEADER_CURL_DOH_H */
Index: trunk/src/libs/curl-8.7.1/lib/dynbuf.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/dynbuf.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/dynbuf.c	(revision 104083)
@@ -0,0 +1,282 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "dynbuf.h"
+#include "curl_printf.h"
+#ifdef BUILDING_LIBCURL
+#include "curl_memory.h"
+#endif
+#include "memdebug.h"
+
+#define MIN_FIRST_ALLOC 32
+
+#define DYNINIT 0xbee51da /* random pattern */
+
+/*
+ * Init a dynbuf struct.
+ */
+void Curl_dyn_init(struct dynbuf *s, size_t toobig)
+{
+  DEBUGASSERT(s);
+  DEBUGASSERT(toobig);
+  s->bufr = NULL;
+  s->leng = 0;
+  s->allc = 0;
+  s->toobig = toobig;
+#ifdef DEBUGBUILD
+  s->init = DYNINIT;
+#endif
+}
+
+/*
+ * free the buffer and re-init the necessary fields. It doesn't touch the
+ * 'init' field and thus this buffer can be reused to add data to again.
+ */
+void Curl_dyn_free(struct dynbuf *s)
+{
+  DEBUGASSERT(s);
+  Curl_safefree(s->bufr);
+  s->leng = s->allc = 0;
+}
+
+/*
+ * Store/append an chunk of memory to the dynbuf.
+ */
+static CURLcode dyn_nappend(struct dynbuf *s,
+                            const unsigned char *mem, size_t len)
+{
+  size_t indx = s->leng;
+  size_t a = s->allc;
+  size_t fit = len + indx + 1; /* new string + old string + zero byte */
+
+  /* try to detect if there's rubbish in the struct */
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(s->toobig);
+  DEBUGASSERT(indx < s->toobig);
+  DEBUGASSERT(!s->leng || s->bufr);
+  DEBUGASSERT(a <= s->toobig);
+  DEBUGASSERT(!len || mem);
+
+  if(fit > s->toobig) {
+    Curl_dyn_free(s);
+    return CURLE_TOO_LARGE;
+  }
+  else if(!a) {
+    DEBUGASSERT(!indx);
+    /* first invoke */
+    if(MIN_FIRST_ALLOC > s->toobig)
+      a = s->toobig;
+    else if(fit < MIN_FIRST_ALLOC)
+      a = MIN_FIRST_ALLOC;
+    else
+      a = fit;
+  }
+  else {
+    while(a < fit)
+      a *= 2;
+    if(a > s->toobig)
+      /* no point in allocating a larger buffer than this is allowed to use */
+      a = s->toobig;
+  }
+
+  if(a != s->allc) {
+    /* this logic is not using Curl_saferealloc() to make the tool not have to
+       include that as well when it uses this code */
+    void *p = realloc(s->bufr, a);
+    if(!p) {
+      Curl_dyn_free(s);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    s->bufr = p;
+    s->allc = a;
+  }
+
+  if(len)
+    memcpy(&s->bufr[indx], mem, len);
+  s->leng = indx + len;
+  s->bufr[s->leng] = 0;
+  return CURLE_OK;
+}
+
+/*
+ * Clears the string, keeps the allocation. This can also be called on a
+ * buffer that already was freed.
+ */
+void Curl_dyn_reset(struct dynbuf *s)
+{
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(!s->leng || s->bufr);
+  if(s->leng)
+    s->bufr[0] = 0;
+  s->leng = 0;
+}
+
+/*
+ * Specify the size of the tail to keep (number of bytes from the end of the
+ * buffer). The rest will be dropped.
+ */
+CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail)
+{
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(!s->leng || s->bufr);
+  if(trail > s->leng)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  else if(trail == s->leng)
+    return CURLE_OK;
+  else if(!trail) {
+    Curl_dyn_reset(s);
+  }
+  else {
+    memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail);
+    s->leng = trail;
+    s->bufr[s->leng] = 0;
+  }
+  return CURLE_OK;
+
+}
+
+/*
+ * Appends a buffer with length.
+ */
+CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
+{
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(!s->leng || s->bufr);
+  return dyn_nappend(s, mem, len);
+}
+
+/*
+ * Append a null-terminated string at the end.
+ */
+CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
+{
+  size_t n;
+  DEBUGASSERT(str);
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(!s->leng || s->bufr);
+  n = strlen(str);
+  return dyn_nappend(s, (unsigned char *)str, n);
+}
+
+/*
+ * Append a string vprintf()-style
+ */
+CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
+{
+#ifdef BUILDING_LIBCURL
+  int rc;
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(!s->leng || s->bufr);
+  DEBUGASSERT(fmt);
+  rc = Curl_dyn_vprintf(s, fmt, ap);
+
+  if(!rc)
+    return CURLE_OK;
+  else if(rc == MERR_TOO_LARGE)
+    return CURLE_TOO_LARGE;
+  return CURLE_OUT_OF_MEMORY;
+#else
+  char *str;
+  str = vaprintf(fmt, ap); /* this allocs a new string to append */
+
+  if(str) {
+    CURLcode result = dyn_nappend(s, (unsigned char *)str, strlen(str));
+    free(str);
+    return result;
+  }
+  /* If we failed, we cleanup the whole buffer and return error */
+  Curl_dyn_free(s);
+  return CURLE_OK;
+#endif
+}
+
+/*
+ * Append a string printf()-style
+ */
+CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
+{
+  CURLcode result;
+  va_list ap;
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(!s->leng || s->bufr);
+  va_start(ap, fmt);
+  result = Curl_dyn_vaddf(s, fmt, ap);
+  va_end(ap);
+  return result;
+}
+
+/*
+ * Returns a pointer to the buffer.
+ */
+char *Curl_dyn_ptr(const struct dynbuf *s)
+{
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(!s->leng || s->bufr);
+  return s->bufr;
+}
+
+/*
+ * Returns an unsigned pointer to the buffer.
+ */
+unsigned char *Curl_dyn_uptr(const struct dynbuf *s)
+{
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(!s->leng || s->bufr);
+  return (unsigned char *)s->bufr;
+}
+
+/*
+ * Returns the length of the buffer.
+ */
+size_t Curl_dyn_len(const struct dynbuf *s)
+{
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(!s->leng || s->bufr);
+  return s->leng;
+}
+
+/*
+ * Set a new (smaller) length.
+ */
+CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set)
+{
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(!s->leng || s->bufr);
+  if(set > s->leng)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  s->leng = set;
+  s->bufr[s->leng] = 0;
+  return CURLE_OK;
+}
Index: trunk/src/libs/curl-8.7.1/lib/dynbuf.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/dynbuf.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/dynbuf.h	(revision 104083)
@@ -0,0 +1,93 @@
+#ifndef HEADER_CURL_DYNBUF_H
+#define HEADER_CURL_DYNBUF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+#ifndef BUILDING_LIBCURL
+/* this renames the functions so that the tool code can use the same code
+   without getting symbol collisions */
+#define Curl_dyn_init(a,b) curlx_dyn_init(a,b)
+#define Curl_dyn_add(a,b) curlx_dyn_add(a,b)
+#define Curl_dyn_addn(a,b,c) curlx_dyn_addn(a,b,c)
+#define Curl_dyn_addf curlx_dyn_addf
+#define Curl_dyn_vaddf curlx_dyn_vaddf
+#define Curl_dyn_free(a) curlx_dyn_free(a)
+#define Curl_dyn_ptr(a) curlx_dyn_ptr(a)
+#define Curl_dyn_uptr(a) curlx_dyn_uptr(a)
+#define Curl_dyn_len(a) curlx_dyn_len(a)
+#define Curl_dyn_reset(a) curlx_dyn_reset(a)
+#define Curl_dyn_tail(a,b) curlx_dyn_tail(a,b)
+#define Curl_dyn_setlen(a,b) curlx_dyn_setlen(a,b)
+#define curlx_dynbuf dynbuf /* for the struct name */
+#endif
+
+struct dynbuf {
+  char *bufr;    /* point to a null-terminated allocated buffer */
+  size_t leng;   /* number of bytes *EXCLUDING* the null-terminator */
+  size_t allc;   /* size of the current allocation */
+  size_t toobig; /* size limit for the buffer */
+#ifdef DEBUGBUILD
+  int init;     /* detect API usage mistakes */
+#endif
+};
+
+void Curl_dyn_init(struct dynbuf *s, size_t toobig);
+void Curl_dyn_free(struct dynbuf *s);
+CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
+  WARN_UNUSED_RESULT;
+CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
+  WARN_UNUSED_RESULT;
+CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
+  WARN_UNUSED_RESULT CURL_PRINTF(2, 3);
+CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
+  WARN_UNUSED_RESULT CURL_PRINTF(2, 0);
+void Curl_dyn_reset(struct dynbuf *s);
+CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail);
+CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set);
+char *Curl_dyn_ptr(const struct dynbuf *s);
+unsigned char *Curl_dyn_uptr(const struct dynbuf *s);
+size_t Curl_dyn_len(const struct dynbuf *s);
+
+/* returns 0 on success, -1 on error */
+/* The implementation of this function exists in mprintf.c */
+int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save);
+
+/* Dynamic buffer max sizes */
+#define DYN_DOH_RESPONSE    3000
+#define DYN_DOH_CNAME       256
+#define DYN_PAUSE_BUFFER    (64 * 1024 * 1024)
+#define DYN_HAXPROXY        2048
+#define DYN_HTTP_REQUEST    (1024*1024)
+#define DYN_APRINTF         8000000
+#define DYN_RTSP_REQ_HEADER (64*1024)
+#define DYN_TRAILERS        (64*1024)
+#define DYN_PROXY_CONNECT_HEADERS 16384
+#define DYN_QLOG_NAME       1024
+#define DYN_H1_TRAILER      4096
+#define DYN_PINGPPONG_CMD   (64*1024)
+#define DYN_IMAP_CMD        (64*1024)
+#define DYN_MQTT_RECV       (64*1024)
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/dynhds.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/dynhds.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/dynhds.c	(revision 104083)
@@ -0,0 +1,396 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "dynhds.h"
+#include "strcase.h"
+
+/* The last 3 #include files should be in this order */
+#ifdef USE_NGHTTP2
+#include <stdint.h>
+#include <nghttp2/nghttp2.h>
+#endif /* USE_NGHTTP2 */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+static struct dynhds_entry *
+entry_new(const char *name, size_t namelen,
+          const char *value, size_t valuelen, int opts)
+{
+  struct dynhds_entry *e;
+  char *p;
+
+  DEBUGASSERT(name);
+  DEBUGASSERT(value);
+  e = calloc(1, sizeof(*e) + namelen + valuelen + 2);
+  if(!e)
+    return NULL;
+  e->name = p = ((char *)e) + sizeof(*e);
+  memcpy(p, name, namelen);
+  e->namelen = namelen;
+  e->value = p += namelen + 1; /* leave a \0 at the end of name */
+  memcpy(p, value, valuelen);
+  e->valuelen = valuelen;
+  if(opts & DYNHDS_OPT_LOWERCASE)
+    Curl_strntolower(e->name, e->name, e->namelen);
+  return e;
+}
+
+static struct dynhds_entry *
+entry_append(struct dynhds_entry *e,
+             const char *value, size_t valuelen)
+{
+  struct dynhds_entry *e2;
+  size_t valuelen2 = e->valuelen + 1 + valuelen;
+  char *p;
+
+  DEBUGASSERT(value);
+  e2 = calloc(1, sizeof(*e) + e->namelen + valuelen2 + 2);
+  if(!e2)
+    return NULL;
+  e2->name = p = ((char *)e2) + sizeof(*e2);
+  memcpy(p, e->name, e->namelen);
+  e2->namelen = e->namelen;
+  e2->value = p += e->namelen + 1; /* leave a \0 at the end of name */
+  memcpy(p, e->value, e->valuelen);
+  p += e->valuelen;
+  p[0] = ' ';
+  memcpy(p + 1, value, valuelen);
+  e2->valuelen = valuelen2;
+  return e2;
+}
+
+static void entry_free(struct dynhds_entry *e)
+{
+  free(e);
+}
+
+void Curl_dynhds_init(struct dynhds *dynhds, size_t max_entries,
+                      size_t max_strs_size)
+{
+  DEBUGASSERT(dynhds);
+  DEBUGASSERT(max_strs_size);
+  dynhds->hds = NULL;
+  dynhds->hds_len = dynhds->hds_allc = dynhds->strs_len = 0;
+  dynhds->max_entries = max_entries;
+  dynhds->max_strs_size = max_strs_size;
+  dynhds->opts = 0;
+}
+
+void Curl_dynhds_free(struct dynhds *dynhds)
+{
+  DEBUGASSERT(dynhds);
+  if(dynhds->hds && dynhds->hds_len) {
+    size_t i;
+    DEBUGASSERT(dynhds->hds);
+    for(i = 0; i < dynhds->hds_len; ++i) {
+      entry_free(dynhds->hds[i]);
+    }
+  }
+  Curl_safefree(dynhds->hds);
+  dynhds->hds_len = dynhds->hds_allc = dynhds->strs_len = 0;
+}
+
+void Curl_dynhds_reset(struct dynhds *dynhds)
+{
+  DEBUGASSERT(dynhds);
+  if(dynhds->hds_len) {
+    size_t i;
+    DEBUGASSERT(dynhds->hds);
+    for(i = 0; i < dynhds->hds_len; ++i) {
+      entry_free(dynhds->hds[i]);
+      dynhds->hds[i] = NULL;
+    }
+  }
+  dynhds->hds_len = dynhds->strs_len = 0;
+}
+
+size_t Curl_dynhds_count(struct dynhds *dynhds)
+{
+  return dynhds->hds_len;
+}
+
+void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts)
+{
+  dynhds->opts = opts;
+}
+
+struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n)
+{
+  DEBUGASSERT(dynhds);
+  return (n < dynhds->hds_len)? dynhds->hds[n] : NULL;
+}
+
+struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds, const char *name,
+                                     size_t namelen)
+{
+  size_t i;
+  for(i = 0; i < dynhds->hds_len; ++i) {
+    if(dynhds->hds[i]->namelen == namelen &&
+       strncasecompare(dynhds->hds[i]->name, name, namelen)) {
+      return dynhds->hds[i];
+    }
+  }
+  return NULL;
+}
+
+struct dynhds_entry *Curl_dynhds_cget(struct dynhds *dynhds, const char *name)
+{
+  return Curl_dynhds_get(dynhds, name, strlen(name));
+}
+
+CURLcode Curl_dynhds_add(struct dynhds *dynhds,
+                         const char *name, size_t namelen,
+                         const char *value, size_t valuelen)
+{
+  struct dynhds_entry *entry = NULL;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+
+  DEBUGASSERT(dynhds);
+  if(dynhds->max_entries && dynhds->hds_len >= dynhds->max_entries)
+    return CURLE_OUT_OF_MEMORY;
+  if(dynhds->strs_len + namelen + valuelen > dynhds->max_strs_size)
+    return CURLE_OUT_OF_MEMORY;
+
+entry = entry_new(name, namelen, value, valuelen, dynhds->opts);
+  if(!entry)
+    goto out;
+
+  if(dynhds->hds_len + 1 >= dynhds->hds_allc) {
+    size_t nallc = dynhds->hds_len + 16;
+    struct dynhds_entry **nhds;
+
+    if(dynhds->max_entries && nallc > dynhds->max_entries)
+      nallc = dynhds->max_entries;
+
+    nhds = calloc(nallc, sizeof(struct dynhds_entry *));
+    if(!nhds)
+      goto out;
+    if(dynhds->hds) {
+      memcpy(nhds, dynhds->hds,
+             dynhds->hds_len * sizeof(struct dynhds_entry *));
+      Curl_safefree(dynhds->hds);
+    }
+    dynhds->hds = nhds;
+    dynhds->hds_allc = nallc;
+  }
+  dynhds->hds[dynhds->hds_len++] = entry;
+  entry = NULL;
+  dynhds->strs_len += namelen + valuelen;
+  result = CURLE_OK;
+
+out:
+  if(entry)
+    entry_free(entry);
+  return result;
+}
+
+CURLcode Curl_dynhds_cadd(struct dynhds *dynhds,
+                          const char *name, const char *value)
+{
+  return Curl_dynhds_add(dynhds, name, strlen(name), value, strlen(value));
+}
+
+CURLcode Curl_dynhds_h1_add_line(struct dynhds *dynhds,
+                                 const char *line, size_t line_len)
+{
+  const char *p;
+  const char *name;
+  size_t namelen;
+  const char *value;
+  size_t valuelen, i;
+
+  if(!line || !line_len)
+    return CURLE_OK;
+
+  if((line[0] == ' ') || (line[0] == '\t')) {
+    struct dynhds_entry *e, *e2;
+    /* header continuation, yikes! */
+    if(!dynhds->hds_len)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+
+    while(line_len && ISBLANK(line[0])) {
+      ++line;
+      --line_len;
+    }
+    if(!line_len)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    e = dynhds->hds[dynhds->hds_len-1];
+    e2 = entry_append(e, line, line_len);
+    if(!e2)
+      return CURLE_OUT_OF_MEMORY;
+    dynhds->hds[dynhds->hds_len-1] = e2;
+    entry_free(e);
+    return CURLE_OK;
+  }
+  else {
+    p = memchr(line, ':', line_len);
+    if(!p)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    name = line;
+    namelen = p - line;
+    p++; /* move past the colon */
+    for(i = namelen + 1; i < line_len; ++i, ++p) {
+      if(!ISBLANK(*p))
+        break;
+    }
+    value = p;
+    valuelen = line_len - i;
+
+    p = memchr(value, '\r', valuelen);
+    if(!p)
+      p = memchr(value, '\n', valuelen);
+    if(p)
+      valuelen = (size_t)(p - value);
+
+    return Curl_dynhds_add(dynhds, name, namelen, value, valuelen);
+  }
+}
+
+CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line)
+{
+  return Curl_dynhds_h1_add_line(dynhds, line, line? strlen(line) : 0);
+}
+
+#ifdef DEBUGBUILD
+/* used by unit2602.c */
+
+bool Curl_dynhds_contains(struct dynhds *dynhds,
+                          const char *name, size_t namelen)
+{
+  return !!Curl_dynhds_get(dynhds, name, namelen);
+}
+
+bool Curl_dynhds_ccontains(struct dynhds *dynhds, const char *name)
+{
+  return Curl_dynhds_contains(dynhds, name, strlen(name));
+}
+
+size_t Curl_dynhds_count_name(struct dynhds *dynhds,
+                              const char *name, size_t namelen)
+{
+  size_t n = 0;
+  if(dynhds->hds_len) {
+    size_t i;
+    for(i = 0; i < dynhds->hds_len; ++i) {
+      if((namelen == dynhds->hds[i]->namelen) &&
+         strncasecompare(name, dynhds->hds[i]->name, namelen))
+        ++n;
+    }
+  }
+  return n;
+}
+
+size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name)
+{
+  return Curl_dynhds_count_name(dynhds, name, strlen(name));
+}
+
+CURLcode Curl_dynhds_set(struct dynhds *dynhds,
+                         const char *name, size_t namelen,
+                         const char *value, size_t valuelen)
+{
+  Curl_dynhds_remove(dynhds, name, namelen);
+  return Curl_dynhds_add(dynhds, name, namelen, value, valuelen);
+}
+
+size_t Curl_dynhds_remove(struct dynhds *dynhds,
+                          const char *name, size_t namelen)
+{
+  size_t n = 0;
+  if(dynhds->hds_len) {
+    size_t i, len;
+    for(i = 0; i < dynhds->hds_len; ++i) {
+      if((namelen == dynhds->hds[i]->namelen) &&
+         strncasecompare(name, dynhds->hds[i]->name, namelen)) {
+        ++n;
+        --dynhds->hds_len;
+        dynhds->strs_len -= (dynhds->hds[i]->namelen +
+                             dynhds->hds[i]->valuelen);
+        entry_free(dynhds->hds[i]);
+        len = dynhds->hds_len - i; /* remaining entries */
+        if(len) {
+          memmove(&dynhds->hds[i], &dynhds->hds[i + 1],
+                  len * sizeof(dynhds->hds[i]));
+        }
+        --i; /* do this index again */
+      }
+    }
+  }
+  return n;
+}
+
+size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name)
+{
+  return Curl_dynhds_remove(dynhds, name, strlen(name));
+}
+
+#endif
+
+CURLcode Curl_dynhds_h1_dprint(struct dynhds *dynhds, struct dynbuf *dbuf)
+{
+  CURLcode result = CURLE_OK;
+  size_t i;
+
+  if(!dynhds->hds_len)
+    return result;
+
+  for(i = 0; i < dynhds->hds_len; ++i) {
+    result = Curl_dyn_addf(dbuf, "%.*s: %.*s\r\n",
+               (int)dynhds->hds[i]->namelen, dynhds->hds[i]->name,
+               (int)dynhds->hds[i]->valuelen, dynhds->hds[i]->value);
+    if(result)
+      break;
+  }
+
+  return result;
+}
+
+#ifdef USE_NGHTTP2
+
+nghttp2_nv *Curl_dynhds_to_nva(struct dynhds *dynhds, size_t *pcount)
+{
+  nghttp2_nv *nva = calloc(1, sizeof(nghttp2_nv) * dynhds->hds_len);
+  size_t i;
+
+  *pcount = 0;
+  if(!nva)
+    return NULL;
+
+  for(i = 0; i < dynhds->hds_len; ++i) {
+    struct dynhds_entry *e = dynhds->hds[i];
+    DEBUGASSERT(e);
+    nva[i].name = (unsigned char *)e->name;
+    nva[i].namelen = e->namelen;
+    nva[i].value = (unsigned char *)e->value;
+    nva[i].valuelen = e->valuelen;
+    nva[i].flags = NGHTTP2_NV_FLAG_NONE;
+  }
+  *pcount = dynhds->hds_len;
+  return nva;
+}
+
+#endif /* USE_NGHTTP2 */
Index: trunk/src/libs/curl-8.7.1/lib/dynhds.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/dynhds.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/dynhds.h	(revision 104083)
@@ -0,0 +1,183 @@
+#ifndef HEADER_CURL_DYNHDS_H
+#define HEADER_CURL_DYNHDS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "dynbuf.h"
+
+struct dynbuf;
+
+/**
+ * A single header entry.
+ * `name` and `value` are non-NULL and always NUL terminated.
+ */
+struct dynhds_entry {
+  char *name;
+  char *value;
+  size_t namelen;
+  size_t valuelen;
+};
+
+struct dynhds {
+  struct dynhds_entry **hds;
+  size_t hds_len;   /* number of entries in hds */
+  size_t hds_allc;  /* size of hds allocation */
+  size_t max_entries;   /* size limit number of entries */
+  size_t strs_len; /* length of all strings */
+  size_t max_strs_size; /* max length of all strings */
+  int opts;
+};
+
+#define DYNHDS_OPT_NONE          (0)
+#define DYNHDS_OPT_LOWERCASE     (1 << 0)
+
+/**
+ * Init for use on first time or after a reset.
+ * Allow `max_entries` headers to be added, 0 for unlimited.
+ * Allow size of all name and values added to not exceed `max_strs_size``
+ */
+void Curl_dynhds_init(struct dynhds *dynhds, size_t max_entries,
+                      size_t max_strs_size);
+/**
+ * Frees all data held in `dynhds`, but not the struct itself.
+ */
+void Curl_dynhds_free(struct dynhds *dynhds);
+
+/**
+ * Reset `dyndns` to the initial init state. May keep allocations
+ * around.
+ */
+void Curl_dynhds_reset(struct dynhds *dynhds);
+
+/**
+ * Return the number of header entries.
+ */
+size_t Curl_dynhds_count(struct dynhds *dynhds);
+
+/**
+ * Set the options to use, replacing any existing ones.
+ * This will not have an effect on already existing headers.
+ */
+void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts);
+
+/**
+ * Return the n-th header entry or NULL if it does not exist.
+ */
+struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n);
+
+/**
+ * Return the 1st header entry of the name or NULL if none exists.
+ */
+struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds,
+                                     const char *name, size_t namelen);
+struct dynhds_entry *Curl_dynhds_cget(struct dynhds *dynhds, const char *name);
+
+/**
+ * Return TRUE iff one or more headers with the given name exist.
+ */
+bool Curl_dynhds_contains(struct dynhds *dynhds,
+                          const char *name, size_t namelen);
+bool Curl_dynhds_ccontains(struct dynhds *dynhds, const char *name);
+
+/**
+ * Return how often the given name appears in `dynhds`.
+ * Names are case-insensitive.
+ */
+size_t Curl_dynhds_count_name(struct dynhds *dynhds,
+                              const char *name, size_t namelen);
+
+/**
+ * Return how often the given 0-terminated name appears in `dynhds`.
+ * Names are case-insensitive.
+ */
+size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name);
+
+/**
+ * Add a header, name + value, to `dynhds` at the end. Does *not*
+ * check for duplicate names.
+ */
+CURLcode Curl_dynhds_add(struct dynhds *dynhds,
+                         const char *name, size_t namelen,
+                         const char *value, size_t valuelen);
+
+/**
+ * Add a header, c-string name + value, to `dynhds` at the end.
+ */
+CURLcode Curl_dynhds_cadd(struct dynhds *dynhds,
+                          const char *name, const char *value);
+
+/**
+ * Remove all entries with the given name.
+ * Returns number of entries removed.
+ */
+size_t Curl_dynhds_remove(struct dynhds *dynhds,
+                          const char *name, size_t namelen);
+size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name);
+
+
+/**
+ * Set the give header name and value, replacing any entries with
+ * the same name. The header is added at the end of all (remaining)
+ * entries.
+ */
+CURLcode Curl_dynhds_set(struct dynhds *dynhds,
+                         const char *name, size_t namelen,
+                         const char *value, size_t valuelen);
+
+CURLcode Curl_dynhds_cset(struct dynhds *dynhds,
+                          const char *name, const char *value);
+
+/**
+ * Add a single header from a HTTP/1.1 formatted line at the end. Line
+ * may contain a delimiting \r\n or just \n. Any characters after
+ * that will be ignored.
+ */
+CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line);
+
+/**
+ * Add a single header from a HTTP/1.1 formatted line at the end. Line
+ * may contain a delimiting \r\n or just \n. Any characters after
+ * that will be ignored.
+ */
+CURLcode Curl_dynhds_h1_add_line(struct dynhds *dynhds,
+                                 const char *line, size_t line_len);
+
+/**
+ * Add the headers to the given `dynbuf` in HTTP/1.1 format with
+ * cr+lf line endings. Will NOT output a last empty line.
+ */
+CURLcode Curl_dynhds_h1_dprint(struct dynhds *dynhds, struct dynbuf *dbuf);
+
+#ifdef USE_NGHTTP2
+
+#include <stdint.h>
+#include <nghttp2/nghttp2.h>
+
+nghttp2_nv *Curl_dynhds_to_nva(struct dynhds *dynhds, size_t *pcount);
+
+#endif /* USE_NGHTTP2 */
+
+#endif /* HEADER_CURL_DYNHDS_H */
Index: trunk/src/libs/curl-8.7.1/lib/easy.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/easy.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/easy.c	(revision 104083)
@@ -0,0 +1,1345 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "vtls/vtls.h"
+#include "url.h"
+#include "getinfo.h"
+#include "hostip.h"
+#include "share.h"
+#include "strdup.h"
+#include "progress.h"
+#include "easyif.h"
+#include "multiif.h"
+#include "select.h"
+#include "cfilters.h"
+#include "cw-out.h"
+#include "sendf.h" /* for failf function prototype */
+#include "connect.h" /* for Curl_getconnectinfo */
+#include "slist.h"
+#include "mime.h"
+#include "amigaos.h"
+#include "macos.h"
+#include "warnless.h"
+#include "sigpipe.h"
+#include "vssh/ssh.h"
+#include "setopt.h"
+#include "http_digest.h"
+#include "system_win32.h"
+#include "http2.h"
+#include "dynbuf.h"
+#include "altsvc.h"
+#include "hsts.h"
+
+#include "easy_lock.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* true globals -- for curl_global_init() and curl_global_cleanup() */
+static unsigned int  initialized;
+static long          easy_init_flags;
+
+#ifdef GLOBAL_INIT_IS_THREADSAFE
+
+static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT;
+#define global_init_lock() curl_simple_lock_lock(&s_lock)
+#define global_init_unlock() curl_simple_lock_unlock(&s_lock)
+
+#else
+
+#define global_init_lock()
+#define global_init_unlock()
+
+#endif
+
+/*
+ * strdup (and other memory functions) is redefined in complicated
+ * ways, but at this point it must be defined as the system-supplied strdup
+ * so the callback pointer is initialized correctly.
+ */
+#if defined(_WIN32_WCE)
+#define system_strdup _strdup
+#elif !defined(HAVE_STRDUP)
+#define system_strdup Curl_strdup
+#else
+#define system_strdup strdup
+#endif
+
+#if defined(_MSC_VER) && defined(_DLL)
+#  pragma warning(disable:4232) /* MSVC extension, dllimport identity */
+#endif
+
+/*
+ * If a memory-using function (like curl_getenv) is used before
+ * curl_global_init() is called, we need to have these pointers set already.
+ */
+curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
+curl_free_callback Curl_cfree = (curl_free_callback)free;
+curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
+curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
+curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
+#if defined(_WIN32) && defined(UNICODE)
+curl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup;
+#endif
+
+#if defined(_MSC_VER) && defined(_DLL)
+#  pragma warning(default:4232) /* MSVC extension, dllimport identity */
+#endif
+
+#ifdef DEBUGBUILD
+static char *leakpointer;
+#endif
+
+/**
+ * curl_global_init() globally initializes curl given a bitwise set of the
+ * different features of what to initialize.
+ */
+static CURLcode global_init(long flags, bool memoryfuncs)
+{
+  if(initialized++)
+    return CURLE_OK;
+
+  if(memoryfuncs) {
+    /* Setup the default memory functions here (again) */
+    Curl_cmalloc = (curl_malloc_callback)malloc;
+    Curl_cfree = (curl_free_callback)free;
+    Curl_crealloc = (curl_realloc_callback)realloc;
+    Curl_cstrdup = (curl_strdup_callback)system_strdup;
+    Curl_ccalloc = (curl_calloc_callback)calloc;
+#if defined(_WIN32) && defined(UNICODE)
+    Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
+#endif
+  }
+
+  if(Curl_trc_init()) {
+    DEBUGF(fprintf(stderr, "Error: Curl_trc_init failed\n"));
+    goto fail;
+  }
+
+  if(!Curl_ssl_init()) {
+    DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
+    goto fail;
+  }
+
+  if(Curl_win32_init(flags)) {
+    DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
+    goto fail;
+  }
+
+  if(Curl_amiga_init()) {
+    DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n"));
+    goto fail;
+  }
+
+  if(Curl_macos_init()) {
+    DEBUGF(fprintf(stderr, "Error: Curl_macos_init failed\n"));
+    goto fail;
+  }
+
+  if(Curl_resolver_global_init()) {
+    DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n"));
+    goto fail;
+  }
+
+  if(Curl_ssh_init()) {
+    DEBUGF(fprintf(stderr, "Error: Curl_ssh_init failed\n"));
+    goto fail;
+  }
+
+  easy_init_flags = flags;
+
+#ifdef DEBUGBUILD
+  if(getenv("CURL_GLOBAL_INIT"))
+    /* alloc data that will leak if *cleanup() is not called! */
+    leakpointer = malloc(1);
+#endif
+
+  return CURLE_OK;
+
+fail:
+  initialized--; /* undo the increase */
+  return CURLE_FAILED_INIT;
+}
+
+
+/**
+ * curl_global_init() globally initializes curl given a bitwise set of the
+ * different features of what to initialize.
+ */
+CURLcode curl_global_init(long flags)
+{
+  CURLcode result;
+  global_init_lock();
+
+  result = global_init(flags, TRUE);
+
+  global_init_unlock();
+
+  return result;
+}
+
+/*
+ * curl_global_init_mem() globally initializes curl and also registers the
+ * user provided callback routines.
+ */
+CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
+                              curl_free_callback f, curl_realloc_callback r,
+                              curl_strdup_callback s, curl_calloc_callback c)
+{
+  CURLcode result;
+
+  /* Invalid input, return immediately */
+  if(!m || !f || !r || !s || !c)
+    return CURLE_FAILED_INIT;
+
+  global_init_lock();
+
+  if(initialized) {
+    /* Already initialized, don't do it again, but bump the variable anyway to
+       work like curl_global_init() and require the same amount of cleanup
+       calls. */
+    initialized++;
+    global_init_unlock();
+    return CURLE_OK;
+  }
+
+  /* set memory functions before global_init() in case it wants memory
+     functions */
+  Curl_cmalloc = m;
+  Curl_cfree = f;
+  Curl_cstrdup = s;
+  Curl_crealloc = r;
+  Curl_ccalloc = c;
+
+  /* Call the actual init function, but without setting */
+  result = global_init(flags, FALSE);
+
+  global_init_unlock();
+
+  return result;
+}
+
+/**
+ * curl_global_cleanup() globally cleanups curl, uses the value of
+ * "easy_init_flags" to determine what needs to be cleaned up and what doesn't.
+ */
+void curl_global_cleanup(void)
+{
+  global_init_lock();
+
+  if(!initialized) {
+    global_init_unlock();
+    return;
+  }
+
+  if(--initialized) {
+    global_init_unlock();
+    return;
+  }
+
+  Curl_ssl_cleanup();
+  Curl_resolver_global_cleanup();
+
+#ifdef _WIN32
+  Curl_win32_cleanup(easy_init_flags);
+#endif
+
+  Curl_amiga_cleanup();
+
+  Curl_ssh_cleanup();
+
+#ifdef DEBUGBUILD
+  free(leakpointer);
+#endif
+
+  easy_init_flags = 0;
+
+  global_init_unlock();
+}
+
+/**
+ * curl_global_trace() globally initializes curl logging.
+ */
+CURLcode curl_global_trace(const char *config)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  CURLcode result;
+  global_init_lock();
+
+  result = Curl_trc_opt(config);
+
+  global_init_unlock();
+
+  return result;
+#else
+  (void)config;
+  return CURLE_OK;
+#endif
+}
+
+/*
+ * curl_global_sslset() globally initializes the SSL backend to use.
+ */
+CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
+                              const curl_ssl_backend ***avail)
+{
+  CURLsslset rc;
+
+  global_init_lock();
+
+  rc = Curl_init_sslset_nolock(id, name, avail);
+
+  global_init_unlock();
+
+  return rc;
+}
+
+/*
+ * curl_easy_init() is the external interface to alloc, setup and init an
+ * easy handle that is returned. If anything goes wrong, NULL is returned.
+ */
+struct Curl_easy *curl_easy_init(void)
+{
+  CURLcode result;
+  struct Curl_easy *data;
+
+  /* Make sure we inited the global SSL stuff */
+  global_init_lock();
+
+  if(!initialized) {
+    result = global_init(CURL_GLOBAL_DEFAULT, TRUE);
+    if(result) {
+      /* something in the global init failed, return nothing */
+      DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
+      global_init_unlock();
+      return NULL;
+    }
+  }
+  global_init_unlock();
+
+  /* We use curl_open() with undefined URL so far */
+  result = Curl_open(&data);
+  if(result) {
+    DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
+    return NULL;
+  }
+
+  return data;
+}
+
+#ifdef CURLDEBUG
+
+struct socketmonitor {
+  struct socketmonitor *next; /* the next node in the list or NULL */
+  struct pollfd socket; /* socket info of what to monitor */
+};
+
+struct events {
+  long ms;              /* timeout, run the timeout function when reached */
+  bool msbump;          /* set TRUE when timeout is set by callback */
+  int num_sockets;      /* number of nodes in the monitor list */
+  struct socketmonitor *list; /* list of sockets to monitor */
+  int running_handles;  /* store the returned number */
+};
+
+/* events_timer
+ *
+ * Callback that gets called with a new value when the timeout should be
+ * updated.
+ */
+
+static int events_timer(struct Curl_multi *multi,    /* multi handle */
+                        long timeout_ms, /* see above */
+                        void *userp)    /* private callback pointer */
+{
+  struct events *ev = userp;
+  (void)multi;
+  if(timeout_ms == -1)
+    /* timeout removed */
+    timeout_ms = 0;
+  else if(timeout_ms == 0)
+    /* timeout is already reached! */
+    timeout_ms = 1; /* trigger asap */
+
+  ev->ms = timeout_ms;
+  ev->msbump = TRUE;
+  return 0;
+}
+
+
+/* poll2cselect
+ *
+ * convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones
+ */
+static int poll2cselect(int pollmask)
+{
+  int omask = 0;
+  if(pollmask & POLLIN)
+    omask |= CURL_CSELECT_IN;
+  if(pollmask & POLLOUT)
+    omask |= CURL_CSELECT_OUT;
+  if(pollmask & POLLERR)
+    omask |= CURL_CSELECT_ERR;
+  return omask;
+}
+
+
+/* socketcb2poll
+ *
+ * convert from libcurl' CURL_POLL_* bit definitions to poll()'s
+ */
+static short socketcb2poll(int pollmask)
+{
+  short omask = 0;
+  if(pollmask & CURL_POLL_IN)
+    omask |= POLLIN;
+  if(pollmask & CURL_POLL_OUT)
+    omask |= POLLOUT;
+  return omask;
+}
+
+/* events_socket
+ *
+ * Callback that gets called with information about socket activity to
+ * monitor.
+ */
+static int events_socket(struct Curl_easy *easy,      /* easy handle */
+                         curl_socket_t s, /* socket */
+                         int what,        /* see above */
+                         void *userp,     /* private callback
+                                             pointer */
+                         void *socketp)   /* private socket
+                                             pointer */
+{
+  struct events *ev = userp;
+  struct socketmonitor *m;
+  struct socketmonitor *prev = NULL;
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) easy;
+#endif
+  (void)socketp;
+
+  m = ev->list;
+  while(m) {
+    if(m->socket.fd == s) {
+
+      if(what == CURL_POLL_REMOVE) {
+        struct socketmonitor *nxt = m->next;
+        /* remove this node from the list of monitored sockets */
+        if(prev)
+          prev->next = nxt;
+        else
+          ev->list = nxt;
+        free(m);
+        m = nxt;
+        infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T
+              " REMOVED", s);
+      }
+      else {
+        /* The socket 's' is already being monitored, update the activity
+           mask. Convert from libcurl bitmask to the poll one. */
+        m->socket.events = socketcb2poll(what);
+        infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T
+              " UPDATED as %s%s", s,
+              (what&CURL_POLL_IN)?"IN":"",
+              (what&CURL_POLL_OUT)?"OUT":"");
+      }
+      break;
+    }
+    prev = m;
+    m = m->next; /* move to next node */
+  }
+  if(!m) {
+    if(what == CURL_POLL_REMOVE) {
+      /* this happens a bit too often, libcurl fix perhaps? */
+      /* fprintf(stderr,
+         "%s: socket %d asked to be REMOVED but not present!\n",
+                 __func__, s); */
+    }
+    else {
+      m = malloc(sizeof(struct socketmonitor));
+      if(m) {
+        m->next = ev->list;
+        m->socket.fd = s;
+        m->socket.events = socketcb2poll(what);
+        m->socket.revents = 0;
+        ev->list = m;
+        infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T
+              " ADDED as %s%s", s,
+              (what&CURL_POLL_IN)?"IN":"",
+              (what&CURL_POLL_OUT)?"OUT":"");
+      }
+      else
+        return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  return 0;
+}
+
+
+/*
+ * events_setup()
+ *
+ * Do the multi handle setups that only event-based transfers need.
+ */
+static void events_setup(struct Curl_multi *multi, struct events *ev)
+{
+  /* timer callback */
+  curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer);
+  curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev);
+
+  /* socket callback */
+  curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket);
+  curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev);
+}
+
+
+/* wait_or_timeout()
+ *
+ * waits for activity on any of the given sockets, or the timeout to trigger.
+ */
+
+static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
+{
+  bool done = FALSE;
+  CURLMcode mcode = CURLM_OK;
+  CURLcode result = CURLE_OK;
+
+  while(!done) {
+    CURLMsg *msg;
+    struct socketmonitor *m;
+    struct pollfd *f;
+    struct pollfd fds[4];
+    int numfds = 0;
+    int pollrc;
+    int i;
+    struct curltime before;
+    struct curltime after;
+
+    /* populate the fds[] array */
+    for(m = ev->list, f = &fds[0]; m; m = m->next) {
+      f->fd = m->socket.fd;
+      f->events = m->socket.events;
+      f->revents = 0;
+      /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */
+      f++;
+      numfds++;
+    }
+
+    /* get the time stamp to use to figure out how long poll takes */
+    before = Curl_now();
+
+    /* wait for activity or timeout */
+    pollrc = Curl_poll(fds, numfds, ev->ms);
+    if(pollrc < 0)
+      return CURLE_UNRECOVERABLE_POLL;
+
+    after = Curl_now();
+
+    ev->msbump = FALSE; /* reset here */
+
+    if(!pollrc) {
+      /* timeout! */
+      ev->ms = 0;
+      /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */
+      mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0,
+                                       &ev->running_handles);
+    }
+    else {
+      /* here pollrc is > 0 */
+
+      /* loop over the monitored sockets to see which ones had activity */
+      for(i = 0; i< numfds; i++) {
+        if(fds[i].revents) {
+          /* socket activity, tell libcurl */
+          int act = poll2cselect(fds[i].revents); /* convert */
+          infof(multi->easyp,
+                "call curl_multi_socket_action(socket "
+                "%" CURL_FORMAT_SOCKET_T ")", fds[i].fd);
+          mcode = curl_multi_socket_action(multi, fds[i].fd, act,
+                                           &ev->running_handles);
+        }
+      }
+
+      if(!ev->msbump) {
+        /* If nothing updated the timeout, we decrease it by the spent time.
+         * If it was updated, it has the new timeout time stored already.
+         */
+        timediff_t timediff = Curl_timediff(after, before);
+        if(timediff > 0) {
+          if(timediff > ev->ms)
+            ev->ms = 0;
+          else
+            ev->ms -= (long)timediff;
+        }
+      }
+    }
+
+    if(mcode)
+      return CURLE_URL_MALFORMAT;
+
+    /* we don't really care about the "msgs_in_queue" value returned in the
+       second argument */
+    msg = curl_multi_info_read(multi, &pollrc);
+    if(msg) {
+      result = msg->data.result;
+      done = TRUE;
+    }
+  }
+
+  return result;
+}
+
+
+/* easy_events()
+ *
+ * Runs a transfer in a blocking manner using the events-based API
+ */
+static CURLcode easy_events(struct Curl_multi *multi)
+{
+  /* this struct is made static to allow it to be used after this function
+     returns and curl_multi_remove_handle() is called */
+  static struct events evs = {2, FALSE, 0, NULL, 0};
+
+  /* if running event-based, do some further multi inits */
+  events_setup(multi, &evs);
+
+  return wait_or_timeout(multi, &evs);
+}
+#else /* CURLDEBUG */
+/* when not built with debug, this function doesn't exist */
+#define easy_events(x) CURLE_NOT_BUILT_IN
+#endif
+
+static CURLcode easy_transfer(struct Curl_multi *multi)
+{
+  bool done = FALSE;
+  CURLMcode mcode = CURLM_OK;
+  CURLcode result = CURLE_OK;
+
+  while(!done && !mcode) {
+    int still_running = 0;
+
+    mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL);
+
+    if(!mcode)
+      mcode = curl_multi_perform(multi, &still_running);
+
+    /* only read 'still_running' if curl_multi_perform() return OK */
+    if(!mcode && !still_running) {
+      int rc;
+      CURLMsg *msg = curl_multi_info_read(multi, &rc);
+      if(msg) {
+        result = msg->data.result;
+        done = TRUE;
+      }
+    }
+  }
+
+  /* Make sure to return some kind of error if there was a multi problem */
+  if(mcode) {
+    result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
+      /* The other multi errors should never happen, so return
+         something suitably generic */
+      CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
+  return result;
+}
+
+
+/*
+ * easy_perform() is the external interface that performs a blocking
+ * transfer as previously setup.
+ *
+ * CONCEPT: This function creates a multi handle, adds the easy handle to it,
+ * runs curl_multi_perform() until the transfer is done, then detaches the
+ * easy handle, destroys the multi handle and returns the easy handle's return
+ * code.
+ *
+ * REALITY: it can't just create and destroy the multi handle that easily. It
+ * needs to keep it around since if this easy handle is used again by this
+ * function, the same multi handle must be reused so that the same pools and
+ * caches can be used.
+ *
+ * DEBUG: if 'events' is set TRUE, this function will use a replacement engine
+ * instead of curl_multi_perform() and use curl_multi_socket_action().
+ */
+static CURLcode easy_perform(struct Curl_easy *data, bool events)
+{
+  struct Curl_multi *multi;
+  CURLMcode mcode;
+  CURLcode result = CURLE_OK;
+  SIGPIPE_VARIABLE(pipe_st);
+
+  if(!data)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  if(data->set.errorbuffer)
+    /* clear this as early as possible */
+    data->set.errorbuffer[0] = 0;
+
+  if(data->multi) {
+    failf(data, "easy handle already used in multi handle");
+    return CURLE_FAILED_INIT;
+  }
+
+  if(data->multi_easy)
+    multi = data->multi_easy;
+  else {
+    /* this multi handle will only ever have a single easy handled attached
+       to it, so make it use minimal hashes */
+    multi = Curl_multi_handle(1, 3, 7);
+    if(!multi)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(multi->in_callback)
+    return CURLE_RECURSIVE_API_CALL;
+
+  /* Copy the MAXCONNECTS option to the multi handle */
+  curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, (long)data->set.maxconnects);
+
+  data->multi_easy = NULL; /* pretend it does not exist */
+  mcode = curl_multi_add_handle(multi, data);
+  if(mcode) {
+    curl_multi_cleanup(multi);
+    if(mcode == CURLM_OUT_OF_MEMORY)
+      return CURLE_OUT_OF_MEMORY;
+    return CURLE_FAILED_INIT;
+  }
+
+  /* assign this after curl_multi_add_handle() */
+  data->multi_easy = multi;
+
+  sigpipe_ignore(data, &pipe_st);
+
+  /* run the transfer */
+  result = events ? easy_events(multi) : easy_transfer(multi);
+
+  /* ignoring the return code isn't nice, but atm we can't really handle
+     a failure here, room for future improvement! */
+  (void)curl_multi_remove_handle(multi, data);
+
+  sigpipe_restore(&pipe_st);
+
+  /* The multi handle is kept alive, owned by the easy handle */
+  return result;
+}
+
+
+/*
+ * curl_easy_perform() is the external interface that performs a blocking
+ * transfer as previously setup.
+ */
+CURLcode curl_easy_perform(struct Curl_easy *data)
+{
+  return easy_perform(data, FALSE);
+}
+
+#ifdef CURLDEBUG
+/*
+ * curl_easy_perform_ev() is the external interface that performs a blocking
+ * transfer using the event-based API internally.
+ */
+CURLcode curl_easy_perform_ev(struct Curl_easy *data)
+{
+  return easy_perform(data, TRUE);
+}
+
+#endif
+
+/*
+ * curl_easy_cleanup() is the external interface to cleaning/freeing the given
+ * easy handle.
+ */
+void curl_easy_cleanup(struct Curl_easy *data)
+{
+  if(GOOD_EASY_HANDLE(data)) {
+    SIGPIPE_VARIABLE(pipe_st);
+    sigpipe_ignore(data, &pipe_st);
+    Curl_close(&data);
+    sigpipe_restore(&pipe_st);
+  }
+}
+
+/*
+ * curl_easy_getinfo() is an external interface that allows an app to retrieve
+ * information from a performed transfer and similar.
+ */
+#undef curl_easy_getinfo
+CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...)
+{
+  va_list arg;
+  void *paramp;
+  CURLcode result;
+
+  va_start(arg, info);
+  paramp = va_arg(arg, void *);
+
+  result = Curl_getinfo(data, info, paramp);
+
+  va_end(arg);
+  return result;
+}
+
+static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
+{
+  CURLcode result = CURLE_OK;
+  enum dupstring i;
+  enum dupblob j;
+
+  /* Copy src->set into dst->set first, then deal with the strings
+     afterwards */
+  dst->set = src->set;
+  Curl_mime_initpart(&dst->set.mimepost);
+
+  /* clear all dest string and blob pointers first, in case we error out
+     mid-function */
+  memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
+  memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *));
+
+  /* duplicate all strings */
+  for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) {
+    result = Curl_setstropt(&dst->set.str[i], src->set.str[i]);
+    if(result)
+      return result;
+  }
+
+  /* duplicate all blobs */
+  for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
+    result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]);
+    if(result)
+      return result;
+  }
+
+  /* duplicate memory areas pointed to */
+  i = STRING_COPYPOSTFIELDS;
+  if(src->set.str[i]) {
+    if(src->set.postfieldsize == -1)
+      dst->set.str[i] = strdup(src->set.str[i]);
+    else
+      /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
+      dst->set.str[i] = Curl_memdup(src->set.str[i],
+                                    curlx_sotouz(src->set.postfieldsize));
+    if(!dst->set.str[i])
+      return CURLE_OUT_OF_MEMORY;
+    /* point to the new copy */
+    dst->set.postfields = dst->set.str[i];
+  }
+
+  /* Duplicate mime data. */
+  result = Curl_mime_duppart(dst, &dst->set.mimepost, &src->set.mimepost);
+
+  if(src->set.resolve)
+    dst->state.resolve = dst->set.resolve;
+
+  return result;
+}
+
+/*
+ * curl_easy_duphandle() is an external interface to allow duplication of a
+ * given input easy handle. The returned handle will be a new working handle
+ * with all options set exactly as the input source handle.
+ */
+struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
+{
+  struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
+  if(!outcurl)
+    goto fail;
+
+  /*
+   * We setup a few buffers we need. We should probably make them
+   * get setup on-demand in the code, as that would probably decrease
+   * the likeliness of us forgetting to init a buffer here in the future.
+   */
+  outcurl->set.buffer_size = data->set.buffer_size;
+
+  /* copy all userdefined values */
+  if(dupset(outcurl, data))
+    goto fail;
+
+  Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER);
+
+  /* the connection cache is setup on demand */
+  outcurl->state.conn_cache = NULL;
+  outcurl->state.lastconnect_id = -1;
+  outcurl->state.recent_conn_id = -1;
+  outcurl->id = -1;
+
+  outcurl->progress.flags    = data->progress.flags;
+  outcurl->progress.callback = data->progress.callback;
+
+#ifndef CURL_DISABLE_COOKIES
+  outcurl->state.cookielist = NULL;
+  if(data->cookies && data->state.cookie_engine) {
+    /* If cookies are enabled in the parent handle, we enable them
+       in the clone as well! */
+    outcurl->cookies = Curl_cookie_init(outcurl, NULL, outcurl->cookies,
+                                        data->set.cookiesession);
+    if(!outcurl->cookies)
+      goto fail;
+  }
+
+  if(data->state.cookielist) {
+    outcurl->state.cookielist = Curl_slist_duplicate(data->state.cookielist);
+    if(!outcurl->state.cookielist)
+      goto fail;
+  }
+#endif
+
+  if(data->state.url) {
+    outcurl->state.url = strdup(data->state.url);
+    if(!outcurl->state.url)
+      goto fail;
+    outcurl->state.url_alloc = TRUE;
+  }
+
+  if(data->state.referer) {
+    outcurl->state.referer = strdup(data->state.referer);
+    if(!outcurl->state.referer)
+      goto fail;
+    outcurl->state.referer_alloc = TRUE;
+  }
+
+  /* Reinitialize an SSL engine for the new handle
+   * note: the engine name has already been copied by dupset */
+  if(outcurl->set.str[STRING_SSL_ENGINE]) {
+    if(Curl_ssl_set_engine(outcurl, outcurl->set.str[STRING_SSL_ENGINE]))
+      goto fail;
+  }
+
+#ifndef CURL_DISABLE_ALTSVC
+  if(data->asi) {
+    outcurl->asi = Curl_altsvc_init();
+    if(!outcurl->asi)
+      goto fail;
+    if(outcurl->set.str[STRING_ALTSVC])
+      (void)Curl_altsvc_load(outcurl->asi, outcurl->set.str[STRING_ALTSVC]);
+  }
+#endif
+#ifndef CURL_DISABLE_HSTS
+  if(data->hsts) {
+    outcurl->hsts = Curl_hsts_init();
+    if(!outcurl->hsts)
+      goto fail;
+    if(outcurl->set.str[STRING_HSTS])
+      (void)Curl_hsts_loadfile(outcurl,
+                               outcurl->hsts, outcurl->set.str[STRING_HSTS]);
+    (void)Curl_hsts_loadcb(outcurl, outcurl->hsts);
+  }
+#endif
+
+#ifdef CURLRES_ASYNCH
+  /* Clone the resolver handle, if present, for the new handle */
+  if(Curl_resolver_duphandle(outcurl,
+                             &outcurl->state.async.resolver,
+                             data->state.async.resolver))
+    goto fail;
+#endif
+
+#ifdef USE_ARES
+  {
+    CURLcode rc;
+
+    rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]);
+    if(rc && rc != CURLE_NOT_BUILT_IN)
+      goto fail;
+
+    rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]);
+    if(rc && rc != CURLE_NOT_BUILT_IN)
+      goto fail;
+
+    rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]);
+    if(rc && rc != CURLE_NOT_BUILT_IN)
+      goto fail;
+
+    rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]);
+    if(rc && rc != CURLE_NOT_BUILT_IN)
+      goto fail;
+  }
+#endif /* USE_ARES */
+
+  Curl_initinfo(outcurl);
+
+  outcurl->magic = CURLEASY_MAGIC_NUMBER;
+
+  /* we reach this point and thus we are OK */
+
+  return outcurl;
+
+fail:
+
+  if(outcurl) {
+#ifndef CURL_DISABLE_COOKIES
+    free(outcurl->cookies);
+#endif
+    Curl_dyn_free(&outcurl->state.headerb);
+    Curl_altsvc_cleanup(&outcurl->asi);
+    Curl_hsts_cleanup(&outcurl->hsts);
+    Curl_freeset(outcurl);
+    free(outcurl);
+  }
+
+  return NULL;
+}
+
+/*
+ * curl_easy_reset() is an external interface that allows an app to re-
+ * initialize a session handle to the default values.
+ */
+void curl_easy_reset(struct Curl_easy *data)
+{
+  Curl_req_hard_reset(&data->req, data);
+
+  /* zero out UserDefined data: */
+  Curl_freeset(data);
+  memset(&data->set, 0, sizeof(struct UserDefined));
+  (void)Curl_init_userdefined(data);
+
+  /* zero out Progress data: */
+  memset(&data->progress, 0, sizeof(struct Progress));
+
+  /* zero out PureInfo data: */
+  Curl_initinfo(data);
+
+  data->progress.flags |= PGRS_HIDE;
+  data->state.current_speed = -1; /* init to negative == impossible */
+  data->state.retrycount = 0;     /* reset the retry counter */
+
+  /* zero out authentication data: */
+  memset(&data->state.authhost, 0, sizeof(struct auth));
+  memset(&data->state.authproxy, 0, sizeof(struct auth));
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
+  Curl_http_auth_cleanup_digest(data);
+#endif
+}
+
+/*
+ * curl_easy_pause() allows an application to pause or unpause a specific
+ * transfer and direction. This function sets the full new state for the
+ * current connection this easy handle operates on.
+ *
+ * NOTE: if you have the receiving paused and you call this function to remove
+ * the pausing, you may get your write callback called at this point.
+ *
+ * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
+ *
+ * NOTE: This is one of few API functions that are allowed to be called from
+ * within a callback.
+ */
+CURLcode curl_easy_pause(struct Curl_easy *data, int action)
+{
+  struct SingleRequest *k;
+  CURLcode result = CURLE_OK;
+  int oldstate;
+  int newstate;
+  bool recursive = FALSE;
+
+  if(!GOOD_EASY_HANDLE(data) || !data->conn)
+    /* crazy input, don't continue */
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  if(Curl_is_in_callback(data))
+    recursive = TRUE;
+  k = &data->req;
+  oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
+
+  /* first switch off both pause bits then set the new pause bits */
+  newstate = (k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) |
+    ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
+    ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
+
+  if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) {
+    /* Not changing any pause state, return */
+    DEBUGF(infof(data, "pause: no change, early return"));
+    return CURLE_OK;
+  }
+
+  /* Unpause parts in active mime tree. */
+  if((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
+     (data->mstate == MSTATE_PERFORMING ||
+      data->mstate == MSTATE_RATELIMITING)) {
+    result = Curl_creader_unpause(data);
+    if(result)
+      return result;
+  }
+
+  /* put it back in the keepon */
+  k->keepon = newstate;
+
+  if(!(newstate & KEEP_RECV_PAUSE)) {
+    Curl_conn_ev_data_pause(data, FALSE);
+    result = Curl_cw_out_flush(data);
+    if(result)
+      return result;
+  }
+
+  /* if there's no error and we're not pausing both directions, we want
+     to have this handle checked soon */
+  if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
+     (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) {
+    Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
+
+    /* reset the too-slow time keeper */
+    data->state.keeps_speed.tv_sec = 0;
+
+    if(!Curl_cw_out_is_paused(data))
+      /* if not pausing again, force a recv/send check of this connection as
+         the data might've been read off the socket already */
+      data->state.select_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
+    if(data->multi) {
+      if(Curl_update_timer(data->multi))
+        return CURLE_ABORTED_BY_CALLBACK;
+    }
+  }
+
+  if(!data->state.done)
+    /* This transfer may have been moved in or out of the bundle, update the
+       corresponding socket callback, if used */
+    result = Curl_updatesocket(data);
+
+  if(recursive)
+    /* this might have called a callback recursively which might have set this
+       to false again on exit */
+    Curl_set_in_callback(data, TRUE);
+
+  return result;
+}
+
+
+static CURLcode easy_connection(struct Curl_easy *data,
+                                struct connectdata **connp)
+{
+  curl_socket_t sfd;
+
+  if(!data)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
+  if(!data->set.connect_only) {
+    failf(data, "CONNECT_ONLY is required");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+  }
+
+  sfd = Curl_getconnectinfo(data, connp);
+
+  if(sfd == CURL_SOCKET_BAD) {
+    failf(data, "Failed to get recent socket");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Receives data from the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ * Returns CURLE_OK on success, error code on error.
+ */
+CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
+                        size_t *n)
+{
+  CURLcode result;
+  ssize_t n1;
+  struct connectdata *c;
+
+  if(Curl_is_in_callback(data))
+    return CURLE_RECURSIVE_API_CALL;
+
+  result = easy_connection(data, &c);
+  if(result)
+    return result;
+
+  if(!data->conn)
+    /* on first invoke, the transfer has been detached from the connection and
+       needs to be reattached */
+    Curl_attach_connection(data, c);
+
+  *n = 0;
+  result = Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, &n1);
+
+  if(result)
+    return result;
+
+  *n = (size_t)n1;
+  return CURLE_OK;
+}
+
+#ifdef USE_WEBSOCKETS
+CURLcode Curl_connect_only_attach(struct Curl_easy *data)
+{
+  CURLcode result;
+  struct connectdata *c = NULL;
+
+  result = easy_connection(data, &c);
+  if(result)
+    return result;
+
+  if(!data->conn)
+    /* on first invoke, the transfer has been detached from the connection and
+       needs to be reattached */
+    Curl_attach_connection(data, c);
+
+  return CURLE_OK;
+}
+#endif /* USE_WEBSOCKETS */
+
+/*
+ * Sends data over the connected socket.
+ *
+ * This is the private internal version of curl_easy_send()
+ */
+CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
+                       size_t buflen, size_t *n)
+{
+  CURLcode result;
+  struct connectdata *c = NULL;
+  SIGPIPE_VARIABLE(pipe_st);
+
+  *n = 0;
+  result = easy_connection(data, &c);
+  if(result)
+    return result;
+
+  if(!data->conn)
+    /* on first invoke, the transfer has been detached from the connection and
+       needs to be reattached */
+    Curl_attach_connection(data, c);
+
+  sigpipe_ignore(data, &pipe_st);
+  result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, n);
+  sigpipe_restore(&pipe_st);
+
+  if(result && result != CURLE_AGAIN)
+    return CURLE_SEND_ERROR;
+  return result;
+}
+
+/*
+ * Sends data over the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
+                        size_t buflen, size_t *n)
+{
+  size_t written = 0;
+  CURLcode result;
+  if(Curl_is_in_callback(data))
+    return CURLE_RECURSIVE_API_CALL;
+
+  result = Curl_senddata(data, buffer, buflen, &written);
+  *n = written;
+  return result;
+}
+
+/*
+ * Wrapper to call functions in Curl_conncache_foreach()
+ *
+ * Returns always 0.
+ */
+static int conn_upkeep(struct Curl_easy *data,
+                       struct connectdata *conn,
+                       void *param)
+{
+  struct curltime *now = param;
+
+  if(Curl_timediff(*now, conn->keepalive) <= data->set.upkeep_interval_ms)
+    return 0;
+
+  /* briefly attach for action */
+  Curl_attach_connection(data, conn);
+  if(conn->handler->connection_check) {
+    /* Do a protocol-specific keepalive check on the connection. */
+    conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
+  }
+  else {
+    /* Do the generic action on the FIRSTSOCKE filter chain */
+    Curl_conn_keep_alive(data, conn, FIRSTSOCKET);
+  }
+  Curl_detach_connection(data);
+
+  conn->keepalive = *now;
+  return 0; /* continue iteration */
+}
+
+static CURLcode upkeep(struct conncache *conn_cache, void *data)
+{
+  struct curltime now = Curl_now();
+  /* Loop over every connection and make connection alive. */
+  Curl_conncache_foreach(data,
+                         conn_cache,
+                         &now,
+                         conn_upkeep);
+  return CURLE_OK;
+}
+
+/*
+ * Performs connection upkeep for the given session handle.
+ */
+CURLcode curl_easy_upkeep(struct Curl_easy *data)
+{
+  /* Verify that we got an easy handle we can work with. */
+  if(!GOOD_EASY_HANDLE(data))
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  if(data->multi_easy) {
+    /* Use the common function to keep connections alive. */
+    return upkeep(&data->multi_easy->conn_cache, data);
+  }
+  else {
+    /* No connections, so just return success */
+    return CURLE_OK;
+  }
+}
Index: trunk/src/libs/curl-8.7.1/lib/easy_lock.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/easy_lock.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/easy_lock.h	(revision 104083)
@@ -0,0 +1,111 @@
+#ifndef HEADER_CURL_EASY_LOCK_H
+#define HEADER_CURL_EASY_LOCK_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#define GLOBAL_INIT_IS_THREADSAFE
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
+
+#ifdef __MINGW32__
+#ifndef SRWLOCK_INIT
+#define SRWLOCK_INIT NULL
+#endif
+#endif /* __MINGW32__ */
+
+#define curl_simple_lock SRWLOCK
+#define CURL_SIMPLE_LOCK_INIT SRWLOCK_INIT
+
+#define curl_simple_lock_lock(m) AcquireSRWLockExclusive(m)
+#define curl_simple_lock_unlock(m) ReleaseSRWLockExclusive(m)
+
+#elif defined(HAVE_ATOMIC) && defined(HAVE_STDATOMIC_H)
+#include <stdatomic.h>
+#if defined(HAVE_SCHED_YIELD)
+#include <sched.h>
+#endif
+
+#define curl_simple_lock atomic_int
+#define CURL_SIMPLE_LOCK_INIT 0
+
+/* a clang-thing */
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#ifndef __INTEL_COMPILER
+/* The Intel compiler tries to look like GCC *and* clang *and* lies in its
+   __has_builtin() function, so override it. */
+
+/* if GCC on i386/x86_64 or if the built-in is present */
+#if ( (defined(__GNUC__) && !defined(__clang__)) &&     \
+      (defined(__i386__) || defined(__x86_64__))) ||    \
+  __has_builtin(__builtin_ia32_pause)
+#define HAVE_BUILTIN_IA32_PAUSE
+#endif
+
+#endif
+
+static inline void curl_simple_lock_lock(curl_simple_lock *lock)
+{
+  for(;;) {
+    if(!atomic_exchange_explicit(lock, true, memory_order_acquire))
+      break;
+    /* Reduce cache coherency traffic */
+    while(atomic_load_explicit(lock, memory_order_relaxed)) {
+      /* Reduce load (not mandatory) */
+#ifdef HAVE_BUILTIN_IA32_PAUSE
+      __builtin_ia32_pause();
+#elif defined(__aarch64__)
+      __asm__ volatile("yield" ::: "memory");
+#elif defined(HAVE_SCHED_YIELD)
+      sched_yield();
+#endif
+    }
+  }
+}
+
+static inline void curl_simple_lock_unlock(curl_simple_lock *lock)
+{
+  atomic_store_explicit(lock, false, memory_order_release);
+}
+
+#elif defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+
+#include <pthread.h>
+
+#define curl_simple_lock pthread_mutex_t
+#define CURL_SIMPLE_LOCK_INIT PTHREAD_MUTEX_INITIALIZER
+#define curl_simple_lock_lock(m) pthread_mutex_lock(m)
+#define curl_simple_lock_unlock(m) pthread_mutex_unlock(m)
+
+#else
+
+#undef  GLOBAL_INIT_IS_THREADSAFE
+
+#endif
+
+#endif /* HEADER_CURL_EASY_LOCK_H */
Index: trunk/src/libs/curl-8.7.1/lib/easygetopt.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/easygetopt.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/easygetopt.c	(revision 104083)
@@ -0,0 +1,98 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ | |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             ___|___/|_| ______|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "strcase.h"
+#include "easyoptions.h"
+
+#ifndef CURL_DISABLE_GETOPTIONS
+
+/* Lookups easy options at runtime */
+static struct curl_easyoption *lookup(const char *name, CURLoption id)
+{
+  DEBUGASSERT(name || id);
+  DEBUGASSERT(!Curl_easyopts_check());
+  if(name || id) {
+    struct curl_easyoption *o = &Curl_easyopts[0];
+    do {
+      if(name) {
+        if(strcasecompare(o->name, name))
+          return o;
+      }
+      else {
+        if((o->id == id) && !(o->flags & CURLOT_FLAG_ALIAS))
+          /* don't match alias options */
+          return o;
+      }
+      o++;
+    } while(o->name);
+  }
+  return NULL;
+}
+
+const struct curl_easyoption *curl_easy_option_by_name(const char *name)
+{
+  /* when name is used, the id argument is ignored */
+  return lookup(name, CURLOPT_LASTENTRY);
+}
+
+const struct curl_easyoption *curl_easy_option_by_id(CURLoption id)
+{
+  return lookup(NULL, id);
+}
+
+/* Iterates over available options */
+const struct curl_easyoption *
+curl_easy_option_next(const struct curl_easyoption *prev)
+{
+  if(prev && prev->name) {
+    prev++;
+    if(prev->name)
+      return prev;
+  }
+  else if(!prev)
+    return &Curl_easyopts[0];
+  return NULL;
+}
+
+#else
+const struct curl_easyoption *curl_easy_option_by_name(const char *name)
+{
+  (void)name;
+  return NULL;
+}
+
+const struct curl_easyoption *curl_easy_option_by_id (CURLoption id)
+{
+  (void)id;
+  return NULL;
+}
+
+const struct curl_easyoption *
+curl_easy_option_next(const struct curl_easyoption *prev)
+{
+  (void)prev;
+  return NULL;
+}
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/easyif.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/easyif.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/easyif.h	(revision 104083)
@@ -0,0 +1,41 @@
+#ifndef HEADER_CURL_EASYIF_H
+#define HEADER_CURL_EASYIF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Prototypes for library-wide functions provided by easy.c
+ */
+CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
+                       size_t buflen, size_t *n);
+
+#ifdef USE_WEBSOCKETS
+CURLcode Curl_connect_only_attach(struct Curl_easy *data);
+#endif
+
+#ifdef CURLDEBUG
+CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
+#endif
+
+#endif /* HEADER_CURL_EASYIF_H */
Index: trunk/src/libs/curl-8.7.1/lib/easyoptions.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/easyoptions.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/easyoptions.c	(revision 104083)
@@ -0,0 +1,380 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* This source code is generated by optiontable.pl - DO NOT EDIT BY HAND */
+
+#include "curl_setup.h"
+#include "easyoptions.h"
+
+/* all easy setopt options listed in alphabetical order */
+struct curl_easyoption Curl_easyopts[] = {
+  {"ABSTRACT_UNIX_SOCKET", CURLOPT_ABSTRACT_UNIX_SOCKET, CURLOT_STRING, 0},
+  {"ACCEPTTIMEOUT_MS", CURLOPT_ACCEPTTIMEOUT_MS, CURLOT_LONG, 0},
+  {"ACCEPT_ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, 0},
+  {"ADDRESS_SCOPE", CURLOPT_ADDRESS_SCOPE, CURLOT_LONG, 0},
+  {"ALTSVC", CURLOPT_ALTSVC, CURLOT_STRING, 0},
+  {"ALTSVC_CTRL", CURLOPT_ALTSVC_CTRL, CURLOT_LONG, 0},
+  {"APPEND", CURLOPT_APPEND, CURLOT_LONG, 0},
+  {"AUTOREFERER", CURLOPT_AUTOREFERER, CURLOT_LONG, 0},
+  {"AWS_SIGV4", CURLOPT_AWS_SIGV4, CURLOT_STRING, 0},
+  {"BUFFERSIZE", CURLOPT_BUFFERSIZE, CURLOT_LONG, 0},
+  {"CAINFO", CURLOPT_CAINFO, CURLOT_STRING, 0},
+  {"CAINFO_BLOB", CURLOPT_CAINFO_BLOB, CURLOT_BLOB, 0},
+  {"CAPATH", CURLOPT_CAPATH, CURLOT_STRING, 0},
+  {"CA_CACHE_TIMEOUT", CURLOPT_CA_CACHE_TIMEOUT, CURLOT_LONG, 0},
+  {"CERTINFO", CURLOPT_CERTINFO, CURLOT_LONG, 0},
+  {"CHUNK_BGN_FUNCTION", CURLOPT_CHUNK_BGN_FUNCTION, CURLOT_FUNCTION, 0},
+  {"CHUNK_DATA", CURLOPT_CHUNK_DATA, CURLOT_CBPTR, 0},
+  {"CHUNK_END_FUNCTION", CURLOPT_CHUNK_END_FUNCTION, CURLOT_FUNCTION, 0},
+  {"CLOSESOCKETDATA", CURLOPT_CLOSESOCKETDATA, CURLOT_CBPTR, 0},
+  {"CLOSESOCKETFUNCTION", CURLOPT_CLOSESOCKETFUNCTION, CURLOT_FUNCTION, 0},
+  {"CONNECTTIMEOUT", CURLOPT_CONNECTTIMEOUT, CURLOT_LONG, 0},
+  {"CONNECTTIMEOUT_MS", CURLOPT_CONNECTTIMEOUT_MS, CURLOT_LONG, 0},
+  {"CONNECT_ONLY", CURLOPT_CONNECT_ONLY, CURLOT_LONG, 0},
+  {"CONNECT_TO", CURLOPT_CONNECT_TO, CURLOT_SLIST, 0},
+  {"CONV_FROM_NETWORK_FUNCTION", CURLOPT_CONV_FROM_NETWORK_FUNCTION,
+   CURLOT_FUNCTION, 0},
+  {"CONV_FROM_UTF8_FUNCTION", CURLOPT_CONV_FROM_UTF8_FUNCTION,
+   CURLOT_FUNCTION, 0},
+  {"CONV_TO_NETWORK_FUNCTION", CURLOPT_CONV_TO_NETWORK_FUNCTION,
+   CURLOT_FUNCTION, 0},
+  {"COOKIE", CURLOPT_COOKIE, CURLOT_STRING, 0},
+  {"COOKIEFILE", CURLOPT_COOKIEFILE, CURLOT_STRING, 0},
+  {"COOKIEJAR", CURLOPT_COOKIEJAR, CURLOT_STRING, 0},
+  {"COOKIELIST", CURLOPT_COOKIELIST, CURLOT_STRING, 0},
+  {"COOKIESESSION", CURLOPT_COOKIESESSION, CURLOT_LONG, 0},
+  {"COPYPOSTFIELDS", CURLOPT_COPYPOSTFIELDS, CURLOT_OBJECT, 0},
+  {"CRLF", CURLOPT_CRLF, CURLOT_LONG, 0},
+  {"CRLFILE", CURLOPT_CRLFILE, CURLOT_STRING, 0},
+  {"CURLU", CURLOPT_CURLU, CURLOT_OBJECT, 0},
+  {"CUSTOMREQUEST", CURLOPT_CUSTOMREQUEST, CURLOT_STRING, 0},
+  {"DEBUGDATA", CURLOPT_DEBUGDATA, CURLOT_CBPTR, 0},
+  {"DEBUGFUNCTION", CURLOPT_DEBUGFUNCTION, CURLOT_FUNCTION, 0},
+  {"DEFAULT_PROTOCOL", CURLOPT_DEFAULT_PROTOCOL, CURLOT_STRING, 0},
+  {"DIRLISTONLY", CURLOPT_DIRLISTONLY, CURLOT_LONG, 0},
+  {"DISALLOW_USERNAME_IN_URL", CURLOPT_DISALLOW_USERNAME_IN_URL,
+   CURLOT_LONG, 0},
+  {"DNS_CACHE_TIMEOUT", CURLOPT_DNS_CACHE_TIMEOUT, CURLOT_LONG, 0},
+  {"DNS_INTERFACE", CURLOPT_DNS_INTERFACE, CURLOT_STRING, 0},
+  {"DNS_LOCAL_IP4", CURLOPT_DNS_LOCAL_IP4, CURLOT_STRING, 0},
+  {"DNS_LOCAL_IP6", CURLOPT_DNS_LOCAL_IP6, CURLOT_STRING, 0},
+  {"DNS_SERVERS", CURLOPT_DNS_SERVERS, CURLOT_STRING, 0},
+  {"DNS_SHUFFLE_ADDRESSES", CURLOPT_DNS_SHUFFLE_ADDRESSES, CURLOT_LONG, 0},
+  {"DNS_USE_GLOBAL_CACHE", CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOT_LONG, 0},
+  {"DOH_SSL_VERIFYHOST", CURLOPT_DOH_SSL_VERIFYHOST, CURLOT_LONG, 0},
+  {"DOH_SSL_VERIFYPEER", CURLOPT_DOH_SSL_VERIFYPEER, CURLOT_LONG, 0},
+  {"DOH_SSL_VERIFYSTATUS", CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOT_LONG, 0},
+  {"DOH_URL", CURLOPT_DOH_URL, CURLOT_STRING, 0},
+  {"EGDSOCKET", CURLOPT_EGDSOCKET, CURLOT_STRING, 0},
+  {"ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, CURLOT_FLAG_ALIAS},
+  {"ERRORBUFFER", CURLOPT_ERRORBUFFER, CURLOT_OBJECT, 0},
+  {"EXPECT_100_TIMEOUT_MS", CURLOPT_EXPECT_100_TIMEOUT_MS, CURLOT_LONG, 0},
+  {"FAILONERROR", CURLOPT_FAILONERROR, CURLOT_LONG, 0},
+  {"FILE", CURLOPT_WRITEDATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS},
+  {"FILETIME", CURLOPT_FILETIME, CURLOT_LONG, 0},
+  {"FNMATCH_DATA", CURLOPT_FNMATCH_DATA, CURLOT_CBPTR, 0},
+  {"FNMATCH_FUNCTION", CURLOPT_FNMATCH_FUNCTION, CURLOT_FUNCTION, 0},
+  {"FOLLOWLOCATION", CURLOPT_FOLLOWLOCATION, CURLOT_LONG, 0},
+  {"FORBID_REUSE", CURLOPT_FORBID_REUSE, CURLOT_LONG, 0},
+  {"FRESH_CONNECT", CURLOPT_FRESH_CONNECT, CURLOT_LONG, 0},
+  {"FTPAPPEND", CURLOPT_APPEND, CURLOT_LONG, CURLOT_FLAG_ALIAS},
+  {"FTPLISTONLY", CURLOPT_DIRLISTONLY, CURLOT_LONG, CURLOT_FLAG_ALIAS},
+  {"FTPPORT", CURLOPT_FTPPORT, CURLOT_STRING, 0},
+  {"FTPSSLAUTH", CURLOPT_FTPSSLAUTH, CURLOT_VALUES, 0},
+  {"FTP_ACCOUNT", CURLOPT_FTP_ACCOUNT, CURLOT_STRING, 0},
+  {"FTP_ALTERNATIVE_TO_USER", CURLOPT_FTP_ALTERNATIVE_TO_USER,
+   CURLOT_STRING, 0},
+  {"FTP_CREATE_MISSING_DIRS", CURLOPT_FTP_CREATE_MISSING_DIRS,
+   CURLOT_LONG, 0},
+  {"FTP_FILEMETHOD", CURLOPT_FTP_FILEMETHOD, CURLOT_VALUES, 0},
+  {"FTP_RESPONSE_TIMEOUT", CURLOPT_SERVER_RESPONSE_TIMEOUT,
+   CURLOT_LONG, CURLOT_FLAG_ALIAS},
+  {"FTP_SKIP_PASV_IP", CURLOPT_FTP_SKIP_PASV_IP, CURLOT_LONG, 0},
+  {"FTP_SSL", CURLOPT_USE_SSL, CURLOT_VALUES, CURLOT_FLAG_ALIAS},
+  {"FTP_SSL_CCC", CURLOPT_FTP_SSL_CCC, CURLOT_LONG, 0},
+  {"FTP_USE_EPRT", CURLOPT_FTP_USE_EPRT, CURLOT_LONG, 0},
+  {"FTP_USE_EPSV", CURLOPT_FTP_USE_EPSV, CURLOT_LONG, 0},
+  {"FTP_USE_PRET", CURLOPT_FTP_USE_PRET, CURLOT_LONG, 0},
+  {"GSSAPI_DELEGATION", CURLOPT_GSSAPI_DELEGATION, CURLOT_VALUES, 0},
+  {"HAPPY_EYEBALLS_TIMEOUT_MS", CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS,
+   CURLOT_LONG, 0},
+  {"HAPROXYPROTOCOL", CURLOPT_HAPROXYPROTOCOL, CURLOT_LONG, 0},
+  {"HAPROXY_CLIENT_IP", CURLOPT_HAPROXY_CLIENT_IP, CURLOT_STRING, 0},
+  {"HEADER", CURLOPT_HEADER, CURLOT_LONG, 0},
+  {"HEADERDATA", CURLOPT_HEADERDATA, CURLOT_CBPTR, 0},
+  {"HEADERFUNCTION", CURLOPT_HEADERFUNCTION, CURLOT_FUNCTION, 0},
+  {"HEADEROPT", CURLOPT_HEADEROPT, CURLOT_VALUES, 0},
+  {"HSTS", CURLOPT_HSTS, CURLOT_STRING, 0},
+  {"HSTSREADDATA", CURLOPT_HSTSREADDATA, CURLOT_CBPTR, 0},
+  {"HSTSREADFUNCTION", CURLOPT_HSTSREADFUNCTION, CURLOT_FUNCTION, 0},
+  {"HSTSWRITEDATA", CURLOPT_HSTSWRITEDATA, CURLOT_CBPTR, 0},
+  {"HSTSWRITEFUNCTION", CURLOPT_HSTSWRITEFUNCTION, CURLOT_FUNCTION, 0},
+  {"HSTS_CTRL", CURLOPT_HSTS_CTRL, CURLOT_LONG, 0},
+  {"HTTP09_ALLOWED", CURLOPT_HTTP09_ALLOWED, CURLOT_LONG, 0},
+  {"HTTP200ALIASES", CURLOPT_HTTP200ALIASES, CURLOT_SLIST, 0},
+  {"HTTPAUTH", CURLOPT_HTTPAUTH, CURLOT_VALUES, 0},
+  {"HTTPGET", CURLOPT_HTTPGET, CURLOT_LONG, 0},
+  {"HTTPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, 0},
+  {"HTTPPOST", CURLOPT_HTTPPOST, CURLOT_OBJECT, 0},
+  {"HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL, CURLOT_LONG, 0},
+  {"HTTP_CONTENT_DECODING", CURLOPT_HTTP_CONTENT_DECODING, CURLOT_LONG, 0},
+  {"HTTP_TRANSFER_DECODING", CURLOPT_HTTP_TRANSFER_DECODING, CURLOT_LONG, 0},
+  {"HTTP_VERSION", CURLOPT_HTTP_VERSION, CURLOT_VALUES, 0},
+  {"IGNORE_CONTENT_LENGTH", CURLOPT_IGNORE_CONTENT_LENGTH, CURLOT_LONG, 0},
+  {"INFILE", CURLOPT_READDATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS},
+  {"INFILESIZE", CURLOPT_INFILESIZE, CURLOT_LONG, 0},
+  {"INFILESIZE_LARGE", CURLOPT_INFILESIZE_LARGE, CURLOT_OFF_T, 0},
+  {"INTERFACE", CURLOPT_INTERFACE, CURLOT_STRING, 0},
+  {"INTERLEAVEDATA", CURLOPT_INTERLEAVEDATA, CURLOT_CBPTR, 0},
+  {"INTERLEAVEFUNCTION", CURLOPT_INTERLEAVEFUNCTION, CURLOT_FUNCTION, 0},
+  {"IOCTLDATA", CURLOPT_IOCTLDATA, CURLOT_CBPTR, 0},
+  {"IOCTLFUNCTION", CURLOPT_IOCTLFUNCTION, CURLOT_FUNCTION, 0},
+  {"IPRESOLVE", CURLOPT_IPRESOLVE, CURLOT_VALUES, 0},
+  {"ISSUERCERT", CURLOPT_ISSUERCERT, CURLOT_STRING, 0},
+  {"ISSUERCERT_BLOB", CURLOPT_ISSUERCERT_BLOB, CURLOT_BLOB, 0},
+  {"KEEP_SENDING_ON_ERROR", CURLOPT_KEEP_SENDING_ON_ERROR, CURLOT_LONG, 0},
+  {"KEYPASSWD", CURLOPT_KEYPASSWD, CURLOT_STRING, 0},
+  {"KRB4LEVEL", CURLOPT_KRBLEVEL, CURLOT_STRING, CURLOT_FLAG_ALIAS},
+  {"KRBLEVEL", CURLOPT_KRBLEVEL, CURLOT_STRING, 0},
+  {"LOCALPORT", CURLOPT_LOCALPORT, CURLOT_LONG, 0},
+  {"LOCALPORTRANGE", CURLOPT_LOCALPORTRANGE, CURLOT_LONG, 0},
+  {"LOGIN_OPTIONS", CURLOPT_LOGIN_OPTIONS, CURLOT_STRING, 0},
+  {"LOW_SPEED_LIMIT", CURLOPT_LOW_SPEED_LIMIT, CURLOT_LONG, 0},
+  {"LOW_SPEED_TIME", CURLOPT_LOW_SPEED_TIME, CURLOT_LONG, 0},
+  {"MAIL_AUTH", CURLOPT_MAIL_AUTH, CURLOT_STRING, 0},
+  {"MAIL_FROM", CURLOPT_MAIL_FROM, CURLOT_STRING, 0},
+  {"MAIL_RCPT", CURLOPT_MAIL_RCPT, CURLOT_SLIST, 0},
+  {"MAIL_RCPT_ALLLOWFAILS", CURLOPT_MAIL_RCPT_ALLOWFAILS,
+   CURLOT_LONG, CURLOT_FLAG_ALIAS},
+  {"MAIL_RCPT_ALLOWFAILS", CURLOPT_MAIL_RCPT_ALLOWFAILS, CURLOT_LONG, 0},
+  {"MAXAGE_CONN", CURLOPT_MAXAGE_CONN, CURLOT_LONG, 0},
+  {"MAXCONNECTS", CURLOPT_MAXCONNECTS, CURLOT_LONG, 0},
+  {"MAXFILESIZE", CURLOPT_MAXFILESIZE, CURLOT_LONG, 0},
+  {"MAXFILESIZE_LARGE", CURLOPT_MAXFILESIZE_LARGE, CURLOT_OFF_T, 0},
+  {"MAXLIFETIME_CONN", CURLOPT_MAXLIFETIME_CONN, CURLOT_LONG, 0},
+  {"MAXREDIRS", CURLOPT_MAXREDIRS, CURLOT_LONG, 0},
+  {"MAX_RECV_SPEED_LARGE", CURLOPT_MAX_RECV_SPEED_LARGE, CURLOT_OFF_T, 0},
+  {"MAX_SEND_SPEED_LARGE", CURLOPT_MAX_SEND_SPEED_LARGE, CURLOT_OFF_T, 0},
+  {"MIMEPOST", CURLOPT_MIMEPOST, CURLOT_OBJECT, 0},
+  {"MIME_OPTIONS", CURLOPT_MIME_OPTIONS, CURLOT_LONG, 0},
+  {"NETRC", CURLOPT_NETRC, CURLOT_VALUES, 0},
+  {"NETRC_FILE", CURLOPT_NETRC_FILE, CURLOT_STRING, 0},
+  {"NEW_DIRECTORY_PERMS", CURLOPT_NEW_DIRECTORY_PERMS, CURLOT_LONG, 0},
+  {"NEW_FILE_PERMS", CURLOPT_NEW_FILE_PERMS, CURLOT_LONG, 0},
+  {"NOBODY", CURLOPT_NOBODY, CURLOT_LONG, 0},
+  {"NOPROGRESS", CURLOPT_NOPROGRESS, CURLOT_LONG, 0},
+  {"NOPROXY", CURLOPT_NOPROXY, CURLOT_STRING, 0},
+  {"NOSIGNAL", CURLOPT_NOSIGNAL, CURLOT_LONG, 0},
+  {"OPENSOCKETDATA", CURLOPT_OPENSOCKETDATA, CURLOT_CBPTR, 0},
+  {"OPENSOCKETFUNCTION", CURLOPT_OPENSOCKETFUNCTION, CURLOT_FUNCTION, 0},
+  {"PASSWORD", CURLOPT_PASSWORD, CURLOT_STRING, 0},
+  {"PATH_AS_IS", CURLOPT_PATH_AS_IS, CURLOT_LONG, 0},
+  {"PINNEDPUBLICKEY", CURLOPT_PINNEDPUBLICKEY, CURLOT_STRING, 0},
+  {"PIPEWAIT", CURLOPT_PIPEWAIT, CURLOT_LONG, 0},
+  {"PORT", CURLOPT_PORT, CURLOT_LONG, 0},
+  {"POST", CURLOPT_POST, CURLOT_LONG, 0},
+  {"POST301", CURLOPT_POSTREDIR, CURLOT_VALUES, CURLOT_FLAG_ALIAS},
+  {"POSTFIELDS", CURLOPT_POSTFIELDS, CURLOT_OBJECT, 0},
+  {"POSTFIELDSIZE", CURLOPT_POSTFIELDSIZE, CURLOT_LONG, 0},
+  {"POSTFIELDSIZE_LARGE", CURLOPT_POSTFIELDSIZE_LARGE, CURLOT_OFF_T, 0},
+  {"POSTQUOTE", CURLOPT_POSTQUOTE, CURLOT_SLIST, 0},
+  {"POSTREDIR", CURLOPT_POSTREDIR, CURLOT_VALUES, 0},
+  {"PREQUOTE", CURLOPT_PREQUOTE, CURLOT_SLIST, 0},
+  {"PREREQDATA", CURLOPT_PREREQDATA, CURLOT_CBPTR, 0},
+  {"PREREQFUNCTION", CURLOPT_PREREQFUNCTION, CURLOT_FUNCTION, 0},
+  {"PRE_PROXY", CURLOPT_PRE_PROXY, CURLOT_STRING, 0},
+  {"PRIVATE", CURLOPT_PRIVATE, CURLOT_OBJECT, 0},
+  {"PROGRESSDATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS},
+  {"PROGRESSFUNCTION", CURLOPT_PROGRESSFUNCTION, CURLOT_FUNCTION, 0},
+  {"PROTOCOLS", CURLOPT_PROTOCOLS, CURLOT_LONG, 0},
+  {"PROTOCOLS_STR", CURLOPT_PROTOCOLS_STR, CURLOT_STRING, 0},
+  {"PROXY", CURLOPT_PROXY, CURLOT_STRING, 0},
+  {"PROXYAUTH", CURLOPT_PROXYAUTH, CURLOT_VALUES, 0},
+  {"PROXYHEADER", CURLOPT_PROXYHEADER, CURLOT_SLIST, 0},
+  {"PROXYPASSWORD", CURLOPT_PROXYPASSWORD, CURLOT_STRING, 0},
+  {"PROXYPORT", CURLOPT_PROXYPORT, CURLOT_LONG, 0},
+  {"PROXYTYPE", CURLOPT_PROXYTYPE, CURLOT_VALUES, 0},
+  {"PROXYUSERNAME", CURLOPT_PROXYUSERNAME, CURLOT_STRING, 0},
+  {"PROXYUSERPWD", CURLOPT_PROXYUSERPWD, CURLOT_STRING, 0},
+  {"PROXY_CAINFO", CURLOPT_PROXY_CAINFO, CURLOT_STRING, 0},
+  {"PROXY_CAINFO_BLOB", CURLOPT_PROXY_CAINFO_BLOB, CURLOT_BLOB, 0},
+  {"PROXY_CAPATH", CURLOPT_PROXY_CAPATH, CURLOT_STRING, 0},
+  {"PROXY_CRLFILE", CURLOPT_PROXY_CRLFILE, CURLOT_STRING, 0},
+  {"PROXY_ISSUERCERT", CURLOPT_PROXY_ISSUERCERT, CURLOT_STRING, 0},
+  {"PROXY_ISSUERCERT_BLOB", CURLOPT_PROXY_ISSUERCERT_BLOB, CURLOT_BLOB, 0},
+  {"PROXY_KEYPASSWD", CURLOPT_PROXY_KEYPASSWD, CURLOT_STRING, 0},
+  {"PROXY_PINNEDPUBLICKEY", CURLOPT_PROXY_PINNEDPUBLICKEY, CURLOT_STRING, 0},
+  {"PROXY_SERVICE_NAME", CURLOPT_PROXY_SERVICE_NAME, CURLOT_STRING, 0},
+  {"PROXY_SSLCERT", CURLOPT_PROXY_SSLCERT, CURLOT_STRING, 0},
+  {"PROXY_SSLCERTTYPE", CURLOPT_PROXY_SSLCERTTYPE, CURLOT_STRING, 0},
+  {"PROXY_SSLCERT_BLOB", CURLOPT_PROXY_SSLCERT_BLOB, CURLOT_BLOB, 0},
+  {"PROXY_SSLKEY", CURLOPT_PROXY_SSLKEY, CURLOT_STRING, 0},
+  {"PROXY_SSLKEYTYPE", CURLOPT_PROXY_SSLKEYTYPE, CURLOT_STRING, 0},
+  {"PROXY_SSLKEY_BLOB", CURLOPT_PROXY_SSLKEY_BLOB, CURLOT_BLOB, 0},
+  {"PROXY_SSLVERSION", CURLOPT_PROXY_SSLVERSION, CURLOT_VALUES, 0},
+  {"PROXY_SSL_CIPHER_LIST", CURLOPT_PROXY_SSL_CIPHER_LIST, CURLOT_STRING, 0},
+  {"PROXY_SSL_OPTIONS", CURLOPT_PROXY_SSL_OPTIONS, CURLOT_LONG, 0},
+  {"PROXY_SSL_VERIFYHOST", CURLOPT_PROXY_SSL_VERIFYHOST, CURLOT_LONG, 0},
+  {"PROXY_SSL_VERIFYPEER", CURLOPT_PROXY_SSL_VERIFYPEER, CURLOT_LONG, 0},
+  {"PROXY_TLS13_CIPHERS", CURLOPT_PROXY_TLS13_CIPHERS, CURLOT_STRING, 0},
+  {"PROXY_TLSAUTH_PASSWORD", CURLOPT_PROXY_TLSAUTH_PASSWORD,
+   CURLOT_STRING, 0},
+  {"PROXY_TLSAUTH_TYPE", CURLOPT_PROXY_TLSAUTH_TYPE, CURLOT_STRING, 0},
+  {"PROXY_TLSAUTH_USERNAME", CURLOPT_PROXY_TLSAUTH_USERNAME,
+   CURLOT_STRING, 0},
+  {"PROXY_TRANSFER_MODE", CURLOPT_PROXY_TRANSFER_MODE, CURLOT_LONG, 0},
+  {"PUT", CURLOPT_PUT, CURLOT_LONG, 0},
+  {"QUICK_EXIT", CURLOPT_QUICK_EXIT, CURLOT_LONG, 0},
+  {"QUOTE", CURLOPT_QUOTE, CURLOT_SLIST, 0},
+  {"RANDOM_FILE", CURLOPT_RANDOM_FILE, CURLOT_STRING, 0},
+  {"RANGE", CURLOPT_RANGE, CURLOT_STRING, 0},
+  {"READDATA", CURLOPT_READDATA, CURLOT_CBPTR, 0},
+  {"READFUNCTION", CURLOPT_READFUNCTION, CURLOT_FUNCTION, 0},
+  {"REDIR_PROTOCOLS", CURLOPT_REDIR_PROTOCOLS, CURLOT_LONG, 0},
+  {"REDIR_PROTOCOLS_STR", CURLOPT_REDIR_PROTOCOLS_STR, CURLOT_STRING, 0},
+  {"REFERER", CURLOPT_REFERER, CURLOT_STRING, 0},
+  {"REQUEST_TARGET", CURLOPT_REQUEST_TARGET, CURLOT_STRING, 0},
+  {"RESOLVE", CURLOPT_RESOLVE, CURLOT_SLIST, 0},
+  {"RESOLVER_START_DATA", CURLOPT_RESOLVER_START_DATA, CURLOT_CBPTR, 0},
+  {"RESOLVER_START_FUNCTION", CURLOPT_RESOLVER_START_FUNCTION,
+   CURLOT_FUNCTION, 0},
+  {"RESUME_FROM", CURLOPT_RESUME_FROM, CURLOT_LONG, 0},
+  {"RESUME_FROM_LARGE", CURLOPT_RESUME_FROM_LARGE, CURLOT_OFF_T, 0},
+  {"RTSPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, CURLOT_FLAG_ALIAS},
+  {"RTSP_CLIENT_CSEQ", CURLOPT_RTSP_CLIENT_CSEQ, CURLOT_LONG, 0},
+  {"RTSP_REQUEST", CURLOPT_RTSP_REQUEST, CURLOT_VALUES, 0},
+  {"RTSP_SERVER_CSEQ", CURLOPT_RTSP_SERVER_CSEQ, CURLOT_LONG, 0},
+  {"RTSP_SESSION_ID", CURLOPT_RTSP_SESSION_ID, CURLOT_STRING, 0},
+  {"RTSP_STREAM_URI", CURLOPT_RTSP_STREAM_URI, CURLOT_STRING, 0},
+  {"RTSP_TRANSPORT", CURLOPT_RTSP_TRANSPORT, CURLOT_STRING, 0},
+  {"SASL_AUTHZID", CURLOPT_SASL_AUTHZID, CURLOT_STRING, 0},
+  {"SASL_IR", CURLOPT_SASL_IR, CURLOT_LONG, 0},
+  {"SEEKDATA", CURLOPT_SEEKDATA, CURLOT_CBPTR, 0},
+  {"SEEKFUNCTION", CURLOPT_SEEKFUNCTION, CURLOT_FUNCTION, 0},
+  {"SERVER_RESPONSE_TIMEOUT", CURLOPT_SERVER_RESPONSE_TIMEOUT,
+   CURLOT_LONG, 0},
+  {"SERVER_RESPONSE_TIMEOUT_MS", CURLOPT_SERVER_RESPONSE_TIMEOUT_MS,
+   CURLOT_LONG, 0},
+  {"SERVICE_NAME", CURLOPT_SERVICE_NAME, CURLOT_STRING, 0},
+  {"SHARE", CURLOPT_SHARE, CURLOT_OBJECT, 0},
+  {"SOCKOPTDATA", CURLOPT_SOCKOPTDATA, CURLOT_CBPTR, 0},
+  {"SOCKOPTFUNCTION", CURLOPT_SOCKOPTFUNCTION, CURLOT_FUNCTION, 0},
+  {"SOCKS5_AUTH", CURLOPT_SOCKS5_AUTH, CURLOT_LONG, 0},
+  {"SOCKS5_GSSAPI_NEC", CURLOPT_SOCKS5_GSSAPI_NEC, CURLOT_LONG, 0},
+  {"SOCKS5_GSSAPI_SERVICE", CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOT_STRING, 0},
+  {"SSH_AUTH_TYPES", CURLOPT_SSH_AUTH_TYPES, CURLOT_VALUES, 0},
+  {"SSH_COMPRESSION", CURLOPT_SSH_COMPRESSION, CURLOT_LONG, 0},
+  {"SSH_HOSTKEYDATA", CURLOPT_SSH_HOSTKEYDATA, CURLOT_CBPTR, 0},
+  {"SSH_HOSTKEYFUNCTION", CURLOPT_SSH_HOSTKEYFUNCTION, CURLOT_FUNCTION, 0},
+  {"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
+   CURLOT_STRING, 0},
+  {"SSH_HOST_PUBLIC_KEY_SHA256", CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256,
+   CURLOT_STRING, 0},
+  {"SSH_KEYDATA", CURLOPT_SSH_KEYDATA, CURLOT_CBPTR, 0},
+  {"SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION, CURLOT_FUNCTION, 0},
+  {"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS, CURLOT_STRING, 0},
+  {"SSH_PRIVATE_KEYFILE", CURLOPT_SSH_PRIVATE_KEYFILE, CURLOT_STRING, 0},
+  {"SSH_PUBLIC_KEYFILE", CURLOPT_SSH_PUBLIC_KEYFILE, CURLOT_STRING, 0},
+  {"SSLCERT", CURLOPT_SSLCERT, CURLOT_STRING, 0},
+  {"SSLCERTPASSWD", CURLOPT_KEYPASSWD, CURLOT_STRING, CURLOT_FLAG_ALIAS},
+  {"SSLCERTTYPE", CURLOPT_SSLCERTTYPE, CURLOT_STRING, 0},
+  {"SSLCERT_BLOB", CURLOPT_SSLCERT_BLOB, CURLOT_BLOB, 0},
+  {"SSLENGINE", CURLOPT_SSLENGINE, CURLOT_STRING, 0},
+  {"SSLENGINE_DEFAULT", CURLOPT_SSLENGINE_DEFAULT, CURLOT_LONG, 0},
+  {"SSLKEY", CURLOPT_SSLKEY, CURLOT_STRING, 0},
+  {"SSLKEYPASSWD", CURLOPT_KEYPASSWD, CURLOT_STRING, CURLOT_FLAG_ALIAS},
+  {"SSLKEYTYPE", CURLOPT_SSLKEYTYPE, CURLOT_STRING, 0},
+  {"SSLKEY_BLOB", CURLOPT_SSLKEY_BLOB, CURLOT_BLOB, 0},
+  {"SSLVERSION", CURLOPT_SSLVERSION, CURLOT_VALUES, 0},
+  {"SSL_CIPHER_LIST", CURLOPT_SSL_CIPHER_LIST, CURLOT_STRING, 0},
+  {"SSL_CTX_DATA", CURLOPT_SSL_CTX_DATA, CURLOT_CBPTR, 0},
+  {"SSL_CTX_FUNCTION", CURLOPT_SSL_CTX_FUNCTION, CURLOT_FUNCTION, 0},
+  {"SSL_EC_CURVES", CURLOPT_SSL_EC_CURVES, CURLOT_STRING, 0},
+  {"SSL_ENABLE_ALPN", CURLOPT_SSL_ENABLE_ALPN, CURLOT_LONG, 0},
+  {"SSL_ENABLE_NPN", CURLOPT_SSL_ENABLE_NPN, CURLOT_LONG, 0},
+  {"SSL_FALSESTART", CURLOPT_SSL_FALSESTART, CURLOT_LONG, 0},
+  {"SSL_OPTIONS", CURLOPT_SSL_OPTIONS, CURLOT_VALUES, 0},
+  {"SSL_SESSIONID_CACHE", CURLOPT_SSL_SESSIONID_CACHE, CURLOT_LONG, 0},
+  {"SSL_VERIFYHOST", CURLOPT_SSL_VERIFYHOST, CURLOT_LONG, 0},
+  {"SSL_VERIFYPEER", CURLOPT_SSL_VERIFYPEER, CURLOT_LONG, 0},
+  {"SSL_VERIFYSTATUS", CURLOPT_SSL_VERIFYSTATUS, CURLOT_LONG, 0},
+  {"STDERR", CURLOPT_STDERR, CURLOT_OBJECT, 0},
+  {"STREAM_DEPENDS", CURLOPT_STREAM_DEPENDS, CURLOT_OBJECT, 0},
+  {"STREAM_DEPENDS_E", CURLOPT_STREAM_DEPENDS_E, CURLOT_OBJECT, 0},
+  {"STREAM_WEIGHT", CURLOPT_STREAM_WEIGHT, CURLOT_LONG, 0},
+  {"SUPPRESS_CONNECT_HEADERS", CURLOPT_SUPPRESS_CONNECT_HEADERS,
+   CURLOT_LONG, 0},
+  {"TCP_FASTOPEN", CURLOPT_TCP_FASTOPEN, CURLOT_LONG, 0},
+  {"TCP_KEEPALIVE", CURLOPT_TCP_KEEPALIVE, CURLOT_LONG, 0},
+  {"TCP_KEEPIDLE", CURLOPT_TCP_KEEPIDLE, CURLOT_LONG, 0},
+  {"TCP_KEEPINTVL", CURLOPT_TCP_KEEPINTVL, CURLOT_LONG, 0},
+  {"TCP_NODELAY", CURLOPT_TCP_NODELAY, CURLOT_LONG, 0},
+  {"TELNETOPTIONS", CURLOPT_TELNETOPTIONS, CURLOT_SLIST, 0},
+  {"TFTP_BLKSIZE", CURLOPT_TFTP_BLKSIZE, CURLOT_LONG, 0},
+  {"TFTP_NO_OPTIONS", CURLOPT_TFTP_NO_OPTIONS, CURLOT_LONG, 0},
+  {"TIMECONDITION", CURLOPT_TIMECONDITION, CURLOT_VALUES, 0},
+  {"TIMEOUT", CURLOPT_TIMEOUT, CURLOT_LONG, 0},
+  {"TIMEOUT_MS", CURLOPT_TIMEOUT_MS, CURLOT_LONG, 0},
+  {"TIMEVALUE", CURLOPT_TIMEVALUE, CURLOT_LONG, 0},
+  {"TIMEVALUE_LARGE", CURLOPT_TIMEVALUE_LARGE, CURLOT_OFF_T, 0},
+  {"TLS13_CIPHERS", CURLOPT_TLS13_CIPHERS, CURLOT_STRING, 0},
+  {"TLSAUTH_PASSWORD", CURLOPT_TLSAUTH_PASSWORD, CURLOT_STRING, 0},
+  {"TLSAUTH_TYPE", CURLOPT_TLSAUTH_TYPE, CURLOT_STRING, 0},
+  {"TLSAUTH_USERNAME", CURLOPT_TLSAUTH_USERNAME, CURLOT_STRING, 0},
+  {"TRAILERDATA", CURLOPT_TRAILERDATA, CURLOT_CBPTR, 0},
+  {"TRAILERFUNCTION", CURLOPT_TRAILERFUNCTION, CURLOT_FUNCTION, 0},
+  {"TRANSFERTEXT", CURLOPT_TRANSFERTEXT, CURLOT_LONG, 0},
+  {"TRANSFER_ENCODING", CURLOPT_TRANSFER_ENCODING, CURLOT_LONG, 0},
+  {"UNIX_SOCKET_PATH", CURLOPT_UNIX_SOCKET_PATH, CURLOT_STRING, 0},
+  {"UNRESTRICTED_AUTH", CURLOPT_UNRESTRICTED_AUTH, CURLOT_LONG, 0},
+  {"UPKEEP_INTERVAL_MS", CURLOPT_UPKEEP_INTERVAL_MS, CURLOT_LONG, 0},
+  {"UPLOAD", CURLOPT_UPLOAD, CURLOT_LONG, 0},
+  {"UPLOAD_BUFFERSIZE", CURLOPT_UPLOAD_BUFFERSIZE, CURLOT_LONG, 0},
+  {"URL", CURLOPT_URL, CURLOT_STRING, 0},
+  {"USERAGENT", CURLOPT_USERAGENT, CURLOT_STRING, 0},
+  {"USERNAME", CURLOPT_USERNAME, CURLOT_STRING, 0},
+  {"USERPWD", CURLOPT_USERPWD, CURLOT_STRING, 0},
+  {"USE_SSL", CURLOPT_USE_SSL, CURLOT_VALUES, 0},
+  {"VERBOSE", CURLOPT_VERBOSE, CURLOT_LONG, 0},
+  {"WILDCARDMATCH", CURLOPT_WILDCARDMATCH, CURLOT_LONG, 0},
+  {"WRITEDATA", CURLOPT_WRITEDATA, CURLOT_CBPTR, 0},
+  {"WRITEFUNCTION", CURLOPT_WRITEFUNCTION, CURLOT_FUNCTION, 0},
+  {"WRITEHEADER", CURLOPT_HEADERDATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS},
+  {"WS_OPTIONS", CURLOPT_WS_OPTIONS, CURLOT_LONG, 0},
+  {"XFERINFODATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, 0},
+  {"XFERINFOFUNCTION", CURLOPT_XFERINFOFUNCTION, CURLOT_FUNCTION, 0},
+  {"XOAUTH2_BEARER", CURLOPT_XOAUTH2_BEARER, CURLOT_STRING, 0},
+  {NULL, CURLOPT_LASTENTRY, CURLOT_LONG, 0} /* end of table */
+};
+
+#ifdef DEBUGBUILD
+/*
+ * Curl_easyopts_check() is a debug-only function that returns non-zero
+ * if this source file is not in sync with the options listed in curl/curl.h
+ */
+int Curl_easyopts_check(void)
+{
+  return ((CURLOPT_LASTENTRY%10000) != (324 + 1));
+}
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/easyoptions.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/easyoptions.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/easyoptions.h	(revision 104083)
@@ -0,0 +1,37 @@
+#ifndef HEADER_CURL_EASYOPTIONS_H
+#define HEADER_CURL_EASYOPTIONS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* should probably go into the public header */
+
+#include <curl/curl.h>
+
+/* generated table with all easy options */
+extern struct curl_easyoption Curl_easyopts[];
+
+#ifdef DEBUGBUILD
+int Curl_easyopts_check(void);
+#endif
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/escape.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/escape.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/escape.c	(revision 104083)
@@ -0,0 +1,234 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* Escape and unescape URL encoding in strings. The functions return a new
+ * allocated string or NULL if an error occurred.  */
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "warnless.h"
+#include "escape.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* for ABI-compatibility with previous versions */
+char *curl_escape(const char *string, int inlength)
+{
+  return curl_easy_escape(NULL, string, inlength);
+}
+
+/* for ABI-compatibility with previous versions */
+char *curl_unescape(const char *string, int length)
+{
+  return curl_easy_unescape(NULL, string, length, NULL);
+}
+
+/* Escapes for URL the given unescaped string of given length.
+ * 'data' is ignored since 7.82.0.
+ */
+char *curl_easy_escape(struct Curl_easy *data, const char *string,
+                       int inlength)
+{
+  size_t length;
+  struct dynbuf d;
+  (void)data;
+
+  if(inlength < 0)
+    return NULL;
+
+  Curl_dyn_init(&d, CURL_MAX_INPUT_LENGTH * 3);
+
+  length = (inlength?(size_t)inlength:strlen(string));
+  if(!length)
+    return strdup("");
+
+  while(length--) {
+    unsigned char in = *string++; /* treat the characters unsigned */
+
+    if(ISUNRESERVED(in)) {
+      /* append this */
+      if(Curl_dyn_addn(&d, &in, 1))
+        return NULL;
+    }
+    else {
+      /* encode it */
+      const char hex[] = "0123456789ABCDEF";
+      char out[3]={'%'};
+      out[1] = hex[in>>4];
+      out[2] = hex[in & 0xf];
+      if(Curl_dyn_addn(&d, out, 3))
+        return NULL;
+    }
+  }
+
+  return Curl_dyn_ptr(&d);
+}
+
+static const unsigned char hextable[] = {
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,       /* 0x30 - 0x3f */
+  0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,       /* 0x50 - 0x5f */
+  0, 10, 11, 12, 13, 14, 15                             /* 0x60 - 0x66 */
+};
+
+/* the input is a single hex digit */
+#define onehex2dec(x) hextable[x - '0']
+
+/*
+ * Curl_urldecode() URL decodes the given string.
+ *
+ * Returns a pointer to a malloced string in *ostring with length given in
+ * *olen. If length == 0, the length is assumed to be strlen(string).
+ *
+ * ctrl options:
+ * - REJECT_NADA: accept everything
+ * - REJECT_CTRL: rejects control characters (byte codes lower than 32) in
+ *                the data
+ * - REJECT_ZERO: rejects decoded zero bytes
+ *
+ * The values for the enum starts at 2, to make the assert detect legacy
+ * invokes that used TRUE/FALSE (0 and 1).
+ */
+
+CURLcode Curl_urldecode(const char *string, size_t length,
+                        char **ostring, size_t *olen,
+                        enum urlreject ctrl)
+{
+  size_t alloc;
+  char *ns;
+
+  DEBUGASSERT(string);
+  DEBUGASSERT(ctrl >= REJECT_NADA); /* crash on TRUE/FALSE */
+
+  alloc = (length?length:strlen(string));
+  ns = malloc(alloc + 1);
+
+  if(!ns)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* store output string */
+  *ostring = ns;
+
+  while(alloc) {
+    unsigned char in = *string;
+    if(('%' == in) && (alloc > 2) &&
+       ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
+      /* this is two hexadecimal digits following a '%' */
+      in = (unsigned char)(onehex2dec(string[1]) << 4) | onehex2dec(string[2]);
+
+      string += 3;
+      alloc -= 3;
+    }
+    else {
+      string++;
+      alloc--;
+    }
+
+    if(((ctrl == REJECT_CTRL) && (in < 0x20)) ||
+       ((ctrl == REJECT_ZERO) && (in == 0))) {
+      Curl_safefree(*ostring);
+      return CURLE_URL_MALFORMAT;
+    }
+
+    *ns++ = in;
+  }
+  *ns = 0; /* terminate it */
+
+  if(olen)
+    /* store output size */
+    *olen = ns - *ostring;
+
+  return CURLE_OK;
+}
+
+/*
+ * Unescapes the given URL escaped string of given length. Returns a
+ * pointer to a malloced string with length given in *olen.
+ * If length == 0, the length is assumed to be strlen(string).
+ * If olen == NULL, no output length is stored.
+ * 'data' is ignored since 7.82.0.
+ */
+char *curl_easy_unescape(struct Curl_easy *data, const char *string,
+                         int length, int *olen)
+{
+  char *str = NULL;
+  (void)data;
+  if(length >= 0) {
+    size_t inputlen = (size_t)length;
+    size_t outputlen;
+    CURLcode res = Curl_urldecode(string, inputlen, &str, &outputlen,
+                                  REJECT_NADA);
+    if(res)
+      return NULL;
+
+    if(olen) {
+      if(outputlen <= (size_t) INT_MAX)
+        *olen = curlx_uztosi(outputlen);
+      else
+        /* too large to return in an int, fail! */
+        Curl_safefree(str);
+    }
+  }
+  return str;
+}
+
+/* For operating systems/environments that use different malloc/free
+   systems for the app and for this library, we provide a free that uses
+   the library's memory system */
+void curl_free(void *p)
+{
+  free(p);
+}
+
+/*
+ * Curl_hexencode()
+ *
+ * Converts binary input to lowercase hex-encoded ASCII output.
+ * Null-terminated.
+ */
+void Curl_hexencode(const unsigned char *src, size_t len, /* input length */
+                    unsigned char *out, size_t olen) /* output buffer size */
+{
+  const char *hex = "0123456789abcdef";
+  DEBUGASSERT(src && len && (olen >= 3));
+  if(src && len && (olen >= 3)) {
+    while(len-- && (olen >= 3)) {
+      /* clang-tidy warns on this line without this comment: */
+      /* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */
+      *out++ = hex[(*src & 0xF0)>>4];
+      *out++ = hex[*src & 0x0F];
+      ++src;
+      olen -= 2;
+    }
+    *out = 0;
+  }
+  else if(olen)
+    *out = 0;
+}
Index: trunk/src/libs/curl-8.7.1/lib/escape.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/escape.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/escape.h	(revision 104083)
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_ESCAPE_H
+#define HEADER_CURL_ESCAPE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+/* Escape and unescape URL encoding in strings. The functions return a new
+ * allocated string or NULL if an error occurred.  */
+
+#include "curl_ctype.h"
+
+enum urlreject {
+  REJECT_NADA = 2,
+  REJECT_CTRL,
+  REJECT_ZERO
+};
+
+CURLcode Curl_urldecode(const char *string, size_t length,
+                        char **ostring, size_t *olen,
+                        enum urlreject ctrl);
+
+void Curl_hexencode(const unsigned char *src, size_t len, /* input length */
+                    unsigned char *out, size_t olen); /* output buffer size */
+
+#endif /* HEADER_CURL_ESCAPE_H */
Index: trunk/src/libs/curl-8.7.1/lib/file.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/file.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/file.c	(revision 104083)
@@ -0,0 +1,597 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FILE
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "strtoofft.h"
+#include "urldata.h"
+#include <curl/curl.h>
+#include "progress.h"
+#include "sendf.h"
+#include "escape.h"
+#include "file.h"
+#include "speedcheck.h"
+#include "getinfo.h"
+#include "multiif.h"
+#include "transfer.h"
+#include "url.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "warnless.h"
+#include "curl_range.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if defined(_WIN32) || defined(MSDOS) || defined(__EMX__)
+#define DOS_FILESYSTEM 1
+#elif defined(__amigaos4__)
+#define AMIGA_FILESYSTEM 1
+#endif
+
+#ifdef OPEN_NEEDS_ARG3
+#  define open_readonly(p,f) open((p),(f),(0))
+#else
+#  define open_readonly(p,f) open((p),(f))
+#endif
+
+/*
+ * Forward declarations.
+ */
+
+static CURLcode file_do(struct Curl_easy *data, bool *done);
+static CURLcode file_done(struct Curl_easy *data,
+                          CURLcode status, bool premature);
+static CURLcode file_connect(struct Curl_easy *data, bool *done);
+static CURLcode file_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                bool dead_connection);
+static CURLcode file_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+
+/*
+ * FILE scheme handler.
+ */
+
+const struct Curl_handler Curl_handler_file = {
+  "FILE",                               /* scheme */
+  file_setup_connection,                /* setup_connection */
+  file_do,                              /* do_it */
+  file_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  file_connect,                         /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  file_disconnect,                      /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  0,                                    /* defport */
+  CURLPROTO_FILE,                       /* protocol */
+  CURLPROTO_FILE,                       /* family */
+  PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */
+};
+
+
+static CURLcode file_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  (void)conn;
+  /* allocate the FILE specific struct */
+  data->req.p.file = calloc(1, sizeof(struct FILEPROTO));
+  if(!data->req.p.file)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+/*
+ * file_connect() gets called from Curl_protocol_connect() to allow us to
+ * do protocol-specific actions at connect-time.  We emulate a
+ * connect-then-transfer protocol and "connect" to the file here
+ */
+static CURLcode file_connect(struct Curl_easy *data, bool *done)
+{
+  char *real_path;
+  struct FILEPROTO *file = data->req.p.file;
+  int fd;
+#ifdef DOS_FILESYSTEM
+  size_t i;
+  char *actual_path;
+#endif
+  size_t real_path_len;
+  CURLcode result;
+
+  if(file->path) {
+    /* already connected.
+     * the handler->connect_it() is normally only called once, but
+     * FILE does a special check on setting up the connection which
+     * calls this explicitly. */
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  result = Curl_urldecode(data->state.up.path, 0, &real_path,
+                          &real_path_len, REJECT_ZERO);
+  if(result)
+    return result;
+
+#ifdef DOS_FILESYSTEM
+  /* If the first character is a slash, and there's
+     something that looks like a drive at the beginning of
+     the path, skip the slash.  If we remove the initial
+     slash in all cases, paths without drive letters end up
+     relative to the current directory which isn't how
+     browsers work.
+
+     Some browsers accept | instead of : as the drive letter
+     separator, so we do too.
+
+     On other platforms, we need the slash to indicate an
+     absolute pathname.  On Windows, absolute paths start
+     with a drive letter.
+  */
+  actual_path = real_path;
+  if((actual_path[0] == '/') &&
+      actual_path[1] &&
+     (actual_path[2] == ':' || actual_path[2] == '|')) {
+    actual_path[2] = ':';
+    actual_path++;
+    real_path_len--;
+  }
+
+  /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */
+  for(i = 0; i < real_path_len; ++i)
+    if(actual_path[i] == '/')
+      actual_path[i] = '\\';
+    else if(!actual_path[i]) { /* binary zero */
+      Curl_safefree(real_path);
+      return CURLE_URL_MALFORMAT;
+    }
+
+  fd = open_readonly(actual_path, O_RDONLY|O_BINARY);
+  file->path = actual_path;
+#else
+  if(memchr(real_path, 0, real_path_len)) {
+    /* binary zeroes indicate foul play */
+    Curl_safefree(real_path);
+    return CURLE_URL_MALFORMAT;
+  }
+
+  #ifdef AMIGA_FILESYSTEM
+  /*
+   * A leading slash in an AmigaDOS path denotes the parent
+   * directory, and hence we block this as it is relative.
+   * Absolute paths start with 'volumename:', so we check for
+   * this first. Failing that, we treat the path as a real unix
+   * path, but only if the application was compiled with -lunix.
+   */
+  fd = -1;
+  file->path = real_path;
+
+  if(real_path[0] == '/') {
+    extern int __unix_path_semantics;
+    if(strchr(real_path + 1, ':')) {
+      /* Amiga absolute path */
+      fd = open_readonly(real_path + 1, O_RDONLY);
+      file->path++;
+    }
+    else if(__unix_path_semantics) {
+      /* -lunix fallback */
+      fd = open_readonly(real_path, O_RDONLY);
+    }
+  }
+  #else
+  fd = open_readonly(real_path, O_RDONLY);
+  file->path = real_path;
+  #endif
+#endif
+  Curl_safefree(file->freepath);
+  file->freepath = real_path; /* free this when done */
+
+  file->fd = fd;
+  if(!data->state.upload && (fd == -1)) {
+    failf(data, "Couldn't open file %s", data->state.up.path);
+    file_done(data, CURLE_FILE_COULDNT_READ_FILE, FALSE);
+    return CURLE_FILE_COULDNT_READ_FILE;
+  }
+  *done = TRUE;
+
+  return CURLE_OK;
+}
+
+static CURLcode file_done(struct Curl_easy *data,
+                          CURLcode status, bool premature)
+{
+  struct FILEPROTO *file = data->req.p.file;
+  (void)status; /* not used */
+  (void)premature; /* not used */
+
+  if(file) {
+    Curl_safefree(file->freepath);
+    file->path = NULL;
+    if(file->fd != -1)
+      close(file->fd);
+    file->fd = -1;
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode file_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                bool dead_connection)
+{
+  (void)dead_connection; /* not used */
+  (void)conn;
+  return file_done(data, CURLE_OK, FALSE);
+}
+
+#ifdef DOS_FILESYSTEM
+#define DIRSEP '\\'
+#else
+#define DIRSEP '/'
+#endif
+
+static CURLcode file_upload(struct Curl_easy *data)
+{
+  struct FILEPROTO *file = data->req.p.file;
+  const char *dir = strchr(file->path, DIRSEP);
+  int fd;
+  int mode;
+  CURLcode result = CURLE_OK;
+  char *xfer_ulbuf;
+  size_t xfer_ulblen;
+  curl_off_t bytecount = 0;
+  struct_stat file_stat;
+  const char *sendbuf;
+  bool eos = FALSE;
+
+  /*
+   * Since FILE: doesn't do the full init, we need to provide some extra
+   * assignments here.
+   */
+
+  if(!dir)
+    return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
+
+  if(!dir[1])
+    return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
+
+#ifdef O_BINARY
+#define MODE_DEFAULT O_WRONLY|O_CREAT|O_BINARY
+#else
+#define MODE_DEFAULT O_WRONLY|O_CREAT
+#endif
+
+  if(data->state.resume_from)
+    mode = MODE_DEFAULT|O_APPEND;
+  else
+    mode = MODE_DEFAULT|O_TRUNC;
+
+  fd = open(file->path, mode, data->set.new_file_perms);
+  if(fd < 0) {
+    failf(data, "Can't open %s for writing", file->path);
+    return CURLE_WRITE_ERROR;
+  }
+
+  if(-1 != data->state.infilesize)
+    /* known size of data to "upload" */
+    Curl_pgrsSetUploadSize(data, data->state.infilesize);
+
+  /* treat the negative resume offset value as the case of "-" */
+  if(data->state.resume_from < 0) {
+    if(fstat(fd, &file_stat)) {
+      close(fd);
+      failf(data, "Can't get the size of %s", file->path);
+      return CURLE_WRITE_ERROR;
+    }
+    data->state.resume_from = (curl_off_t)file_stat.st_size;
+  }
+
+  result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
+  if(result)
+    goto out;
+
+  while(!result && !eos) {
+    size_t nread;
+    ssize_t nwrite;
+    size_t readcount;
+
+    result = Curl_client_read(data, xfer_ulbuf, xfer_ulblen, &readcount, &eos);
+    if(result)
+      break;
+
+    if(!readcount)
+      break;
+
+    nread = readcount;
+
+    /* skip bytes before resume point */
+    if(data->state.resume_from) {
+      if((curl_off_t)nread <= data->state.resume_from) {
+        data->state.resume_from -= nread;
+        nread = 0;
+        sendbuf = xfer_ulbuf;
+      }
+      else {
+        sendbuf = xfer_ulbuf + data->state.resume_from;
+        nread -= (size_t)data->state.resume_from;
+        data->state.resume_from = 0;
+      }
+    }
+    else
+      sendbuf = xfer_ulbuf;
+
+    /* write the data to the target */
+    nwrite = write(fd, sendbuf, nread);
+    if((size_t)nwrite != nread) {
+      result = CURLE_SEND_ERROR;
+      break;
+    }
+
+    bytecount += nread;
+
+    Curl_pgrsSetUploadCounter(data, bytecount);
+
+    if(Curl_pgrsUpdate(data))
+      result = CURLE_ABORTED_BY_CALLBACK;
+    else
+      result = Curl_speedcheck(data, Curl_now());
+  }
+  if(!result && Curl_pgrsUpdate(data))
+    result = CURLE_ABORTED_BY_CALLBACK;
+
+out:
+  close(fd);
+  Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);
+
+  return result;
+}
+
+/*
+ * file_do() is the protocol-specific function for the do-phase, separated
+ * from the connect-phase above. Other protocols merely setup the transfer in
+ * the do-phase, to have it done in the main transfer loop but since some
+ * platforms we support don't allow select()ing etc on file handles (as
+ * opposed to sockets) we instead perform the whole do-operation in this
+ * function.
+ */
+static CURLcode file_do(struct Curl_easy *data, bool *done)
+{
+  /* This implementation ignores the host name in conformance with
+     RFC 1738. Only local files (reachable via the standard file system)
+     are supported. This means that files on remotely mounted directories
+     (via NFS, Samba, NT sharing) can be accessed through a file:// URL
+  */
+  CURLcode result = CURLE_OK;
+  struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
+                          Windows version to have a different struct without
+                          having to redefine the simple word 'stat' */
+  curl_off_t expected_size = -1;
+  bool size_known;
+  bool fstated = FALSE;
+  int fd;
+  struct FILEPROTO *file;
+  char *xfer_buf;
+  size_t xfer_blen;
+
+  *done = TRUE; /* unconditionally */
+
+  if(data->state.upload)
+    return file_upload(data);
+
+  file = data->req.p.file;
+
+  /* get the fd from the connection phase */
+  fd = file->fd;
+
+  /* VMS: This only works reliable for STREAMLF files */
+  if(-1 != fstat(fd, &statbuf)) {
+    if(!S_ISDIR(statbuf.st_mode))
+      expected_size = statbuf.st_size;
+    /* and store the modification time */
+    data->info.filetime = statbuf.st_mtime;
+    fstated = TRUE;
+  }
+
+  if(fstated && !data->state.range && data->set.timecondition) {
+    if(!Curl_meets_timecondition(data, data->info.filetime)) {
+      *done = TRUE;
+      return CURLE_OK;
+    }
+  }
+
+  if(fstated) {
+    time_t filetime;
+    struct tm buffer;
+    const struct tm *tm = &buffer;
+    char header[80];
+    int headerlen;
+    char accept_ranges[24]= { "Accept-ranges: bytes\r\n" };
+    if(expected_size >= 0) {
+      headerlen = msnprintf(header, sizeof(header),
+                "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
+                expected_size);
+      result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
+      if(result)
+        return result;
+
+      result = Curl_client_write(data, CLIENTWRITE_HEADER,
+                                 accept_ranges, strlen(accept_ranges));
+      if(result != CURLE_OK)
+        return result;
+    }
+
+    filetime = (time_t)statbuf.st_mtime;
+    result = Curl_gmtime(filetime, &buffer);
+    if(result)
+      return result;
+
+    /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+    headerlen = msnprintf(header, sizeof(header),
+              "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s",
+              Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+              tm->tm_mday,
+              Curl_month[tm->tm_mon],
+              tm->tm_year + 1900,
+              tm->tm_hour,
+              tm->tm_min,
+              tm->tm_sec,
+              data->req.no_body ? "": "\r\n");
+    result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
+    if(result)
+      return result;
+    /* set the file size to make it available post transfer */
+    Curl_pgrsSetDownloadSize(data, expected_size);
+    if(data->req.no_body)
+      return result;
+  }
+
+  /* Check whether file range has been specified */
+  result = Curl_range(data);
+  if(result)
+    return result;
+
+  /* Adjust the start offset in case we want to get the N last bytes
+   * of the stream if the filesize could be determined */
+  if(data->state.resume_from < 0) {
+    if(!fstated) {
+      failf(data, "Can't get the size of file.");
+      return CURLE_READ_ERROR;
+    }
+    data->state.resume_from += (curl_off_t)statbuf.st_size;
+  }
+
+  if(data->state.resume_from > 0) {
+    /* We check explicitly if we have a start offset, because
+     * expected_size may be -1 if we don't know how large the file is,
+     * in which case we should not adjust it. */
+    if(data->state.resume_from <= expected_size)
+      expected_size -= data->state.resume_from;
+    else {
+      failf(data, "failed to resume file:// transfer");
+      return CURLE_BAD_DOWNLOAD_RESUME;
+    }
+  }
+
+  /* A high water mark has been specified so we obey... */
+  if(data->req.maxdownload > 0)
+    expected_size = data->req.maxdownload;
+
+  if(!fstated || (expected_size <= 0))
+    size_known = FALSE;
+  else
+    size_known = TRUE;
+
+  /* The following is a shortcut implementation of file reading
+     this is both more efficient than the former call to download() and
+     it avoids problems with select() and recv() on file descriptors
+     in Winsock */
+  if(size_known)
+    Curl_pgrsSetDownloadSize(data, expected_size);
+
+  if(data->state.resume_from) {
+    if(data->state.resume_from !=
+       lseek(fd, data->state.resume_from, SEEK_SET))
+      return CURLE_BAD_DOWNLOAD_RESUME;
+  }
+
+  result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
+  if(result)
+    goto out;
+
+  while(!result) {
+    ssize_t nread;
+    /* Don't fill a whole buffer if we want less than all data */
+    size_t bytestoread;
+
+    if(size_known) {
+      bytestoread = (expected_size < (curl_off_t)(xfer_blen-1)) ?
+        curlx_sotouz(expected_size) : (xfer_blen-1);
+    }
+    else
+      bytestoread = xfer_blen-1;
+
+    nread = read(fd, xfer_buf, bytestoread);
+
+    if(nread > 0)
+      xfer_buf[nread] = 0;
+
+    if(nread <= 0 || (size_known && (expected_size == 0)))
+      break;
+
+    if(size_known)
+      expected_size -= nread;
+
+    result = Curl_client_write(data, CLIENTWRITE_BODY, xfer_buf, nread);
+    if(result)
+      goto out;
+
+    if(Curl_pgrsUpdate(data))
+      result = CURLE_ABORTED_BY_CALLBACK;
+    else
+      result = Curl_speedcheck(data, Curl_now());
+    if(result)
+      goto out;
+  }
+  if(Curl_pgrsUpdate(data))
+    result = CURLE_ABORTED_BY_CALLBACK;
+
+out:
+  Curl_multi_xfer_buf_release(data, xfer_buf);
+  return result;
+}
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/file.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/file.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/file.h	(revision 104083)
@@ -0,0 +1,42 @@
+#ifndef HEADER_CURL_FILE_H
+#define HEADER_CURL_FILE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+
+/****************************************************************************
+ * FILE unique setup
+ ***************************************************************************/
+struct FILEPROTO {
+  char *path; /* the path we operate on */
+  char *freepath; /* pointer to the allocated block we must free, this might
+                     differ from the 'path' pointer */
+  int fd;     /* open file descriptor to read from! */
+};
+
+#ifndef CURL_DISABLE_FILE
+extern const struct Curl_handler Curl_handler_file;
+#endif
+
+#endif /* HEADER_CURL_FILE_H */
Index: trunk/src/libs/curl-8.7.1/lib/fileinfo.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/fileinfo.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/fileinfo.c	(revision 104083)
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#ifndef CURL_DISABLE_FTP
+#include "strdup.h"
+#include "fileinfo.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+struct fileinfo *Curl_fileinfo_alloc(void)
+{
+  return calloc(1, sizeof(struct fileinfo));
+}
+
+void Curl_fileinfo_cleanup(struct fileinfo *finfo)
+{
+  if(!finfo)
+    return;
+
+  Curl_dyn_free(&finfo->buf);
+  free(finfo);
+}
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/fileinfo.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/fileinfo.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/fileinfo.h	(revision 104083)
@@ -0,0 +1,40 @@
+#ifndef HEADER_CURL_FILEINFO_H
+#define HEADER_CURL_FILEINFO_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+#include "llist.h"
+#include "dynbuf.h"
+
+struct fileinfo {
+  struct curl_fileinfo info;
+  struct Curl_llist_element list;
+  struct dynbuf buf;
+};
+
+struct fileinfo *Curl_fileinfo_alloc(void);
+void Curl_fileinfo_cleanup(struct fileinfo *finfo);
+
+#endif /* HEADER_CURL_FILEINFO_H */
Index: trunk/src/libs/curl-8.7.1/lib/fopen.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/fopen.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/fopen.c	(revision 104083)
@@ -0,0 +1,158 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) ||  \
+  !defined(CURL_DISABLE_HSTS)
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "urldata.h"
+#include "rand.h"
+#include "fopen.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+  The dirslash() function breaks a null-terminated pathname string into
+  directory and filename components then returns the directory component up
+  to, *AND INCLUDING*, a final '/'.  If there is no directory in the path,
+  this instead returns a "" string.
+
+  This function returns a pointer to malloc'ed memory.
+
+  The input path to this function is expected to have a file name part.
+*/
+
+#ifdef _WIN32
+#define PATHSEP "\\"
+#define IS_SEP(x) (((x) == '/') || ((x) == '\\'))
+#elif defined(MSDOS) || defined(__EMX__) || defined(OS2)
+#define PATHSEP "\\"
+#define IS_SEP(x) ((x) == '\\')
+#else
+#define PATHSEP "/"
+#define IS_SEP(x) ((x) == '/')
+#endif
+
+static char *dirslash(const char *path)
+{
+  size_t n;
+  struct dynbuf out;
+  DEBUGASSERT(path);
+  Curl_dyn_init(&out, CURL_MAX_INPUT_LENGTH);
+  n = strlen(path);
+  if(n) {
+    /* find the rightmost path separator, if any */
+    while(n && !IS_SEP(path[n-1]))
+      --n;
+    /* skip over all the path separators, if any */
+    while(n && IS_SEP(path[n-1]))
+      --n;
+  }
+  if(Curl_dyn_addn(&out, path, n))
+    return NULL;
+  /* if there was a directory, append a single trailing slash */
+  if(n && Curl_dyn_addn(&out, PATHSEP, 1))
+    return NULL;
+  return Curl_dyn_ptr(&out);
+}
+
+/*
+ * Curl_fopen() opens a file for writing with a temp name, to be renamed
+ * to the final name when completed. If there is an existing file using this
+ * name at the time of the open, this function will clone the mode from that
+ * file.  if 'tempname' is non-NULL, it needs a rename after the file is
+ * written.
+ */
+CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
+                    FILE **fh, char **tempname)
+{
+  CURLcode result = CURLE_WRITE_ERROR;
+  unsigned char randbuf[41];
+  char *tempstore = NULL;
+  struct_stat sb;
+  int fd = -1;
+  char *dir = NULL;
+  *tempname = NULL;
+
+  *fh = fopen(filename, FOPEN_WRITETEXT);
+  if(!*fh)
+    goto fail;
+  if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode)) {
+    return CURLE_OK;
+  }
+  fclose(*fh);
+  *fh = NULL;
+
+  result = Curl_rand_alnum(data, randbuf, sizeof(randbuf));
+  if(result)
+    goto fail;
+
+  dir = dirslash(filename);
+  if(dir) {
+    /* The temp file name should not end up too long for the target file
+       system */
+    tempstore = aprintf("%s%s.tmp", dir, randbuf);
+    free(dir);
+  }
+
+  if(!tempstore) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto fail;
+  }
+
+  result = CURLE_WRITE_ERROR;
+#if (defined(ANDROID) || defined(__ANDROID__)) && \
+    (defined(__i386__) || defined(__arm__))
+  fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, (mode_t)(0600|sb.st_mode));
+#else
+  fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, 0600|sb.st_mode);
+#endif
+  if(fd == -1)
+    goto fail;
+
+  *fh = fdopen(fd, FOPEN_WRITETEXT);
+  if(!*fh)
+    goto fail;
+
+  *tempname = tempstore;
+  return CURLE_OK;
+
+fail:
+  if(fd != -1) {
+    close(fd);
+    unlink(tempstore);
+  }
+
+  free(tempstore);
+  return result;
+}
+
+#endif /* ! disabled */
Index: trunk/src/libs/curl-8.7.1/lib/fopen.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/fopen.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/fopen.h	(revision 104083)
@@ -0,0 +1,30 @@
+#ifndef HEADER_CURL_FOPEN_H
+#define HEADER_CURL_FOPEN_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
+                    FILE **fh, char **tempname);
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/formdata.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/formdata.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/formdata.c	(revision 104083)
@@ -0,0 +1,958 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "formdata.h"
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
+
+#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
+#include <libgen.h>
+#endif
+
+#include "urldata.h" /* for struct Curl_easy */
+#include "mime.h"
+#include "vtls/vtls.h"
+#include "strcase.h"
+#include "sendf.h"
+#include "strdup.h"
+#include "rand.h"
+#include "warnless.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
+#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
+#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
+#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
+#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
+#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
+#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
+
+/***************************************************************************
+ *
+ * AddHttpPost()
+ *
+ * Adds an HttpPost structure to the list, if parent_post is given becomes
+ * a subpost of parent_post instead of a direct list element.
+ *
+ * Returns newly allocated HttpPost on success and NULL if malloc failed.
+ *
+ ***************************************************************************/
+static struct curl_httppost *
+AddHttpPost(char *name, size_t namelength,
+            char *value, curl_off_t contentslength,
+            char *buffer, size_t bufferlength,
+            char *contenttype,
+            long flags,
+            struct curl_slist *contentHeader,
+            char *showfilename, char *userp,
+            struct curl_httppost *parent_post,
+            struct curl_httppost **httppost,
+            struct curl_httppost **last_post)
+{
+  struct curl_httppost *post;
+  if(!namelength && name)
+    namelength = strlen(name);
+  if((bufferlength > LONG_MAX) || (namelength > LONG_MAX))
+    /* avoid overflow in typecasts below */
+    return NULL;
+  post = calloc(1, sizeof(struct curl_httppost));
+  if(post) {
+    post->name = name;
+    post->namelength = (long)namelength;
+    post->contents = value;
+    post->contentlen = contentslength;
+    post->buffer = buffer;
+    post->bufferlength = (long)bufferlength;
+    post->contenttype = contenttype;
+    post->contentheader = contentHeader;
+    post->showfilename = showfilename;
+    post->userp = userp;
+    post->flags = flags | CURL_HTTPPOST_LARGE;
+  }
+  else
+    return NULL;
+
+  if(parent_post) {
+    /* now, point our 'more' to the original 'more' */
+    post->more = parent_post->more;
+
+    /* then move the original 'more' to point to ourselves */
+    parent_post->more = post;
+  }
+  else {
+    /* make the previous point to this */
+    if(*last_post)
+      (*last_post)->next = post;
+    else
+      (*httppost) = post;
+
+    (*last_post) = post;
+  }
+  return post;
+}
+
+/***************************************************************************
+ *
+ * AddFormInfo()
+ *
+ * Adds a FormInfo structure to the list presented by parent_form_info.
+ *
+ * Returns newly allocated FormInfo on success and NULL if malloc failed/
+ * parent_form_info is NULL.
+ *
+ ***************************************************************************/
+static struct FormInfo *AddFormInfo(char *value,
+                                    char *contenttype,
+                                    struct FormInfo *parent_form_info)
+{
+  struct FormInfo *form_info;
+  form_info = calloc(1, sizeof(struct FormInfo));
+  if(!form_info)
+    return NULL;
+  if(value)
+    form_info->value = value;
+  if(contenttype)
+    form_info->contenttype = contenttype;
+  form_info->flags = HTTPPOST_FILENAME;
+
+  if(parent_form_info) {
+    /* now, point our 'more' to the original 'more' */
+    form_info->more = parent_form_info->more;
+
+    /* then move the original 'more' to point to ourselves */
+    parent_form_info->more = form_info;
+  }
+
+  return form_info;
+}
+
+/***************************************************************************
+ *
+ * FormAdd()
+ *
+ * Stores a formpost parameter and builds the appropriate linked list.
+ *
+ * Has two principal functionalities: using files and byte arrays as
+ * post parts. Byte arrays are either copied or just the pointer is stored
+ * (as the user requests) while for files only the filename and not the
+ * content is stored.
+ *
+ * While you may have only one byte array for each name, multiple filenames
+ * are allowed (and because of this feature CURLFORM_END is needed after
+ * using CURLFORM_FILE).
+ *
+ * Examples:
+ *
+ * Simple name/value pair with copied contents:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
+ *
+ * name/value pair where only the content pointer is remembered:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
+ * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
+ *
+ * storing a filename (CONTENTTYPE is optional!):
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
+ * CURLFORM_END);
+ *
+ * storing multiple filenames:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
+ *
+ * Returns:
+ * CURL_FORMADD_OK             on success
+ * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
+ * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
+ * CURL_FORMADD_NULL           if a null pointer was given for a char
+ * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
+ * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
+ * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
+ * CURL_FORMADD_MEMORY         if an HttpPost struct cannot be allocated
+ * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
+ * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
+ *
+ ***************************************************************************/
+
+static
+CURLFORMcode FormAdd(struct curl_httppost **httppost,
+                     struct curl_httppost **last_post,
+                     va_list params)
+{
+  struct FormInfo *first_form, *current_form, *form = NULL;
+  CURLFORMcode return_value = CURL_FORMADD_OK;
+  const char *prevtype = NULL;
+  struct curl_httppost *post = NULL;
+  CURLformoption option;
+  struct curl_forms *forms = NULL;
+  char *array_value = NULL; /* value read from an array */
+
+  /* This is a state variable, that if TRUE means that we're parsing an
+     array that we got passed to us. If FALSE we're parsing the input
+     va_list arguments. */
+  bool array_state = FALSE;
+
+  /*
+   * We need to allocate the first struct to fill in.
+   */
+  first_form = calloc(1, sizeof(struct FormInfo));
+  if(!first_form)
+    return CURL_FORMADD_MEMORY;
+
+  current_form = first_form;
+
+  /*
+   * Loop through all the options set. Break if we have an error to report.
+   */
+  while(return_value == CURL_FORMADD_OK) {
+
+    /* first see if we have more parts of the array param */
+    if(array_state && forms) {
+      /* get the upcoming option from the given array */
+      option = forms->option;
+      array_value = (char *)forms->value;
+
+      forms++; /* advance this to next entry */
+      if(CURLFORM_END == option) {
+        /* end of array state */
+        array_state = FALSE;
+        continue;
+      }
+    }
+    else {
+      /* This is not array-state, get next option. This gets an 'int' with
+         va_arg() because CURLformoption might be a smaller type than int and
+         might cause compiler warnings and wrong behavior. */
+      option = (CURLformoption)va_arg(params, int);
+      if(CURLFORM_END == option)
+        break;
+    }
+
+    switch(option) {
+    case CURLFORM_ARRAY:
+      if(array_state)
+        /* we don't support an array from within an array */
+        return_value = CURL_FORMADD_ILLEGAL_ARRAY;
+      else {
+        forms = va_arg(params, struct curl_forms *);
+        if(forms)
+          array_state = TRUE;
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+
+      /*
+       * Set the Name property.
+       */
+    case CURLFORM_PTRNAME:
+      current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
+
+      FALLTHROUGH();
+    case CURLFORM_COPYNAME:
+      if(current_form->name)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *name = array_state?
+          array_value:va_arg(params, char *);
+        if(name)
+          current_form->name = name; /* store for the moment */
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+    case CURLFORM_NAMELENGTH:
+      if(current_form->namelength)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else
+        current_form->namelength =
+          array_state?(size_t)array_value:(size_t)va_arg(params, long);
+      break;
+
+      /*
+       * Set the contents property.
+       */
+    case CURLFORM_PTRCONTENTS:
+      current_form->flags |= HTTPPOST_PTRCONTENTS;
+      FALLTHROUGH();
+    case CURLFORM_COPYCONTENTS:
+      if(current_form->value)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *value =
+          array_state?array_value:va_arg(params, char *);
+        if(value)
+          current_form->value = value; /* store for the moment */
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+    case CURLFORM_CONTENTSLENGTH:
+      current_form->contentslength =
+        array_state?(size_t)array_value:(size_t)va_arg(params, long);
+      break;
+
+    case CURLFORM_CONTENTLEN:
+      current_form->flags |= CURL_HTTPPOST_LARGE;
+      current_form->contentslength =
+        array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
+      break;
+
+      /* Get contents from a given file name */
+    case CURLFORM_FILECONTENT:
+      if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        const char *filename = array_state?
+          array_value:va_arg(params, char *);
+        if(filename) {
+          current_form->value = strdup(filename);
+          if(!current_form->value)
+            return_value = CURL_FORMADD_MEMORY;
+          else {
+            current_form->flags |= HTTPPOST_READFILE;
+            current_form->value_alloc = TRUE;
+          }
+        }
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+
+      /* We upload a file */
+    case CURLFORM_FILE:
+      {
+        const char *filename = array_state?array_value:
+          va_arg(params, char *);
+
+        if(current_form->value) {
+          if(current_form->flags & HTTPPOST_FILENAME) {
+            if(filename) {
+              char *fname = strdup(filename);
+              if(!fname)
+                return_value = CURL_FORMADD_MEMORY;
+              else {
+                form = AddFormInfo(fname, NULL, current_form);
+                if(!form) {
+                  free(fname);
+                  return_value = CURL_FORMADD_MEMORY;
+                }
+                else {
+                  form->value_alloc = TRUE;
+                  current_form = form;
+                  form = NULL;
+                }
+              }
+            }
+            else
+              return_value = CURL_FORMADD_NULL;
+          }
+          else
+            return_value = CURL_FORMADD_OPTION_TWICE;
+        }
+        else {
+          if(filename) {
+            current_form->value = strdup(filename);
+            if(!current_form->value)
+              return_value = CURL_FORMADD_MEMORY;
+            else {
+              current_form->flags |= HTTPPOST_FILENAME;
+              current_form->value_alloc = TRUE;
+            }
+          }
+          else
+            return_value = CURL_FORMADD_NULL;
+        }
+        break;
+      }
+
+    case CURLFORM_BUFFERPTR:
+      current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
+      if(current_form->buffer)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *buffer =
+          array_state?array_value:va_arg(params, char *);
+        if(buffer) {
+          current_form->buffer = buffer; /* store for the moment */
+          current_form->value = buffer; /* make it non-NULL to be accepted
+                                           as fine */
+        }
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+
+    case CURLFORM_BUFFERLENGTH:
+      if(current_form->bufferlength)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else
+        current_form->bufferlength =
+          array_state?(size_t)array_value:(size_t)va_arg(params, long);
+      break;
+
+    case CURLFORM_STREAM:
+      current_form->flags |= HTTPPOST_CALLBACK;
+      if(current_form->userp)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *userp =
+          array_state?array_value:va_arg(params, char *);
+        if(userp) {
+          current_form->userp = userp;
+          current_form->value = userp; /* this isn't strictly true but we
+                                          derive a value from this later on
+                                          and we need this non-NULL to be
+                                          accepted as a fine form part */
+        }
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+
+    case CURLFORM_CONTENTTYPE:
+      {
+        const char *contenttype =
+          array_state?array_value:va_arg(params, char *);
+        if(current_form->contenttype) {
+          if(current_form->flags & HTTPPOST_FILENAME) {
+            if(contenttype) {
+              char *type = strdup(contenttype);
+              if(!type)
+                return_value = CURL_FORMADD_MEMORY;
+              else {
+                form = AddFormInfo(NULL, type, current_form);
+                if(!form) {
+                  free(type);
+                  return_value = CURL_FORMADD_MEMORY;
+                }
+                else {
+                  form->contenttype_alloc = TRUE;
+                  current_form = form;
+                  form = NULL;
+                }
+              }
+            }
+            else
+              return_value = CURL_FORMADD_NULL;
+          }
+          else
+            return_value = CURL_FORMADD_OPTION_TWICE;
+        }
+        else {
+          if(contenttype) {
+            current_form->contenttype = strdup(contenttype);
+            if(!current_form->contenttype)
+              return_value = CURL_FORMADD_MEMORY;
+            else
+              current_form->contenttype_alloc = TRUE;
+          }
+          else
+            return_value = CURL_FORMADD_NULL;
+        }
+        break;
+      }
+    case CURLFORM_CONTENTHEADER:
+      {
+        /* this "cast increases required alignment of target type" but
+           we consider it OK anyway */
+        struct curl_slist *list = array_state?
+          (struct curl_slist *)(void *)array_value:
+          va_arg(params, struct curl_slist *);
+
+        if(current_form->contentheader)
+          return_value = CURL_FORMADD_OPTION_TWICE;
+        else
+          current_form->contentheader = list;
+
+        break;
+      }
+    case CURLFORM_FILENAME:
+    case CURLFORM_BUFFER:
+      {
+        const char *filename = array_state?array_value:
+          va_arg(params, char *);
+        if(current_form->showfilename)
+          return_value = CURL_FORMADD_OPTION_TWICE;
+        else {
+          current_form->showfilename = strdup(filename);
+          if(!current_form->showfilename)
+            return_value = CURL_FORMADD_MEMORY;
+          else
+            current_form->showfilename_alloc = TRUE;
+        }
+        break;
+      }
+    default:
+      return_value = CURL_FORMADD_UNKNOWN_OPTION;
+      break;
+    }
+  }
+
+  if(CURL_FORMADD_OK != return_value) {
+    /* On error, free allocated fields for all nodes of the FormInfo linked
+       list without deallocating nodes. List nodes are deallocated later on */
+    struct FormInfo *ptr;
+    for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
+      if(ptr->name_alloc) {
+        Curl_safefree(ptr->name);
+        ptr->name_alloc = FALSE;
+      }
+      if(ptr->value_alloc) {
+        Curl_safefree(ptr->value);
+        ptr->value_alloc = FALSE;
+      }
+      if(ptr->contenttype_alloc) {
+        Curl_safefree(ptr->contenttype);
+        ptr->contenttype_alloc = FALSE;
+      }
+      if(ptr->showfilename_alloc) {
+        Curl_safefree(ptr->showfilename);
+        ptr->showfilename_alloc = FALSE;
+      }
+    }
+  }
+
+  if(CURL_FORMADD_OK == return_value) {
+    /* go through the list, check for completeness and if everything is
+     * alright add the HttpPost item otherwise set return_value accordingly */
+
+    post = NULL;
+    for(form = first_form;
+        form != NULL;
+        form = form->more) {
+      if(((!form->name || !form->value) && !post) ||
+         ( (form->contentslength) &&
+           (form->flags & HTTPPOST_FILENAME) ) ||
+         ( (form->flags & HTTPPOST_FILENAME) &&
+           (form->flags & HTTPPOST_PTRCONTENTS) ) ||
+
+         ( (!form->buffer) &&
+           (form->flags & HTTPPOST_BUFFER) &&
+           (form->flags & HTTPPOST_PTRBUFFER) ) ||
+
+         ( (form->flags & HTTPPOST_READFILE) &&
+           (form->flags & HTTPPOST_PTRCONTENTS) )
+        ) {
+        return_value = CURL_FORMADD_INCOMPLETE;
+        break;
+      }
+      if(((form->flags & HTTPPOST_FILENAME) ||
+          (form->flags & HTTPPOST_BUFFER)) &&
+         !form->contenttype) {
+        char *f = (form->flags & HTTPPOST_BUFFER)?
+          form->showfilename : form->value;
+        char const *type;
+        type = Curl_mime_contenttype(f);
+        if(!type)
+          type = prevtype;
+        if(!type)
+          type = FILE_CONTENTTYPE_DEFAULT;
+
+        /* our contenttype is missing */
+        form->contenttype = strdup(type);
+        if(!form->contenttype) {
+          return_value = CURL_FORMADD_MEMORY;
+          break;
+        }
+        form->contenttype_alloc = TRUE;
+      }
+      if(form->name && form->namelength) {
+        /* Name should not contain nul bytes. */
+        size_t i;
+        for(i = 0; i < form->namelength; i++)
+          if(!form->name[i]) {
+            return_value = CURL_FORMADD_NULL;
+            break;
+          }
+        if(return_value != CURL_FORMADD_OK)
+          break;
+      }
+      if(!(form->flags & HTTPPOST_PTRNAME) &&
+         (form == first_form) ) {
+        /* Note that there's small risk that form->name is NULL here if the
+           app passed in a bad combo, so we better check for that first. */
+        if(form->name) {
+          /* copy name (without strdup; possibly not null-terminated) */
+          form->name = Curl_memdup0(form->name, form->namelength?
+                                    form->namelength:
+                                    strlen(form->name));
+        }
+        if(!form->name) {
+          return_value = CURL_FORMADD_MEMORY;
+          break;
+        }
+        form->name_alloc = TRUE;
+      }
+      if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
+                          HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
+                          HTTPPOST_CALLBACK)) && form->value) {
+        /* copy value (without strdup; possibly contains null characters) */
+        size_t clen  = (size_t) form->contentslength;
+        if(!clen)
+          clen = strlen(form->value) + 1;
+
+        form->value = Curl_memdup(form->value, clen);
+
+        if(!form->value) {
+          return_value = CURL_FORMADD_MEMORY;
+          break;
+        }
+        form->value_alloc = TRUE;
+      }
+      post = AddHttpPost(form->name, form->namelength,
+                         form->value, form->contentslength,
+                         form->buffer, form->bufferlength,
+                         form->contenttype, form->flags,
+                         form->contentheader, form->showfilename,
+                         form->userp,
+                         post, httppost,
+                         last_post);
+
+      if(!post) {
+        return_value = CURL_FORMADD_MEMORY;
+        break;
+      }
+
+      if(form->contenttype)
+        prevtype = form->contenttype;
+    }
+    if(CURL_FORMADD_OK != return_value) {
+      /* On error, free allocated fields for nodes of the FormInfo linked
+         list which are not already owned by the httppost linked list
+         without deallocating nodes. List nodes are deallocated later on */
+      struct FormInfo *ptr;
+      for(ptr = form; ptr != NULL; ptr = ptr->more) {
+        if(ptr->name_alloc) {
+          Curl_safefree(ptr->name);
+          ptr->name_alloc = FALSE;
+        }
+        if(ptr->value_alloc) {
+          Curl_safefree(ptr->value);
+          ptr->value_alloc = FALSE;
+        }
+        if(ptr->contenttype_alloc) {
+          Curl_safefree(ptr->contenttype);
+          ptr->contenttype_alloc = FALSE;
+        }
+        if(ptr->showfilename_alloc) {
+          Curl_safefree(ptr->showfilename);
+          ptr->showfilename_alloc = FALSE;
+        }
+      }
+    }
+  }
+
+  /* Always deallocate FormInfo linked list nodes without touching node
+     fields given that these have either been deallocated or are owned
+     now by the httppost linked list */
+  while(first_form) {
+    struct FormInfo *ptr = first_form->more;
+    free(first_form);
+    first_form = ptr;
+  }
+
+  return return_value;
+}
+
+/*
+ * curl_formadd() is a public API to add a section to the multipart formpost.
+ *
+ * @unittest: 1308
+ */
+
+CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+                          struct curl_httppost **last_post,
+                          ...)
+{
+  va_list arg;
+  CURLFORMcode result;
+  va_start(arg, last_post);
+  result = FormAdd(httppost, last_post, arg);
+  va_end(arg);
+  return result;
+}
+
+/*
+ * curl_formget()
+ * Serialize a curl_httppost struct.
+ * Returns 0 on success.
+ *
+ * @unittest: 1308
+ */
+int curl_formget(struct curl_httppost *form, void *arg,
+                 curl_formget_callback append)
+{
+  CURLcode result;
+  curl_mimepart toppart;
+
+  Curl_mime_initpart(&toppart); /* default form is empty */
+  result = Curl_getformdata(NULL, &toppart, form, NULL);
+  if(!result)
+    result = Curl_mime_prepare_headers(NULL, &toppart, "multipart/form-data",
+                                       NULL, MIMESTRATEGY_FORM);
+
+  while(!result) {
+    char buffer[8192];
+    size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart);
+
+    if(!nread)
+      break;
+
+    if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) {
+      result = CURLE_READ_ERROR;
+      if(nread == CURL_READFUNC_ABORT)
+        result = CURLE_ABORTED_BY_CALLBACK;
+    }
+  }
+
+  Curl_mime_cleanpart(&toppart);
+  return (int) result;
+}
+
+/*
+ * curl_formfree() is an external function to free up a whole form post
+ * chain
+ */
+void curl_formfree(struct curl_httppost *form)
+{
+  struct curl_httppost *next;
+
+  if(!form)
+    /* no form to free, just get out of this */
+    return;
+
+  do {
+    next = form->next;  /* the following form line */
+
+    /* recurse to sub-contents */
+    curl_formfree(form->more);
+
+    if(!(form->flags & HTTPPOST_PTRNAME))
+      free(form->name); /* free the name */
+    if(!(form->flags &
+         (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
+      )
+      free(form->contents); /* free the contents */
+    free(form->contenttype); /* free the content type */
+    free(form->showfilename); /* free the faked file name */
+    free(form);       /* free the struct */
+    form = next;
+  } while(form); /* continue */
+}
+
+
+/* Set mime part name, taking care of non null-terminated name string. */
+static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
+{
+  char *zname;
+  CURLcode res;
+
+  if(!name || !len)
+    return curl_mime_name(part, name);
+  zname = Curl_memdup0(name, len);
+  if(!zname)
+    return CURLE_OUT_OF_MEMORY;
+  res = curl_mime_name(part, zname);
+  free(zname);
+  return res;
+}
+
+/* wrap call to fseeko so it matches the calling convention of callback */
+static int fseeko_wrapper(void *stream, curl_off_t offset, int whence)
+{
+#if defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
+  return fseeko(stream, (off_t)offset, whence);
+#elif defined(HAVE__FSEEKI64)
+  return _fseeki64(stream, (__int64)offset, whence);
+#else
+  if(offset > LONG_MAX)
+    return -1;
+  return fseek(stream, (long)offset, whence);
+#endif
+}
+
+/*
+ * Curl_getformdata() converts a linked list of "meta data" into a mime
+ * structure. The input list is in 'post', while the output is stored in
+ * mime part at '*finalform'.
+ *
+ * This function will not do a failf() for the potential memory failures but
+ * should for all other errors it spots. Just note that this function MAY get
+ * a NULL pointer in the 'data' argument.
+ */
+
+CURLcode Curl_getformdata(struct Curl_easy *data,
+                          curl_mimepart *finalform,
+                          struct curl_httppost *post,
+                          curl_read_callback fread_func)
+{
+  CURLcode result = CURLE_OK;
+  curl_mime *form = NULL;
+  curl_mimepart *part;
+  struct curl_httppost *file;
+
+  Curl_mime_cleanpart(finalform); /* default form is empty */
+
+  if(!post)
+    return result; /* no input => no output! */
+
+  form = curl_mime_init(data);
+  if(!form)
+    result = CURLE_OUT_OF_MEMORY;
+
+  if(!result)
+    result = curl_mime_subparts(finalform, form);
+
+  /* Process each top part. */
+  for(; !result && post; post = post->next) {
+    /* If we have more than a file here, create a mime subpart and fill it. */
+    curl_mime *multipart = form;
+    if(post->more) {
+      part = curl_mime_addpart(form);
+      if(!part)
+        result = CURLE_OUT_OF_MEMORY;
+      if(!result)
+        result = setname(part, post->name, post->namelength);
+      if(!result) {
+        multipart = curl_mime_init(data);
+        if(!multipart)
+          result = CURLE_OUT_OF_MEMORY;
+      }
+      if(!result)
+        result = curl_mime_subparts(part, multipart);
+    }
+
+    /* Generate all the part contents. */
+    for(file = post; !result && file; file = file->more) {
+      /* Create the part. */
+      part = curl_mime_addpart(multipart);
+      if(!part)
+        result = CURLE_OUT_OF_MEMORY;
+
+      /* Set the headers. */
+      if(!result)
+        result = curl_mime_headers(part, file->contentheader, 0);
+
+      /* Set the content type. */
+      if(!result && file->contenttype)
+        result = curl_mime_type(part, file->contenttype);
+
+      /* Set field name. */
+      if(!result && !post->more)
+        result = setname(part, post->name, post->namelength);
+
+      /* Process contents. */
+      if(!result) {
+        curl_off_t clen = post->contentslength;
+
+        if(post->flags & CURL_HTTPPOST_LARGE)
+          clen = post->contentlen;
+
+        if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
+          if(!strcmp(file->contents, "-")) {
+            /* There are a few cases where the code below won't work; in
+               particular, freopen(stdin) by the caller is not guaranteed
+               to result as expected. This feature has been kept for backward
+               compatibility: use of "-" pseudo file name should be avoided. */
+            result = curl_mime_data_cb(part, (curl_off_t) -1,
+                                       (curl_read_callback) fread,
+                                       fseeko_wrapper,
+                                       NULL, (void *) stdin);
+          }
+          else
+            result = curl_mime_filedata(part, file->contents);
+          if(!result && (post->flags & HTTPPOST_READFILE))
+            result = curl_mime_filename(part, NULL);
+        }
+        else if(post->flags & HTTPPOST_BUFFER)
+          result = curl_mime_data(part, post->buffer,
+                                  post->bufferlength? post->bufferlength: -1);
+        else if(post->flags & HTTPPOST_CALLBACK) {
+          /* the contents should be read with the callback and the size is set
+             with the contentslength */
+          if(!clen)
+            clen = -1;
+          result = curl_mime_data_cb(part, clen,
+                                     fread_func, NULL, NULL, post->userp);
+        }
+        else {
+          size_t uclen;
+          if(!clen)
+            uclen = CURL_ZERO_TERMINATED;
+          else
+            uclen = (size_t)clen;
+          result = curl_mime_data(part, post->contents, uclen);
+        }
+      }
+
+      /* Set fake file name. */
+      if(!result && post->showfilename)
+        if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
+                                        HTTPPOST_CALLBACK)))
+          result = curl_mime_filename(part, post->showfilename);
+    }
+  }
+
+  if(result)
+    Curl_mime_cleanpart(finalform);
+
+  return result;
+}
+
+#else
+/* if disabled */
+CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+                          struct curl_httppost **last_post,
+                          ...)
+{
+  (void)httppost;
+  (void)last_post;
+  return CURL_FORMADD_DISABLED;
+}
+
+int curl_formget(struct curl_httppost *form, void *arg,
+                 curl_formget_callback append)
+{
+  (void) form;
+  (void) arg;
+  (void) append;
+  return CURL_FORMADD_DISABLED;
+}
+
+void curl_formfree(struct curl_httppost *form)
+{
+  (void)form;
+  /* Nothing to do. */
+}
+
+#endif  /* if disabled */
Index: trunk/src/libs/curl-8.7.1/lib/formdata.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/formdata.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/formdata.h	(revision 104083)
@@ -0,0 +1,59 @@
+#ifndef HEADER_CURL_FORMDATA_H
+#define HEADER_CURL_FORMDATA_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FORM_API
+
+/* used by FormAdd for temporary storage */
+struct FormInfo {
+  char *name;
+  size_t namelength;
+  char *value;
+  curl_off_t contentslength;
+  char *contenttype;
+  long flags;
+  char *buffer;      /* pointer to existing buffer used for file upload */
+  size_t bufferlength;
+  char *showfilename; /* The file name to show. If not set, the actual
+                         file name will be used */
+  char *userp;        /* pointer for the read callback */
+  struct curl_slist *contentheader;
+  struct FormInfo *more;
+  bool name_alloc;
+  bool value_alloc;
+  bool contenttype_alloc;
+  bool showfilename_alloc;
+};
+
+CURLcode Curl_getformdata(struct Curl_easy *data,
+                          curl_mimepart *,
+                          struct curl_httppost *post,
+                          curl_read_callback fread_func);
+#endif /* CURL_DISABLE_FORM_API */
+
+
+#endif /* HEADER_CURL_FORMDATA_H */
Index: trunk/src/libs/curl-8.7.1/lib/ftp.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/ftp.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/ftp.c	(revision 104083)
@@ -0,0 +1,4565 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FTP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "if2ip.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "ftp.h"
+#include "fileinfo.h"
+#include "ftplistparser.h"
+#include "curl_range.h"
+#include "curl_krb5.h"
+#include "strtoofft.h"
+#include "strcase.h"
+#include "vtls/vtls.h"
+#include "cfilters.h"
+#include "cf-socket.h"
+#include "connect.h"
+#include "strerror.h"
+#include "inet_ntop.h"
+#include "inet_pton.h"
+#include "select.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "multiif.h"
+#include "url.h"
+#include "speedcheck.h"
+#include "warnless.h"
+#include "http_proxy.h"
+#include "socks.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif
+
+/* macro to check for a three-digit ftp status code at the start of the
+   given string */
+#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) &&       \
+                          ISDIGIT(line[2]))
+
+/* macro to check for the last line in an FTP server response */
+#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+#define ftp_pasv_verbose(a,b,c,d)  Curl_nop_stmt
+#endif
+
+/* Local API functions */
+#ifndef DEBUGBUILD
+static void _ftp_state(struct Curl_easy *data,
+                       ftpstate newstate);
+#define ftp_state(x,y) _ftp_state(x,y)
+#else
+static void _ftp_state(struct Curl_easy *data,
+                       ftpstate newstate,
+                       int lineno);
+#define ftp_state(x,y) _ftp_state(x,y,__LINE__)
+#endif
+
+static CURLcode ftp_sendquote(struct Curl_easy *data,
+                              struct connectdata *conn,
+                              struct curl_slist *quote);
+static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn);
+static CURLcode ftp_parse_url_path(struct Curl_easy *data);
+static CURLcode ftp_regular_transfer(struct Curl_easy *data, bool *done);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void ftp_pasv_verbose(struct Curl_easy *data,
+                             struct Curl_addrinfo *ai,
+                             char *newhost, /* ascii version */
+                             int port);
+#endif
+static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data);
+static CURLcode ftp_state_mdtm(struct Curl_easy *data);
+static CURLcode ftp_state_quote(struct Curl_easy *data,
+                                bool init, ftpstate instate);
+static CURLcode ftp_nb_type(struct Curl_easy *data,
+                            struct connectdata *conn,
+                            bool ascii, ftpstate newstate);
+static int ftp_need_type(struct connectdata *conn,
+                         bool ascii);
+static CURLcode ftp_do(struct Curl_easy *data, bool *done);
+static CURLcode ftp_done(struct Curl_easy *data,
+                         CURLcode, bool premature);
+static CURLcode ftp_connect(struct Curl_easy *data, bool *done);
+static CURLcode ftp_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn, bool dead_connection);
+static CURLcode ftp_do_more(struct Curl_easy *data, int *completed);
+static CURLcode ftp_multi_statemach(struct Curl_easy *data, bool *done);
+static int ftp_getsock(struct Curl_easy *data, struct connectdata *conn,
+                       curl_socket_t *socks);
+static int ftp_domore_getsock(struct Curl_easy *data,
+                              struct connectdata *conn, curl_socket_t *socks);
+static CURLcode ftp_doing(struct Curl_easy *data,
+                          bool *dophase_done);
+static CURLcode ftp_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn);
+static CURLcode init_wc_data(struct Curl_easy *data);
+static CURLcode wc_statemach(struct Curl_easy *data);
+static void wc_data_dtor(void *ptr);
+static CURLcode ftp_state_retr(struct Curl_easy *data, curl_off_t filesize);
+static CURLcode ftp_readresp(struct Curl_easy *data,
+                             int sockindex,
+                             struct pingpong *pp,
+                             int *ftpcode,
+                             size_t *size);
+static CURLcode ftp_dophase_done(struct Curl_easy *data,
+                                 bool connected);
+
+/*
+ * FTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ftp = {
+  "FTP",                           /* scheme */
+  ftp_setup_connection,            /* setup_connection */
+  ftp_do,                          /* do_it */
+  ftp_done,                        /* done */
+  ftp_do_more,                     /* do_more */
+  ftp_connect,                     /* connect_it */
+  ftp_multi_statemach,             /* connecting */
+  ftp_doing,                       /* doing */
+  ftp_getsock,                     /* proto_getsock */
+  ftp_getsock,                     /* doing_getsock */
+  ftp_domore_getsock,              /* domore_getsock */
+  ZERO_NULL,                       /* perform_getsock */
+  ftp_disconnect,                  /* disconnect */
+  ZERO_NULL,                       /* write_resp */
+  ZERO_NULL,                       /* connection_check */
+  ZERO_NULL,                       /* attach connection */
+  PORT_FTP,                        /* defport */
+  CURLPROTO_FTP,                   /* protocol */
+  CURLPROTO_FTP,                   /* family */
+  PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD |
+  PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP |
+  PROTOPT_WILDCARD /* flags */
+};
+
+
+#ifdef USE_SSL
+/*
+ * FTPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ftps = {
+  "FTPS",                          /* scheme */
+  ftp_setup_connection,            /* setup_connection */
+  ftp_do,                          /* do_it */
+  ftp_done,                        /* done */
+  ftp_do_more,                     /* do_more */
+  ftp_connect,                     /* connect_it */
+  ftp_multi_statemach,             /* connecting */
+  ftp_doing,                       /* doing */
+  ftp_getsock,                     /* proto_getsock */
+  ftp_getsock,                     /* doing_getsock */
+  ftp_domore_getsock,              /* domore_getsock */
+  ZERO_NULL,                       /* perform_getsock */
+  ftp_disconnect,                  /* disconnect */
+  ZERO_NULL,                       /* write_resp */
+  ZERO_NULL,                       /* connection_check */
+  ZERO_NULL,                       /* attach connection */
+  PORT_FTPS,                       /* defport */
+  CURLPROTO_FTPS,                  /* protocol */
+  CURLPROTO_FTP,                   /* family */
+  PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
+  PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */
+};
+#endif
+
+static void close_secondarysocket(struct Curl_easy *data,
+                                  struct connectdata *conn)
+{
+  Curl_conn_close(data, SECONDARYSOCKET);
+  Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET);
+}
+
+/*
+ * NOTE: back in the old days, we added code in the FTP code that made NOBODY
+ * requests on files respond with headers passed to the client/stdout that
+ * looked like HTTP ones.
+ *
+ * This approach is not very elegant, it causes confusion and is error-prone.
+ * It is subject for removal at the next (or at least a future) soname bump.
+ * Until then you can test the effects of the removal by undefining the
+ * following define named CURL_FTP_HTTPSTYLE_HEAD.
+ */
+#define CURL_FTP_HTTPSTYLE_HEAD 1
+
+static void freedirs(struct ftp_conn *ftpc)
+{
+  if(ftpc->dirs) {
+    int i;
+    for(i = 0; i < ftpc->dirdepth; i++) {
+      free(ftpc->dirs[i]);
+      ftpc->dirs[i] = NULL;
+    }
+    free(ftpc->dirs);
+    ftpc->dirs = NULL;
+    ftpc->dirdepth = 0;
+  }
+  Curl_safefree(ftpc->file);
+
+  /* no longer of any use */
+  Curl_safefree(ftpc->newhost);
+}
+
+#ifdef CURL_DO_LINEEND_CONV
+/***********************************************************************
+ *
+ * Lineend Conversions
+ * On ASCII transfers, e.g. directory listings, we might get lines
+ * ending in '\r\n' and we prefer just '\n'.
+ * We might also get a lonely '\r' which we convert into a '\n'.
+ */
+struct ftp_cw_lc_ctx {
+  struct Curl_cwriter super;
+  bool newline_pending;
+};
+
+static CURLcode ftp_cw_lc_write(struct Curl_easy *data,
+                                struct Curl_cwriter *writer, int type,
+                                const char *buf, size_t blen)
+{
+  static const char nl = '\n';
+  struct ftp_cw_lc_ctx *ctx = writer->ctx;
+
+  if(!(type & CLIENTWRITE_BODY) ||
+     data->conn->proto.ftpc.transfertype != 'A')
+    return Curl_cwriter_write(data, writer->next, type, buf, blen);
+
+  /* ASCII mode BODY data, convert lineends */
+  while(blen) {
+    /* do not pass EOS when writing parts */
+    int chunk_type = (type & ~CLIENTWRITE_EOS);
+    const char *cp;
+    size_t chunk_len;
+    CURLcode result;
+
+    if(ctx->newline_pending) {
+      if(buf[0] != '\n') {
+        /* previous chunk ended in '\r' and we do not see a '\n' in this one,
+         * need to write a newline. */
+        result = Curl_cwriter_write(data, writer->next, chunk_type, &nl, 1);
+        if(result)
+          return result;
+      }
+      /* either we just wrote the newline or it is part of the next
+       * chunk of bytes we write. */
+      data->state.crlf_conversions++;
+      ctx->newline_pending = FALSE;
+    }
+
+    cp = memchr(buf, '\r', blen);
+    if(!cp)
+      break;
+
+    /* write the bytes before the '\r', excluding the '\r' */
+    chunk_len = cp - buf;
+    if(chunk_len) {
+      result = Curl_cwriter_write(data, writer->next, chunk_type,
+                                  buf, chunk_len);
+      if(result)
+        return result;
+    }
+    /* skip the '\r', we now have a newline pending */
+    buf = cp + 1;
+    blen = blen - chunk_len - 1;
+    ctx->newline_pending = TRUE;
+  }
+
+  /* Any remaining data does not contain a '\r' */
+  if(blen) {
+    DEBUGASSERT(!ctx->newline_pending);
+    return Curl_cwriter_write(data, writer->next, type, buf, blen);
+  }
+  else if(type & CLIENTWRITE_EOS) {
+    /* EndOfStream, if we have a trailing cr, now is the time to write it */
+    if(ctx->newline_pending) {
+      ctx->newline_pending = FALSE;
+      data->state.crlf_conversions++;
+      return Curl_cwriter_write(data, writer->next, type, &nl, 1);
+    }
+    /* Always pass on the EOS type indicator */
+    return Curl_cwriter_write(data, writer->next, type, buf, 0);
+  }
+  return CURLE_OK;
+}
+
+static const struct Curl_cwtype ftp_cw_lc = {
+  "ftp-lineconv",
+  NULL,
+  Curl_cwriter_def_init,
+  ftp_cw_lc_write,
+  Curl_cwriter_def_close,
+  sizeof(struct ftp_cw_lc_ctx)
+};
+
+#endif /* CURL_DO_LINEEND_CONV */
+/***********************************************************************
+ *
+ * AcceptServerConnect()
+ *
+ * After connection request is received from the server this function is
+ * called to accept the connection and close the listening socket
+ *
+ */
+static CURLcode AcceptServerConnect(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+  curl_socket_t sock = conn->sock[SECONDARYSOCKET];
+  curl_socket_t s = CURL_SOCKET_BAD;
+#ifdef ENABLE_IPV6
+  struct Curl_sockaddr_storage add;
+#else
+  struct sockaddr_in add;
+#endif
+  curl_socklen_t size = (curl_socklen_t) sizeof(add);
+  CURLcode result;
+
+  if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
+    size = sizeof(add);
+
+    s = accept(sock, (struct sockaddr *) &add, &size);
+  }
+
+  if(CURL_SOCKET_BAD == s) {
+    failf(data, "Error accept()ing server connect");
+    return CURLE_FTP_PORT_FAILED;
+  }
+  infof(data, "Connection accepted from server");
+  /* when this happens within the DO state it is important that we mark us as
+     not needing DO_MORE anymore */
+  conn->bits.do_more = FALSE;
+
+  (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
+  /* Replace any filter on SECONDARY with one listening on this socket */
+  result = Curl_conn_tcp_accepted_set(data, conn, SECONDARYSOCKET, &s);
+  if(result)
+    return result;
+
+  if(data->set.fsockopt) {
+    int error = 0;
+
+    /* activate callback for setting socket options */
+    Curl_set_in_callback(data, true);
+    error = data->set.fsockopt(data->set.sockopt_client,
+                               s,
+                               CURLSOCKTYPE_ACCEPT);
+    Curl_set_in_callback(data, false);
+
+    if(error) {
+      close_secondarysocket(data, conn);
+      return CURLE_ABORTED_BY_CALLBACK;
+    }
+  }
+
+  return CURLE_OK;
+
+}
+
+/*
+ * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
+ * waiting server to connect. If the value is negative, the timeout time has
+ * already elapsed.
+ *
+ * The start time is stored in progress.t_acceptdata - as set with
+ * Curl_pgrsTime(..., TIMER_STARTACCEPT);
+ *
+ */
+static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
+{
+  timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
+  timediff_t other;
+  struct curltime now;
+
+  if(data->set.accepttimeout > 0)
+    timeout_ms = data->set.accepttimeout;
+
+  now = Curl_now();
+
+  /* check if the generic timeout possibly is set shorter */
+  other = Curl_timeleft(data, &now, FALSE);
+  if(other && (other < timeout_ms))
+    /* note that this also works fine for when other happens to be negative
+       due to it already having elapsed */
+    timeout_ms = other;
+  else {
+    /* subtract elapsed time */
+    timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata);
+    if(!timeout_ms)
+      /* avoid returning 0 as that means no timeout! */
+      return -1;
+  }
+
+  return timeout_ms;
+}
+
+
+/***********************************************************************
+ *
+ * ReceivedServerConnect()
+ *
+ * After allowing server to connect to us from data port, this function
+ * checks both data connection for connection establishment and ctrl
+ * connection for a negative response regarding a failure in connecting
+ *
+ */
+static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
+{
+  struct connectdata *conn = data->conn;
+  curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
+  curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+  int socketstate = 0;
+  timediff_t timeout_ms;
+  ssize_t nread;
+  int ftpcode;
+  bool response = FALSE;
+
+  *received = FALSE;
+
+  timeout_ms = ftp_timeleft_accept(data);
+  infof(data, "Checking for server connect");
+  if(timeout_ms < 0) {
+    /* if a timeout was already reached, bail out */
+    failf(data, "Accept timeout occurred while waiting server connect");
+    return CURLE_FTP_ACCEPT_TIMEOUT;
+  }
+
+  /* First check whether there is a cached response from server */
+  if(Curl_dyn_len(&pp->recvbuf) && (*Curl_dyn_ptr(&pp->recvbuf) > '3')) {
+    /* Data connection could not be established, let's return */
+    infof(data, "There is negative response in cache while serv connect");
+    (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
+    return CURLE_FTP_ACCEPT_FAILED;
+  }
+
+  if(pp->overflow)
+    /* there is pending control data still in the buffer to read */
+    response = TRUE;
+  else
+    socketstate = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
+
+  /* see if the connection request is already here */
+  switch(socketstate) {
+  case -1: /* error */
+    /* let's die here */
+    failf(data, "Error while waiting for server connect");
+    return CURLE_FTP_ACCEPT_FAILED;
+  case 0:  /* Server connect is not received yet */
+    break; /* loop */
+  default:
+    if(socketstate & CURL_CSELECT_IN2) {
+      infof(data, "Ready to accept data connection from server");
+      *received = TRUE;
+    }
+    else if(socketstate & CURL_CSELECT_IN)
+      response = TRUE;
+    break;
+  }
+  if(response) {
+    infof(data, "Ctrl conn has data while waiting for data conn");
+    if(pp->overflow > 3) {
+      char *r = Curl_dyn_ptr(&pp->recvbuf);
+
+      DEBUGASSERT((pp->overflow + pp->nfinal) <=
+                  Curl_dyn_len(&pp->recvbuf));
+      /* move over the most recently handled response line */
+      r += pp->nfinal;
+
+      if(LASTLINE(r)) {
+        int status = curlx_sltosi(strtol(r, NULL, 10));
+        if(status == 226) {
+          /* funny timing situation where we get the final message on the
+             control connection before traffic on the data connection has been
+             noticed. Leave the 226 in there and use this as a trigger to read
+             the data socket. */
+          infof(data, "Got 226 before data activity");
+          *received = TRUE;
+          return CURLE_OK;
+        }
+      }
+    }
+
+    (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
+
+    infof(data, "FTP code: %03d", ftpcode);
+
+    if(ftpcode/100 > 3)
+      return CURLE_FTP_ACCEPT_FAILED;
+
+    return CURLE_WEIRD_SERVER_REPLY;
+  }
+
+  return CURLE_OK;
+}
+
+
+/***********************************************************************
+ *
+ * InitiateTransfer()
+ *
+ * After connection from server is accepted this function is called to
+ * setup transfer parameters and initiate the data transfer.
+ *
+ */
+static CURLcode InitiateTransfer(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  bool connected;
+
+  DEBUGF(infof(data, "ftp InitiateTransfer()"));
+  if(conn->bits.ftp_use_data_ssl && data->set.ftp_use_port &&
+     !Curl_conn_is_ssl(conn, SECONDARYSOCKET)) {
+    result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET);
+    if(result)
+      return result;
+  }
+  result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &connected);
+  if(result || !connected)
+    return result;
+
+  if(conn->proto.ftpc.state_saved == FTP_STOR) {
+    /* When we know we're uploading a specified file, we can get the file
+       size prior to the actual upload. */
+    Curl_pgrsSetUploadSize(data, data->state.infilesize);
+
+    /* set the SO_SNDBUF for the secondary socket for those who need it */
+    Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
+
+    Curl_xfer_setup(data, -1, -1, FALSE, SECONDARYSOCKET);
+  }
+  else {
+    /* FTP download: */
+    Curl_xfer_setup(data, SECONDARYSOCKET,
+                    conn->proto.ftpc.retr_size_saved, FALSE, -1);
+  }
+
+  conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
+  ftp_state(data, FTP_STOP);
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * AllowServerConnect()
+ *
+ * When we've issue the PORT command, we have told the server to connect to
+ * us. This function checks whether data connection is established if so it is
+ * accepted.
+ *
+ */
+static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
+{
+  timediff_t timeout_ms;
+  CURLcode result = CURLE_OK;
+
+  *connected = FALSE;
+  infof(data, "Preparing for accepting server on data port");
+
+  /* Save the time we start accepting server connect */
+  Curl_pgrsTime(data, TIMER_STARTACCEPT);
+
+  timeout_ms = ftp_timeleft_accept(data);
+  if(timeout_ms < 0) {
+    /* if a timeout was already reached, bail out */
+    failf(data, "Accept timeout occurred while waiting server connect");
+    result = CURLE_FTP_ACCEPT_TIMEOUT;
+    goto out;
+  }
+
+  /* see if the connection request is already here */
+  result = ReceivedServerConnect(data, connected);
+  if(result)
+    goto out;
+
+  if(*connected) {
+    result = AcceptServerConnect(data);
+    if(result)
+      goto out;
+
+    result = InitiateTransfer(data);
+    if(result)
+      goto out;
+  }
+  else {
+    /* Add timeout to multi handle and break out of the loop */
+    Curl_expire(data, data->set.accepttimeout ?
+                data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT,
+                EXPIRE_FTP_ACCEPT);
+  }
+
+out:
+  DEBUGF(infof(data, "ftp AllowServerConnect() -> %d", result));
+  return result;
+}
+
+static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn,
+                          char *line, size_t len, int *code)
+{
+  (void)data;
+  (void)conn;
+
+  if((len > 3) && LASTLINE(line)) {
+    *code = curlx_sltosi(strtol(line, NULL, 10));
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+static CURLcode ftp_readresp(struct Curl_easy *data,
+                             int sockindex,
+                             struct pingpong *pp,
+                             int *ftpcode, /* return the ftp-code if done */
+                             size_t *size) /* size of the response */
+{
+  int code;
+  CURLcode result = Curl_pp_readresp(data, sockindex, pp, &code, size);
+
+#ifdef HAVE_GSSAPI
+  {
+    struct connectdata *conn = data->conn;
+    char * const buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf);
+
+    /* handle the security-oriented responses 6xx ***/
+    switch(code) {
+    case 631:
+      code = Curl_sec_read_msg(data, conn, buf, PROT_SAFE);
+      break;
+    case 632:
+      code = Curl_sec_read_msg(data, conn, buf, PROT_PRIVATE);
+      break;
+    case 633:
+      code = Curl_sec_read_msg(data, conn, buf, PROT_CONFIDENTIAL);
+      break;
+    default:
+      /* normal ftp stuff we pass through! */
+      break;
+    }
+  }
+#endif
+
+  /* store the latest code for later retrieval */
+  data->info.httpcode = code;
+
+  if(ftpcode)
+    *ftpcode = code;
+
+  if(421 == code) {
+    /* 421 means "Service not available, closing control connection." and FTP
+     * servers use it to signal that idle session timeout has been exceeded.
+     * If we ignored the response, it could end up hanging in some cases.
+     *
+     * This response code can come at any point so having it treated
+     * generically is a good idea.
+     */
+    infof(data, "We got a 421 - timeout");
+    ftp_state(data, FTP_STOP);
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  return result;
+}
+
+/* --- parse FTP server responses --- */
+
+/*
+ * Curl_GetFTPResponse() is a BLOCKING function to read the full response
+ * from a server after a command.
+ *
+ */
+
+CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
+                             ssize_t *nreadp, /* return number of bytes read */
+                             int *ftpcode) /* return the ftp-code */
+{
+  /*
+   * We cannot read just one byte per read() and then go back to select() as
+   * the OpenSSL read() doesn't grok that properly.
+   *
+   * Alas, read as much as possible, split up into lines, use the ending
+   * line in a response or continue reading.  */
+
+  struct connectdata *conn = data->conn;
+  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+  CURLcode result = CURLE_OK;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+  size_t nread;
+  int cache_skip = 0;
+  int value_to_be_ignored = 0;
+
+  if(ftpcode)
+    *ftpcode = 0; /* 0 for errors */
+  else
+    /* make the pointer point to something for the rest of this function */
+    ftpcode = &value_to_be_ignored;
+
+  *nreadp = 0;
+
+  while(!*ftpcode && !result) {
+    /* check and reset timeout value every lap */
+    timediff_t timeout = Curl_pp_state_timeout(data, pp, FALSE);
+    timediff_t interval_ms;
+
+    if(timeout <= 0) {
+      failf(data, "FTP response timeout");
+      return CURLE_OPERATION_TIMEDOUT; /* already too little time */
+    }
+
+    interval_ms = 1000;  /* use 1 second timeout intervals */
+    if(timeout < interval_ms)
+      interval_ms = timeout;
+
+    /*
+     * Since this function is blocking, we need to wait here for input on the
+     * connection and only then we call the response reading function. We do
+     * timeout at least every second to make the timeout check run.
+     *
+     * A caution here is that the ftp_readresp() function has a cache that may
+     * contain pieces of a response from the previous invoke and we need to
+     * make sure we don't just wait for input while there is unhandled data in
+     * that cache. But also, if the cache is there, we call ftp_readresp() and
+     * the cache wasn't good enough to continue we must not just busy-loop
+     * around this function.
+     *
+     */
+
+    if(Curl_dyn_len(&pp->recvbuf) && (cache_skip < 2)) {
+      /*
+       * There's a cache left since before. We then skipping the wait for
+       * socket action, unless this is the same cache like the previous round
+       * as then the cache was deemed not enough to act on and we then need to
+       * wait for more data anyway.
+       */
+    }
+    else if(!Curl_conn_data_pending(data, FIRSTSOCKET)) {
+      switch(SOCKET_READABLE(sockfd, interval_ms)) {
+      case -1: /* select() error, stop reading */
+        failf(data, "FTP response aborted due to select/poll error: %d",
+              SOCKERRNO);
+        return CURLE_RECV_ERROR;
+
+      case 0: /* timeout */
+        if(Curl_pgrsUpdate(data))
+          return CURLE_ABORTED_BY_CALLBACK;
+        continue; /* just continue in our loop for the timeout duration */
+
+      default: /* for clarity */
+        break;
+      }
+    }
+    result = ftp_readresp(data, FIRSTSOCKET, pp, ftpcode, &nread);
+    if(result)
+      break;
+
+    if(!nread && Curl_dyn_len(&pp->recvbuf))
+      /* bump cache skip counter as on repeated skips we must wait for more
+         data */
+      cache_skip++;
+    else
+      /* when we got data or there is no cache left, we reset the cache skip
+         counter */
+      cache_skip = 0;
+
+    *nreadp += nread;
+
+  } /* while there's buffer left and loop is requested */
+
+  pp->pending_resp = FALSE;
+
+  return result;
+}
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+static const char * const ftp_state_names[]={
+  "STOP",
+  "WAIT220",
+  "AUTH",
+  "USER",
+  "PASS",
+  "ACCT",
+  "PBSZ",
+  "PROT",
+  "CCC",
+  "PWD",
+  "SYST",
+  "NAMEFMT",
+  "QUOTE",
+  "RETR_PREQUOTE",
+  "STOR_PREQUOTE",
+  "POSTQUOTE",
+  "CWD",
+  "MKD",
+  "MDTM",
+  "TYPE",
+  "LIST_TYPE",
+  "RETR_TYPE",
+  "STOR_TYPE",
+  "SIZE",
+  "RETR_SIZE",
+  "STOR_SIZE",
+  "REST",
+  "RETR_REST",
+  "PORT",
+  "PRET",
+  "PASV",
+  "LIST",
+  "RETR",
+  "STOR",
+  "QUIT"
+};
+#endif
+
+/* This is the ONLY way to change FTP state! */
+static void _ftp_state(struct Curl_easy *data,
+                       ftpstate newstate
+#ifdef DEBUGBUILD
+                       , int lineno
+#endif
+  )
+{
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+#if defined(DEBUGBUILD)
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) lineno;
+#else
+  if(ftpc->state != newstate)
+    infof(data, "FTP %p (line %d) state change from %s to %s",
+          (void *)ftpc, lineno, ftp_state_names[ftpc->state],
+          ftp_state_names[newstate]);
+#endif
+#endif
+
+  ftpc->state = newstate;
+}
+
+static CURLcode ftp_state_user(struct Curl_easy *data,
+                               struct connectdata *conn)
+{
+  CURLcode result = Curl_pp_sendf(data,
+                                  &conn->proto.ftpc.pp, "USER %s",
+                                  conn->user?conn->user:"");
+  if(!result) {
+    struct ftp_conn *ftpc = &conn->proto.ftpc;
+    ftpc->ftp_trying_alternative = FALSE;
+    ftp_state(data, FTP_USER);
+  }
+  return result;
+}
+
+static CURLcode ftp_state_pwd(struct Curl_easy *data,
+                              struct connectdata *conn)
+{
+  CURLcode result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PWD");
+  if(!result)
+    ftp_state(data, FTP_PWD);
+
+  return result;
+}
+
+/* For the FTP "protocol connect" and "doing" phases only */
+static int ftp_getsock(struct Curl_easy *data,
+                       struct connectdata *conn,
+                       curl_socket_t *socks)
+{
+  return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks);
+}
+
+/* For the FTP "DO_MORE" phase only */
+static int ftp_domore_getsock(struct Curl_easy *data,
+                              struct connectdata *conn, curl_socket_t *socks)
+{
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  (void)data;
+
+  /* When in DO_MORE state, we could be either waiting for us to connect to a
+   * remote site, or we could wait for that site to connect to us. Or just
+   * handle ordinary commands.
+   */
+  DEBUGF(infof(data, "ftp_domore_getsock()"));
+
+  if(FTP_STOP == ftpc->state) {
+    /* if stopped and still in this state, then we're also waiting for a
+       connect on the secondary connection */
+    DEBUGASSERT(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD ||
+               (conn->cfilter[SECONDARYSOCKET] &&
+                !Curl_conn_is_connected(conn, SECONDARYSOCKET)));
+    socks[0] = conn->sock[FIRSTSOCKET];
+    /* An unconnected SECONDARY will add its socket by itself
+     * via its adjust_pollset() */
+    return GETSOCK_READSOCK(0);
+  }
+  return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks);
+}
+
+/* This is called after the FTP_QUOTE state is passed.
+
+   ftp_state_cwd() sends the range of CWD commands to the server to change to
+   the correct directory. It may also need to send MKD commands to create
+   missing ones, if that option is enabled.
+*/
+static CURLcode ftp_state_cwd(struct Curl_easy *data,
+                              struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  if(ftpc->cwddone)
+    /* already done and fine */
+    result = ftp_state_mdtm(data);
+  else {
+    /* FTPFILE_NOCWD with full path: expect ftpc->cwddone! */
+    DEBUGASSERT((data->set.ftp_filemethod != FTPFILE_NOCWD) ||
+                !(ftpc->dirdepth && ftpc->dirs[0][0] == '/'));
+
+    ftpc->count2 = 0; /* count2 counts failed CWDs */
+
+    if(conn->bits.reuse && ftpc->entrypath &&
+       /* no need to go to entrypath when we have an absolute path */
+       !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) {
+      /* This is a reused connection. Since we change directory to where the
+         transfer is taking place, we must first get back to the original dir
+         where we ended up after login: */
+      ftpc->cwdcount = 0; /* we count this as the first path, then we add one
+                             for all upcoming ones in the ftp->dirs[] array */
+      result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->entrypath);
+      if(!result)
+        ftp_state(data, FTP_CWD);
+    }
+    else {
+      if(ftpc->dirdepth) {
+        ftpc->cwdcount = 1;
+        /* issue the first CWD, the rest is sent when the CWD responses are
+           received... */
+        result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
+                               ftpc->dirs[ftpc->cwdcount -1]);
+        if(!result)
+          ftp_state(data, FTP_CWD);
+      }
+      else {
+        /* No CWD necessary */
+        result = ftp_state_mdtm(data);
+      }
+    }
+  }
+  return result;
+}
+
+typedef enum {
+  EPRT,
+  PORT,
+  DONE
+} ftpport;
+
+static CURLcode ftp_state_use_port(struct Curl_easy *data,
+                                   ftpport fcmd) /* start with this */
+{
+  CURLcode result = CURLE_FTP_PORT_FAILED;
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  curl_socket_t portsock = CURL_SOCKET_BAD;
+  char myhost[MAX_IPADR_LEN + 1] = "";
+
+  struct Curl_sockaddr_storage ss;
+  struct Curl_addrinfo *res, *ai;
+  curl_socklen_t sslen;
+  char hbuf[NI_MAXHOST];
+  struct sockaddr *sa = (struct sockaddr *)&ss;
+  struct sockaddr_in * const sa4 = (void *)sa;
+#ifdef ENABLE_IPV6
+  struct sockaddr_in6 * const sa6 = (void *)sa;
+#endif
+  static const char mode[][5] = { "EPRT", "PORT" };
+  enum resolve_t rc;
+  int error;
+  char *host = NULL;
+  char *string_ftpport = data->set.str[STRING_FTPPORT];
+  struct Curl_dns_entry *h = NULL;
+  unsigned short port_min = 0;
+  unsigned short port_max = 0;
+  unsigned short port;
+  bool possibly_non_local = TRUE;
+  char buffer[STRERROR_LEN];
+  char *addr = NULL;
+  size_t addrlen = 0;
+  char ipstr[50];
+
+  /* Step 1, figure out what is requested,
+   * accepted format :
+   * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
+   */
+
+  if(data->set.str[STRING_FTPPORT] &&
+     (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
+    char *ip_end = NULL;
+
+#ifdef ENABLE_IPV6
+    if(*string_ftpport == '[') {
+      /* [ipv6]:port(-range) */
+      char *ip_start = string_ftpport + 1;
+      ip_end = strchr(ip_start, ']');
+      if(ip_end) {
+        addrlen = ip_end - ip_start;
+        addr = ip_start;
+      }
+    }
+    else
+#endif
+      if(*string_ftpport == ':') {
+        /* :port */
+        ip_end = string_ftpport;
+      }
+      else {
+        ip_end = strchr(string_ftpport, ':');
+        addr = string_ftpport;
+        if(ip_end) {
+          /* either ipv6 or (ipv4|domain|interface):port(-range) */
+          addrlen = ip_end - string_ftpport;
+#ifdef ENABLE_IPV6
+          if(Curl_inet_pton(AF_INET6, string_ftpport, &sa6->sin6_addr) == 1) {
+            /* ipv6 */
+            port_min = port_max = 0;
+            ip_end = NULL; /* this got no port ! */
+          }
+#endif
+        }
+        else
+          /* ipv4|interface */
+          addrlen = strlen(string_ftpport);
+      }
+
+    /* parse the port */
+    if(ip_end) {
+      char *port_sep = NULL;
+      char *port_start = strchr(ip_end, ':');
+      if(port_start) {
+        port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
+        port_sep = strchr(port_start, '-');
+        if(port_sep) {
+          port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
+        }
+        else
+          port_max = port_min;
+      }
+    }
+
+    /* correct errors like:
+     *  :1234-1230
+     *  :-4711,  in this case port_min is (unsigned)-1,
+     *           therefore port_min > port_max for all cases
+     *           but port_max = (unsigned)-1
+     */
+    if(port_min > port_max)
+      port_min = port_max = 0;
+
+    if(addrlen) {
+      DEBUGASSERT(addr);
+      if(addrlen >= sizeof(ipstr))
+        goto out;
+      memcpy(ipstr, addr, addrlen);
+      ipstr[addrlen] = 0;
+
+      /* attempt to get the address of the given interface name */
+      switch(Curl_if2ip(conn->remote_addr->family,
+#ifdef ENABLE_IPV6
+                        Curl_ipv6_scope(&conn->remote_addr->sa_addr),
+                        conn->scope_id,
+#endif
+                        ipstr, hbuf, sizeof(hbuf))) {
+        case IF2IP_NOT_FOUND:
+          /* not an interface, use the given string as host name instead */
+          host = ipstr;
+          break;
+        case IF2IP_AF_NOT_SUPPORTED:
+          goto out;
+        case IF2IP_FOUND:
+          host = hbuf; /* use the hbuf for host name */
+          break;
+      }
+    }
+    else
+      /* there was only a port(-range) given, default the host */
+      host = NULL;
+  } /* data->set.ftpport */
+
+  if(!host) {
+    const char *r;
+    /* not an interface and not a host name, get default by extracting
+       the IP from the control connection */
+    sslen = sizeof(ss);
+    if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
+      failf(data, "getsockname() failed: %s",
+            Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+      goto out;
+    }
+    switch(sa->sa_family) {
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+      r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
+      break;
+#endif
+    default:
+      r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
+      break;
+    }
+    if(!r) {
+      goto out;
+    }
+    host = hbuf; /* use this host name */
+    possibly_non_local = FALSE; /* we know it is local now */
+  }
+
+  /* resolv ip/host to ip */
+  rc = Curl_resolv(data, host, 0, FALSE, &h);
+  if(rc == CURLRESOLV_PENDING)
+    (void)Curl_resolver_wait_resolv(data, &h);
+  if(h) {
+    res = h->addr;
+    /* when we return from this function, we can forget about this entry
+       to we can unlock it now already */
+    Curl_resolv_unlock(data, h);
+  } /* (h) */
+  else
+    res = NULL; /* failure! */
+
+  if(!res) {
+    failf(data, "failed to resolve the address provided to PORT: %s", host);
+    goto out;
+  }
+
+  host = NULL;
+
+  /* step 2, create a socket for the requested address */
+  error = 0;
+  for(ai = res; ai; ai = ai->ai_next) {
+    if(Curl_socket_open(data, ai, NULL, conn->transport, &portsock)) {
+      error = SOCKERRNO;
+      continue;
+    }
+    break;
+  }
+  if(!ai) {
+    failf(data, "socket failure: %s",
+          Curl_strerror(error, buffer, sizeof(buffer)));
+    goto out;
+  }
+  DEBUGF(infof(data, "ftp_state_use_port(), opened socket"));
+
+  /* step 3, bind to a suitable local address */
+
+  memcpy(sa, ai->ai_addr, ai->ai_addrlen);
+  sslen = ai->ai_addrlen;
+
+  for(port = port_min; port <= port_max;) {
+    if(sa->sa_family == AF_INET)
+      sa4->sin_port = htons(port);
+#ifdef ENABLE_IPV6
+    else
+      sa6->sin6_port = htons(port);
+#endif
+    /* Try binding the given address. */
+    if(bind(portsock, sa, sslen) ) {
+      /* It failed. */
+      error = SOCKERRNO;
+      if(possibly_non_local && (error == EADDRNOTAVAIL)) {
+        /* The requested bind address is not local.  Use the address used for
+         * the control connection instead and restart the port loop
+         */
+        infof(data, "bind(port=%hu) on non-local address failed: %s", port,
+              Curl_strerror(error, buffer, sizeof(buffer)));
+
+        sslen = sizeof(ss);
+        if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
+          failf(data, "getsockname() failed: %s",
+                Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+          goto out;
+        }
+        port = port_min;
+        possibly_non_local = FALSE; /* don't try this again */
+        continue;
+      }
+      if(error != EADDRINUSE && error != EACCES) {
+        failf(data, "bind(port=%hu) failed: %s", port,
+              Curl_strerror(error, buffer, sizeof(buffer)));
+        goto out;
+      }
+    }
+    else
+      break;
+
+    port++;
+  }
+
+  /* maybe all ports were in use already */
+  if(port > port_max) {
+    failf(data, "bind() failed, we ran out of ports");
+    goto out;
+  }
+
+  /* get the name again after the bind() so that we can extract the
+     port number it uses now */
+  sslen = sizeof(ss);
+  if(getsockname(portsock, sa, &sslen)) {
+    failf(data, "getsockname() failed: %s",
+          Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+    goto out;
+  }
+  DEBUGF(infof(data, "ftp_state_use_port(), socket bound to port %d", port));
+
+  /* step 4, listen on the socket */
+
+  if(listen(portsock, 1)) {
+    failf(data, "socket failure: %s",
+          Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+    goto out;
+  }
+  DEBUGF(infof(data, "ftp_state_use_port(), listening on %d", port));
+
+  /* step 5, send the proper FTP command */
+
+  /* get a plain printable version of the numerical address to work with
+     below */
+  Curl_printable_address(ai, myhost, sizeof(myhost));
+
+#ifdef ENABLE_IPV6
+  if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
+    /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
+       request and enable EPRT again! */
+    conn->bits.ftp_use_eprt = TRUE;
+#endif
+
+  /* Replace any filter on SECONDARY with one listening on this socket */
+  result = Curl_conn_tcp_listen_set(data, conn, SECONDARYSOCKET, &portsock);
+  if(result)
+    goto out;
+  portsock = CURL_SOCKET_BAD; /* now held in filter */
+
+  for(; fcmd != DONE; fcmd++) {
+
+    if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
+      /* if disabled, goto next */
+      continue;
+
+    if((PORT == fcmd) && sa->sa_family != AF_INET)
+      /* PORT is IPv4 only */
+      continue;
+
+    switch(sa->sa_family) {
+    case AF_INET:
+      port = ntohs(sa4->sin_port);
+      break;
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+      port = ntohs(sa6->sin6_port);
+      break;
+#endif
+    default:
+      continue; /* might as well skip this */
+    }
+
+    if(EPRT == fcmd) {
+      /*
+       * Two fine examples from RFC2428;
+       *
+       * EPRT |1|132.235.1.2|6275|
+       *
+       * EPRT |2|1080::8:800:200C:417A|5282|
+       */
+
+      result = Curl_pp_sendf(data, &ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
+                             sa->sa_family == AF_INET?1:2,
+                             myhost, port);
+      if(result) {
+        failf(data, "Failure sending EPRT command: %s",
+              curl_easy_strerror(result));
+        goto out;
+      }
+      break;
+    }
+    if(PORT == fcmd) {
+      /* large enough for [IP address],[num],[num] */
+      char target[sizeof(myhost) + 20];
+      char *source = myhost;
+      char *dest = target;
+
+      /* translate x.x.x.x to x,x,x,x */
+      while(source && *source) {
+        if(*source == '.')
+          *dest = ',';
+        else
+          *dest = *source;
+        dest++;
+        source++;
+      }
+      *dest = 0;
+      msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
+
+      result = Curl_pp_sendf(data, &ftpc->pp, "%s %s", mode[fcmd], target);
+      if(result) {
+        failf(data, "Failure sending PORT command: %s",
+              curl_easy_strerror(result));
+        goto out;
+      }
+      break;
+    }
+  }
+
+  /* store which command was sent */
+  ftpc->count1 = fcmd;
+
+  ftp_state(data, FTP_PORT);
+
+out:
+  if(result) {
+    ftp_state(data, FTP_STOP);
+  }
+  if(portsock != CURL_SOCKET_BAD)
+    Curl_socket_close(data, conn, portsock);
+  return result;
+}
+
+static CURLcode ftp_state_use_pasv(struct Curl_easy *data,
+                                   struct connectdata *conn)
+{
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  CURLcode result = CURLE_OK;
+  /*
+    Here's the executive summary on what to do:
+
+    PASV is RFC959, expect:
+    227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
+
+    LPSV is RFC1639, expect:
+    228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
+
+    EPSV is RFC2428, expect:
+    229 Entering Extended Passive Mode (|||port|)
+
+  */
+
+  static const char mode[][5] = { "EPSV", "PASV" };
+  int modeoff;
+
+#ifdef PF_INET6
+  if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
+    /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
+       request and enable EPSV again! */
+    conn->bits.ftp_use_epsv = TRUE;
+#endif
+
+  modeoff = conn->bits.ftp_use_epsv?0:1;
+
+  result = Curl_pp_sendf(data, &ftpc->pp, "%s", mode[modeoff]);
+  if(!result) {
+    ftpc->count1 = modeoff;
+    ftp_state(data, FTP_PASV);
+    infof(data, "Connect data stream passively");
+  }
+  return result;
+}
+
+/*
+ * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
+ *
+ * REST is the last command in the chain of commands when a "head"-like
+ * request is made. Thus, if an actual transfer is to be made this is where we
+ * take off for real.
+ */
+static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
+
+  if(ftp->transfer != PPTRANSFER_BODY) {
+    /* doesn't transfer any data */
+
+    /* still possibly do PRE QUOTE jobs */
+    ftp_state(data, FTP_RETR_PREQUOTE);
+    result = ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
+  }
+  else if(data->set.ftp_use_port) {
+    /* We have chosen to use the PORT (or similar) command */
+    result = ftp_state_use_port(data, EPRT);
+  }
+  else {
+    /* We have chosen (this is default) to use the PASV (or similar) command */
+    if(data->set.ftp_use_pret) {
+      /* The user has requested that we send a PRET command
+         to prepare the server for the upcoming PASV */
+      struct ftp_conn *ftpc = &conn->proto.ftpc;
+      if(!conn->proto.ftpc.file)
+        result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s",
+                               data->set.str[STRING_CUSTOMREQUEST]?
+                               data->set.str[STRING_CUSTOMREQUEST]:
+                               (data->state.list_only?"NLST":"LIST"));
+      else if(data->state.upload)
+        result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s",
+                               conn->proto.ftpc.file);
+      else
+        result = Curl_pp_sendf(data, &ftpc->pp, "PRET RETR %s",
+                               conn->proto.ftpc.file);
+      if(!result)
+        ftp_state(data, FTP_PRET);
+    }
+    else
+      result = ftp_state_use_pasv(data, conn);
+  }
+  return result;
+}
+
+static CURLcode ftp_state_rest(struct Curl_easy *data,
+                               struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = data->req.p.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  if((ftp->transfer != PPTRANSFER_BODY) && ftpc->file) {
+    /* if a "head"-like request is being made (on a file) */
+
+    /* Determine if server can respond to REST command and therefore
+       whether it supports range */
+    result = Curl_pp_sendf(data, &ftpc->pp, "REST %d", 0);
+    if(!result)
+      ftp_state(data, FTP_REST);
+  }
+  else
+    result = ftp_state_prepare_transfer(data);
+
+  return result;
+}
+
+static CURLcode ftp_state_size(struct Curl_easy *data,
+                               struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = data->req.p.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) {
+    /* if a "head"-like request is being made (on a file) */
+
+    /* we know ftpc->file is a valid pointer to a file name */
+    result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
+    if(!result)
+      ftp_state(data, FTP_SIZE);
+  }
+  else
+    result = ftp_state_rest(data, conn);
+
+  return result;
+}
+
+static CURLcode ftp_state_list(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
+
+  /* If this output is to be machine-parsed, the NLST command might be better
+     to use, since the LIST command output is not specified or standard in any
+     way. It has turned out that the NLST list output is not the same on all
+     servers either... */
+
+  /*
+     if FTPFILE_NOCWD was specified, we should add the path
+     as argument for the LIST / NLST / or custom command.
+     Whether the server will support this, is uncertain.
+
+     The other ftp_filemethods will CWD into dir/dir/ first and
+     then just do LIST (in that case: nothing to do here)
+  */
+  char *lstArg = NULL;
+  char *cmd;
+
+  if((data->set.ftp_filemethod == FTPFILE_NOCWD) && ftp->path) {
+    /* url-decode before evaluation: e.g. paths starting/ending with %2f */
+    const char *slashPos = NULL;
+    char *rawPath = NULL;
+    result = Curl_urldecode(ftp->path, 0, &rawPath, NULL, REJECT_CTRL);
+    if(result)
+      return result;
+
+    slashPos = strrchr(rawPath, '/');
+    if(slashPos) {
+      /* chop off the file part if format is dir/file otherwise remove
+         the trailing slash for dir/dir/ except for absolute path / */
+      size_t n = slashPos - rawPath;
+      if(n == 0)
+        ++n;
+
+      lstArg = rawPath;
+      lstArg[n] = '\0';
+    }
+    else
+      free(rawPath);
+  }
+
+  cmd = aprintf("%s%s%s",
+                data->set.str[STRING_CUSTOMREQUEST]?
+                data->set.str[STRING_CUSTOMREQUEST]:
+                (data->state.list_only?"NLST":"LIST"),
+                lstArg? " ": "",
+                lstArg? lstArg: "");
+  free(lstArg);
+
+  if(!cmd)
+    return CURLE_OUT_OF_MEMORY;
+
+  result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", cmd);
+  free(cmd);
+
+  if(!result)
+    ftp_state(data, FTP_LIST);
+
+  return result;
+}
+
+static CURLcode ftp_state_retr_prequote(struct Curl_easy *data)
+{
+  /* We've sent the TYPE, now we must send the list of prequote strings */
+  return ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
+}
+
+static CURLcode ftp_state_stor_prequote(struct Curl_easy *data)
+{
+  /* We've sent the TYPE, now we must send the list of prequote strings */
+  return ftp_state_quote(data, TRUE, FTP_STOR_PREQUOTE);
+}
+
+static CURLcode ftp_state_type(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  /* If we have selected NOBODY and HEADER, it means that we only want file
+     information. Which in FTP can't be much more than the file size and
+     date. */
+  if(data->req.no_body && ftpc->file &&
+     ftp_need_type(conn, data->state.prefer_ascii)) {
+    /* The SIZE command is _not_ RFC 959 specified, and therefore many servers
+       may not support it! It is however the only way we have to get a file's
+       size! */
+
+    ftp->transfer = PPTRANSFER_INFO;
+    /* this means no actual transfer will be made */
+
+    /* Some servers return different sizes for different modes, and thus we
+       must set the proper type before we check the size */
+    result = ftp_nb_type(data, conn, data->state.prefer_ascii, FTP_TYPE);
+    if(result)
+      return result;
+  }
+  else
+    result = ftp_state_size(data, conn);
+
+  return result;
+}
+
+/* This is called after the CWD commands have been done in the beginning of
+   the DO phase */
+static CURLcode ftp_state_mdtm(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  /* Requested time of file or time-depended transfer? */
+  if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
+
+    /* we have requested to get the modified-time of the file, this is a white
+       spot as the MDTM is not mentioned in RFC959 */
+    result = Curl_pp_sendf(data, &ftpc->pp, "MDTM %s", ftpc->file);
+
+    if(!result)
+      ftp_state(data, FTP_MDTM);
+  }
+  else
+    result = ftp_state_type(data);
+
+  return result;
+}
+
+
+/* This is called after the TYPE and possible quote commands have been sent */
+static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
+                                   bool sizechecked)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct FTP *ftp = data->req.p.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  bool append = data->set.remote_append;
+
+  if((data->state.resume_from && !sizechecked) ||
+     ((data->state.resume_from > 0) && sizechecked)) {
+    /* we're about to continue the uploading of a file */
+    /* 1. get already existing file's size. We use the SIZE command for this
+       which may not exist in the server!  The SIZE command is not in
+       RFC959. */
+
+    /* 2. This used to set REST. But since we can do append, we
+       don't another ftp command. We just skip the source file
+       offset and then we APPEND the rest on the file instead */
+
+    /* 3. pass file-size number of bytes in the source file */
+    /* 4. lower the infilesize counter */
+    /* => transfer as usual */
+    int seekerr = CURL_SEEKFUNC_OK;
+
+    if(data->state.resume_from < 0) {
+      /* Got no given size to start from, figure it out */
+      result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
+      if(!result)
+        ftp_state(data, FTP_STOR_SIZE);
+      return result;
+    }
+
+    /* enable append */
+    append = TRUE;
+
+    /* Let's read off the proper amount of bytes from the input. */
+    if(data->set.seek_func) {
+      Curl_set_in_callback(data, true);
+      seekerr = data->set.seek_func(data->set.seek_client,
+                                    data->state.resume_from, SEEK_SET);
+      Curl_set_in_callback(data, false);
+    }
+
+    if(seekerr != CURL_SEEKFUNC_OK) {
+      curl_off_t passed = 0;
+      if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+        failf(data, "Could not seek stream");
+        return CURLE_FTP_COULDNT_USE_REST;
+      }
+      /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+      do {
+        char scratch[4*1024];
+        size_t readthisamountnow =
+          (data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ?
+          sizeof(scratch) :
+          curlx_sotouz(data->state.resume_from - passed);
+
+        size_t actuallyread =
+          data->state.fread_func(scratch, 1, readthisamountnow,
+                                 data->state.in);
+
+        passed += actuallyread;
+        if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+          /* this checks for greater-than only to make sure that the
+             CURL_READFUNC_ABORT return code still aborts */
+          failf(data, "Failed to read data");
+          return CURLE_FTP_COULDNT_USE_REST;
+        }
+      } while(passed < data->state.resume_from);
+    }
+    /* now, decrease the size of the read */
+    if(data->state.infilesize>0) {
+      data->state.infilesize -= data->state.resume_from;
+
+      if(data->state.infilesize <= 0) {
+        infof(data, "File already completely uploaded");
+
+        /* no data to transfer */
+        Curl_xfer_setup(data, -1, -1, FALSE, -1);
+
+        /* Set ->transfer so that we won't get any error in
+         * ftp_done() because we didn't transfer anything! */
+        ftp->transfer = PPTRANSFER_NONE;
+
+        ftp_state(data, FTP_STOP);
+        return CURLE_OK;
+      }
+    }
+    /* we've passed, proceed as normal */
+  } /* resume_from */
+
+  result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s",
+                         ftpc->file);
+  if(!result)
+    ftp_state(data, FTP_STOR);
+
+  return result;
+}
+
+static CURLcode ftp_state_quote(struct Curl_easy *data,
+                                bool init,
+                                ftpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  bool quote = FALSE;
+  struct curl_slist *item;
+
+  switch(instate) {
+  case FTP_QUOTE:
+  default:
+    item = data->set.quote;
+    break;
+  case FTP_RETR_PREQUOTE:
+  case FTP_STOR_PREQUOTE:
+    item = data->set.prequote;
+    break;
+  case FTP_POSTQUOTE:
+    item = data->set.postquote;
+    break;
+  }
+
+  /*
+   * This state uses:
+   * 'count1' to iterate over the commands to send
+   * 'count2' to store whether to allow commands to fail
+   */
+
+  if(init)
+    ftpc->count1 = 0;
+  else
+    ftpc->count1++;
+
+  if(item) {
+    int i = 0;
+
+    /* Skip count1 items in the linked list */
+    while((i< ftpc->count1) && item) {
+      item = item->next;
+      i++;
+    }
+    if(item) {
+      char *cmd = item->data;
+      if(cmd[0] == '*') {
+        cmd++;
+        ftpc->count2 = 1; /* the sent command is allowed to fail */
+      }
+      else
+        ftpc->count2 = 0; /* failure means cancel operation */
+
+      result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd);
+      if(result)
+        return result;
+      ftp_state(data, instate);
+      quote = TRUE;
+    }
+  }
+
+  if(!quote) {
+    /* No more quote to send, continue to ... */
+    switch(instate) {
+    case FTP_QUOTE:
+    default:
+      result = ftp_state_cwd(data, conn);
+      break;
+    case FTP_RETR_PREQUOTE:
+      if(ftp->transfer != PPTRANSFER_BODY)
+        ftp_state(data, FTP_STOP);
+      else {
+        if(ftpc->known_filesize != -1) {
+          Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
+          result = ftp_state_retr(data, ftpc->known_filesize);
+        }
+        else {
+          if(data->set.ignorecl || data->state.prefer_ascii) {
+            /* 'ignorecl' is used to support download of growing files.  It
+               prevents the state machine from requesting the file size from
+               the server.  With an unknown file size the download continues
+               until the server terminates it, otherwise the client stops if
+               the received byte count exceeds the reported file size.  Set
+               option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this
+               behavior.
+
+               In addition: asking for the size for 'TYPE A' transfers is not
+               constructive since servers don't report the converted size. So
+               skip it.
+            */
+            result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
+            if(!result)
+              ftp_state(data, FTP_RETR);
+          }
+          else {
+            result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
+            if(!result)
+              ftp_state(data, FTP_RETR_SIZE);
+          }
+        }
+      }
+      break;
+    case FTP_STOR_PREQUOTE:
+      result = ftp_state_ul_setup(data, FALSE);
+      break;
+    case FTP_POSTQUOTE:
+      break;
+    }
+  }
+
+  return result;
+}
+
+/* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
+   problems */
+static CURLcode ftp_epsv_disable(struct Curl_easy *data,
+                                 struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+
+  if(conn->bits.ipv6
+#ifndef CURL_DISABLE_PROXY
+     && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)
+#endif
+    ) {
+    /* We can't disable EPSV when doing IPv6, so this is instead a fail */
+    failf(data, "Failed EPSV attempt, exiting");
+    return CURLE_WEIRD_SERVER_REPLY;
+  }
+
+  infof(data, "Failed EPSV attempt. Disabling EPSV");
+  /* disable it for next transfer */
+  conn->bits.ftp_use_epsv = FALSE;
+  Curl_conn_close(data, SECONDARYSOCKET);
+  Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET);
+  data->state.errorbuf = FALSE; /* allow error message to get
+                                         rewritten */
+  result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PASV");
+  if(!result) {
+    conn->proto.ftpc.count1++;
+    /* remain in/go to the FTP_PASV state */
+    ftp_state(data, FTP_PASV);
+  }
+  return result;
+}
+
+
+static char *control_address(struct connectdata *conn)
+{
+  /* Returns the control connection IP address.
+     If a proxy tunnel is used, returns the original host name instead, because
+     the effective control connection address is the proxy address,
+     not the ftp host. */
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
+    return conn->host.name;
+#endif
+  return conn->primary.remote_ip;
+}
+
+static bool match_pasv_6nums(const char *p,
+                             unsigned int *array) /* 6 numbers */
+{
+  int i;
+  for(i = 0; i < 6; i++) {
+    unsigned long num;
+    char *endp;
+    if(i) {
+      if(*p != ',')
+        return FALSE;
+      p++;
+    }
+    if(!ISDIGIT(*p))
+      return FALSE;
+    num = strtoul(p, &endp, 10);
+    if(num > 255)
+      return FALSE;
+    array[i] = (unsigned int)num;
+    p = endp;
+  }
+  return TRUE;
+}
+
+static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
+                                    int ftpcode)
+{
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  CURLcode result;
+  struct Curl_dns_entry *addr = NULL;
+  enum resolve_t rc;
+  unsigned short connectport; /* the local port connect() should use! */
+  struct pingpong *pp = &ftpc->pp;
+  char *str =
+    Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first letter */
+
+  /* if we come here again, make sure the former name is cleared */
+  Curl_safefree(ftpc->newhost);
+
+  if((ftpc->count1 == 0) &&
+     (ftpcode == 229)) {
+    /* positive EPSV response */
+    char *ptr = strchr(str, '(');
+    if(ptr) {
+      char sep;
+      ptr++;
+      /* |||12345| */
+      sep = ptr[0];
+      /* the ISDIGIT() check here is because strtoul() accepts leading minus
+         etc */
+      if((ptr[1] == sep) && (ptr[2] == sep) && ISDIGIT(ptr[3])) {
+        char *endp;
+        unsigned long num = strtoul(&ptr[3], &endp, 10);
+        if(*endp != sep)
+          ptr = NULL;
+        else if(num > 0xffff) {
+          failf(data, "Illegal port number in EPSV reply");
+          return CURLE_FTP_WEIRD_PASV_REPLY;
+        }
+        if(ptr) {
+          ftpc->newport = (unsigned short)(num & 0xffff);
+          ftpc->newhost = strdup(control_address(conn));
+          if(!ftpc->newhost)
+            return CURLE_OUT_OF_MEMORY;
+        }
+      }
+      else
+        ptr = NULL;
+    }
+    if(!ptr) {
+      failf(data, "Weirdly formatted EPSV reply");
+      return CURLE_FTP_WEIRD_PASV_REPLY;
+    }
+  }
+  else if((ftpc->count1 == 1) &&
+          (ftpcode == 227)) {
+    /* positive PASV response */
+    unsigned int ip[6];
+
+    /*
+     * Scan for a sequence of six comma-separated numbers and use them as
+     * IP+port indicators.
+     *
+     * Found reply-strings include:
+     * "227 Entering Passive Mode (127,0,0,1,4,51)"
+     * "227 Data transfer will passively listen to 127,0,0,1,4,51"
+     * "227 Entering passive mode. 127,0,0,1,4,51"
+     */
+    while(*str) {
+      if(match_pasv_6nums(str, ip))
+        break;
+      str++;
+    }
+
+    if(!*str) {
+      failf(data, "Couldn't interpret the 227-response");
+      return CURLE_FTP_WEIRD_227_FORMAT;
+    }
+
+    /* we got OK from server */
+    if(data->set.ftp_skip_ip) {
+      /* told to ignore the remotely given IP but instead use the host we used
+         for the control connection */
+      infof(data, "Skip %u.%u.%u.%u for data connection, reuse %s instead",
+            ip[0], ip[1], ip[2], ip[3],
+            conn->host.name);
+      ftpc->newhost = strdup(control_address(conn));
+    }
+    else
+      ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
+
+    if(!ftpc->newhost)
+      return CURLE_OUT_OF_MEMORY;
+
+    ftpc->newport = (unsigned short)(((ip[4]<<8) + ip[5]) & 0xffff);
+  }
+  else if(ftpc->count1 == 0) {
+    /* EPSV failed, move on to PASV */
+    return ftp_epsv_disable(data, conn);
+  }
+  else {
+    failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
+    return CURLE_FTP_WEIRD_PASV_REPLY;
+  }
+
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.proxy) {
+    /*
+     * This connection uses a proxy and we need to connect to the proxy again
+     * here. We don't want to rely on a former host lookup that might've
+     * expired now, instead we remake the lookup here and now!
+     */
+    const char * const host_name = conn->bits.socksproxy ?
+      conn->socks_proxy.host.name : conn->http_proxy.host.name;
+    rc = Curl_resolv(data, host_name, conn->primary.remote_port, FALSE, &addr);
+    if(rc == CURLRESOLV_PENDING)
+      /* BLOCKING, ignores the return code but 'addr' will be NULL in
+         case of failure */
+      (void)Curl_resolver_wait_resolv(data, &addr);
+
+    /* we connect to the proxy's port */
+    connectport = (unsigned short)conn->primary.remote_port;
+
+    if(!addr) {
+      failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
+      return CURLE_COULDNT_RESOLVE_PROXY;
+    }
+  }
+  else
+#endif
+  {
+    /* normal, direct, ftp connection */
+    DEBUGASSERT(ftpc->newhost);
+
+    /* postponed address resolution in case of tcp fastopen */
+    if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) {
+      Curl_conn_ev_update_info(data, conn);
+      Curl_safefree(ftpc->newhost);
+      ftpc->newhost = strdup(control_address(conn));
+      if(!ftpc->newhost)
+        return CURLE_OUT_OF_MEMORY;
+    }
+
+    rc = Curl_resolv(data, ftpc->newhost, ftpc->newport, FALSE, &addr);
+    if(rc == CURLRESOLV_PENDING)
+      /* BLOCKING */
+      (void)Curl_resolver_wait_resolv(data, &addr);
+
+    connectport = ftpc->newport; /* we connect to the remote port */
+
+    if(!addr) {
+      failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
+      return CURLE_FTP_CANT_GET_HOST;
+    }
+  }
+
+  result = Curl_conn_setup(data, conn, SECONDARYSOCKET, addr,
+                           conn->bits.ftp_use_data_ssl?
+                           CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE);
+
+  if(result) {
+    Curl_resolv_unlock(data, addr); /* we're done using this address */
+    if(ftpc->count1 == 0 && ftpcode == 229)
+      return ftp_epsv_disable(data, conn);
+
+    return result;
+  }
+
+
+  /*
+   * When this is used from the multi interface, this might've returned with
+   * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
+   * connect to connect.
+   */
+
+  if(data->set.verbose)
+    /* this just dumps information about this second connection */
+    ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport);
+
+  Curl_resolv_unlock(data, addr); /* we're done using this address */
+
+  Curl_safefree(conn->secondaryhostname);
+  conn->secondary_port = ftpc->newport;
+  conn->secondaryhostname = strdup(ftpc->newhost);
+  if(!conn->secondaryhostname)
+    return CURLE_OUT_OF_MEMORY;
+
+  conn->bits.do_more = TRUE;
+  ftp_state(data, FTP_STOP); /* this phase is completed */
+
+  return result;
+}
+
+static CURLcode ftp_state_port_resp(struct Curl_easy *data,
+                                    int ftpcode)
+{
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  ftpport fcmd = (ftpport)ftpc->count1;
+  CURLcode result = CURLE_OK;
+
+  /* The FTP spec tells a positive response should have code 200.
+     Be more permissive here to tolerate deviant servers. */
+  if(ftpcode / 100 != 2) {
+    /* the command failed */
+
+    if(EPRT == fcmd) {
+      infof(data, "disabling EPRT usage");
+      conn->bits.ftp_use_eprt = FALSE;
+    }
+    fcmd++;
+
+    if(fcmd == DONE) {
+      failf(data, "Failed to do PORT");
+      result = CURLE_FTP_PORT_FAILED;
+    }
+    else
+      /* try next */
+      result = ftp_state_use_port(data, fcmd);
+  }
+  else {
+    infof(data, "Connect data stream actively");
+    ftp_state(data, FTP_STOP); /* end of DO phase */
+    result = ftp_dophase_done(data, FALSE);
+  }
+
+  return result;
+}
+
+static int twodigit(const char *p)
+{
+  return (p[0]-'0') * 10 + (p[1]-'0');
+}
+
+static bool ftp_213_date(const char *p, int *year, int *month, int *day,
+                         int *hour, int *minute, int *second)
+{
+  size_t len = strlen(p);
+  if(len < 14)
+    return FALSE;
+  *year = twodigit(&p[0]) * 100 + twodigit(&p[2]);
+  *month = twodigit(&p[4]);
+  *day = twodigit(&p[6]);
+  *hour = twodigit(&p[8]);
+  *minute = twodigit(&p[10]);
+  *second = twodigit(&p[12]);
+
+  if((*month > 12) || (*day > 31) || (*hour > 23) || (*minute > 59) ||
+     (*second > 60))
+    return FALSE;
+  return TRUE;
+}
+
+static CURLcode client_write_header(struct Curl_easy *data,
+                                    char *buf, size_t blen)
+{
+  /* Some replies from an FTP server are written to the client
+   * as CLIENTWRITE_HEADER, formatted as if they came from a
+   * HTTP conversation.
+   * In all protocols, CLIENTWRITE_HEADER data is only passed to
+   * the body write callback when data->set.include_header is set
+   * via CURLOPT_HEADER.
+   * For historic reasons, FTP never played this game and expects
+   * all its HEADERs to do that always. Set that flag during the
+   * call to Curl_client_write() so it does the right thing.
+   *
+   * Notice that we cannot enable this flag for FTP in general,
+   * as an FTP transfer might involve a HTTP proxy connection and
+   * headers from CONNECT should not automatically be part of the
+   * output. */
+  CURLcode result;
+  int save = data->set.include_header;
+  data->set.include_header = TRUE;
+  result = Curl_client_write(data, CLIENTWRITE_HEADER, buf, blen);
+  data->set.include_header = save? TRUE:FALSE;
+  return result;
+}
+
+static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
+                                    int ftpcode)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  switch(ftpcode) {
+  case 213:
+    {
+      /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
+         last .sss part is optional and means fractions of a second */
+      int year, month, day, hour, minute, second;
+      struct pingpong *pp = &ftpc->pp;
+      char *resp = Curl_dyn_ptr(&pp->recvbuf) + 4;
+      if(ftp_213_date(resp, &year, &month, &day, &hour, &minute, &second)) {
+        /* we have a time, reformat it */
+        char timebuf[24];
+        msnprintf(timebuf, sizeof(timebuf),
+                  "%04d%02d%02d %02d:%02d:%02d GMT",
+                  year, month, day, hour, minute, second);
+        /* now, convert this into a time() value: */
+        data->info.filetime = Curl_getdate_capped(timebuf);
+      }
+
+#ifdef CURL_FTP_HTTPSTYLE_HEAD
+      /* If we asked for a time of the file and we actually got one as well,
+         we "emulate" an HTTP-style header in our output. */
+
+      if(data->req.no_body &&
+         ftpc->file &&
+         data->set.get_filetime &&
+         (data->info.filetime >= 0) ) {
+        char headerbuf[128];
+        int headerbuflen;
+        time_t filetime = data->info.filetime;
+        struct tm buffer;
+        const struct tm *tm = &buffer;
+
+        result = Curl_gmtime(filetime, &buffer);
+        if(result)
+          return result;
+
+        /* format: "Tue, 15 Nov 1994 12:45:26" */
+        headerbuflen = msnprintf(headerbuf, sizeof(headerbuf),
+                  "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+                  Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+                  tm->tm_mday,
+                  Curl_month[tm->tm_mon],
+                  tm->tm_year + 1900,
+                  tm->tm_hour,
+                  tm->tm_min,
+                  tm->tm_sec);
+        result = client_write_header(data, headerbuf, headerbuflen);
+        if(result)
+          return result;
+      } /* end of a ridiculous amount of conditionals */
+#endif
+    }
+    break;
+  default:
+    infof(data, "unsupported MDTM reply format");
+    break;
+  case 550: /* 550 is used for several different problems, e.g.
+               "No such file or directory" or "Permission denied".
+               It does not mean that the file does not exist at all. */
+    infof(data, "MDTM failed: file does not exist or permission problem,"
+          " continuing");
+    break;
+  }
+
+  if(data->set.timecondition) {
+    if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
+      switch(data->set.timecondition) {
+      case CURL_TIMECOND_IFMODSINCE:
+      default:
+        if(data->info.filetime <= data->set.timevalue) {
+          infof(data, "The requested document is not new enough");
+          ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
+          data->info.timecond = TRUE;
+          ftp_state(data, FTP_STOP);
+          return CURLE_OK;
+        }
+        break;
+      case CURL_TIMECOND_IFUNMODSINCE:
+        if(data->info.filetime > data->set.timevalue) {
+          infof(data, "The requested document is not old enough");
+          ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
+          data->info.timecond = TRUE;
+          ftp_state(data, FTP_STOP);
+          return CURLE_OK;
+        }
+        break;
+      } /* switch */
+    }
+    else {
+      infof(data, "Skipping time comparison");
+    }
+  }
+
+  if(!result)
+    result = ftp_state_type(data);
+
+  return result;
+}
+
+static CURLcode ftp_state_type_resp(struct Curl_easy *data,
+                                    int ftpcode,
+                                    ftpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+
+  if(ftpcode/100 != 2) {
+    /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
+       successful 'TYPE I'. While that is not as RFC959 says, it is still a
+       positive response code and we allow that. */
+    failf(data, "Couldn't set desired mode");
+    return CURLE_FTP_COULDNT_SET_TYPE;
+  }
+  if(ftpcode != 200)
+    infof(data, "Got a %03d response code instead of the assumed 200",
+          ftpcode);
+
+  if(instate == FTP_TYPE)
+    result = ftp_state_size(data, conn);
+  else if(instate == FTP_LIST_TYPE)
+    result = ftp_state_list(data);
+  else if(instate == FTP_RETR_TYPE)
+    result = ftp_state_retr_prequote(data);
+  else if(instate == FTP_STOR_TYPE)
+    result = ftp_state_stor_prequote(data);
+
+  return result;
+}
+
+static CURLcode ftp_state_retr(struct Curl_easy *data,
+                               curl_off_t filesize)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  DEBUGF(infof(data, "ftp_state_retr()"));
+  if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
+    failf(data, "Maximum file size exceeded");
+    return CURLE_FILESIZE_EXCEEDED;
+  }
+  ftp->downloadsize = filesize;
+
+  if(data->state.resume_from) {
+    /* We always (attempt to) get the size of downloads, so it is done before
+       this even when not doing resumes. */
+    if(filesize == -1) {
+      infof(data, "ftp server doesn't support SIZE");
+      /* We couldn't get the size and therefore we can't know if there really
+         is a part of the file left to get, although the server will just
+         close the connection when we start the connection so it won't cause
+         us any harm, just not make us exit as nicely. */
+    }
+    else {
+      /* We got a file size report, so we check that there actually is a
+         part of the file left to get, or else we go home.  */
+      if(data->state.resume_from< 0) {
+        /* We're supposed to download the last abs(from) bytes */
+        if(filesize < -data->state.resume_from) {
+          failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
+                ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
+                data->state.resume_from, filesize);
+          return CURLE_BAD_DOWNLOAD_RESUME;
+        }
+        /* convert to size to download */
+        ftp->downloadsize = -data->state.resume_from;
+        /* download from where? */
+        data->state.resume_from = filesize - ftp->downloadsize;
+      }
+      else {
+        if(filesize < data->state.resume_from) {
+          failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
+                ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
+                data->state.resume_from, filesize);
+          return CURLE_BAD_DOWNLOAD_RESUME;
+        }
+        /* Now store the number of bytes we are expected to download */
+        ftp->downloadsize = filesize-data->state.resume_from;
+      }
+    }
+
+    if(ftp->downloadsize == 0) {
+      /* no data to transfer */
+      Curl_xfer_setup(data, -1, -1, FALSE, -1);
+      infof(data, "File already completely downloaded");
+
+      /* Set ->transfer so that we won't get any error in ftp_done()
+       * because we didn't transfer the any file */
+      ftp->transfer = PPTRANSFER_NONE;
+      ftp_state(data, FTP_STOP);
+      return CURLE_OK;
+    }
+
+    /* Set resume file transfer offset */
+    infof(data, "Instructs server to resume from offset %"
+          CURL_FORMAT_CURL_OFF_T, data->state.resume_from);
+
+    result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
+                           data->state.resume_from);
+    if(!result)
+      ftp_state(data, FTP_RETR_REST);
+  }
+  else {
+    /* no resume */
+    result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
+    if(!result)
+      ftp_state(data, FTP_RETR);
+  }
+
+  return result;
+}
+
+static CURLcode ftp_state_size_resp(struct Curl_easy *data,
+                                    int ftpcode,
+                                    ftpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  curl_off_t filesize = -1;
+  char *buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf);
+  size_t len = data->conn->proto.ftpc.pp.nfinal;
+
+  /* get the size from the ascii string: */
+  if(ftpcode == 213) {
+    /* To allow servers to prepend "rubbish" in the response string, we scan
+       for all the digits at the end of the response and parse only those as a
+       number. */
+    char *start = &buf[4];
+    char *fdigit = memchr(start, '\r', len);
+    if(fdigit) {
+      fdigit--;
+      if(*fdigit == '\n')
+        fdigit--;
+      while(ISDIGIT(fdigit[-1]) && (fdigit > start))
+        fdigit--;
+    }
+    else
+      fdigit = start;
+    /* ignores parsing errors, which will make the size remain unknown */
+    (void)curlx_strtoofft(fdigit, NULL, 10, &filesize);
+
+  }
+  else if(ftpcode == 550) { /* "No such file or directory" */
+    /* allow a SIZE failure for (resumed) uploads, when probing what command
+       to use */
+    if(instate != FTP_STOR_SIZE) {
+      failf(data, "The file does not exist");
+      return CURLE_REMOTE_FILE_NOT_FOUND;
+    }
+  }
+
+  if(instate == FTP_SIZE) {
+#ifdef CURL_FTP_HTTPSTYLE_HEAD
+    if(-1 != filesize) {
+      char clbuf[128];
+      int clbuflen = msnprintf(clbuf, sizeof(clbuf),
+                "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
+      result = client_write_header(data, clbuf, clbuflen);
+      if(result)
+        return result;
+    }
+#endif
+    Curl_pgrsSetDownloadSize(data, filesize);
+    result = ftp_state_rest(data, data->conn);
+  }
+  else if(instate == FTP_RETR_SIZE) {
+    Curl_pgrsSetDownloadSize(data, filesize);
+    result = ftp_state_retr(data, filesize);
+  }
+  else if(instate == FTP_STOR_SIZE) {
+    data->state.resume_from = filesize;
+    result = ftp_state_ul_setup(data, TRUE);
+  }
+
+  return result;
+}
+
+static CURLcode ftp_state_rest_resp(struct Curl_easy *data,
+                                    struct connectdata *conn,
+                                    int ftpcode,
+                                    ftpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  switch(instate) {
+  case FTP_REST:
+  default:
+#ifdef CURL_FTP_HTTPSTYLE_HEAD
+    if(ftpcode == 350) {
+      char buffer[24]= { "Accept-ranges: bytes\r\n" };
+      result = client_write_header(data, buffer, strlen(buffer));
+      if(result)
+        return result;
+    }
+#endif
+    result = ftp_state_prepare_transfer(data);
+    break;
+
+  case FTP_RETR_REST:
+    if(ftpcode != 350) {
+      failf(data, "Couldn't use REST");
+      result = CURLE_FTP_COULDNT_USE_REST;
+    }
+    else {
+      result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
+      if(!result)
+        ftp_state(data, FTP_RETR);
+    }
+    break;
+  }
+
+  return result;
+}
+
+static CURLcode ftp_state_stor_resp(struct Curl_easy *data,
+                                    int ftpcode, ftpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+
+  if(ftpcode >= 400) {
+    failf(data, "Failed FTP upload: %0d", ftpcode);
+    ftp_state(data, FTP_STOP);
+    /* oops, we never close the sockets! */
+    return CURLE_UPLOAD_FAILED;
+  }
+
+  conn->proto.ftpc.state_saved = instate;
+
+  /* PORT means we are now awaiting the server to connect to us. */
+  if(data->set.ftp_use_port) {
+    bool connected;
+
+    ftp_state(data, FTP_STOP); /* no longer in STOR state */
+
+    result = AllowServerConnect(data, &connected);
+    if(result)
+      return result;
+
+    if(!connected) {
+      struct ftp_conn *ftpc = &conn->proto.ftpc;
+      infof(data, "Data conn was not available immediately");
+      ftpc->wait_data_conn = TRUE;
+    }
+
+    return CURLE_OK;
+  }
+  return InitiateTransfer(data);
+}
+
+/* for LIST and RETR responses */
+static CURLcode ftp_state_get_resp(struct Curl_easy *data,
+                                   int ftpcode,
+                                   ftpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
+
+  if((ftpcode == 150) || (ftpcode == 125)) {
+
+    /*
+      A;
+      150 Opening BINARY mode data connection for /etc/passwd (2241
+      bytes).  (ok, the file is being transferred)
+
+      B:
+      150 Opening ASCII mode data connection for /bin/ls
+
+      C:
+      150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
+
+      D:
+      150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
+
+      E:
+      125 Data connection already open; Transfer starting. */
+
+    curl_off_t size = -1; /* default unknown size */
+
+
+    /*
+     * It appears that there are FTP-servers that return size 0 for files when
+     * SIZE is used on the file while being in BINARY mode. To work around
+     * that (stupid) behavior, we attempt to parse the RETR response even if
+     * the SIZE returned size zero.
+     *
+     * Debugging help from Salvatore Sorrentino on February 26, 2003.
+     */
+
+    if((instate != FTP_LIST) &&
+       !data->state.prefer_ascii &&
+       !data->set.ignorecl &&
+       (ftp->downloadsize < 1)) {
+      /*
+       * It seems directory listings either don't show the size or very
+       * often uses size 0 anyway. ASCII transfers may very well turn out
+       * that the transferred amount of data is not the same as this line
+       * tells, why using this number in those cases only confuses us.
+       *
+       * Example D above makes this parsing a little tricky */
+      char *bytes;
+      char *buf = Curl_dyn_ptr(&conn->proto.ftpc.pp.recvbuf);
+      bytes = strstr(buf, " bytes");
+      if(bytes) {
+        long in = (long)(--bytes-buf);
+        /* this is a hint there is size information in there! ;-) */
+        while(--in) {
+          /* scan for the left parenthesis and break there */
+          if('(' == *bytes)
+            break;
+          /* skip only digits */
+          if(!ISDIGIT(*bytes)) {
+            bytes = NULL;
+            break;
+          }
+          /* one more estep backwards */
+          bytes--;
+        }
+        /* if we have nothing but digits: */
+        if(bytes) {
+          ++bytes;
+          /* get the number! */
+          (void)curlx_strtoofft(bytes, NULL, 10, &size);
+        }
+      }
+    }
+    else if(ftp->downloadsize > -1)
+      size = ftp->downloadsize;
+
+    if(size > data->req.maxdownload && data->req.maxdownload > 0)
+      size = data->req.size = data->req.maxdownload;
+    else if((instate != FTP_LIST) && (data->state.prefer_ascii))
+      size = -1; /* kludge for servers that understate ASCII mode file size */
+
+    infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T,
+          data->req.maxdownload);
+
+    if(instate != FTP_LIST)
+      infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T,
+            size);
+
+    /* FTP download: */
+    conn->proto.ftpc.state_saved = instate;
+    conn->proto.ftpc.retr_size_saved = size;
+
+    if(data->set.ftp_use_port) {
+      bool connected;
+
+      result = AllowServerConnect(data, &connected);
+      if(result)
+        return result;
+
+      if(!connected) {
+        struct ftp_conn *ftpc = &conn->proto.ftpc;
+        infof(data, "Data conn was not available immediately");
+        ftp_state(data, FTP_STOP);
+        ftpc->wait_data_conn = TRUE;
+      }
+    }
+    else
+      return InitiateTransfer(data);
+  }
+  else {
+    if((instate == FTP_LIST) && (ftpcode == 450)) {
+      /* simply no matching files in the dir listing */
+      ftp->transfer = PPTRANSFER_NONE; /* don't download anything */
+      ftp_state(data, FTP_STOP); /* this phase is over */
+    }
+    else {
+      failf(data, "RETR response: %03d", ftpcode);
+      return instate == FTP_RETR && ftpcode == 550?
+        CURLE_REMOTE_FILE_NOT_FOUND:
+        CURLE_FTP_COULDNT_RETR_FILE;
+    }
+  }
+
+  return result;
+}
+
+/* after USER, PASS and ACCT */
+static CURLcode ftp_state_loggedin(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+
+  if(conn->bits.ftp_use_control_ssl) {
+    /* PBSZ = PROTECTION BUFFER SIZE.
+
+    The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
+
+    Specifically, the PROT command MUST be preceded by a PBSZ
+    command and a PBSZ command MUST be preceded by a successful
+    security data exchange (the TLS negotiation in this case)
+
+    ... (and on page 8):
+
+    Thus the PBSZ command must still be issued, but must have a
+    parameter of '0' to indicate that no buffering is taking place
+    and the data connection should not be encapsulated.
+    */
+    result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "PBSZ %d", 0);
+    if(!result)
+      ftp_state(data, FTP_PBSZ);
+  }
+  else {
+    result = ftp_state_pwd(data, conn);
+  }
+  return result;
+}
+
+/* for USER and PASS responses */
+static CURLcode ftp_state_user_resp(struct Curl_easy *data,
+                                    int ftpcode)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  /* some need password anyway, and others just return 2xx ignored */
+  if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
+    /* 331 Password required for ...
+       (the server requires to send the user's password too) */
+    result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s",
+                           conn->passwd?conn->passwd:"");
+    if(!result)
+      ftp_state(data, FTP_PASS);
+  }
+  else if(ftpcode/100 == 2) {
+    /* 230 User ... logged in.
+       (the user logged in with or without password) */
+    result = ftp_state_loggedin(data);
+  }
+  else if(ftpcode == 332) {
+    if(data->set.str[STRING_FTP_ACCOUNT]) {
+      result = Curl_pp_sendf(data, &ftpc->pp, "ACCT %s",
+                             data->set.str[STRING_FTP_ACCOUNT]);
+      if(!result)
+        ftp_state(data, FTP_ACCT);
+    }
+    else {
+      failf(data, "ACCT requested but none available");
+      result = CURLE_LOGIN_DENIED;
+    }
+  }
+  else {
+    /* All other response codes, like:
+
+    530 User ... access denied
+    (the server denies to log the specified user) */
+
+    if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
+       !ftpc->ftp_trying_alternative) {
+      /* Ok, USER failed.  Let's try the supplied command. */
+      result =
+        Curl_pp_sendf(data, &ftpc->pp, "%s",
+                      data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
+      if(!result) {
+        ftpc->ftp_trying_alternative = TRUE;
+        ftp_state(data, FTP_USER);
+      }
+    }
+    else {
+      failf(data, "Access denied: %03d", ftpcode);
+      result = CURLE_LOGIN_DENIED;
+    }
+  }
+  return result;
+}
+
+/* for ACCT response */
+static CURLcode ftp_state_acct_resp(struct Curl_easy *data,
+                                    int ftpcode)
+{
+  CURLcode result = CURLE_OK;
+  if(ftpcode != 230) {
+    failf(data, "ACCT rejected by server: %03d", ftpcode);
+    result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
+  }
+  else
+    result = ftp_state_loggedin(data);
+
+  return result;
+}
+
+
+static CURLcode ftp_statemachine(struct Curl_easy *data,
+                                 struct connectdata *conn)
+{
+  CURLcode result;
+  int ftpcode;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+  static const char * const ftpauth[] = { "SSL", "TLS" };
+  size_t nread = 0;
+
+  if(pp->sendleft)
+    return Curl_pp_flushsend(data, pp);
+
+  result = ftp_readresp(data, FIRSTSOCKET, pp, &ftpcode, &nread);
+  if(result)
+    return result;
+
+  if(ftpcode) {
+    /* we have now received a full FTP server response */
+    switch(ftpc->state) {
+    case FTP_WAIT220:
+      if(ftpcode == 230) {
+        /* 230 User logged in - already! Take as 220 if TLS required. */
+        if(data->set.use_ssl <= CURLUSESSL_TRY ||
+           conn->bits.ftp_use_control_ssl)
+          return ftp_state_user_resp(data, ftpcode);
+      }
+      else if(ftpcode != 220) {
+        failf(data, "Got a %03d ftp-server response when 220 was expected",
+              ftpcode);
+        return CURLE_WEIRD_SERVER_REPLY;
+      }
+
+      /* We have received a 220 response fine, now we proceed. */
+#ifdef HAVE_GSSAPI
+      if(data->set.krb) {
+        /* If not anonymous login, try a secure login. Note that this
+           procedure is still BLOCKING. */
+
+        Curl_sec_request_prot(conn, "private");
+        /* We set private first as default, in case the line below fails to
+           set a valid level */
+        Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
+
+        if(Curl_sec_login(data, conn)) {
+          failf(data, "secure login failed");
+          return CURLE_WEIRD_SERVER_REPLY;
+        }
+        infof(data, "Authentication successful");
+      }
+#endif
+
+      if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) {
+        /* We don't have a SSL/TLS control connection yet, but FTPS is
+           requested. Try a FTPS connection now */
+
+        ftpc->count3 = 0;
+        switch(data->set.ftpsslauth) {
+        case CURLFTPAUTH_DEFAULT:
+        case CURLFTPAUTH_SSL:
+          ftpc->count2 = 1; /* add one to get next */
+          ftpc->count1 = 0;
+          break;
+        case CURLFTPAUTH_TLS:
+          ftpc->count2 = -1; /* subtract one to get next */
+          ftpc->count1 = 1;
+          break;
+        default:
+          failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
+                (int)data->set.ftpsslauth);
+          return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
+        }
+        result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
+                               ftpauth[ftpc->count1]);
+        if(!result)
+          ftp_state(data, FTP_AUTH);
+      }
+      else
+        result = ftp_state_user(data, conn);
+      break;
+
+    case FTP_AUTH:
+      /* we have gotten the response to a previous AUTH command */
+
+      if(pp->overflow)
+        return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */
+
+      /* RFC2228 (page 5) says:
+       *
+       * If the server is willing to accept the named security mechanism,
+       * and does not require any security data, it must respond with
+       * reply code 234/334.
+       */
+
+      if((ftpcode == 234) || (ftpcode == 334)) {
+        /* this was BLOCKING, keep it so for now */
+        bool done;
+        if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
+          result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
+          if(result) {
+            /* we failed and bail out */
+            return CURLE_USE_SSL_FAILED;
+          }
+        }
+        result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, &done);
+        if(!result) {
+          conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
+          conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */
+          result = ftp_state_user(data, conn);
+        }
+      }
+      else if(ftpc->count3 < 1) {
+        ftpc->count3++;
+        ftpc->count1 += ftpc->count2; /* get next attempt */
+        result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
+                               ftpauth[ftpc->count1]);
+        /* remain in this same state */
+      }
+      else {
+        if(data->set.use_ssl > CURLUSESSL_TRY)
+          /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
+          result = CURLE_USE_SSL_FAILED;
+        else
+          /* ignore the failure and continue */
+          result = ftp_state_user(data, conn);
+      }
+      break;
+
+    case FTP_USER:
+    case FTP_PASS:
+      result = ftp_state_user_resp(data, ftpcode);
+      break;
+
+    case FTP_ACCT:
+      result = ftp_state_acct_resp(data, ftpcode);
+      break;
+
+    case FTP_PBSZ:
+      result =
+        Curl_pp_sendf(data, &ftpc->pp, "PROT %c",
+                      data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
+      if(!result)
+        ftp_state(data, FTP_PROT);
+      break;
+
+    case FTP_PROT:
+      if(ftpcode/100 == 2)
+        /* We have enabled SSL for the data connection! */
+        conn->bits.ftp_use_data_ssl =
+          (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
+      /* FTP servers typically responds with 500 if they decide to reject
+         our 'P' request */
+      else if(data->set.use_ssl > CURLUSESSL_CONTROL)
+        /* we failed and bails out */
+        return CURLE_USE_SSL_FAILED;
+
+      if(data->set.ftp_ccc) {
+        /* CCC - Clear Command Channel
+         */
+        result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC");
+        if(!result)
+          ftp_state(data, FTP_CCC);
+      }
+      else
+        result = ftp_state_pwd(data, conn);
+      break;
+
+    case FTP_CCC:
+      if(ftpcode < 500) {
+        /* First shut down the SSL layer (note: this call will block) */
+        result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET);
+
+        if(result)
+          failf(data, "Failed to clear the command channel (CCC)");
+      }
+      if(!result)
+        /* Then continue as normal */
+        result = ftp_state_pwd(data, conn);
+      break;
+
+    case FTP_PWD:
+      if(ftpcode == 257) {
+        char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first
+                                                       letter */
+        bool entry_extracted = FALSE;
+        struct dynbuf out;
+        Curl_dyn_init(&out, 1000);
+
+        /* Reply format is like
+           257<space>[rubbish]"<directory-name>"<space><commentary> and the
+           RFC959 says
+
+           The directory name can contain any character; embedded
+           double-quotes should be escaped by double-quotes (the
+           "quote-doubling" convention).
+        */
+
+        /* scan for the first double-quote for non-standard responses */
+        while(*ptr != '\n' && *ptr != '\0' && *ptr != '"')
+          ptr++;
+
+        if('\"' == *ptr) {
+          /* it started good */
+          for(ptr++; *ptr; ptr++) {
+            if('\"' == *ptr) {
+              if('\"' == ptr[1]) {
+                /* "quote-doubling" */
+                result = Curl_dyn_addn(&out, &ptr[1], 1);
+                ptr++;
+              }
+              else {
+                /* end of path */
+                if(Curl_dyn_len(&out))
+                  entry_extracted = TRUE;
+                break; /* get out of this loop */
+              }
+            }
+            else
+              result = Curl_dyn_addn(&out, ptr, 1);
+            if(result)
+              return result;
+          }
+        }
+        if(entry_extracted) {
+          /* If the path name does not look like an absolute path (i.e.: it
+             does not start with a '/'), we probably need some server-dependent
+             adjustments. For example, this is the case when connecting to
+             an OS400 FTP server: this server supports two name syntaxes,
+             the default one being incompatible with standard paths. In
+             addition, this server switches automatically to the regular path
+             syntax when one is encountered in a command: this results in
+             having an entrypath in the wrong syntax when later used in CWD.
+               The method used here is to check the server OS: we do it only
+             if the path name looks strange to minimize overhead on other
+             systems. */
+          char *dir = Curl_dyn_ptr(&out);
+
+          if(!ftpc->server_os && dir[0] != '/') {
+            result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST");
+            if(result) {
+              free(dir);
+              return result;
+            }
+            Curl_safefree(ftpc->entrypath);
+            ftpc->entrypath = dir; /* remember this */
+            infof(data, "Entry path is '%s'", ftpc->entrypath);
+            /* also save it where getinfo can access it: */
+            data->state.most_recent_ftp_entrypath = ftpc->entrypath;
+            ftp_state(data, FTP_SYST);
+            break;
+          }
+
+          Curl_safefree(ftpc->entrypath);
+          ftpc->entrypath = dir; /* remember this */
+          infof(data, "Entry path is '%s'", ftpc->entrypath);
+          /* also save it where getinfo can access it: */
+          data->state.most_recent_ftp_entrypath = ftpc->entrypath;
+        }
+        else {
+          /* couldn't get the path */
+          Curl_dyn_free(&out);
+          infof(data, "Failed to figure out path");
+        }
+      }
+      ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
+      DEBUGF(infof(data, "protocol connect phase DONE"));
+      break;
+
+    case FTP_SYST:
+      if(ftpcode == 215) {
+        char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first
+                                                       letter */
+        char *os;
+        char *start;
+
+        /* Reply format is like
+           215<space><OS-name><space><commentary>
+        */
+        while(*ptr == ' ')
+          ptr++;
+        for(start = ptr; *ptr && *ptr != ' '; ptr++)
+          ;
+        os = Curl_memdup0(start, ptr - start);
+        if(!os)
+          return CURLE_OUT_OF_MEMORY;
+
+        /* Check for special servers here. */
+        if(strcasecompare(os, "OS/400")) {
+          /* Force OS400 name format 1. */
+          result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1");
+          if(result) {
+            free(os);
+            return result;
+          }
+          /* remember target server OS */
+          Curl_safefree(ftpc->server_os);
+          ftpc->server_os = os;
+          ftp_state(data, FTP_NAMEFMT);
+          break;
+        }
+        /* Nothing special for the target server. */
+        /* remember target server OS */
+        Curl_safefree(ftpc->server_os);
+        ftpc->server_os = os;
+      }
+      else {
+        /* Cannot identify server OS. Continue anyway and cross fingers. */
+      }
+
+      ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
+      DEBUGF(infof(data, "protocol connect phase DONE"));
+      break;
+
+    case FTP_NAMEFMT:
+      if(ftpcode == 250) {
+        /* Name format change successful: reload initial path. */
+        ftp_state_pwd(data, conn);
+        break;
+      }
+
+      ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
+      DEBUGF(infof(data, "protocol connect phase DONE"));
+      break;
+
+    case FTP_QUOTE:
+    case FTP_POSTQUOTE:
+    case FTP_RETR_PREQUOTE:
+    case FTP_STOR_PREQUOTE:
+      if((ftpcode >= 400) && !ftpc->count2) {
+        /* failure response code, and not allowed to fail */
+        failf(data, "QUOT command failed with %03d", ftpcode);
+        result = CURLE_QUOTE_ERROR;
+      }
+      else
+        result = ftp_state_quote(data, FALSE, ftpc->state);
+      break;
+
+    case FTP_CWD:
+      if(ftpcode/100 != 2) {
+        /* failure to CWD there */
+        if(data->set.ftp_create_missing_dirs &&
+           ftpc->cwdcount && !ftpc->count2) {
+          /* try making it */
+          ftpc->count2++; /* counter to prevent CWD-MKD loops */
+
+          /* count3 is set to allow MKD to fail once per dir. In the case when
+          CWD fails and then MKD fails (due to another session raced it to
+          create the dir) this then allows for a second try to CWD to it. */
+          ftpc->count3 = (data->set.ftp_create_missing_dirs == 2) ? 1 : 0;
+
+          result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s",
+                                 ftpc->dirs[ftpc->cwdcount - 1]);
+          if(!result)
+            ftp_state(data, FTP_MKD);
+        }
+        else {
+          /* return failure */
+          failf(data, "Server denied you to change to the given directory");
+          ftpc->cwdfail = TRUE; /* don't remember this path as we failed
+                                   to enter it */
+          result = CURLE_REMOTE_ACCESS_DENIED;
+        }
+      }
+      else {
+        /* success */
+        ftpc->count2 = 0;
+        if(++ftpc->cwdcount <= ftpc->dirdepth)
+          /* send next CWD */
+          result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
+                                 ftpc->dirs[ftpc->cwdcount - 1]);
+        else
+          result = ftp_state_mdtm(data);
+      }
+      break;
+
+    case FTP_MKD:
+      if((ftpcode/100 != 2) && !ftpc->count3--) {
+        /* failure to MKD the dir */
+        failf(data, "Failed to MKD dir: %03d", ftpcode);
+        result = CURLE_REMOTE_ACCESS_DENIED;
+      }
+      else {
+        ftp_state(data, FTP_CWD);
+        /* send CWD */
+        result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
+                               ftpc->dirs[ftpc->cwdcount - 1]);
+      }
+      break;
+
+    case FTP_MDTM:
+      result = ftp_state_mdtm_resp(data, ftpcode);
+      break;
+
+    case FTP_TYPE:
+    case FTP_LIST_TYPE:
+    case FTP_RETR_TYPE:
+    case FTP_STOR_TYPE:
+      result = ftp_state_type_resp(data, ftpcode, ftpc->state);
+      break;
+
+    case FTP_SIZE:
+    case FTP_RETR_SIZE:
+    case FTP_STOR_SIZE:
+      result = ftp_state_size_resp(data, ftpcode, ftpc->state);
+      break;
+
+    case FTP_REST:
+    case FTP_RETR_REST:
+      result = ftp_state_rest_resp(data, conn, ftpcode, ftpc->state);
+      break;
+
+    case FTP_PRET:
+      if(ftpcode != 200) {
+        /* there only is this one standard OK return code. */
+        failf(data, "PRET command not accepted: %03d", ftpcode);
+        return CURLE_FTP_PRET_FAILED;
+      }
+      result = ftp_state_use_pasv(data, conn);
+      break;
+
+    case FTP_PASV:
+      result = ftp_state_pasv_resp(data, ftpcode);
+      break;
+
+    case FTP_PORT:
+      result = ftp_state_port_resp(data, ftpcode);
+      break;
+
+    case FTP_LIST:
+    case FTP_RETR:
+      result = ftp_state_get_resp(data, ftpcode, ftpc->state);
+      break;
+
+    case FTP_STOR:
+      result = ftp_state_stor_resp(data, ftpcode, ftpc->state);
+      break;
+
+    case FTP_QUIT:
+    default:
+      /* internal error */
+      ftp_state(data, FTP_STOP);
+      break;
+    }
+  } /* if(ftpcode) */
+
+  return result;
+}
+
+
+/* called repeatedly until done from multi.c */
+static CURLcode ftp_multi_statemach(struct Curl_easy *data,
+                                    bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  CURLcode result = Curl_pp_statemach(data, &ftpc->pp, FALSE, FALSE);
+
+  /* Check for the state outside of the Curl_socket_check() return code checks
+     since at times we are in fact already in this state when this function
+     gets called. */
+  *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
+
+  return result;
+}
+
+static CURLcode ftp_block_statemach(struct Curl_easy *data,
+                                    struct connectdata *conn)
+{
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+  CURLcode result = CURLE_OK;
+
+  while(ftpc->state != FTP_STOP) {
+    result = Curl_pp_statemach(data, pp, TRUE, TRUE /* disconnecting */);
+    if(result)
+      break;
+  }
+
+  return result;
+}
+
+/*
+ * ftp_connect() should do everything that is to be considered a part of
+ * the connection phase.
+ *
+ * The variable 'done' points to will be TRUE if the protocol-layer connect
+ * phase is done when this function returns, or FALSE if not.
+ *
+ */
+static CURLcode ftp_connect(struct Curl_easy *data,
+                            bool *done) /* see description above */
+{
+  CURLcode result;
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+
+  *done = FALSE; /* default to not done yet */
+
+  /* We always support persistent connections on ftp */
+  connkeep(conn, "FTP default");
+
+  PINGPONG_SETUP(pp, ftp_statemachine, ftp_endofresp);
+
+  if(conn->handler->flags & PROTOPT_SSL) {
+    /* BLOCKING */
+    result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done);
+    if(result)
+      return result;
+    conn->bits.ftp_use_control_ssl = TRUE;
+  }
+
+  Curl_pp_init(pp); /* once per transfer */
+
+  /* When we connect, we start in the state where we await the 220
+     response */
+  ftp_state(data, FTP_WAIT220);
+
+  result = ftp_multi_statemach(data, done);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
+                         bool premature)
+{
+  struct connectdata *conn = data->conn;
+  struct FTP *ftp = data->req.p.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+  ssize_t nread;
+  int ftpcode;
+  CURLcode result = CURLE_OK;
+  char *rawPath = NULL;
+  size_t pathLen = 0;
+
+  if(!ftp)
+    return CURLE_OK;
+
+  switch(status) {
+  case CURLE_BAD_DOWNLOAD_RESUME:
+  case CURLE_FTP_WEIRD_PASV_REPLY:
+  case CURLE_FTP_PORT_FAILED:
+  case CURLE_FTP_ACCEPT_FAILED:
+  case CURLE_FTP_ACCEPT_TIMEOUT:
+  case CURLE_FTP_COULDNT_SET_TYPE:
+  case CURLE_FTP_COULDNT_RETR_FILE:
+  case CURLE_PARTIAL_FILE:
+  case CURLE_UPLOAD_FAILED:
+  case CURLE_REMOTE_ACCESS_DENIED:
+  case CURLE_FILESIZE_EXCEEDED:
+  case CURLE_REMOTE_FILE_NOT_FOUND:
+  case CURLE_WRITE_ERROR:
+    /* the connection stays alive fine even though this happened */
+  case CURLE_OK: /* doesn't affect the control connection's status */
+    if(!premature)
+      break;
+
+    /* until we cope better with prematurely ended requests, let them
+     * fallback as if in complete failure */
+    FALLTHROUGH();
+  default:       /* by default, an error means the control connection is
+                    wedged and should not be used anymore */
+    ftpc->ctl_valid = FALSE;
+    ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
+                             current path, as this connection is going */
+    connclose(conn, "FTP ended with bad error code");
+    result = status;      /* use the already set error code */
+    break;
+  }
+
+  if(data->state.wildcardmatch) {
+    if(data->set.chunk_end && ftpc->file) {
+      Curl_set_in_callback(data, true);
+      data->set.chunk_end(data->set.wildcardptr);
+      Curl_set_in_callback(data, false);
+    }
+    ftpc->known_filesize = -1;
+  }
+
+  if(!result)
+    /* get the url-decoded "raw" path */
+    result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen,
+                            REJECT_CTRL);
+  if(result) {
+    /* We can limp along anyway (and should try to since we may already be in
+     * the error path) */
+    ftpc->ctl_valid = FALSE; /* mark control connection as bad */
+    connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
+    free(ftpc->prevpath);
+    ftpc->prevpath = NULL; /* no path remembering */
+  }
+  else { /* remember working directory for connection reuse */
+    if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/'))
+      free(rawPath); /* full path => no CWDs happened => keep ftpc->prevpath */
+    else {
+      free(ftpc->prevpath);
+
+      if(!ftpc->cwdfail) {
+        if(data->set.ftp_filemethod == FTPFILE_NOCWD)
+          pathLen = 0; /* relative path => working directory is FTP home */
+        else
+          pathLen -= ftpc->file?strlen(ftpc->file):0; /* file is url-decoded */
+
+        rawPath[pathLen] = '\0';
+        ftpc->prevpath = rawPath;
+      }
+      else {
+        free(rawPath);
+        ftpc->prevpath = NULL; /* no path */
+      }
+    }
+
+    if(ftpc->prevpath)
+      infof(data, "Remembering we are in dir \"%s\"", ftpc->prevpath);
+  }
+
+  /* free the dir tree and file parts */
+  freedirs(ftpc);
+
+  /* shut down the socket to inform the server we're done */
+
+#ifdef _WIN32_WCE
+  shutdown(conn->sock[SECONDARYSOCKET], 2);  /* SD_BOTH */
+#endif
+
+  if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
+    if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
+      /* partial download completed */
+      result = Curl_pp_sendf(data, pp, "%s", "ABOR");
+      if(result) {
+        failf(data, "Failure sending ABOR command: %s",
+              curl_easy_strerror(result));
+        ftpc->ctl_valid = FALSE; /* mark control connection as bad */
+        connclose(conn, "ABOR command failed"); /* connection closure */
+      }
+    }
+
+    close_secondarysocket(data, conn);
+  }
+
+  if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid &&
+     pp->pending_resp && !premature) {
+    /*
+     * Let's see what the server says about the transfer we just performed,
+     * but lower the timeout as sometimes this connection has died while the
+     * data has been transferred. This happens when doing through NATs etc that
+     * abandon old silent connections.
+     */
+    timediff_t old_time = pp->response_time;
+
+    pp->response_time = 60*1000; /* give it only a minute for now */
+    pp->response = Curl_now(); /* timeout relative now */
+
+    result = Curl_GetFTPResponse(data, &nread, &ftpcode);
+
+    pp->response_time = old_time; /* set this back to previous value */
+
+    if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
+      failf(data, "control connection looks dead");
+      ftpc->ctl_valid = FALSE; /* mark control connection as bad */
+      connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
+    }
+
+    if(result) {
+      Curl_safefree(ftp->pathalloc);
+      return result;
+    }
+
+    if(ftpc->dont_check && data->req.maxdownload > 0) {
+      /* we have just sent ABOR and there is no reliable way to check if it was
+       * successful or not; we have to close the connection now */
+      infof(data, "partial download completed, closing connection");
+      connclose(conn, "Partial download with no ability to check");
+      return result;
+    }
+
+    if(!ftpc->dont_check) {
+      /* 226 Transfer complete, 250 Requested file action okay, completed. */
+      switch(ftpcode) {
+      case 226:
+      case 250:
+        break;
+      case 552:
+        failf(data, "Exceeded storage allocation");
+        result = CURLE_REMOTE_DISK_FULL;
+        break;
+      default:
+        failf(data, "server did not report OK, got %d", ftpcode);
+        result = CURLE_PARTIAL_FILE;
+        break;
+      }
+    }
+  }
+
+  if(result || premature)
+    /* the response code from the transfer showed an error already so no
+       use checking further */
+    ;
+  else if(data->state.upload) {
+    if((-1 != data->state.infilesize) &&
+       (data->state.infilesize != data->req.writebytecount) &&
+       !data->set.crlf &&
+       (ftp->transfer == PPTRANSFER_BODY)) {
+      failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
+            " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
+            data->req.writebytecount, data->state.infilesize);
+      result = CURLE_PARTIAL_FILE;
+    }
+  }
+  else {
+    if((-1 != data->req.size) &&
+       (data->req.size != data->req.bytecount) &&
+#ifdef CURL_DO_LINEEND_CONV
+       /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
+        * we'll check to see if the discrepancy can be explained by the number
+        * of CRLFs we've changed to LFs.
+        */
+       ((data->req.size + data->state.crlf_conversions) !=
+        data->req.bytecount) &&
+#endif /* CURL_DO_LINEEND_CONV */
+       (data->req.maxdownload != data->req.bytecount)) {
+      failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
+            " bytes", data->req.bytecount);
+      result = CURLE_PARTIAL_FILE;
+    }
+    else if(!ftpc->dont_check &&
+            !data->req.bytecount &&
+            (data->req.size>0)) {
+      failf(data, "No data was received");
+      result = CURLE_FTP_COULDNT_RETR_FILE;
+    }
+  }
+
+  /* clear these for next connection */
+  ftp->transfer = PPTRANSFER_BODY;
+  ftpc->dont_check = FALSE;
+
+  /* Send any post-transfer QUOTE strings? */
+  if(!status && !result && !premature && data->set.postquote)
+    result = ftp_sendquote(data, conn, data->set.postquote);
+  Curl_safefree(ftp->pathalloc);
+  return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_sendquote()
+ *
+ * Where a 'quote' means a list of custom commands to send to the server.
+ * The quote list is passed as an argument.
+ *
+ * BLOCKING
+ */
+
+static
+CURLcode ftp_sendquote(struct Curl_easy *data,
+                       struct connectdata *conn, struct curl_slist *quote)
+{
+  struct curl_slist *item;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+
+  item = quote;
+  while(item) {
+    if(item->data) {
+      ssize_t nread;
+      char *cmd = item->data;
+      bool acceptfail = FALSE;
+      CURLcode result;
+      int ftpcode = 0;
+
+      /* if a command starts with an asterisk, which a legal FTP command never
+         can, the command will be allowed to fail without it causing any
+         aborts or cancels etc. It will cause libcurl to act as if the command
+         is successful, whatever the server responds. */
+
+      if(cmd[0] == '*') {
+        cmd++;
+        acceptfail = TRUE;
+      }
+
+      result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd);
+      if(!result) {
+        pp->response = Curl_now(); /* timeout relative now */
+        result = Curl_GetFTPResponse(data, &nread, &ftpcode);
+      }
+      if(result)
+        return result;
+
+      if(!acceptfail && (ftpcode >= 400)) {
+        failf(data, "QUOT string not accepted: %s", cmd);
+        return CURLE_QUOTE_ERROR;
+      }
+    }
+
+    item = item->next;
+  }
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_need_type()
+ *
+ * Returns TRUE if we in the current situation should send TYPE
+ */
+static int ftp_need_type(struct connectdata *conn,
+                         bool ascii_wanted)
+{
+  return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
+}
+
+/***********************************************************************
+ *
+ * ftp_nb_type()
+ *
+ * Set TYPE. We only deal with ASCII or BINARY so this function
+ * sets one of them.
+ * If the transfer type is not sent, simulate on OK response in newstate
+ */
+static CURLcode ftp_nb_type(struct Curl_easy *data,
+                            struct connectdata *conn,
+                            bool ascii, ftpstate newstate)
+{
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  CURLcode result;
+  char want = (char)(ascii?'A':'I');
+
+  if(ftpc->transfertype == want) {
+    ftp_state(data, newstate);
+    return ftp_state_type_resp(data, 200, newstate);
+  }
+
+  result = Curl_pp_sendf(data, &ftpc->pp, "TYPE %c", want);
+  if(!result) {
+    ftp_state(data, newstate);
+
+    /* keep track of our current transfer type */
+    ftpc->transfertype = want;
+  }
+  return result;
+}
+
+/***************************************************************************
+ *
+ * ftp_pasv_verbose()
+ *
+ * This function only outputs some informationals about this second connection
+ * when we've issued a PASV command before and thus we have connected to a
+ * possibly new IP address.
+ *
+ */
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void
+ftp_pasv_verbose(struct Curl_easy *data,
+                 struct Curl_addrinfo *ai,
+                 char *newhost, /* ascii version */
+                 int port)
+{
+  char buf[256];
+  Curl_printable_address(ai, buf, sizeof(buf));
+  infof(data, "Connecting to %s (%s) port %d", newhost, buf, port);
+}
+#endif
+
+/*
+ * ftp_do_more()
+ *
+ * This function shall be called when the second FTP (data) connection is
+ * connected.
+ *
+ * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
+ * (which basically is only for when PASV is being sent to retry a failed
+ * EPSV).
+ */
+
+static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
+{
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  CURLcode result = CURLE_OK;
+  bool connected = FALSE;
+  bool complete = FALSE;
+
+  /* the ftp struct is inited in ftp_connect(). If we are connecting to an HTTP
+   * proxy then the state will not be valid until after that connection is
+   * complete */
+  struct FTP *ftp = NULL;
+
+  /* if the second connection isn't done yet, wait for it to have
+   * connected to the remote host. When using proxy tunneling, this
+   * means the tunnel needs to have been establish. However, we
+   * can not expect the remote host to talk to us in any way yet.
+   * So, when using ftps: the SSL handshake will not start until we
+   * tell the remote server that we are there. */
+  if(conn->cfilter[SECONDARYSOCKET]) {
+    result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &connected);
+    if(result || !Curl_conn_is_ip_connected(data, SECONDARYSOCKET)) {
+      if(result && (ftpc->count1 == 0)) {
+        *completep = -1; /* go back to DOING please */
+        /* this is a EPSV connect failing, try PASV instead */
+        return ftp_epsv_disable(data, conn);
+      }
+      return result;
+    }
+  }
+
+  /* Curl_proxy_connect might have moved the protocol state */
+  ftp = data->req.p.ftp;
+
+  if(ftpc->state) {
+    /* already in a state so skip the initial commands.
+       They are only done to kickstart the do_more state */
+    result = ftp_multi_statemach(data, &complete);
+
+    *completep = (int)complete;
+
+    /* if we got an error or if we don't wait for a data connection return
+       immediately */
+    if(result || !ftpc->wait_data_conn)
+      return result;
+
+    /* if we reach the end of the FTP state machine here, *complete will be
+       TRUE but so is ftpc->wait_data_conn, which says we need to wait for the
+       data connection and therefore we're not actually complete */
+    *completep = 0;
+  }
+
+  if(ftp->transfer <= PPTRANSFER_INFO) {
+    /* a transfer is about to take place, or if not a file name was given
+       so we'll do a SIZE on it later and then we need the right TYPE first */
+
+    if(ftpc->wait_data_conn) {
+      bool serv_conned;
+
+      result = ReceivedServerConnect(data, &serv_conned);
+      if(result)
+        return result; /* Failed to accept data connection */
+
+      if(serv_conned) {
+        /* It looks data connection is established */
+        result = AcceptServerConnect(data);
+        ftpc->wait_data_conn = FALSE;
+        if(!result)
+          result = InitiateTransfer(data);
+
+        if(result)
+          return result;
+
+        *completep = 1; /* this state is now complete when the server has
+                           connected back to us */
+      }
+    }
+    else if(data->state.upload) {
+      result = ftp_nb_type(data, conn, data->state.prefer_ascii,
+                           FTP_STOR_TYPE);
+      if(result)
+        return result;
+
+      result = ftp_multi_statemach(data, &complete);
+      *completep = (int)complete;
+    }
+    else {
+      /* download */
+      ftp->downloadsize = -1; /* unknown as of yet */
+
+      result = Curl_range(data);
+
+      if(result == CURLE_OK && data->req.maxdownload >= 0) {
+        /* Don't check for successful transfer */
+        ftpc->dont_check = TRUE;
+      }
+
+      if(result)
+        ;
+      else if(data->state.list_only || !ftpc->file) {
+        /* The specified path ends with a slash, and therefore we think this
+           is a directory that is requested, use LIST. But before that we
+           need to set ASCII transfer mode. */
+
+        /* But only if a body transfer was requested. */
+        if(ftp->transfer == PPTRANSFER_BODY) {
+          result = ftp_nb_type(data, conn, TRUE, FTP_LIST_TYPE);
+          if(result)
+            return result;
+        }
+        /* otherwise just fall through */
+      }
+      else {
+        result = ftp_nb_type(data, conn, data->state.prefer_ascii,
+                             FTP_RETR_TYPE);
+        if(result)
+          return result;
+      }
+
+      result = ftp_multi_statemach(data, &complete);
+      *completep = (int)complete;
+    }
+    return result;
+  }
+
+  /* no data to transfer */
+  Curl_xfer_setup(data, -1, -1, FALSE, -1);
+
+  if(!ftpc->wait_data_conn) {
+    /* no waiting for the data connection so this is now complete */
+    *completep = 1;
+    DEBUGF(infof(data, "DO-MORE phase ends with %d", (int)result));
+  }
+
+  return result;
+}
+
+
+
+/***********************************************************************
+ *
+ * ftp_perform()
+ *
+ * This is the actual DO function for FTP. Get a file/directory according to
+ * the options previously setup.
+ */
+
+static
+CURLcode ftp_perform(struct Curl_easy *data,
+                     bool *connected,  /* connect status after PASV / PORT */
+                     bool *dophase_done)
+{
+  /* this is FTP and no proxy */
+  CURLcode result = CURLE_OK;
+
+  DEBUGF(infof(data, "DO phase starts"));
+
+  if(data->req.no_body) {
+    /* requested no body means no transfer... */
+    struct FTP *ftp = data->req.p.ftp;
+    ftp->transfer = PPTRANSFER_INFO;
+  }
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* start the first command in the DO phase */
+  result = ftp_state_quote(data, TRUE, FTP_QUOTE);
+  if(result)
+    return result;
+
+  /* run the state-machine */
+  result = ftp_multi_statemach(data, dophase_done);
+
+  *connected = Curl_conn_is_connected(data->conn, SECONDARYSOCKET);
+
+  infof(data, "ftp_perform ends with SECONDARY: %d", *connected);
+
+  if(*dophase_done)
+    DEBUGF(infof(data, "DO phase is complete1"));
+
+  return result;
+}
+
+static void wc_data_dtor(void *ptr)
+{
+  struct ftp_wc *ftpwc = ptr;
+  if(ftpwc && ftpwc->parser)
+    Curl_ftp_parselist_data_free(&ftpwc->parser);
+  free(ftpwc);
+}
+
+static CURLcode init_wc_data(struct Curl_easy *data)
+{
+  char *last_slash;
+  struct FTP *ftp = data->req.p.ftp;
+  char *path = ftp->path;
+  struct WildcardData *wildcard = data->wildcard;
+  CURLcode result = CURLE_OK;
+  struct ftp_wc *ftpwc = NULL;
+
+  last_slash = strrchr(ftp->path, '/');
+  if(last_slash) {
+    last_slash++;
+    if(last_slash[0] == '\0') {
+      wildcard->state = CURLWC_CLEAN;
+      result = ftp_parse_url_path(data);
+      return result;
+    }
+    wildcard->pattern = strdup(last_slash);
+    if(!wildcard->pattern)
+      return CURLE_OUT_OF_MEMORY;
+    last_slash[0] = '\0'; /* cut file from path */
+  }
+  else { /* there is only 'wildcard pattern' or nothing */
+    if(path[0]) {
+      wildcard->pattern = strdup(path);
+      if(!wildcard->pattern)
+        return CURLE_OUT_OF_MEMORY;
+      path[0] = '\0';
+    }
+    else { /* only list */
+      wildcard->state = CURLWC_CLEAN;
+      result = ftp_parse_url_path(data);
+      return result;
+    }
+  }
+
+  /* program continues only if URL is not ending with slash, allocate needed
+     resources for wildcard transfer */
+
+  /* allocate ftp protocol specific wildcard data */
+  ftpwc = calloc(1, sizeof(struct ftp_wc));
+  if(!ftpwc) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto fail;
+  }
+
+  /* INITIALIZE parselist structure */
+  ftpwc->parser = Curl_ftp_parselist_data_alloc();
+  if(!ftpwc->parser) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto fail;
+  }
+
+  wildcard->ftpwc = ftpwc; /* put it to the WildcardData tmp pointer */
+  wildcard->dtor = wc_data_dtor;
+
+  /* wildcard does not support NOCWD option (assert it?) */
+  if(data->set.ftp_filemethod == FTPFILE_NOCWD)
+    data->set.ftp_filemethod = FTPFILE_MULTICWD;
+
+  /* try to parse ftp url */
+  result = ftp_parse_url_path(data);
+  if(result) {
+    goto fail;
+  }
+
+  wildcard->path = strdup(ftp->path);
+  if(!wildcard->path) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto fail;
+  }
+
+  /* backup old write_function */
+  ftpwc->backup.write_function = data->set.fwrite_func;
+  /* parsing write function */
+  data->set.fwrite_func = Curl_ftp_parselist;
+  /* backup old file descriptor */
+  ftpwc->backup.file_descriptor = data->set.out;
+  /* let the writefunc callback know the transfer */
+  data->set.out = data;
+
+  infof(data, "Wildcard - Parsing started");
+  return CURLE_OK;
+
+fail:
+  if(ftpwc) {
+    Curl_ftp_parselist_data_free(&ftpwc->parser);
+    free(ftpwc);
+  }
+  Curl_safefree(wildcard->pattern);
+  wildcard->dtor = ZERO_NULL;
+  wildcard->ftpwc = NULL;
+  return result;
+}
+
+static CURLcode wc_statemach(struct Curl_easy *data)
+{
+  struct WildcardData * const wildcard = data->wildcard;
+  struct connectdata *conn = data->conn;
+  CURLcode result = CURLE_OK;
+
+  for(;;) {
+    switch(wildcard->state) {
+    case CURLWC_INIT:
+      result = init_wc_data(data);
+      if(wildcard->state == CURLWC_CLEAN)
+        /* only listing! */
+        return result;
+      wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
+      return result;
+
+    case CURLWC_MATCHING: {
+      /* In this state is LIST response successfully parsed, so lets restore
+         previous WRITEFUNCTION callback and WRITEDATA pointer */
+      struct ftp_wc *ftpwc = wildcard->ftpwc;
+      data->set.fwrite_func = ftpwc->backup.write_function;
+      data->set.out = ftpwc->backup.file_descriptor;
+      ftpwc->backup.write_function = ZERO_NULL;
+      ftpwc->backup.file_descriptor = NULL;
+      wildcard->state = CURLWC_DOWNLOADING;
+
+      if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
+        /* error found in LIST parsing */
+        wildcard->state = CURLWC_CLEAN;
+        continue;
+      }
+      if(wildcard->filelist.size == 0) {
+        /* no corresponding file */
+        wildcard->state = CURLWC_CLEAN;
+        return CURLE_REMOTE_FILE_NOT_FOUND;
+      }
+      continue;
+    }
+
+    case CURLWC_DOWNLOADING: {
+      /* filelist has at least one file, lets get first one */
+      struct ftp_conn *ftpc = &conn->proto.ftpc;
+      struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
+      struct FTP *ftp = data->req.p.ftp;
+
+      char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
+      if(!tmp_path)
+        return CURLE_OUT_OF_MEMORY;
+
+      /* switch default ftp->path and tmp_path */
+      free(ftp->pathalloc);
+      ftp->pathalloc = ftp->path = tmp_path;
+
+      infof(data, "Wildcard - START of \"%s\"", finfo->filename);
+      if(data->set.chunk_bgn) {
+        long userresponse;
+        Curl_set_in_callback(data, true);
+        userresponse = data->set.chunk_bgn(
+          finfo, data->set.wildcardptr, (int)wildcard->filelist.size);
+        Curl_set_in_callback(data, false);
+        switch(userresponse) {
+        case CURL_CHUNK_BGN_FUNC_SKIP:
+          infof(data, "Wildcard - \"%s\" skipped by user",
+                finfo->filename);
+          wildcard->state = CURLWC_SKIP;
+          continue;
+        case CURL_CHUNK_BGN_FUNC_FAIL:
+          return CURLE_CHUNK_FAILED;
+        }
+      }
+
+      if(finfo->filetype != CURLFILETYPE_FILE) {
+        wildcard->state = CURLWC_SKIP;
+        continue;
+      }
+
+      if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
+        ftpc->known_filesize = finfo->size;
+
+      result = ftp_parse_url_path(data);
+      if(result)
+        return result;
+
+      /* we don't need the Curl_fileinfo of first file anymore */
+      Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
+
+      if(wildcard->filelist.size == 0) { /* remains only one file to down. */
+        wildcard->state = CURLWC_CLEAN;
+        /* after that will be ftp_do called once again and no transfer
+           will be done because of CURLWC_CLEAN state */
+        return CURLE_OK;
+      }
+      return result;
+    }
+
+    case CURLWC_SKIP: {
+      if(data->set.chunk_end) {
+        Curl_set_in_callback(data, true);
+        data->set.chunk_end(data->set.wildcardptr);
+        Curl_set_in_callback(data, false);
+      }
+      Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
+      wildcard->state = (wildcard->filelist.size == 0) ?
+        CURLWC_CLEAN : CURLWC_DOWNLOADING;
+      continue;
+    }
+
+    case CURLWC_CLEAN: {
+      struct ftp_wc *ftpwc = wildcard->ftpwc;
+      result = CURLE_OK;
+      if(ftpwc)
+        result = Curl_ftp_parselist_geterror(ftpwc->parser);
+
+      wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
+      return result;
+    }
+
+    case CURLWC_DONE:
+    case CURLWC_ERROR:
+    case CURLWC_CLEAR:
+      if(wildcard->dtor) {
+        wildcard->dtor(wildcard->ftpwc);
+        wildcard->ftpwc = NULL;
+      }
+      return result;
+    }
+  }
+  /* UNREACHABLE */
+}
+
+/***********************************************************************
+ *
+ * ftp_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (ftp_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode ftp_do(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  *done = FALSE; /* default to false */
+  ftpc->wait_data_conn = FALSE; /* default to no such wait */
+
+#ifdef CURL_DO_LINEEND_CONV
+  {
+    /* FTP data may need conversion. */
+    struct Curl_cwriter *ftp_lc_writer;
+
+    result = Curl_cwriter_create(&ftp_lc_writer, data, &ftp_cw_lc,
+                                 CURL_CW_CONTENT_DECODE);
+    if(result)
+      return result;
+
+    result = Curl_cwriter_add(data, ftp_lc_writer);
+    if(result) {
+      Curl_cwriter_free(data, ftp_lc_writer);
+      return result;
+    }
+  }
+#endif /* CURL_DO_LINEEND_CONV */
+
+  if(data->state.wildcardmatch) {
+    result = wc_statemach(data);
+    if(data->wildcard->state == CURLWC_SKIP ||
+       data->wildcard->state == CURLWC_DONE) {
+      /* do not call ftp_regular_transfer */
+      return CURLE_OK;
+    }
+    if(result) /* error, loop or skipping the file */
+      return result;
+  }
+  else { /* no wildcard FSM needed */
+    result = ftp_parse_url_path(data);
+    if(result)
+      return result;
+  }
+
+  result = ftp_regular_transfer(data, done);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_quit()
+ *
+ * This should be called before calling sclose() on an ftp control connection
+ * (not data connections). We should then wait for the response from the
+ * server before returning. The calling code should then try to close the
+ * connection.
+ *
+ */
+static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+
+  if(conn->proto.ftpc.ctl_valid) {
+    result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "QUIT");
+    if(result) {
+      failf(data, "Failure sending QUIT command: %s",
+            curl_easy_strerror(result));
+      conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
+      connclose(conn, "QUIT command failed"); /* mark for connection closure */
+      ftp_state(data, FTP_STOP);
+      return result;
+    }
+
+    ftp_state(data, FTP_QUIT);
+
+    result = ftp_block_statemach(data, conn);
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_disconnect()
+ *
+ * Disconnect from an FTP server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode ftp_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn,
+                               bool dead_connection)
+{
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+
+  /* We cannot send quit unconditionally. If this connection is stale or
+     bad in any way, sending quit and waiting around here will make the
+     disconnect wait in vain and cause more problems than we need to.
+
+     ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
+     will try to send the QUIT command, otherwise it will just return.
+  */
+  if(dead_connection)
+    ftpc->ctl_valid = FALSE;
+
+  /* The FTP session may or may not have been allocated/setup at this point! */
+  (void)ftp_quit(data, conn); /* ignore errors on the QUIT */
+
+  if(ftpc->entrypath) {
+    if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
+      data->state.most_recent_ftp_entrypath = NULL;
+    }
+    Curl_safefree(ftpc->entrypath);
+  }
+
+  freedirs(ftpc);
+  Curl_safefree(ftpc->account);
+  Curl_safefree(ftpc->alternative_to_user);
+  Curl_safefree(ftpc->prevpath);
+  Curl_safefree(ftpc->server_os);
+  Curl_pp_disconnect(pp);
+  Curl_sec_end(conn);
+  return CURLE_OK;
+}
+
+#ifdef _MSC_VER
+/* warning C4706: assignment within conditional expression */
+#pragma warning(disable:4706)
+#endif
+
+/***********************************************************************
+ *
+ * ftp_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ *
+ */
+static
+CURLcode ftp_parse_url_path(struct Curl_easy *data)
+{
+  /* the ftp struct is already inited in ftp_connect() */
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  const char *slashPos = NULL;
+  const char *fileName = NULL;
+  CURLcode result = CURLE_OK;
+  char *rawPath = NULL; /* url-decoded "raw" path */
+  size_t pathLen = 0;
+
+  ftpc->ctl_valid = FALSE;
+  ftpc->cwdfail = FALSE;
+
+  /* url-decode ftp path before further evaluation */
+  result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL);
+  if(result) {
+    failf(data, "path contains control characters");
+    return result;
+  }
+
+  switch(data->set.ftp_filemethod) {
+    case FTPFILE_NOCWD: /* fastest, but less standard-compliant */
+
+      if((pathLen > 0) && (rawPath[pathLen - 1] != '/'))
+        fileName = rawPath;  /* this is a full file path */
+      /*
+        else: ftpc->file is not used anywhere other than for operations on
+              a file. In other words, never for directory operations.
+              So we can safely leave filename as NULL here and use it as a
+              argument in dir/file decisions.
+      */
+      break;
+
+    case FTPFILE_SINGLECWD:
+      slashPos = strrchr(rawPath, '/');
+      if(slashPos) {
+        /* get path before last slash, except for / */
+        size_t dirlen = slashPos - rawPath;
+        if(dirlen == 0)
+          dirlen = 1;
+
+        ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
+        if(!ftpc->dirs) {
+          free(rawPath);
+          return CURLE_OUT_OF_MEMORY;
+        }
+
+        ftpc->dirs[0] = Curl_memdup0(rawPath, dirlen);
+        if(!ftpc->dirs[0]) {
+          free(rawPath);
+          return CURLE_OUT_OF_MEMORY;
+        }
+
+        ftpc->dirdepth = 1; /* we consider it to be a single dir */
+        fileName = slashPos + 1; /* rest is file name */
+      }
+      else
+        fileName = rawPath; /* file name only (or empty) */
+      break;
+
+    default: /* allow pretty much anything */
+    case FTPFILE_MULTICWD: {
+      /* current position: begin of next path component */
+      const char *curPos = rawPath;
+
+      /* number of entries allocated for the 'dirs' array */
+      size_t dirAlloc = 0;
+      const char *str = rawPath;
+      for(; *str != 0; ++str)
+        if(*str == '/')
+          ++dirAlloc;
+
+      if(dirAlloc) {
+        ftpc->dirs = calloc(dirAlloc, sizeof(ftpc->dirs[0]));
+        if(!ftpc->dirs) {
+          free(rawPath);
+          return CURLE_OUT_OF_MEMORY;
+        }
+
+        /* parse the URL path into separate path components */
+        while((slashPos = strchr(curPos, '/'))) {
+          size_t compLen = slashPos - curPos;
+
+          /* path starts with a slash: add that as a directory */
+          if((compLen == 0) && (ftpc->dirdepth == 0))
+            ++compLen;
+
+          /* we skip empty path components, like "x//y" since the FTP command
+             CWD requires a parameter and a non-existent parameter a) doesn't
+             work on many servers and b) has no effect on the others. */
+          if(compLen > 0) {
+            char *comp = Curl_memdup0(curPos, compLen);
+            if(!comp) {
+              free(rawPath);
+              return CURLE_OUT_OF_MEMORY;
+            }
+            ftpc->dirs[ftpc->dirdepth++] = comp;
+          }
+          curPos = slashPos + 1;
+        }
+      }
+      DEBUGASSERT((size_t)ftpc->dirdepth <= dirAlloc);
+      fileName = curPos; /* the rest is the file name (or empty) */
+    }
+    break;
+  } /* switch */
+
+  if(fileName && *fileName)
+    ftpc->file = strdup(fileName);
+  else
+    ftpc->file = NULL; /* instead of point to a zero byte,
+                            we make it a NULL pointer */
+
+  if(data->state.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) {
+    /* We need a file name when uploading. Return error! */
+    failf(data, "Uploading to a URL without a file name");
+    free(rawPath);
+    return CURLE_URL_MALFORMAT;
+  }
+
+  ftpc->cwddone = FALSE; /* default to not done */
+
+  if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/'))
+    ftpc->cwddone = TRUE; /* skip CWD for absolute paths */
+  else { /* newly created FTP connections are already in entry path */
+    const char *oldPath = conn->bits.reuse ? ftpc->prevpath : "";
+    if(oldPath) {
+      size_t n = pathLen;
+      if(data->set.ftp_filemethod == FTPFILE_NOCWD)
+        n = 0; /* CWD to entry for relative paths */
+      else
+        n -= ftpc->file?strlen(ftpc->file):0;
+
+      if((strlen(oldPath) == n) && !strncmp(rawPath, oldPath, n)) {
+        infof(data, "Request has same path as previous transfer");
+        ftpc->cwddone = TRUE;
+      }
+    }
+  }
+
+  free(rawPath);
+  return CURLE_OK;
+}
+
+/* call this when the DO phase has completed */
+static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
+{
+  struct connectdata *conn = data->conn;
+  struct FTP *ftp = data->req.p.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  if(connected) {
+    int completed;
+    CURLcode result = ftp_do_more(data, &completed);
+
+    if(result) {
+      close_secondarysocket(data, conn);
+      return result;
+    }
+  }
+
+  if(ftp->transfer != PPTRANSFER_BODY)
+    /* no data to transfer */
+    Curl_xfer_setup(data, -1, -1, FALSE, -1);
+  else if(!connected)
+    /* since we didn't connect now, we want do_more to get called */
+    conn->bits.do_more = TRUE;
+
+  ftpc->ctl_valid = TRUE; /* seems good */
+
+  return CURLE_OK;
+}
+
+/* called from multi.c while DOing */
+static CURLcode ftp_doing(struct Curl_easy *data,
+                          bool *dophase_done)
+{
+  CURLcode result = ftp_multi_statemach(data, dophase_done);
+
+  if(result)
+    DEBUGF(infof(data, "DO phase failed"));
+  else if(*dophase_done) {
+    result = ftp_dophase_done(data, FALSE /* not connected */);
+
+    DEBUGF(infof(data, "DO phase is complete2"));
+  }
+  return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ *
+ * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
+ * ftp_done() function without finding any major problem.
+ */
+static
+CURLcode ftp_regular_transfer(struct Curl_easy *data,
+                              bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+  bool connected = FALSE;
+  struct connectdata *conn = data->conn;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  data->req.size = -1; /* make sure this is unknown at this point */
+
+  Curl_pgrsSetUploadCounter(data, 0);
+  Curl_pgrsSetDownloadCounter(data, 0);
+  Curl_pgrsSetUploadSize(data, -1);
+  Curl_pgrsSetDownloadSize(data, -1);
+
+  ftpc->ctl_valid = TRUE; /* starts good */
+
+  result = ftp_perform(data,
+                       &connected, /* have we connected after PASV/PORT */
+                       dophase_done); /* all commands in the DO-phase done? */
+
+  if(!result) {
+
+    if(!*dophase_done)
+      /* the DO phase has not completed yet */
+      return CURLE_OK;
+
+    result = ftp_dophase_done(data, connected);
+
+    if(result)
+      return result;
+  }
+  else
+    freedirs(ftpc);
+
+  return result;
+}
+
+static CURLcode ftp_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn)
+{
+  char *type;
+  struct FTP *ftp;
+  CURLcode result = CURLE_OK;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  ftp = calloc(1, sizeof(struct FTP));
+  if(!ftp)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* clone connection related data that is FTP specific */
+  if(data->set.str[STRING_FTP_ACCOUNT]) {
+    ftpc->account = strdup(data->set.str[STRING_FTP_ACCOUNT]);
+    if(!ftpc->account) {
+      free(ftp);
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]) {
+    ftpc->alternative_to_user =
+      strdup(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
+    if(!ftpc->alternative_to_user) {
+      Curl_safefree(ftpc->account);
+      free(ftp);
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  data->req.p.ftp = ftp;
+
+  ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
+
+  /* FTP URLs support an extension like ";type=<typecode>" that
+   * we'll try to get now! */
+  type = strstr(ftp->path, ";type=");
+
+  if(!type)
+    type = strstr(conn->host.rawalloc, ";type=");
+
+  if(type) {
+    char command;
+    *type = 0;                     /* it was in the middle of the hostname */
+    command = Curl_raw_toupper(type[6]);
+
+    switch(command) {
+    case 'A': /* ASCII mode */
+      data->state.prefer_ascii = TRUE;
+      break;
+
+    case 'D': /* directory mode */
+      data->state.list_only = TRUE;
+      break;
+
+    case 'I': /* binary mode */
+    default:
+      /* switch off ASCII */
+      data->state.prefer_ascii = FALSE;
+      break;
+    }
+  }
+
+  /* get some initial data into the ftp struct */
+  ftp->transfer = PPTRANSFER_BODY;
+  ftp->downloadsize = 0;
+  ftpc->known_filesize = -1; /* unknown size for now */
+  ftpc->use_ssl = data->set.use_ssl;
+  ftpc->ccc = data->set.ftp_ccc;
+
+  return result;
+}
+
+#endif /* CURL_DISABLE_FTP */
Index: trunk/src/libs/curl-8.7.1/lib/ftp.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/ftp.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/ftp.h	(revision 104083)
@@ -0,0 +1,167 @@
+#ifndef HEADER_CURL_FTP_H
+#define HEADER_CURL_FTP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "pingpong.h"
+
+#ifndef CURL_DISABLE_FTP
+extern const struct Curl_handler Curl_handler_ftp;
+
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_ftps;
+#endif
+
+CURLcode Curl_GetFTPResponse(struct Curl_easy *data, ssize_t *nread,
+                             int *ftpcode);
+#endif /* CURL_DISABLE_FTP */
+
+/****************************************************************************
+ * FTP unique setup
+ ***************************************************************************/
+enum {
+  FTP_STOP,    /* do nothing state, stops the state machine */
+  FTP_WAIT220, /* waiting for the initial 220 response immediately after
+                  a connect */
+  FTP_AUTH,
+  FTP_USER,
+  FTP_PASS,
+  FTP_ACCT,
+  FTP_PBSZ,
+  FTP_PROT,
+  FTP_CCC,
+  FTP_PWD,
+  FTP_SYST,
+  FTP_NAMEFMT,
+  FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
+  FTP_RETR_PREQUOTE,
+  FTP_STOR_PREQUOTE,
+  FTP_POSTQUOTE,
+  FTP_CWD,  /* change dir */
+  FTP_MKD,  /* if the dir didn't exist */
+  FTP_MDTM, /* to figure out the datestamp */
+  FTP_TYPE, /* to set type when doing a head-like request */
+  FTP_LIST_TYPE, /* set type when about to do a dir list */
+  FTP_RETR_TYPE, /* set type when about to RETR a file */
+  FTP_STOR_TYPE, /* set type when about to STOR a file */
+  FTP_SIZE, /* get the remote file's size for head-like request */
+  FTP_RETR_SIZE, /* get the remote file's size for RETR */
+  FTP_STOR_SIZE, /* get the size for STOR */
+  FTP_REST, /* when used to check if the server supports it in head-like */
+  FTP_RETR_REST, /* when asking for "resume" in for RETR */
+  FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */
+  FTP_PRET, /* generic state for PRET RETR, PRET STOR and PRET LIST/NLST */
+  FTP_PASV, /* generic state for PASV and EPSV, check count1 */
+  FTP_LIST, /* generic state for LIST, NLST or a custom list command */
+  FTP_RETR,
+  FTP_STOR, /* generic state for STOR and APPE */
+  FTP_QUIT,
+  FTP_LAST  /* never used */
+};
+typedef unsigned char ftpstate; /* use the enum values */
+
+struct ftp_parselist_data; /* defined later in ftplistparser.c */
+
+struct ftp_wc {
+  struct ftp_parselist_data *parser;
+
+  struct {
+    curl_write_callback write_function;
+    FILE *file_descriptor;
+  } backup;
+};
+
+typedef enum {
+  FTPFILE_MULTICWD  = 1, /* as defined by RFC1738 */
+  FTPFILE_NOCWD     = 2, /* use SIZE / RETR / STOR on the full path */
+  FTPFILE_SINGLECWD = 3  /* make one CWD, then SIZE / RETR / STOR on the
+                            file */
+} curl_ftpfile;
+
+/* This FTP struct is used in the Curl_easy. All FTP data that is
+   connection-oriented must be in FTP_conn to properly deal with the fact that
+   perhaps the Curl_easy is changed between the times the connection is
+   used. */
+struct FTP {
+  char *path;    /* points to the urlpieces struct field */
+  char *pathalloc; /* if non-NULL a pointer to an allocated path */
+
+  /* transfer a file/body or not, done as a typedefed enum just to make
+     debuggers display the full symbol and not just the numerical value */
+  curl_pp_transfer transfer;
+  curl_off_t downloadsize;
+};
+
+
+/* ftp_conn is used for struct connection-oriented data in the connectdata
+   struct */
+struct ftp_conn {
+  struct pingpong pp;
+  char *account;
+  char *alternative_to_user;
+  char *entrypath; /* the PWD reply when we logged on */
+  char *file;    /* url-decoded file name (or path) */
+  char **dirs;   /* realloc()ed array for path components */
+  char *newhost;
+  char *prevpath;   /* url-decoded conn->path from the previous transfer */
+  char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
+                        and others (A/I or zero) */
+  curl_off_t retr_size_saved; /* Size of retrieved file saved */
+  char *server_os;     /* The target server operating system. */
+  curl_off_t known_filesize; /* file size is different from -1, if wildcard
+                                LIST parsing was done and wc_statemach set
+                                it */
+  int dirdepth;  /* number of entries used in the 'dirs' array */
+  int cwdcount;     /* number of CWD commands issued */
+  int count1; /* general purpose counter for the state machine */
+  int count2; /* general purpose counter for the state machine */
+  int count3; /* general purpose counter for the state machine */
+  /* newhost is the (allocated) IP addr or host name to connect the data
+     connection to */
+  unsigned short newport;
+  ftpstate state; /* always use ftp.c:state() to change state! */
+  ftpstate state_saved; /* transfer type saved to be reloaded after data
+                           connection is established */
+  unsigned char use_ssl;   /* if AUTH TLS is to be attempted etc, for FTP or
+                              IMAP or POP3 or others! (type: curl_usessl)*/
+  unsigned char ccc;       /* ccc level for this connection */
+  BIT(ftp_trying_alternative);
+  BIT(dont_check);  /* Set to TRUE to prevent the final (post-transfer)
+                       file size and 226/250 status check. It should still
+                       read the line, just ignore the result. */
+  BIT(ctl_valid);   /* Tells Curl_ftp_quit() whether or not to do anything. If
+                       the connection has timed out or been closed, this
+                       should be FALSE when it gets to Curl_ftp_quit() */
+  BIT(cwddone);     /* if it has been determined that the proper CWD combo
+                       already has been done */
+  BIT(cwdfail);     /* set TRUE if a CWD command fails, as then we must prevent
+                       caching the current directory */
+  BIT(wait_data_conn); /* this is set TRUE if data connection is waited */
+};
+
+#define DEFAULT_ACCEPT_TIMEOUT   60000 /* milliseconds == one minute */
+
+#endif /* HEADER_CURL_FTP_H */
Index: trunk/src/libs/curl-8.7.1/lib/ftplistparser.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/ftplistparser.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/ftplistparser.c	(revision 104083)
@@ -0,0 +1,1041 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/**
+ * Now implemented:
+ *
+ * 1) Unix version 1
+ * drwxr-xr-x 1 user01 ftp  512 Jan 29 23:32 prog
+ * 2) Unix version 2
+ * drwxr-xr-x 1 user01 ftp  512 Jan 29 1997  prog
+ * 3) Unix version 3
+ * drwxr-xr-x 1      1   1  512 Jan 29 23:32 prog
+ * 4) Unix symlink
+ * lrwxr-xr-x 1 user01 ftp  512 Jan 29 23:32 prog -> prog2000
+ * 5) DOS style
+ * 01-29-97 11:32PM <DIR> prog
+ */
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FTP
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "fileinfo.h"
+#include "llist.h"
+#include "strtoofft.h"
+#include "ftp.h"
+#include "ftplistparser.h"
+#include "curl_fnmatch.h"
+#include "curl_memory.h"
+#include "multiif.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+typedef enum {
+  PL_UNIX_TOTALSIZE = 0,
+  PL_UNIX_FILETYPE,
+  PL_UNIX_PERMISSION,
+  PL_UNIX_HLINKS,
+  PL_UNIX_USER,
+  PL_UNIX_GROUP,
+  PL_UNIX_SIZE,
+  PL_UNIX_TIME,
+  PL_UNIX_FILENAME,
+  PL_UNIX_SYMLINK
+} pl_unix_mainstate;
+
+typedef union {
+  enum {
+    PL_UNIX_TOTALSIZE_INIT = 0,
+    PL_UNIX_TOTALSIZE_READING
+  } total_dirsize;
+
+  enum {
+    PL_UNIX_HLINKS_PRESPACE = 0,
+    PL_UNIX_HLINKS_NUMBER
+  } hlinks;
+
+  enum {
+    PL_UNIX_USER_PRESPACE = 0,
+    PL_UNIX_USER_PARSING
+  } user;
+
+  enum {
+    PL_UNIX_GROUP_PRESPACE = 0,
+    PL_UNIX_GROUP_NAME
+  } group;
+
+  enum {
+    PL_UNIX_SIZE_PRESPACE = 0,
+    PL_UNIX_SIZE_NUMBER
+  } size;
+
+  enum {
+    PL_UNIX_TIME_PREPART1 = 0,
+    PL_UNIX_TIME_PART1,
+    PL_UNIX_TIME_PREPART2,
+    PL_UNIX_TIME_PART2,
+    PL_UNIX_TIME_PREPART3,
+    PL_UNIX_TIME_PART3
+  } time;
+
+  enum {
+    PL_UNIX_FILENAME_PRESPACE = 0,
+    PL_UNIX_FILENAME_NAME,
+    PL_UNIX_FILENAME_WINDOWSEOL
+  } filename;
+
+  enum {
+    PL_UNIX_SYMLINK_PRESPACE = 0,
+    PL_UNIX_SYMLINK_NAME,
+    PL_UNIX_SYMLINK_PRETARGET1,
+    PL_UNIX_SYMLINK_PRETARGET2,
+    PL_UNIX_SYMLINK_PRETARGET3,
+    PL_UNIX_SYMLINK_PRETARGET4,
+    PL_UNIX_SYMLINK_TARGET,
+    PL_UNIX_SYMLINK_WINDOWSEOL
+  } symlink;
+} pl_unix_substate;
+
+typedef enum {
+  PL_WINNT_DATE = 0,
+  PL_WINNT_TIME,
+  PL_WINNT_DIRORSIZE,
+  PL_WINNT_FILENAME
+} pl_winNT_mainstate;
+
+typedef union {
+  enum {
+    PL_WINNT_TIME_PRESPACE = 0,
+    PL_WINNT_TIME_TIME
+  } time;
+  enum {
+    PL_WINNT_DIRORSIZE_PRESPACE = 0,
+    PL_WINNT_DIRORSIZE_CONTENT
+  } dirorsize;
+  enum {
+    PL_WINNT_FILENAME_PRESPACE = 0,
+    PL_WINNT_FILENAME_CONTENT,
+    PL_WINNT_FILENAME_WINEOL
+  } filename;
+} pl_winNT_substate;
+
+/* This struct is used in wildcard downloading - for parsing LIST response */
+struct ftp_parselist_data {
+  enum {
+    OS_TYPE_UNKNOWN = 0,
+    OS_TYPE_UNIX,
+    OS_TYPE_WIN_NT
+  } os_type;
+
+  union {
+    struct {
+      pl_unix_mainstate main;
+      pl_unix_substate sub;
+    } UNIX;
+
+    struct {
+      pl_winNT_mainstate main;
+      pl_winNT_substate sub;
+    } NT;
+  } state;
+
+  CURLcode error;
+  struct fileinfo *file_data;
+  unsigned int item_length;
+  size_t item_offset;
+  struct {
+    size_t filename;
+    size_t user;
+    size_t group;
+    size_t time;
+    size_t perm;
+    size_t symlink_target;
+  } offsets;
+};
+
+static void fileinfo_dtor(void *user, void *element)
+{
+  (void)user;
+  Curl_fileinfo_cleanup(element);
+}
+
+CURLcode Curl_wildcard_init(struct WildcardData *wc)
+{
+  Curl_llist_init(&wc->filelist, fileinfo_dtor);
+  wc->state = CURLWC_INIT;
+
+  return CURLE_OK;
+}
+
+void Curl_wildcard_dtor(struct WildcardData **wcp)
+{
+  struct WildcardData *wc = *wcp;
+  if(!wc)
+    return;
+
+  if(wc->dtor) {
+    wc->dtor(wc->ftpwc);
+    wc->dtor = ZERO_NULL;
+    wc->ftpwc = NULL;
+  }
+  DEBUGASSERT(wc->ftpwc == NULL);
+
+  Curl_llist_destroy(&wc->filelist, NULL);
+  free(wc->path);
+  wc->path = NULL;
+  free(wc->pattern);
+  wc->pattern = NULL;
+  wc->state = CURLWC_INIT;
+  free(wc);
+  *wcp = NULL;
+}
+
+struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
+{
+  return calloc(1, sizeof(struct ftp_parselist_data));
+}
+
+
+void Curl_ftp_parselist_data_free(struct ftp_parselist_data **parserp)
+{
+  struct ftp_parselist_data *parser = *parserp;
+  if(parser)
+    Curl_fileinfo_cleanup(parser->file_data);
+  free(parser);
+  *parserp = NULL;
+}
+
+
+CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
+{
+  return pl_data->error;
+}
+
+
+#define FTP_LP_MALFORMATED_PERM 0x01000000
+
+static unsigned int ftp_pl_get_permission(const char *str)
+{
+  unsigned int permissions = 0;
+  /* USER */
+  if(str[0] == 'r')
+    permissions |= 1 << 8;
+  else if(str[0] != '-')
+    permissions |= FTP_LP_MALFORMATED_PERM;
+  if(str[1] == 'w')
+    permissions |= 1 << 7;
+  else if(str[1] != '-')
+    permissions |= FTP_LP_MALFORMATED_PERM;
+
+  if(str[2] == 'x')
+    permissions |= 1 << 6;
+  else if(str[2] == 's') {
+    permissions |= 1 << 6;
+    permissions |= 1 << 11;
+  }
+  else if(str[2] == 'S')
+    permissions |= 1 << 11;
+  else if(str[2] != '-')
+    permissions |= FTP_LP_MALFORMATED_PERM;
+  /* GROUP */
+  if(str[3] == 'r')
+    permissions |= 1 << 5;
+  else if(str[3] != '-')
+    permissions |= FTP_LP_MALFORMATED_PERM;
+  if(str[4] == 'w')
+    permissions |= 1 << 4;
+  else if(str[4] != '-')
+    permissions |= FTP_LP_MALFORMATED_PERM;
+  if(str[5] == 'x')
+    permissions |= 1 << 3;
+  else if(str[5] == 's') {
+    permissions |= 1 << 3;
+    permissions |= 1 << 10;
+  }
+  else if(str[5] == 'S')
+    permissions |= 1 << 10;
+  else if(str[5] != '-')
+    permissions |= FTP_LP_MALFORMATED_PERM;
+  /* others */
+  if(str[6] == 'r')
+    permissions |= 1 << 2;
+  else if(str[6] != '-')
+    permissions |= FTP_LP_MALFORMATED_PERM;
+  if(str[7] == 'w')
+    permissions |= 1 << 1;
+  else if(str[7] != '-')
+      permissions |= FTP_LP_MALFORMATED_PERM;
+  if(str[8] == 'x')
+    permissions |= 1;
+  else if(str[8] == 't') {
+    permissions |= 1;
+    permissions |= 1 << 9;
+  }
+  else if(str[8] == 'T')
+    permissions |= 1 << 9;
+  else if(str[8] != '-')
+    permissions |= FTP_LP_MALFORMATED_PERM;
+
+  return permissions;
+}
+
+static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
+                                    struct fileinfo *infop)
+{
+  curl_fnmatch_callback compare;
+  struct WildcardData *wc = data->wildcard;
+  struct ftp_wc *ftpwc = wc->ftpwc;
+  struct Curl_llist *llist = &wc->filelist;
+  struct ftp_parselist_data *parser = ftpwc->parser;
+  bool add = TRUE;
+  struct curl_fileinfo *finfo = &infop->info;
+
+  /* set the finfo pointers */
+  char *str = Curl_dyn_ptr(&infop->buf);
+  finfo->filename       = str + parser->offsets.filename;
+  finfo->strings.group  = parser->offsets.group ?
+                          str + parser->offsets.group : NULL;
+  finfo->strings.perm   = parser->offsets.perm ?
+                          str + parser->offsets.perm : NULL;
+  finfo->strings.target = parser->offsets.symlink_target ?
+                          str + parser->offsets.symlink_target : NULL;
+  finfo->strings.time   = str + parser->offsets.time;
+  finfo->strings.user   = parser->offsets.user ?
+                          str + parser->offsets.user : NULL;
+
+  /* get correct fnmatch callback */
+  compare = data->set.fnmatch;
+  if(!compare)
+    compare = Curl_fnmatch;
+
+  /* filter pattern-corresponding filenames */
+  Curl_set_in_callback(data, true);
+  if(compare(data->set.fnmatch_data, wc->pattern,
+             finfo->filename) == 0) {
+    /* discard symlink which is containing multiple " -> " */
+    if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
+       (strstr(finfo->strings.target, " -> "))) {
+      add = FALSE;
+    }
+  }
+  else {
+    add = FALSE;
+  }
+  Curl_set_in_callback(data, false);
+
+  if(add) {
+    Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
+  }
+  else {
+    Curl_fileinfo_cleanup(infop);
+  }
+
+  ftpwc->parser->file_data = NULL;
+  return CURLE_OK;
+}
+
+#define MAX_FTPLIST_BUFFER 10000 /* arbitrarily set */
+
+size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
+                          void *connptr)
+{
+  size_t bufflen = size*nmemb;
+  struct Curl_easy *data = (struct Curl_easy *)connptr;
+  struct ftp_wc *ftpwc = data->wildcard->ftpwc;
+  struct ftp_parselist_data *parser = ftpwc->parser;
+  size_t i = 0;
+  CURLcode result;
+  size_t retsize = bufflen;
+
+  if(parser->error) { /* error in previous call */
+    /* scenario:
+     * 1. call => OK..
+     * 2. call => OUT_OF_MEMORY (or other error)
+     * 3. (last) call => is skipped RIGHT HERE and the error is handled later
+     *    in wc_statemach()
+     */
+    goto fail;
+  }
+
+  if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
+    /* considering info about FILE response format */
+    parser->os_type = ISDIGIT(buffer[0]) ? OS_TYPE_WIN_NT : OS_TYPE_UNIX;
+  }
+
+  while(i < bufflen) { /* FSM */
+    char *mem;
+    size_t len; /* number of bytes of data in the dynbuf */
+    char c = buffer[i];
+    struct fileinfo *infop;
+    struct curl_fileinfo *finfo;
+    if(!parser->file_data) { /* tmp file data is not allocated yet */
+      parser->file_data = Curl_fileinfo_alloc();
+      if(!parser->file_data) {
+        parser->error = CURLE_OUT_OF_MEMORY;
+        goto fail;
+      }
+      parser->item_offset = 0;
+      parser->item_length = 0;
+      Curl_dyn_init(&parser->file_data->buf, MAX_FTPLIST_BUFFER);
+    }
+
+    infop = parser->file_data;
+    finfo = &infop->info;
+
+    if(Curl_dyn_addn(&infop->buf, &c, 1)) {
+      parser->error = CURLE_OUT_OF_MEMORY;
+      goto fail;
+    }
+    len = Curl_dyn_len(&infop->buf);
+    mem = Curl_dyn_ptr(&infop->buf);
+
+    switch(parser->os_type) {
+    case OS_TYPE_UNIX:
+      switch(parser->state.UNIX.main) {
+      case PL_UNIX_TOTALSIZE:
+        switch(parser->state.UNIX.sub.total_dirsize) {
+        case PL_UNIX_TOTALSIZE_INIT:
+          if(c == 't') {
+            parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
+            parser->item_length++;
+          }
+          else {
+            parser->state.UNIX.main = PL_UNIX_FILETYPE;
+            /* start FSM again not considering size of directory */
+            Curl_dyn_reset(&infop->buf);
+            continue;
+          }
+          break;
+        case PL_UNIX_TOTALSIZE_READING:
+          parser->item_length++;
+          if(c == '\r') {
+            parser->item_length--;
+            Curl_dyn_setlen(&infop->buf, --len);
+          }
+          else if(c == '\n') {
+            mem[parser->item_length - 1] = 0;
+            if(!strncmp("total ", mem, 6)) {
+              char *endptr = mem + 6;
+              /* here we can deal with directory size, pass the leading
+                 whitespace and then the digits */
+              while(ISBLANK(*endptr))
+                endptr++;
+              while(ISDIGIT(*endptr))
+                endptr++;
+              if(*endptr) {
+                parser->error = CURLE_FTP_BAD_FILE_LIST;
+                goto fail;
+              }
+              parser->state.UNIX.main = PL_UNIX_FILETYPE;
+              Curl_dyn_reset(&infop->buf);
+            }
+            else {
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
+            }
+          }
+          break;
+        }
+        break;
+      case PL_UNIX_FILETYPE:
+        switch(c) {
+        case '-':
+          finfo->filetype = CURLFILETYPE_FILE;
+          break;
+        case 'd':
+          finfo->filetype = CURLFILETYPE_DIRECTORY;
+          break;
+        case 'l':
+          finfo->filetype = CURLFILETYPE_SYMLINK;
+          break;
+        case 'p':
+          finfo->filetype = CURLFILETYPE_NAMEDPIPE;
+          break;
+        case 's':
+          finfo->filetype = CURLFILETYPE_SOCKET;
+          break;
+        case 'c':
+          finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
+          break;
+        case 'b':
+          finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
+          break;
+        case 'D':
+          finfo->filetype = CURLFILETYPE_DOOR;
+          break;
+        default:
+          parser->error = CURLE_FTP_BAD_FILE_LIST;
+          goto fail;
+        }
+        parser->state.UNIX.main = PL_UNIX_PERMISSION;
+        parser->item_length = 0;
+        parser->item_offset = 1;
+        break;
+      case PL_UNIX_PERMISSION:
+        parser->item_length++;
+        if(parser->item_length <= 9) {
+          if(!strchr("rwx-tTsS", c)) {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+        }
+        else if(parser->item_length == 10) {
+          unsigned int perm;
+          if(c != ' ') {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          mem[10] = 0; /* terminate permissions */
+          perm = ftp_pl_get_permission(mem + parser->item_offset);
+          if(perm & FTP_LP_MALFORMATED_PERM) {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
+          parser->file_data->info.perm = perm;
+          parser->offsets.perm = parser->item_offset;
+
+          parser->item_length = 0;
+          parser->state.UNIX.main = PL_UNIX_HLINKS;
+          parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
+        }
+        break;
+      case PL_UNIX_HLINKS:
+        switch(parser->state.UNIX.sub.hlinks) {
+        case PL_UNIX_HLINKS_PRESPACE:
+          if(c != ' ') {
+            if(ISDIGIT(c)) {
+              parser->item_offset = len - 1;
+              parser->item_length = 1;
+              parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
+            }
+            else {
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
+            }
+          }
+          break;
+        case PL_UNIX_HLINKS_NUMBER:
+          parser->item_length ++;
+          if(c == ' ') {
+            char *p;
+            long int hlinks;
+            mem[parser->item_offset + parser->item_length - 1] = 0;
+            hlinks = strtol(mem + parser->item_offset, &p, 10);
+            if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
+              parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
+              parser->file_data->info.hardlinks = hlinks;
+            }
+            parser->item_length = 0;
+            parser->item_offset = 0;
+            parser->state.UNIX.main = PL_UNIX_USER;
+            parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
+          }
+          else if(!ISDIGIT(c)) {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          break;
+        }
+        break;
+      case PL_UNIX_USER:
+        switch(parser->state.UNIX.sub.user) {
+        case PL_UNIX_USER_PRESPACE:
+          if(c != ' ') {
+            parser->item_offset = len - 1;
+            parser->item_length = 1;
+            parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
+          }
+          break;
+        case PL_UNIX_USER_PARSING:
+          parser->item_length++;
+          if(c == ' ') {
+            mem[parser->item_offset + parser->item_length - 1] = 0;
+            parser->offsets.user = parser->item_offset;
+            parser->state.UNIX.main = PL_UNIX_GROUP;
+            parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
+            parser->item_offset = 0;
+            parser->item_length = 0;
+          }
+          break;
+        }
+        break;
+      case PL_UNIX_GROUP:
+        switch(parser->state.UNIX.sub.group) {
+        case PL_UNIX_GROUP_PRESPACE:
+          if(c != ' ') {
+            parser->item_offset = len - 1;
+            parser->item_length = 1;
+            parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
+          }
+          break;
+        case PL_UNIX_GROUP_NAME:
+          parser->item_length++;
+          if(c == ' ') {
+            mem[parser->item_offset + parser->item_length - 1] = 0;
+            parser->offsets.group = parser->item_offset;
+            parser->state.UNIX.main = PL_UNIX_SIZE;
+            parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
+            parser->item_offset = 0;
+            parser->item_length = 0;
+          }
+          break;
+        }
+        break;
+      case PL_UNIX_SIZE:
+        switch(parser->state.UNIX.sub.size) {
+        case PL_UNIX_SIZE_PRESPACE:
+          if(c != ' ') {
+            if(ISDIGIT(c)) {
+              parser->item_offset = len - 1;
+              parser->item_length = 1;
+              parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
+            }
+            else {
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
+            }
+          }
+          break;
+        case PL_UNIX_SIZE_NUMBER:
+          parser->item_length++;
+          if(c == ' ') {
+            char *p;
+            curl_off_t fsize;
+            mem[parser->item_offset + parser->item_length - 1] = 0;
+            if(!curlx_strtoofft(mem + parser->item_offset,
+                                &p, 10, &fsize)) {
+              if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
+                 fsize != CURL_OFF_T_MIN) {
+                parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
+                parser->file_data->info.size = fsize;
+              }
+              parser->item_length = 0;
+              parser->item_offset = 0;
+              parser->state.UNIX.main = PL_UNIX_TIME;
+              parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
+            }
+          }
+          else if(!ISDIGIT(c)) {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          break;
+        }
+        break;
+      case PL_UNIX_TIME:
+        switch(parser->state.UNIX.sub.time) {
+        case PL_UNIX_TIME_PREPART1:
+          if(c != ' ') {
+            if(ISALNUM(c)) {
+              parser->item_offset = len -1;
+              parser->item_length = 1;
+              parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
+            }
+            else {
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
+            }
+          }
+          break;
+        case PL_UNIX_TIME_PART1:
+          parser->item_length++;
+          if(c == ' ') {
+            parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
+          }
+          else if(!ISALNUM(c) && c != '.') {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          break;
+        case PL_UNIX_TIME_PREPART2:
+          parser->item_length++;
+          if(c != ' ') {
+            if(ISALNUM(c)) {
+              parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
+            }
+            else {
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
+            }
+          }
+          break;
+        case PL_UNIX_TIME_PART2:
+          parser->item_length++;
+          if(c == ' ') {
+            parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
+          }
+          else if(!ISALNUM(c) && c != '.') {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          break;
+        case PL_UNIX_TIME_PREPART3:
+          parser->item_length++;
+          if(c != ' ') {
+            if(ISALNUM(c)) {
+              parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
+            }
+            else {
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
+            }
+          }
+          break;
+        case PL_UNIX_TIME_PART3:
+          parser->item_length++;
+          if(c == ' ') {
+            mem[parser->item_offset + parser->item_length -1] = 0;
+            parser->offsets.time = parser->item_offset;
+            /*
+              if(ftp_pl_gettime(parser, finfo->mem + parser->item_offset)) {
+                parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
+              }
+            */
+            if(finfo->filetype == CURLFILETYPE_SYMLINK) {
+              parser->state.UNIX.main = PL_UNIX_SYMLINK;
+              parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
+            }
+            else {
+              parser->state.UNIX.main = PL_UNIX_FILENAME;
+              parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
+            }
+          }
+          else if(!ISALNUM(c) && c != '.' && c != ':') {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          break;
+        }
+        break;
+      case PL_UNIX_FILENAME:
+        switch(parser->state.UNIX.sub.filename) {
+        case PL_UNIX_FILENAME_PRESPACE:
+          if(c != ' ') {
+            parser->item_offset = len - 1;
+            parser->item_length = 1;
+            parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
+          }
+          break;
+        case PL_UNIX_FILENAME_NAME:
+          parser->item_length++;
+          if(c == '\r') {
+            parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
+          }
+          else if(c == '\n') {
+            mem[parser->item_offset + parser->item_length - 1] = 0;
+            parser->offsets.filename = parser->item_offset;
+            parser->state.UNIX.main = PL_UNIX_FILETYPE;
+            result = ftp_pl_insert_finfo(data, infop);
+            if(result) {
+              parser->error = result;
+              goto fail;
+            }
+          }
+          break;
+        case PL_UNIX_FILENAME_WINDOWSEOL:
+          if(c == '\n') {
+            mem[parser->item_offset + parser->item_length - 1] = 0;
+            parser->offsets.filename = parser->item_offset;
+            parser->state.UNIX.main = PL_UNIX_FILETYPE;
+            result = ftp_pl_insert_finfo(data, infop);
+            if(result) {
+              parser->error = result;
+              goto fail;
+            }
+          }
+          else {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          break;
+        }
+        break;
+      case PL_UNIX_SYMLINK:
+        switch(parser->state.UNIX.sub.symlink) {
+        case PL_UNIX_SYMLINK_PRESPACE:
+          if(c != ' ') {
+            parser->item_offset = len - 1;
+            parser->item_length = 1;
+            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+          }
+          break;
+        case PL_UNIX_SYMLINK_NAME:
+          parser->item_length++;
+          if(c == ' ') {
+            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
+          }
+          else if(c == '\r' || c == '\n') {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          break;
+        case PL_UNIX_SYMLINK_PRETARGET1:
+          parser->item_length++;
+          if(c == '-') {
+            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
+          }
+          else if(c == '\r' || c == '\n') {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          else {
+            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+          }
+          break;
+        case PL_UNIX_SYMLINK_PRETARGET2:
+          parser->item_length++;
+          if(c == '>') {
+            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
+          }
+          else if(c == '\r' || c == '\n') {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          else {
+            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+          }
+          break;
+        case PL_UNIX_SYMLINK_PRETARGET3:
+          parser->item_length++;
+          if(c == ' ') {
+            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
+            /* now place where is symlink following */
+            mem[parser->item_offset + parser->item_length - 4] = 0;
+            parser->offsets.filename = parser->item_offset;
+            parser->item_length = 0;
+            parser->item_offset = 0;
+          }
+          else if(c == '\r' || c == '\n') {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          else {
+            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+          }
+          break;
+        case PL_UNIX_SYMLINK_PRETARGET4:
+          if(c != '\r' && c != '\n') {
+            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
+            parser->item_offset = len - 1;
+            parser->item_length = 1;
+          }
+          else {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          break;
+        case PL_UNIX_SYMLINK_TARGET:
+          parser->item_length++;
+          if(c == '\r') {
+            parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
+          }
+          else if(c == '\n') {
+            mem[parser->item_offset + parser->item_length - 1] = 0;
+            parser->offsets.symlink_target = parser->item_offset;
+            result = ftp_pl_insert_finfo(data, infop);
+            if(result) {
+              parser->error = result;
+              goto fail;
+            }
+            parser->state.UNIX.main = PL_UNIX_FILETYPE;
+          }
+          break;
+        case PL_UNIX_SYMLINK_WINDOWSEOL:
+          if(c == '\n') {
+            mem[parser->item_offset + parser->item_length - 1] = 0;
+            parser->offsets.symlink_target = parser->item_offset;
+            result = ftp_pl_insert_finfo(data, infop);
+            if(result) {
+              parser->error = result;
+              goto fail;
+            }
+            parser->state.UNIX.main = PL_UNIX_FILETYPE;
+          }
+          else {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          break;
+        }
+        break;
+      }
+      break;
+    case OS_TYPE_WIN_NT:
+      switch(parser->state.NT.main) {
+      case PL_WINNT_DATE:
+        parser->item_length++;
+        if(parser->item_length < 9) {
+          if(!strchr("0123456789-", c)) { /* only simple control */
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+        }
+        else if(parser->item_length == 9) {
+          if(c == ' ') {
+            parser->state.NT.main = PL_WINNT_TIME;
+            parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
+          }
+          else {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+        }
+        else {
+          parser->error = CURLE_FTP_BAD_FILE_LIST;
+          goto fail;
+        }
+        break;
+      case PL_WINNT_TIME:
+        parser->item_length++;
+        switch(parser->state.NT.sub.time) {
+        case PL_WINNT_TIME_PRESPACE:
+          if(!ISBLANK(c)) {
+            parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
+          }
+          break;
+        case PL_WINNT_TIME_TIME:
+          if(c == ' ') {
+            parser->offsets.time = parser->item_offset;
+            mem[parser->item_offset + parser->item_length -1] = 0;
+            parser->state.NT.main = PL_WINNT_DIRORSIZE;
+            parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
+            parser->item_length = 0;
+          }
+          else if(!strchr("APM0123456789:", c)) {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          break;
+        }
+        break;
+      case PL_WINNT_DIRORSIZE:
+        switch(parser->state.NT.sub.dirorsize) {
+        case PL_WINNT_DIRORSIZE_PRESPACE:
+          if(c != ' ') {
+            parser->item_offset = len - 1;
+            parser->item_length = 1;
+            parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
+          }
+          break;
+        case PL_WINNT_DIRORSIZE_CONTENT:
+          parser->item_length ++;
+          if(c == ' ') {
+            mem[parser->item_offset + parser->item_length - 1] = 0;
+            if(strcmp("<DIR>", mem + parser->item_offset) == 0) {
+              finfo->filetype = CURLFILETYPE_DIRECTORY;
+              finfo->size = 0;
+            }
+            else {
+              char *endptr;
+              if(curlx_strtoofft(mem +
+                                 parser->item_offset,
+                                 &endptr, 10, &finfo->size)) {
+                parser->error = CURLE_FTP_BAD_FILE_LIST;
+                goto fail;
+              }
+              /* correct file type */
+              parser->file_data->info.filetype = CURLFILETYPE_FILE;
+            }
+
+            parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
+            parser->item_length = 0;
+            parser->state.NT.main = PL_WINNT_FILENAME;
+            parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
+          }
+          break;
+        }
+        break;
+      case PL_WINNT_FILENAME:
+        switch(parser->state.NT.sub.filename) {
+        case PL_WINNT_FILENAME_PRESPACE:
+          if(c != ' ') {
+            parser->item_offset = len -1;
+            parser->item_length = 1;
+            parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
+          }
+          break;
+        case PL_WINNT_FILENAME_CONTENT:
+          parser->item_length++;
+          if(c == '\r') {
+            parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
+            mem[len - 1] = 0;
+          }
+          else if(c == '\n') {
+            parser->offsets.filename = parser->item_offset;
+            mem[len - 1] = 0;
+            result = ftp_pl_insert_finfo(data, infop);
+            if(result) {
+              parser->error = result;
+              goto fail;
+            }
+            parser->state.NT.main = PL_WINNT_DATE;
+            parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
+          }
+          break;
+        case PL_WINNT_FILENAME_WINEOL:
+          if(c == '\n') {
+            parser->offsets.filename = parser->item_offset;
+            result = ftp_pl_insert_finfo(data, infop);
+            if(result) {
+              parser->error = result;
+              goto fail;
+            }
+            parser->state.NT.main = PL_WINNT_DATE;
+            parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
+          }
+          else {
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
+          }
+          break;
+        }
+        break;
+      }
+      break;
+    default:
+      retsize = bufflen + 1;
+      goto fail;
+    }
+
+    i++;
+  }
+  return retsize;
+
+fail:
+
+  /* Clean up any allocated memory. */
+  if(parser->file_data) {
+    Curl_fileinfo_cleanup(parser->file_data);
+    parser->file_data = NULL;
+  }
+
+  return retsize;
+}
+
+#endif /* CURL_DISABLE_FTP */
Index: trunk/src/libs/curl-8.7.1/lib/ftplistparser.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/ftplistparser.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/ftplistparser.h	(revision 104083)
@@ -0,0 +1,77 @@
+#ifndef HEADER_CURL_FTPLISTPARSER_H
+#define HEADER_CURL_FTPLISTPARSER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FTP
+
+/* WRITEFUNCTION callback for parsing LIST responses */
+size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
+                          void *connptr);
+
+struct ftp_parselist_data; /* defined inside ftplibparser.c */
+
+CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data);
+
+struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void);
+
+void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data);
+
+/* list of wildcard process states */
+typedef enum {
+  CURLWC_CLEAR = 0,
+  CURLWC_INIT = 1,
+  CURLWC_MATCHING, /* library is trying to get list of addresses for
+                      downloading */
+  CURLWC_DOWNLOADING,
+  CURLWC_CLEAN, /* deallocate resources and reset settings */
+  CURLWC_SKIP,  /* skip over concrete file */
+  CURLWC_ERROR, /* error cases */
+  CURLWC_DONE   /* if is wildcard->state == CURLWC_DONE wildcard loop
+                   will end */
+} wildcard_states;
+
+typedef void (*wildcard_dtor)(void *ptr);
+
+/* struct keeping information about wildcard download process */
+struct WildcardData {
+  char *path; /* path to the directory, where we trying wildcard-match */
+  char *pattern; /* wildcard pattern */
+  struct Curl_llist filelist; /* llist with struct Curl_fileinfo */
+  struct ftp_wc *ftpwc; /* pointer to FTP wildcard data */
+  wildcard_dtor dtor;
+  unsigned char state; /* wildcard_states */
+};
+
+CURLcode Curl_wildcard_init(struct WildcardData *wc);
+void Curl_wildcard_dtor(struct WildcardData **wcp);
+
+struct Curl_easy;
+
+#else
+/* FTP is disabled */
+#define Curl_wildcard_dtor(x)
+#endif /* CURL_DISABLE_FTP */
+#endif /* HEADER_CURL_FTPLISTPARSER_H */
Index: trunk/src/libs/curl-8.7.1/lib/functypes.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/functypes.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/functypes.h	(revision 104083)
@@ -0,0 +1,115 @@
+#ifndef HEADER_CURL_FUNCTYPES_H
+#define HEADER_CURL_FUNCTYPES_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+/* defaults:
+
+   ssize_t recv(int, void *, size_t, int);
+   ssize_t send(int, const void *, size_t, int);
+
+   If other argument or return types are needed:
+
+   1. For systems that run configure or cmake, the alternatives are provided
+      here.
+   2. For systems with config-*.h files, define them there.
+*/
+
+#ifdef _WIN32
+/* int recv(SOCKET, char *, int, int) */
+#define RECV_TYPE_ARG1 SOCKET
+#define RECV_TYPE_ARG2 char *
+#define RECV_TYPE_ARG3 int
+#define RECV_TYPE_RETV int
+
+/* int send(SOCKET, const char *, int, int); */
+#define SEND_TYPE_ARG1 SOCKET
+#define SEND_TYPE_ARG2 char *
+#define SEND_TYPE_ARG3 int
+#define SEND_TYPE_RETV int
+
+#elif defined(__AMIGA__) /* Any AmigaOS flavour */
+
+/* long recv(long, char *, long, long); */
+#define RECV_TYPE_ARG1 long
+#define RECV_TYPE_ARG2 char *
+#define RECV_TYPE_ARG3 long
+#define RECV_TYPE_ARG4 long
+#define RECV_TYPE_RETV long
+
+/* int send(int, const char *, int, int); */
+#define SEND_TYPE_ARG1 int
+#define SEND_TYPE_ARG2 char *
+#define SEND_TYPE_ARG3 int
+#define SEND_TYPE_RETV int
+#endif
+
+
+#ifndef RECV_TYPE_ARG1
+#define RECV_TYPE_ARG1 int
+#endif
+
+#ifndef RECV_TYPE_ARG2
+#define RECV_TYPE_ARG2 void *
+#endif
+
+#ifndef RECV_TYPE_ARG3
+#define RECV_TYPE_ARG3 size_t
+#endif
+
+#ifndef RECV_TYPE_ARG4
+#define RECV_TYPE_ARG4 int
+#endif
+
+#ifndef RECV_TYPE_RETV
+#define RECV_TYPE_RETV ssize_t
+#endif
+
+#ifndef SEND_QUAL_ARG2
+#define SEND_QUAL_ARG2 const
+#endif
+
+#ifndef SEND_TYPE_ARG1
+#define SEND_TYPE_ARG1 int
+#endif
+
+#ifndef SEND_TYPE_ARG2
+#define SEND_TYPE_ARG2 void *
+#endif
+
+#ifndef SEND_TYPE_ARG3
+#define SEND_TYPE_ARG3 size_t
+#endif
+
+#ifndef SEND_TYPE_ARG4
+#define SEND_TYPE_ARG4 int
+#endif
+
+#ifndef SEND_TYPE_RETV
+#define SEND_TYPE_RETV ssize_t
+#endif
+
+#endif /* HEADER_CURL_FUNCTYPES_H */
Index: trunk/src/libs/curl-8.7.1/lib/getenv.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/getenv.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/getenv.c	(revision 104083)
@@ -0,0 +1,80 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "curl_memory.h"
+
+#include "memdebug.h"
+
+static char *GetEnv(const char *variable)
+{
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP) || \
+  defined(__ORBIS__) || defined(__PROSPERO__) /* PlayStation 4 and 5 */
+  (void)variable;
+  return NULL;
+#elif defined(_WIN32)
+  /* This uses Windows API instead of C runtime getenv() to get the environment
+     variable since some changes aren't always visible to the latter. #4774 */
+  char *buf = NULL;
+  char *tmp;
+  DWORD bufsize;
+  DWORD rc = 1;
+  const DWORD max = 32768; /* max env var size from MSCRT source */
+
+  for(;;) {
+    tmp = realloc(buf, rc);
+    if(!tmp) {
+      free(buf);
+      return NULL;
+    }
+
+    buf = tmp;
+    bufsize = rc;
+
+    /* It's possible for rc to be 0 if the variable was found but empty.
+       Since getenv doesn't make that distinction we ignore it as well. */
+    rc = GetEnvironmentVariableA(variable, buf, bufsize);
+    if(!rc || rc == bufsize || rc > max) {
+      free(buf);
+      return NULL;
+    }
+
+    /* if rc < bufsize then rc is bytes written not including null */
+    if(rc < bufsize)
+      return buf;
+
+    /* else rc is bytes needed, try again */
+  }
+#else
+  char *env = getenv(variable);
+  return (env && env[0])?strdup(env):NULL;
+#endif
+}
+
+char *curl_getenv(const char *v)
+{
+  return GetEnv(v);
+}
Index: trunk/src/libs/curl-8.7.1/lib/getinfo.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/getinfo.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/getinfo.c	(revision 104083)
@@ -0,0 +1,636 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "getinfo.h"
+
+#include "vtls/vtls.h"
+#include "connect.h" /* Curl_getconnectinfo() */
+#include "progress.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Initialize statistical and informational data.
+ *
+ * This function is called in curl_easy_reset, curl_easy_duphandle and at the
+ * beginning of a perform session. It must reset the session-info variables,
+ * in particular all variables in struct PureInfo.
+ */
+CURLcode Curl_initinfo(struct Curl_easy *data)
+{
+  struct Progress *pro = &data->progress;
+  struct PureInfo *info = &data->info;
+
+  pro->t_nslookup = 0;
+  pro->t_connect = 0;
+  pro->t_appconnect = 0;
+  pro->t_pretransfer = 0;
+  pro->t_starttransfer = 0;
+  pro->timespent = 0;
+  pro->t_redirect = 0;
+  pro->is_t_startransfer_set = false;
+
+  info->httpcode = 0;
+  info->httpproxycode = 0;
+  info->httpversion = 0;
+  info->filetime = -1; /* -1 is an illegal time and thus means unknown */
+  info->timecond = FALSE;
+
+  info->header_size = 0;
+  info->request_size = 0;
+  info->proxyauthavail = 0;
+  info->httpauthavail = 0;
+  info->numconnects = 0;
+
+  free(info->contenttype);
+  info->contenttype = NULL;
+
+  free(info->wouldredirect);
+  info->wouldredirect = NULL;
+
+  info->primary.remote_ip[0] = '\0';
+  info->primary.local_ip[0] = '\0';
+  info->primary.remote_port = 0;
+  info->primary.local_port = 0;
+  info->retry_after = 0;
+
+  info->conn_scheme = 0;
+  info->conn_protocol = 0;
+
+#ifdef USE_SSL
+  Curl_ssl_free_certinfo(data);
+#endif
+  return CURLE_OK;
+}
+
+static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
+                             const char **param_charp)
+{
+  switch(info) {
+  case CURLINFO_EFFECTIVE_URL:
+    *param_charp = data->state.url?data->state.url:(char *)"";
+    break;
+  case CURLINFO_EFFECTIVE_METHOD: {
+    const char *m = data->set.str[STRING_CUSTOMREQUEST];
+    if(!m) {
+      if(data->set.opt_no_body)
+        m = "HEAD";
+#ifndef CURL_DISABLE_HTTP
+      else {
+        switch(data->state.httpreq) {
+        case HTTPREQ_POST:
+        case HTTPREQ_POST_FORM:
+        case HTTPREQ_POST_MIME:
+          m = "POST";
+          break;
+        case HTTPREQ_PUT:
+          m = "PUT";
+          break;
+        default: /* this should never happen */
+        case HTTPREQ_GET:
+          m = "GET";
+          break;
+        case HTTPREQ_HEAD:
+          m = "HEAD";
+          break;
+        }
+      }
+#endif
+    }
+    *param_charp = m;
+  }
+    break;
+  case CURLINFO_CONTENT_TYPE:
+    *param_charp = data->info.contenttype;
+    break;
+  case CURLINFO_PRIVATE:
+    *param_charp = (char *) data->set.private_data;
+    break;
+  case CURLINFO_FTP_ENTRY_PATH:
+    /* Return the entrypath string from the most recent connection.
+       This pointer was copied from the connectdata structure by FTP.
+       The actual string may be free()ed by subsequent libcurl calls so
+       it must be copied to a safer area before the next libcurl call.
+       Callers must never free it themselves. */
+    *param_charp = data->state.most_recent_ftp_entrypath;
+    break;
+  case CURLINFO_REDIRECT_URL:
+    /* Return the URL this request would have been redirected to if that
+       option had been enabled! */
+    *param_charp = data->info.wouldredirect;
+    break;
+  case CURLINFO_REFERER:
+    /* Return the referrer header for this request, or NULL if unset */
+    *param_charp = data->state.referer;
+    break;
+  case CURLINFO_PRIMARY_IP:
+    /* Return the ip address of the most recent (primary) connection */
+    *param_charp = data->info.primary.remote_ip;
+    break;
+  case CURLINFO_LOCAL_IP:
+    /* Return the source/local ip address of the most recent (primary)
+       connection */
+    *param_charp = data->info.primary.local_ip;
+    break;
+  case CURLINFO_RTSP_SESSION_ID:
+    *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
+    break;
+  case CURLINFO_SCHEME:
+    *param_charp = data->info.conn_scheme;
+    break;
+  case CURLINFO_CAPATH:
+#ifdef CURL_CA_PATH
+    *param_charp = CURL_CA_PATH;
+#else
+    *param_charp = NULL;
+#endif
+    break;
+  case CURLINFO_CAINFO:
+#ifdef CURL_CA_BUNDLE
+    *param_charp = CURL_CA_BUNDLE;
+#else
+    *param_charp = NULL;
+#endif
+    break;
+  default:
+    return CURLE_UNKNOWN_OPTION;
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
+                             long *param_longp)
+{
+  curl_socket_t sockfd;
+
+  union {
+    unsigned long *to_ulong;
+    long          *to_long;
+  } lptr;
+
+#ifdef DEBUGBUILD
+  char *timestr = getenv("CURL_TIME");
+  if(timestr) {
+    unsigned long val = strtol(timestr, NULL, 10);
+    switch(info) {
+    case CURLINFO_LOCAL_PORT:
+      *param_longp = (long)val;
+      return CURLE_OK;
+    default:
+      break;
+    }
+  }
+  /* use another variable for this to allow different values */
+  timestr = getenv("CURL_DEBUG_SIZE");
+  if(timestr) {
+    unsigned long val = strtol(timestr, NULL, 10);
+    switch(info) {
+    case CURLINFO_HEADER_SIZE:
+    case CURLINFO_REQUEST_SIZE:
+      *param_longp = (long)val;
+      return CURLE_OK;
+    default:
+      break;
+    }
+  }
+#endif
+
+  switch(info) {
+  case CURLINFO_RESPONSE_CODE:
+    *param_longp = data->info.httpcode;
+    break;
+  case CURLINFO_HTTP_CONNECTCODE:
+    *param_longp = data->info.httpproxycode;
+    break;
+  case CURLINFO_FILETIME:
+    if(data->info.filetime > LONG_MAX)
+      *param_longp = LONG_MAX;
+    else if(data->info.filetime < LONG_MIN)
+      *param_longp = LONG_MIN;
+    else
+      *param_longp = (long)data->info.filetime;
+    break;
+  case CURLINFO_HEADER_SIZE:
+    *param_longp = (long)data->info.header_size;
+    break;
+  case CURLINFO_REQUEST_SIZE:
+    *param_longp = (long)data->info.request_size;
+    break;
+  case CURLINFO_SSL_VERIFYRESULT:
+    *param_longp = data->set.ssl.certverifyresult;
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLINFO_PROXY_SSL_VERIFYRESULT:
+    *param_longp = data->set.proxy_ssl.certverifyresult;
+    break;
+#endif
+  case CURLINFO_REDIRECT_COUNT:
+    *param_longp = data->state.followlocation;
+    break;
+  case CURLINFO_HTTPAUTH_AVAIL:
+    lptr.to_long = param_longp;
+    *lptr.to_ulong = data->info.httpauthavail;
+    break;
+  case CURLINFO_PROXYAUTH_AVAIL:
+    lptr.to_long = param_longp;
+    *lptr.to_ulong = data->info.proxyauthavail;
+    break;
+  case CURLINFO_OS_ERRNO:
+    *param_longp = data->state.os_errno;
+    break;
+  case CURLINFO_NUM_CONNECTS:
+    *param_longp = data->info.numconnects;
+    break;
+  case CURLINFO_LASTSOCKET:
+    sockfd = Curl_getconnectinfo(data, NULL);
+
+    /* note: this is not a good conversion for systems with 64 bit sockets and
+       32 bit longs */
+    if(sockfd != CURL_SOCKET_BAD)
+      *param_longp = (long)sockfd;
+    else
+      /* this interface is documented to return -1 in case of badness, which
+         may not be the same as the CURL_SOCKET_BAD value */
+      *param_longp = -1;
+    break;
+  case CURLINFO_PRIMARY_PORT:
+    /* Return the (remote) port of the most recent (primary) connection */
+    *param_longp = data->info.primary.remote_port;
+    break;
+  case CURLINFO_LOCAL_PORT:
+    /* Return the local port of the most recent (primary) connection */
+    *param_longp = data->info.primary.local_port;
+    break;
+  case CURLINFO_PROXY_ERROR:
+    *param_longp = (long)data->info.pxcode;
+    break;
+  case CURLINFO_CONDITION_UNMET:
+    if(data->info.httpcode == 304)
+      *param_longp = 1L;
+    else
+      /* return if the condition prevented the document to get transferred */
+      *param_longp = data->info.timecond ? 1L : 0L;
+    break;
+#ifndef CURL_DISABLE_RTSP
+  case CURLINFO_RTSP_CLIENT_CSEQ:
+    *param_longp = data->state.rtsp_next_client_CSeq;
+    break;
+  case CURLINFO_RTSP_SERVER_CSEQ:
+    *param_longp = data->state.rtsp_next_server_CSeq;
+    break;
+  case CURLINFO_RTSP_CSEQ_RECV:
+    *param_longp = data->state.rtsp_CSeq_recv;
+    break;
+#endif
+  case CURLINFO_HTTP_VERSION:
+    switch(data->info.httpversion) {
+    case 10:
+      *param_longp = CURL_HTTP_VERSION_1_0;
+      break;
+    case 11:
+      *param_longp = CURL_HTTP_VERSION_1_1;
+      break;
+    case 20:
+      *param_longp = CURL_HTTP_VERSION_2_0;
+      break;
+    case 30:
+      *param_longp = CURL_HTTP_VERSION_3;
+      break;
+    default:
+      *param_longp = CURL_HTTP_VERSION_NONE;
+      break;
+    }
+    break;
+  case CURLINFO_PROTOCOL:
+    *param_longp = data->info.conn_protocol;
+    break;
+  case CURLINFO_USED_PROXY:
+    *param_longp =
+#ifdef CURL_DISABLE_PROXY
+      0
+#else
+      data->info.used_proxy
+#endif
+      ;
+    break;
+  default:
+    return CURLE_UNKNOWN_OPTION;
+  }
+
+  return CURLE_OK;
+}
+
+#define DOUBLE_SECS(x) (double)(x)/1000000
+
+static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
+                             curl_off_t *param_offt)
+{
+#ifdef DEBUGBUILD
+  char *timestr = getenv("CURL_TIME");
+  if(timestr) {
+    unsigned long val = strtol(timestr, NULL, 10);
+    switch(info) {
+    case CURLINFO_TOTAL_TIME_T:
+    case CURLINFO_NAMELOOKUP_TIME_T:
+    case CURLINFO_CONNECT_TIME_T:
+    case CURLINFO_APPCONNECT_TIME_T:
+    case CURLINFO_PRETRANSFER_TIME_T:
+    case CURLINFO_STARTTRANSFER_TIME_T:
+    case CURLINFO_REDIRECT_TIME_T:
+    case CURLINFO_SPEED_DOWNLOAD_T:
+    case CURLINFO_SPEED_UPLOAD_T:
+      *param_offt = (curl_off_t)val;
+      return CURLE_OK;
+    default:
+      break;
+    }
+  }
+#endif
+  switch(info) {
+  case CURLINFO_FILETIME_T:
+    *param_offt = (curl_off_t)data->info.filetime;
+    break;
+  case CURLINFO_SIZE_UPLOAD_T:
+    *param_offt = data->progress.uploaded;
+    break;
+  case CURLINFO_SIZE_DOWNLOAD_T:
+    *param_offt = data->progress.downloaded;
+    break;
+  case CURLINFO_SPEED_DOWNLOAD_T:
+    *param_offt = data->progress.dlspeed;
+    break;
+  case CURLINFO_SPEED_UPLOAD_T:
+    *param_offt = data->progress.ulspeed;
+    break;
+  case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
+    *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
+      data->progress.size_dl:-1;
+    break;
+  case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
+    *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
+      data->progress.size_ul:-1;
+    break;
+   case CURLINFO_TOTAL_TIME_T:
+    *param_offt = data->progress.timespent;
+    break;
+  case CURLINFO_NAMELOOKUP_TIME_T:
+    *param_offt = data->progress.t_nslookup;
+    break;
+  case CURLINFO_CONNECT_TIME_T:
+    *param_offt = data->progress.t_connect;
+    break;
+  case CURLINFO_APPCONNECT_TIME_T:
+    *param_offt = data->progress.t_appconnect;
+    break;
+  case CURLINFO_PRETRANSFER_TIME_T:
+    *param_offt = data->progress.t_pretransfer;
+    break;
+  case CURLINFO_STARTTRANSFER_TIME_T:
+    *param_offt = data->progress.t_starttransfer;
+    break;
+  case CURLINFO_QUEUE_TIME_T:
+    *param_offt = data->progress.t_postqueue;
+    break;
+  case CURLINFO_REDIRECT_TIME_T:
+    *param_offt = data->progress.t_redirect;
+    break;
+  case CURLINFO_RETRY_AFTER:
+    *param_offt = data->info.retry_after;
+    break;
+  case CURLINFO_XFER_ID:
+    *param_offt = data->id;
+    break;
+  case CURLINFO_CONN_ID:
+    *param_offt = data->conn?
+      data->conn->connection_id : data->state.recent_conn_id;
+    break;
+  default:
+    return CURLE_UNKNOWN_OPTION;
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
+                               double *param_doublep)
+{
+#ifdef DEBUGBUILD
+  char *timestr = getenv("CURL_TIME");
+  if(timestr) {
+    unsigned long val = strtol(timestr, NULL, 10);
+    switch(info) {
+    case CURLINFO_TOTAL_TIME:
+    case CURLINFO_NAMELOOKUP_TIME:
+    case CURLINFO_CONNECT_TIME:
+    case CURLINFO_APPCONNECT_TIME:
+    case CURLINFO_PRETRANSFER_TIME:
+    case CURLINFO_STARTTRANSFER_TIME:
+    case CURLINFO_REDIRECT_TIME:
+    case CURLINFO_SPEED_DOWNLOAD:
+    case CURLINFO_SPEED_UPLOAD:
+      *param_doublep = (double)val;
+      return CURLE_OK;
+    default:
+      break;
+    }
+  }
+#endif
+  switch(info) {
+  case CURLINFO_TOTAL_TIME:
+    *param_doublep = DOUBLE_SECS(data->progress.timespent);
+    break;
+  case CURLINFO_NAMELOOKUP_TIME:
+    *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
+    break;
+  case CURLINFO_CONNECT_TIME:
+    *param_doublep = DOUBLE_SECS(data->progress.t_connect);
+    break;
+  case CURLINFO_APPCONNECT_TIME:
+    *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
+    break;
+  case CURLINFO_PRETRANSFER_TIME:
+    *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
+    break;
+  case CURLINFO_STARTTRANSFER_TIME:
+    *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
+    break;
+  case CURLINFO_SIZE_UPLOAD:
+    *param_doublep = (double)data->progress.uploaded;
+    break;
+  case CURLINFO_SIZE_DOWNLOAD:
+    *param_doublep = (double)data->progress.downloaded;
+    break;
+  case CURLINFO_SPEED_DOWNLOAD:
+    *param_doublep = (double)data->progress.dlspeed;
+    break;
+  case CURLINFO_SPEED_UPLOAD:
+    *param_doublep = (double)data->progress.ulspeed;
+    break;
+  case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
+    *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
+      (double)data->progress.size_dl:-1;
+    break;
+  case CURLINFO_CONTENT_LENGTH_UPLOAD:
+    *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
+      (double)data->progress.size_ul:-1;
+    break;
+  case CURLINFO_REDIRECT_TIME:
+    *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
+    break;
+
+  default:
+    return CURLE_UNKNOWN_OPTION;
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
+                              struct curl_slist **param_slistp)
+{
+  union {
+    struct curl_certinfo *to_certinfo;
+    struct curl_slist    *to_slist;
+  } ptr;
+
+  switch(info) {
+  case CURLINFO_SSL_ENGINES:
+    *param_slistp = Curl_ssl_engines_list(data);
+    break;
+  case CURLINFO_COOKIELIST:
+    *param_slistp = Curl_cookie_list(data);
+    break;
+  case CURLINFO_CERTINFO:
+    /* Return the a pointer to the certinfo struct. Not really an slist
+       pointer but we can pretend it is here */
+    ptr.to_certinfo = &data->info.certs;
+    *param_slistp = ptr.to_slist;
+    break;
+  case CURLINFO_TLS_SESSION:
+  case CURLINFO_TLS_SSL_PTR:
+    {
+      struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
+                                          param_slistp;
+      struct curl_tlssessioninfo *tsi = &data->tsi;
+#ifdef USE_SSL
+      struct connectdata *conn = data->conn;
+#endif
+
+      *tsip = tsi;
+      tsi->backend = Curl_ssl_backend();
+      tsi->internals = NULL;
+
+#ifdef USE_SSL
+      if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
+        tsi->internals = Curl_ssl_get_internals(data, FIRSTSOCKET, info, 0);
+      }
+#endif
+    }
+    break;
+  default:
+    return CURLE_UNKNOWN_OPTION;
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
+                               curl_socket_t *param_socketp)
+{
+  switch(info) {
+  case CURLINFO_ACTIVESOCKET:
+    *param_socketp = Curl_getconnectinfo(data, NULL);
+    break;
+  default:
+    return CURLE_UNKNOWN_OPTION;
+  }
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
+{
+  va_list arg;
+  long *param_longp = NULL;
+  double *param_doublep = NULL;
+  curl_off_t *param_offt = NULL;
+  const char **param_charp = NULL;
+  struct curl_slist **param_slistp = NULL;
+  curl_socket_t *param_socketp = NULL;
+  int type;
+  CURLcode result = CURLE_UNKNOWN_OPTION;
+
+  if(!data)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  va_start(arg, info);
+
+  type = CURLINFO_TYPEMASK & (int)info;
+  switch(type) {
+  case CURLINFO_STRING:
+    param_charp = va_arg(arg, const char **);
+    if(param_charp)
+      result = getinfo_char(data, info, param_charp);
+    break;
+  case CURLINFO_LONG:
+    param_longp = va_arg(arg, long *);
+    if(param_longp)
+      result = getinfo_long(data, info, param_longp);
+    break;
+  case CURLINFO_DOUBLE:
+    param_doublep = va_arg(arg, double *);
+    if(param_doublep)
+      result = getinfo_double(data, info, param_doublep);
+    break;
+  case CURLINFO_OFF_T:
+    param_offt = va_arg(arg, curl_off_t *);
+    if(param_offt)
+      result = getinfo_offt(data, info, param_offt);
+    break;
+  case CURLINFO_SLIST:
+    param_slistp = va_arg(arg, struct curl_slist **);
+    if(param_slistp)
+      result = getinfo_slist(data, info, param_slistp);
+    break;
+  case CURLINFO_SOCKET:
+    param_socketp = va_arg(arg, curl_socket_t *);
+    if(param_socketp)
+      result = getinfo_socket(data, info, param_socketp);
+    break;
+  default:
+    break;
+  }
+
+  va_end(arg);
+
+  return result;
+}
Index: trunk/src/libs/curl-8.7.1/lib/getinfo.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/getinfo.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/getinfo.h	(revision 104083)
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_GETINFO_H
+#define HEADER_CURL_GETINFO_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...);
+CURLcode Curl_initinfo(struct Curl_easy *data);
+
+#endif /* HEADER_CURL_GETINFO_H */
Index: trunk/src/libs/curl-8.7.1/lib/gopher.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/gopher.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/gopher.c	(revision 104083)
@@ -0,0 +1,242 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_GOPHER
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "progress.h"
+#include "gopher.h"
+#include "select.h"
+#include "strdup.h"
+#include "vtls/vtls.h"
+#include "url.h"
+#include "escape.h"
+#include "warnless.h"
+#include "curl_printf.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Forward declarations.
+ */
+
+static CURLcode gopher_do(struct Curl_easy *data, bool *done);
+#ifdef USE_SSL
+static CURLcode gopher_connect(struct Curl_easy *data, bool *done);
+static CURLcode gopher_connecting(struct Curl_easy *data, bool *done);
+#endif
+
+/*
+ * Gopher protocol handler.
+ * This is also a nice simple template to build off for simple
+ * connect-command-download protocols.
+ */
+
+const struct Curl_handler Curl_handler_gopher = {
+  "GOPHER",                             /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  gopher_do,                            /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_GOPHER,                          /* defport */
+  CURLPROTO_GOPHER,                     /* protocol */
+  CURLPROTO_GOPHER,                     /* family */
+  PROTOPT_NONE                          /* flags */
+};
+
+#ifdef USE_SSL
+const struct Curl_handler Curl_handler_gophers = {
+  "GOPHERS",                            /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  gopher_do,                            /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  gopher_connect,                       /* connect_it */
+  gopher_connecting,                    /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_GOPHER,                          /* defport */
+  CURLPROTO_GOPHERS,                    /* protocol */
+  CURLPROTO_GOPHER,                     /* family */
+  PROTOPT_SSL                           /* flags */
+};
+
+static CURLcode gopher_connect(struct Curl_easy *data, bool *done)
+{
+  (void)data;
+  (void)done;
+  return CURLE_OK;
+}
+
+static CURLcode gopher_connecting(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  CURLcode result;
+
+  result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done);
+  if(result)
+    connclose(conn, "Failed TLS connection");
+  *done = TRUE;
+  return result;
+}
+#endif
+
+static CURLcode gopher_do(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+  char *gopherpath;
+  char *path = data->state.up.path;
+  char *query = data->state.up.query;
+  char *sel = NULL;
+  char *sel_org = NULL;
+  timediff_t timeout_ms;
+  ssize_t k;
+  size_t amount, len;
+  int what;
+
+  *done = TRUE; /* unconditionally */
+
+  /* path is guaranteed non-NULL */
+  DEBUGASSERT(path);
+
+  if(query)
+    gopherpath = aprintf("%s?%s", path, query);
+  else
+    gopherpath = strdup(path);
+
+  if(!gopherpath)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Create selector. Degenerate cases: / and /1 => convert to "" */
+  if(strlen(gopherpath) <= 2) {
+    sel = (char *)"";
+    len = strlen(sel);
+    free(gopherpath);
+  }
+  else {
+    char *newp;
+
+    /* Otherwise, drop / and the first character (i.e., item type) ... */
+    newp = gopherpath;
+    newp += 2;
+
+    /* ... and finally unescape */
+    result = Curl_urldecode(newp, 0, &sel, &len, REJECT_ZERO);
+    free(gopherpath);
+    if(result)
+      return result;
+    sel_org = sel;
+  }
+
+  k = curlx_uztosz(len);
+
+  for(;;) {
+    /* Break out of the loop if the selector is empty because OpenSSL and/or
+       LibreSSL fail with errno 0 if this is the case. */
+    if(strlen(sel) < 1)
+      break;
+
+    result = Curl_xfer_send(data, sel, k, &amount);
+    if(!result) { /* Which may not have written it all! */
+      result = Curl_client_write(data, CLIENTWRITE_HEADER, sel, amount);
+      if(result)
+        break;
+
+      k -= amount;
+      sel += amount;
+      if(k < 1)
+        break; /* but it did write it all */
+    }
+    else
+      break;
+
+    timeout_ms = Curl_timeleft(data, NULL, FALSE);
+    if(timeout_ms < 0) {
+      result = CURLE_OPERATION_TIMEDOUT;
+      break;
+    }
+    if(!timeout_ms)
+      timeout_ms = TIMEDIFF_T_MAX;
+
+    /* Don't busyloop. The entire loop thing is a work-around as it causes a
+       BLOCKING behavior which is a NO-NO. This function should rather be
+       split up in a do and a doing piece where the pieces that aren't
+       possible to send now will be sent in the doing function repeatedly
+       until the entire request is sent.
+    */
+    what = SOCKET_WRITABLE(sockfd, timeout_ms);
+    if(what < 0) {
+      result = CURLE_SEND_ERROR;
+      break;
+    }
+    else if(!what) {
+      result = CURLE_OPERATION_TIMEDOUT;
+      break;
+    }
+  }
+
+  free(sel_org);
+
+  if(!result)
+    result = Curl_xfer_send(data, "\r\n", 2, &amount);
+  if(result) {
+    failf(data, "Failed sending Gopher request");
+    return result;
+  }
+  result = Curl_client_write(data, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
+  if(result)
+    return result;
+
+  Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
+  return CURLE_OK;
+}
+#endif /* CURL_DISABLE_GOPHER */
Index: trunk/src/libs/curl-8.7.1/lib/gopher.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/gopher.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/gopher.h	(revision 104083)
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_GOPHER_H
+#define HEADER_CURL_GOPHER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_GOPHER
+extern const struct Curl_handler Curl_handler_gopher;
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_gophers;
+#endif
+#endif
+
+#endif /* HEADER_CURL_GOPHER_H */
Index: trunk/src/libs/curl-8.7.1/lib/hash.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/hash.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/hash.c	(revision 104083)
@@ -0,0 +1,370 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "hash.h"
+#include "llist.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static void
+hash_element_dtor(void *user, void *element)
+{
+  struct Curl_hash *h = (struct Curl_hash *) user;
+  struct Curl_hash_element *e = (struct Curl_hash_element *) element;
+
+  if(e->ptr) {
+    h->dtor(e->ptr);
+    e->ptr = NULL;
+  }
+
+  e->key_len = 0;
+
+  free(e);
+}
+
+/* Initializes a hash structure.
+ * Return 1 on error, 0 is fine.
+ *
+ * @unittest: 1602
+ * @unittest: 1603
+ */
+void
+Curl_hash_init(struct Curl_hash *h,
+               int slots,
+               hash_function hfunc,
+               comp_function comparator,
+               Curl_hash_dtor dtor)
+{
+  DEBUGASSERT(h);
+  DEBUGASSERT(slots);
+  DEBUGASSERT(hfunc);
+  DEBUGASSERT(comparator);
+  DEBUGASSERT(dtor);
+
+  h->table = NULL;
+  h->hash_func = hfunc;
+  h->comp_func = comparator;
+  h->dtor = dtor;
+  h->size = 0;
+  h->slots = slots;
+}
+
+static struct Curl_hash_element *
+mk_hash_element(const void *key, size_t key_len, const void *p)
+{
+  /* allocate the struct plus memory after it to store the key */
+  struct Curl_hash_element *he = malloc(sizeof(struct Curl_hash_element) +
+                                        key_len);
+  if(he) {
+    /* copy the key */
+    memcpy(he->key, key, key_len);
+    he->key_len = key_len;
+    he->ptr = (void *) p;
+  }
+  return he;
+}
+
+#define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)]
+
+/* Insert the data in the hash. If there already was a match in the hash, that
+ * data is replaced. This function also "lazily" allocates the table if
+ * needed, as it isn't done in the _init function (anymore).
+ *
+ * @unittest: 1305
+ * @unittest: 1602
+ * @unittest: 1603
+ */
+void *
+Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
+{
+  struct Curl_hash_element  *he;
+  struct Curl_llist_element *le;
+  struct Curl_llist *l;
+
+  DEBUGASSERT(h);
+  DEBUGASSERT(h->slots);
+  if(!h->table) {
+    int i;
+    h->table = malloc(h->slots * sizeof(struct Curl_llist));
+    if(!h->table)
+      return NULL; /* OOM */
+    for(i = 0; i < h->slots; ++i)
+      Curl_llist_init(&h->table[i], hash_element_dtor);
+  }
+
+  l = FETCH_LIST(h, key, key_len);
+
+  for(le = l->head; le; le = le->next) {
+    he = (struct Curl_hash_element *) le->ptr;
+    if(h->comp_func(he->key, he->key_len, key, key_len)) {
+      Curl_llist_remove(l, le, (void *)h);
+      --h->size;
+      break;
+    }
+  }
+
+  he = mk_hash_element(key, key_len, p);
+  if(he) {
+    Curl_llist_insert_next(l, l->tail, he, &he->list);
+    ++h->size;
+    return p; /* return the new entry */
+  }
+
+  return NULL; /* failure */
+}
+
+/* Remove the identified hash entry.
+ * Returns non-zero on failure.
+ *
+ * @unittest: 1603
+ */
+int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
+{
+  struct Curl_llist_element *le;
+  struct Curl_llist *l;
+
+  DEBUGASSERT(h);
+  DEBUGASSERT(h->slots);
+  if(h->table) {
+    l = FETCH_LIST(h, key, key_len);
+
+    for(le = l->head; le; le = le->next) {
+      struct Curl_hash_element *he = le->ptr;
+      if(h->comp_func(he->key, he->key_len, key, key_len)) {
+        Curl_llist_remove(l, le, (void *) h);
+        --h->size;
+        return 0;
+      }
+    }
+  }
+  return 1;
+}
+
+/* Retrieves a hash element.
+ *
+ * @unittest: 1603
+ */
+void *
+Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
+{
+  struct Curl_llist_element *le;
+  struct Curl_llist *l;
+
+  DEBUGASSERT(h);
+  if(h->table) {
+    DEBUGASSERT(h->slots);
+    l = FETCH_LIST(h, key, key_len);
+    for(le = l->head; le; le = le->next) {
+      struct Curl_hash_element *he = le->ptr;
+      if(h->comp_func(he->key, he->key_len, key, key_len)) {
+        return he->ptr;
+      }
+    }
+  }
+
+  return NULL;
+}
+
+#if defined(DEBUGBUILD) && defined(AGGRESSIVE_TEST)
+void
+Curl_hash_apply(Curl_hash *h, void *user,
+                void (*cb)(void *user, void *ptr))
+{
+  struct Curl_llist_element  *le;
+  int                  i;
+
+  for(i = 0; i < h->slots; ++i) {
+    for(le = (h->table[i])->head;
+        le;
+        le = le->next) {
+      Curl_hash_element *el = le->ptr;
+      cb(user, el->ptr);
+    }
+  }
+}
+#endif
+
+/* Destroys all the entries in the given hash and resets its attributes,
+ * prepping the given hash for [static|dynamic] deallocation.
+ *
+ * @unittest: 1305
+ * @unittest: 1602
+ * @unittest: 1603
+ */
+void
+Curl_hash_destroy(struct Curl_hash *h)
+{
+  if(h->table) {
+    int i;
+    for(i = 0; i < h->slots; ++i) {
+      Curl_llist_destroy(&h->table[i], (void *) h);
+    }
+    Curl_safefree(h->table);
+  }
+  h->size = 0;
+  h->slots = 0;
+}
+
+/* Removes all the entries in the given hash.
+ *
+ * @unittest: 1602
+ */
+void
+Curl_hash_clean(struct Curl_hash *h)
+{
+  Curl_hash_clean_with_criterium(h, NULL, NULL);
+}
+
+/* Cleans all entries that pass the comp function criteria. */
+void
+Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
+                               int (*comp)(void *, void *))
+{
+  struct Curl_llist_element *le;
+  struct Curl_llist_element *lnext;
+  struct Curl_llist *list;
+  int i;
+
+  if(!h || !h->table)
+    return;
+
+  for(i = 0; i < h->slots; ++i) {
+    list = &h->table[i];
+    le = list->head; /* get first list entry */
+    while(le) {
+      struct Curl_hash_element *he = le->ptr;
+      lnext = le->next;
+      /* ask the callback function if we shall remove this entry or not */
+      if(!comp || comp(user, he->ptr)) {
+        Curl_llist_remove(list, le, (void *) h);
+        --h->size; /* one less entry in the hash now */
+      }
+      le = lnext;
+    }
+  }
+}
+
+size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num)
+{
+  const char *key_str = (const char *) key;
+  const char *end = key_str + key_length;
+  size_t h = 5381;
+
+  while(key_str < end) {
+    h += h << 5;
+    h ^= *key_str++;
+  }
+
+  return (h % slots_num);
+}
+
+size_t Curl_str_key_compare(void *k1, size_t key1_len,
+                            void *k2, size_t key2_len)
+{
+  if((key1_len == key2_len) && !memcmp(k1, k2, key1_len))
+    return 1;
+
+  return 0;
+}
+
+void Curl_hash_start_iterate(struct Curl_hash *hash,
+                             struct Curl_hash_iterator *iter)
+{
+  iter->hash = hash;
+  iter->slot_index = 0;
+  iter->current_element = NULL;
+}
+
+struct Curl_hash_element *
+Curl_hash_next_element(struct Curl_hash_iterator *iter)
+{
+  struct Curl_hash *h = iter->hash;
+
+  if(!h->table)
+    return NULL; /* empty hash, nothing to return */
+
+  /* Get the next element in the current list, if any */
+  if(iter->current_element)
+    iter->current_element = iter->current_element->next;
+
+  /* If we have reached the end of the list, find the next one */
+  if(!iter->current_element) {
+    int i;
+    for(i = iter->slot_index; i < h->slots; i++) {
+      if(h->table[i].head) {
+        iter->current_element = h->table[i].head;
+        iter->slot_index = i + 1;
+        break;
+      }
+    }
+  }
+
+  if(iter->current_element) {
+    struct Curl_hash_element *he = iter->current_element->ptr;
+    return he;
+  }
+  return NULL;
+}
+
+#if 0 /* useful function for debugging hashes and their contents */
+void Curl_hash_print(struct Curl_hash *h,
+                     void (*func)(void *))
+{
+  struct Curl_hash_iterator iter;
+  struct Curl_hash_element *he;
+  int last_index = -1;
+
+  if(!h)
+    return;
+
+  fprintf(stderr, "=Hash dump=\n");
+
+  Curl_hash_start_iterate(h, &iter);
+
+  he = Curl_hash_next_element(&iter);
+  while(he) {
+    if(iter.slot_index != last_index) {
+      fprintf(stderr, "index %d:", iter.slot_index);
+      if(last_index >= 0) {
+        fprintf(stderr, "\n");
+      }
+      last_index = iter.slot_index;
+    }
+
+    if(func)
+      func(he->ptr);
+    else
+      fprintf(stderr, " [%p]", (void *)he->ptr);
+
+    he = Curl_hash_next_element(&iter);
+  }
+  fprintf(stderr, "\n");
+}
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/hash.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/hash.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/hash.h	(revision 104083)
@@ -0,0 +1,102 @@
+#ifndef HEADER_CURL_HASH_H
+#define HEADER_CURL_HASH_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <stddef.h>
+
+#include "llist.h"
+
+/* Hash function prototype */
+typedef size_t (*hash_function) (void *key,
+                                 size_t key_length,
+                                 size_t slots_num);
+
+/*
+   Comparator function prototype. Compares two keys.
+*/
+typedef size_t (*comp_function) (void *key1,
+                                 size_t key1_len,
+                                 void *key2,
+                                 size_t key2_len);
+
+typedef void (*Curl_hash_dtor)(void *);
+
+struct Curl_hash {
+  struct Curl_llist *table;
+
+  /* Hash function to be used for this hash table */
+  hash_function hash_func;
+
+  /* Comparator function to compare keys */
+  comp_function comp_func;
+  Curl_hash_dtor   dtor;
+  int slots;
+  size_t size;
+};
+
+struct Curl_hash_element {
+  struct Curl_llist_element list;
+  void   *ptr;
+  size_t key_len;
+  char   key[1]; /* allocated memory following the struct */
+};
+
+struct Curl_hash_iterator {
+  struct Curl_hash *hash;
+  int slot_index;
+  struct Curl_llist_element *current_element;
+};
+
+void Curl_hash_init(struct Curl_hash *h,
+                    int slots,
+                    hash_function hfunc,
+                    comp_function comparator,
+                    Curl_hash_dtor dtor);
+
+void *Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p);
+int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len);
+void *Curl_hash_pick(struct Curl_hash *, void *key, size_t key_len);
+void Curl_hash_apply(struct Curl_hash *h, void *user,
+                     void (*cb)(void *user, void *ptr));
+#define Curl_hash_count(h) ((h)->size)
+void Curl_hash_destroy(struct Curl_hash *h);
+void Curl_hash_clean(struct Curl_hash *h);
+void Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
+                                    int (*comp)(void *, void *));
+size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num);
+size_t Curl_str_key_compare(void *k1, size_t key1_len, void *k2,
+                            size_t key2_len);
+void Curl_hash_start_iterate(struct Curl_hash *hash,
+                             struct Curl_hash_iterator *iter);
+struct Curl_hash_element *
+Curl_hash_next_element(struct Curl_hash_iterator *iter);
+
+void Curl_hash_print(struct Curl_hash *h,
+                     void (*func)(void *));
+
+
+#endif /* HEADER_CURL_HASH_H */
Index: trunk/src/libs/curl-8.7.1/lib/headers.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/headers.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/headers.c	(revision 104083)
@@ -0,0 +1,449 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "urldata.h"
+#include "strdup.h"
+#include "strcase.h"
+#include "sendf.h"
+#include "headers.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API)
+
+/* Generate the curl_header struct for the user. This function MUST assign all
+   struct fields in the output struct. */
+static void copy_header_external(struct Curl_header_store *hs,
+                                 size_t index,
+                                 size_t amount,
+                                 struct Curl_llist_element *e,
+                                 struct curl_header *hout)
+{
+  struct curl_header *h = hout;
+  h->name = hs->name;
+  h->value = hs->value;
+  h->amount = amount;
+  h->index = index;
+  /* this will randomly OR a reserved bit for the sole purpose of making it
+     impossible for applications to do == comparisons, as that would otherwise
+     be very tempting and then lead to the reserved bits not being reserved
+     anymore. */
+  h->origin = hs->type | (1<<27);
+  h->anchor = e;
+}
+
+/* public API */
+CURLHcode curl_easy_header(CURL *easy,
+                           const char *name,
+                           size_t nameindex,
+                           unsigned int type,
+                           int request,
+                           struct curl_header **hout)
+{
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *e_pick = NULL;
+  struct Curl_easy *data = easy;
+  size_t match = 0;
+  size_t amount = 0;
+  struct Curl_header_store *hs = NULL;
+  struct Curl_header_store *pick = NULL;
+  if(!name || !hout || !data ||
+     (type > (CURLH_HEADER|CURLH_TRAILER|CURLH_CONNECT|CURLH_1XX|
+              CURLH_PSEUDO)) || !type || (request < -1))
+    return CURLHE_BAD_ARGUMENT;
+  if(!Curl_llist_count(&data->state.httphdrs))
+    return CURLHE_NOHEADERS; /* no headers available */
+  if(request > data->state.requests)
+    return CURLHE_NOREQUEST;
+  if(request == -1)
+    request = data->state.requests;
+
+  /* we need a first round to count amount of this header */
+  for(e = data->state.httphdrs.head; e; e = e->next) {
+    hs = e->ptr;
+    if(strcasecompare(hs->name, name) &&
+       (hs->type & type) &&
+       (hs->request == request)) {
+      amount++;
+      pick = hs;
+      e_pick = e;
+    }
+  }
+  if(!amount)
+    return CURLHE_MISSING;
+  else if(nameindex >= amount)
+    return CURLHE_BADINDEX;
+
+  if(nameindex == amount - 1)
+    /* if the last or only occurrence is what's asked for, then we know it */
+    hs = pick;
+  else {
+    for(e = data->state.httphdrs.head; e; e = e->next) {
+      hs = e->ptr;
+      if(strcasecompare(hs->name, name) &&
+         (hs->type & type) &&
+         (hs->request == request) &&
+         (match++ == nameindex)) {
+        e_pick = e;
+        break;
+      }
+    }
+    if(!e) /* this shouldn't happen */
+      return CURLHE_MISSING;
+  }
+  /* this is the name we want */
+  copy_header_external(hs, nameindex, amount, e_pick,
+                       &data->state.headerout[0]);
+  *hout = &data->state.headerout[0];
+  return CURLHE_OK;
+}
+
+/* public API */
+struct curl_header *curl_easy_nextheader(CURL *easy,
+                                         unsigned int type,
+                                         int request,
+                                         struct curl_header *prev)
+{
+  struct Curl_easy *data = easy;
+  struct Curl_llist_element *pick;
+  struct Curl_llist_element *e;
+  struct Curl_header_store *hs;
+  size_t amount = 0;
+  size_t index = 0;
+
+  if(request > data->state.requests)
+    return NULL;
+  if(request == -1)
+    request = data->state.requests;
+
+  if(prev) {
+    pick = prev->anchor;
+    if(!pick)
+      /* something is wrong */
+      return NULL;
+    pick = pick->next;
+  }
+  else
+    pick = data->state.httphdrs.head;
+
+  if(pick) {
+    /* make sure it is the next header of the desired type */
+    do {
+      hs = pick->ptr;
+      if((hs->type & type) && (hs->request == request))
+        break;
+      pick = pick->next;
+    } while(pick);
+  }
+
+  if(!pick)
+    /* no more headers available */
+    return NULL;
+
+  hs = pick->ptr;
+
+  /* count number of occurrences of this name within the mask and figure out
+     the index for the currently selected entry */
+  for(e = data->state.httphdrs.head; e; e = e->next) {
+    struct Curl_header_store *check = e->ptr;
+    if(strcasecompare(hs->name, check->name) &&
+       (check->request == request) &&
+       (check->type & type))
+      amount++;
+    if(e == pick)
+      index = amount - 1;
+  }
+
+  copy_header_external(hs, index, amount, pick,
+                       &data->state.headerout[1]);
+  return &data->state.headerout[1];
+}
+
+static CURLcode namevalue(char *header, size_t hlen, unsigned int type,
+                          char **name, char **value)
+{
+  char *end = header + hlen - 1; /* point to the last byte */
+  DEBUGASSERT(hlen);
+  *name = header;
+
+  if(type == CURLH_PSEUDO) {
+    if(*header != ':')
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    header++;
+  }
+
+  /* Find the end of the header name */
+  while(*header && (*header != ':'))
+    ++header;
+
+  if(*header)
+    /* Skip over colon, null it */
+    *header++ = 0;
+  else
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  /* skip all leading space letters */
+  while(*header && ISBLANK(*header))
+    header++;
+
+  *value = header;
+
+  /* skip all trailing space letters */
+  while((end > header) && ISSPACE(*end))
+    *end-- = 0; /* nul terminate */
+  return CURLE_OK;
+}
+
+static CURLcode unfold_value(struct Curl_easy *data, const char *value,
+                             size_t vlen)  /* length of the incoming header */
+{
+  struct Curl_header_store *hs;
+  struct Curl_header_store *newhs;
+  size_t olen; /* length of the old value */
+  size_t oalloc; /* length of the old name + value + separator */
+  size_t offset;
+  DEBUGASSERT(data->state.prevhead);
+  hs = data->state.prevhead;
+  olen = strlen(hs->value);
+  offset = hs->value - hs->buffer;
+  oalloc = olen + offset + 1;
+
+  /* skip all trailing space letters */
+  while(vlen && ISSPACE(value[vlen - 1]))
+    vlen--;
+
+  /* save only one leading space */
+  while((vlen > 1) && ISBLANK(value[0]) && ISBLANK(value[1])) {
+    vlen--;
+    value++;
+  }
+
+  /* since this header block might move in the realloc below, it needs to
+     first be unlinked from the list and then re-added again after the
+     realloc */
+  Curl_llist_remove(&data->state.httphdrs, &hs->node, NULL);
+
+  /* new size = struct + new value length + old name+value length */
+  newhs = Curl_saferealloc(hs, sizeof(*hs) + vlen + oalloc + 1);
+  if(!newhs)
+    return CURLE_OUT_OF_MEMORY;
+  /* ->name' and ->value point into ->buffer (to keep the header allocation
+     in a single memory block), which now potentially have moved. Adjust
+     them. */
+  newhs->name = newhs->buffer;
+  newhs->value = &newhs->buffer[offset];
+
+  /* put the data at the end of the previous data, not the newline */
+  memcpy(&newhs->value[olen], value, vlen);
+  newhs->value[olen + vlen] = 0; /* null-terminate at newline */
+
+  /* insert this node into the list of headers */
+  Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
+                         newhs, &newhs->node);
+  data->state.prevhead = newhs;
+  return CURLE_OK;
+}
+
+
+/*
+ * Curl_headers_push() gets passed a full HTTP header to store. It gets called
+ * immediately before the header callback. The header is CRLF terminated.
+ */
+CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
+                           unsigned char type)
+{
+  char *value = NULL;
+  char *name = NULL;
+  char *end;
+  size_t hlen; /* length of the incoming header */
+  struct Curl_header_store *hs;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+
+  if((header[0] == '\r') || (header[0] == '\n'))
+    /* ignore the body separator */
+    return CURLE_OK;
+
+  end = strchr(header, '\r');
+  if(!end) {
+    end = strchr(header, '\n');
+    if(!end)
+      /* neither CR nor LF as terminator is not a valid header */
+      return CURLE_WEIRD_SERVER_REPLY;
+  }
+  hlen = end - header;
+
+  if((header[0] == ' ') || (header[0] == '\t')) {
+    if(data->state.prevhead)
+      /* line folding, append value to the previous header's value */
+      return unfold_value(data, header, hlen);
+    else {
+      /* Can't unfold without a previous header. Instead of erroring, just
+         pass the leading blanks. */
+      while(hlen && ISBLANK(*header)) {
+        header++;
+        hlen--;
+      }
+      if(!hlen)
+        return CURLE_WEIRD_SERVER_REPLY;
+    }
+  }
+
+  hs = calloc(1, sizeof(*hs) + hlen);
+  if(!hs)
+    return CURLE_OUT_OF_MEMORY;
+  memcpy(hs->buffer, header, hlen);
+  hs->buffer[hlen] = 0; /* nul terminate */
+
+  result = namevalue(hs->buffer, hlen, type, &name, &value);
+  if(!result) {
+    hs->name = name;
+    hs->value = value;
+    hs->type = type;
+    hs->request = data->state.requests;
+
+    /* insert this node into the list of headers */
+    Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
+                           hs, &hs->node);
+    data->state.prevhead = hs;
+  }
+  else
+    free(hs);
+  return result;
+}
+
+/*
+ * Curl_headers_reset(). Reset the headers subsystem.
+ */
+static void headers_reset(struct Curl_easy *data)
+{
+  Curl_llist_init(&data->state.httphdrs, NULL);
+  data->state.prevhead = NULL;
+}
+
+struct hds_cw_collect_ctx {
+  struct Curl_cwriter super;
+};
+
+static CURLcode hds_cw_collect_write(struct Curl_easy *data,
+                                     struct Curl_cwriter *writer, int type,
+                                     const char *buf, size_t blen)
+{
+  if((type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS)) {
+    unsigned char htype = (unsigned char)
+      (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT :
+       (type & CLIENTWRITE_1XX ? CURLH_1XX :
+        (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
+         CURLH_HEADER)));
+    CURLcode result = Curl_headers_push(data, buf, htype);
+    if(result)
+      return result;
+  }
+  return Curl_cwriter_write(data, writer->next, type, buf, blen);
+}
+
+static const struct Curl_cwtype hds_cw_collect = {
+  "hds-collect",
+  NULL,
+  Curl_cwriter_def_init,
+  hds_cw_collect_write,
+  Curl_cwriter_def_close,
+  sizeof(struct hds_cw_collect_ctx)
+};
+
+CURLcode Curl_headers_init(struct Curl_easy *data)
+{
+  struct Curl_cwriter *writer;
+  CURLcode result;
+
+  if(data->conn && (data->conn->handler->protocol & PROTO_FAMILY_HTTP)) {
+    /* avoid installing it twice */
+    if(Curl_cwriter_get_by_name(data, hds_cw_collect.name))
+      return CURLE_OK;
+
+    result = Curl_cwriter_create(&writer, data, &hds_cw_collect,
+                                 CURL_CW_PROTOCOL);
+    if(result)
+      return result;
+
+    result = Curl_cwriter_add(data, writer);
+    if(result) {
+      Curl_cwriter_free(data, writer);
+      return result;
+    }
+  }
+  return CURLE_OK;
+}
+
+/*
+ * Curl_headers_cleanup(). Free all stored headers and associated memory.
+ */
+CURLcode Curl_headers_cleanup(struct Curl_easy *data)
+{
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *n;
+
+  for(e = data->state.httphdrs.head; e; e = n) {
+    struct Curl_header_store *hs = e->ptr;
+    n = e->next;
+    free(hs);
+  }
+  headers_reset(data);
+  return CURLE_OK;
+}
+
+#else /* HTTP-disabled builds below */
+
+CURLHcode curl_easy_header(CURL *easy,
+                           const char *name,
+                           size_t index,
+                           unsigned int origin,
+                           int request,
+                           struct curl_header **hout)
+{
+  (void)easy;
+  (void)name;
+  (void)index;
+  (void)origin;
+  (void)request;
+  (void)hout;
+  return CURLHE_NOT_BUILT_IN;
+}
+
+struct curl_header *curl_easy_nextheader(CURL *easy,
+                                         unsigned int type,
+                                         int request,
+                                         struct curl_header *prev)
+{
+  (void)easy;
+  (void)type;
+  (void)request;
+  (void)prev;
+  return NULL;
+}
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/headers.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/headers.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/headers.h	(revision 104083)
@@ -0,0 +1,62 @@
+#ifndef HEADER_CURL_HEADER_H
+#define HEADER_CURL_HEADER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API)
+
+struct Curl_header_store {
+  struct Curl_llist_element node;
+  char *name; /* points into 'buffer' */
+  char *value; /* points into 'buffer */
+  int request; /* 0 is the first request, then 1.. 2.. */
+  unsigned char type; /* CURLH_* defines */
+  char buffer[1]; /* this is the raw header blob */
+};
+
+/*
+ * Initialize header collecting for a transfer.
+ * Will add a client writer that catches CLIENTWRITE_HEADER writes.
+ */
+CURLcode Curl_headers_init(struct Curl_easy *data);
+
+/*
+ * Curl_headers_push() gets passed a full header to store.
+ */
+CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
+                           unsigned char type);
+
+/*
+ * Curl_headers_cleanup(). Free all stored headers and associated memory.
+ */
+CURLcode Curl_headers_cleanup(struct Curl_easy *data);
+
+#else
+#define Curl_headers_init(x) CURLE_OK
+#define Curl_headers_push(x,y,z) CURLE_OK
+#define Curl_headers_cleanup(x) Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_HEADER_H */
Index: trunk/src/libs/curl-8.7.1/lib/hmac.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/hmac.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/hmac.c	(revision 104083)
@@ -0,0 +1,173 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC2104 Keyed-Hashing for Message Authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI))         \
+  || !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH)
+
+#include <curl/curl.h>
+
+#include "curl_hmac.h"
+#include "curl_memory.h"
+#include "warnless.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Generic HMAC algorithm.
+ *
+ *   This module computes HMAC digests based on any hash function. Parameters
+ * and computing procedures are set-up dynamically at HMAC computation context
+ * initialization.
+ */
+
+static const unsigned char hmac_ipad = 0x36;
+static const unsigned char hmac_opad = 0x5C;
+
+
+
+struct HMAC_context *
+Curl_HMAC_init(const struct HMAC_params *hashparams,
+               const unsigned char *key,
+               unsigned int keylen)
+{
+  size_t i;
+  struct HMAC_context *ctxt;
+  unsigned char *hkey;
+  unsigned char b;
+
+  /* Create HMAC context. */
+  i = sizeof(*ctxt) + 2 * hashparams->hmac_ctxtsize +
+    hashparams->hmac_resultlen;
+  ctxt = malloc(i);
+
+  if(!ctxt)
+    return ctxt;
+
+  ctxt->hmac_hash = hashparams;
+  ctxt->hmac_hashctxt1 = (void *) (ctxt + 1);
+  ctxt->hmac_hashctxt2 = (void *) ((char *) ctxt->hmac_hashctxt1 +
+      hashparams->hmac_ctxtsize);
+
+  /* If the key is too long, replace it by its hash digest. */
+  if(keylen > hashparams->hmac_maxkeylen) {
+    (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1);
+    (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, key, keylen);
+    hkey = (unsigned char *) ctxt->hmac_hashctxt2 + hashparams->hmac_ctxtsize;
+    (*hashparams->hmac_hfinal)(hkey, ctxt->hmac_hashctxt1);
+    key = hkey;
+    keylen = hashparams->hmac_resultlen;
+  }
+
+  /* Prime the two hash contexts with the modified key. */
+  (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1);
+  (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt2);
+
+  for(i = 0; i < keylen; i++) {
+    b = (unsigned char)(*key ^ hmac_ipad);
+    (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &b, 1);
+    b = (unsigned char)(*key++ ^ hmac_opad);
+    (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &b, 1);
+  }
+
+  for(; i < hashparams->hmac_maxkeylen; i++) {
+    (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &hmac_ipad, 1);
+    (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &hmac_opad, 1);
+  }
+
+  /* Done, return pointer to HMAC context. */
+  return ctxt;
+}
+
+int Curl_HMAC_update(struct HMAC_context *ctxt,
+                     const unsigned char *data,
+                     unsigned int len)
+{
+  /* Update first hash calculation. */
+  (*ctxt->hmac_hash->hmac_hupdate)(ctxt->hmac_hashctxt1, data, len);
+  return 0;
+}
+
+
+int Curl_HMAC_final(struct HMAC_context *ctxt, unsigned char *result)
+{
+  const struct HMAC_params *hashparams = ctxt->hmac_hash;
+
+  /* Do not get result if called with a null parameter: only release
+     storage. */
+
+  if(!result)
+    result = (unsigned char *) ctxt->hmac_hashctxt2 +
+     ctxt->hmac_hash->hmac_ctxtsize;
+
+  (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt1);
+  (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2,
+   result, hashparams->hmac_resultlen);
+  (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt2);
+  free((char *) ctxt);
+  return 0;
+}
+
+/*
+ * Curl_hmacit()
+ *
+ * This is used to generate a HMAC hash, for the specified input data, given
+ * the specified hash function and key.
+ *
+ * Parameters:
+ *
+ * hashparams [in]     - The hash function (Curl_HMAC_MD5).
+ * key        [in]     - The key to use.
+ * keylen     [in]     - The length of the key.
+ * data       [in]     - The data to encrypt.
+ * datalen    [in]     - The length of the data.
+ * output     [in/out] - The output buffer.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_hmacit(const struct HMAC_params *hashparams,
+                     const unsigned char *key, const size_t keylen,
+                     const unsigned char *data, const size_t datalen,
+                     unsigned char *output)
+{
+  struct HMAC_context *ctxt =
+    Curl_HMAC_init(hashparams, key, curlx_uztoui(keylen));
+
+  if(!ctxt)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Update the digest with the given challenge */
+  Curl_HMAC_update(ctxt, data, curlx_uztoui(datalen));
+
+  /* Finalise the digest */
+  Curl_HMAC_final(ctxt, output);
+
+  return CURLE_OK;
+}
+
+#endif /* Using NTLM (without SSPI) or AWS */
Index: trunk/src/libs/curl-8.7.1/lib/hostasyn.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/hostasyn.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/hostasyn.c	(revision 104083)
@@ -0,0 +1,123 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+/***********************************************************************
+ * Only for builds using asynchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_ASYNCH
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "url.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Curl_addrinfo_callback() gets called by ares, gethostbyname_thread()
+ * or getaddrinfo_thread() when we got the name resolved (or not!).
+ *
+ * If the status argument is CURL_ASYNC_SUCCESS, this function takes
+ * ownership of the Curl_addrinfo passed, storing the resolved data
+ * in the DNS cache.
+ *
+ * The storage operation locks and unlocks the DNS cache.
+ */
+CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
+                                int status,
+                                struct Curl_addrinfo *ai)
+{
+  struct Curl_dns_entry *dns = NULL;
+  CURLcode result = CURLE_OK;
+
+  data->state.async.status = status;
+
+  if(CURL_ASYNC_SUCCESS == status) {
+    if(ai) {
+      if(data->share)
+        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+      dns = Curl_cache_addr(data, ai,
+                            data->state.async.hostname, 0,
+                            data->state.async.port);
+      if(data->share)
+        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+      if(!dns) {
+        /* failed to store, cleanup and return error */
+        Curl_freeaddrinfo(ai);
+        result = CURLE_OUT_OF_MEMORY;
+      }
+    }
+    else {
+      result = CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  data->state.async.dns = dns;
+
+ /* Set async.done TRUE last in this function since it may be used multi-
+    threaded and once this is TRUE the other thread may read fields from the
+    async struct */
+  data->state.async.done = TRUE;
+
+  /* IPv4: The input hostent struct will be freed by ares when we return from
+     this function */
+  return result;
+}
+
+/*
+ * Curl_getaddrinfo() is the generic low-level name resolve API within this
+ * source file. There are several versions of this function - for different
+ * name resolve layers (selected at build-time). They all take this same set
+ * of arguments
+ */
+struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
+                                       const char *hostname,
+                                       int port,
+                                       int *waitp)
+{
+  return Curl_resolver_getaddrinfo(data, hostname, port, waitp);
+}
+
+#endif /* CURLRES_ASYNCH */
Index: trunk/src/libs/curl-8.7.1/lib/hostip.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/hostip.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/hostip.c	(revision 104083)
@@ -0,0 +1,1469 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include <setjmp.h>
+#include <signal.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "rand.h"
+#include "share.h"
+#include "url.h"
+#include "inet_ntop.h"
+#include "inet_pton.h"
+#include "multiif.h"
+#include "doh.h"
+#include "warnless.h"
+#include "strcase.h"
+#include "easy_lock.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if defined(CURLRES_SYNCH) &&                   \
+  defined(HAVE_ALARM) &&                        \
+  defined(SIGALRM) &&                           \
+  defined(HAVE_SIGSETJMP) &&                    \
+  defined(GLOBAL_INIT_IS_THREADSAFE)
+/* alarm-based timeouts can only be used with all the dependencies satisfied */
+#define USE_ALARM_TIMEOUT
+#endif
+
+#define MAX_HOSTCACHE_LEN (255 + 7) /* max FQDN + colon + port number + zero */
+
+#define MAX_DNS_CACHE_SIZE 29999
+
+/*
+ * hostip.c explained
+ * ==================
+ *
+ * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
+ * source file are these:
+ *
+ * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
+ * that. The host may not be able to resolve IPv6, but we don't really have to
+ * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
+ * defined.
+ *
+ * CURLRES_ARES - is defined if libcurl is built to use c-ares for
+ * asynchronous name resolves. This can be Windows or *nix.
+ *
+ * CURLRES_THREADED - is defined if libcurl is built to run under (native)
+ * Windows, and then the name resolve will be done in a new thread, and the
+ * supported API will be the same as for ares-builds.
+ *
+ * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If
+ * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is
+ * defined.
+ *
+ * The host*.c sources files are split up like this:
+ *
+ * hostip.c   - method-independent resolver functions and utility functions
+ * hostasyn.c - functions for asynchronous name resolves
+ * hostsyn.c  - functions for synchronous name resolves
+ * hostip4.c  - IPv4 specific functions
+ * hostip6.c  - IPv6 specific functions
+ *
+ * The two asynchronous name resolver backends are implemented in:
+ * asyn-ares.c   - functions for ares-using name resolves
+ * asyn-thread.c - functions for threaded name resolves
+
+ * The hostip.h is the united header file for all this. It defines the
+ * CURLRES_* defines based on the config*.h and curl_setup.h defines.
+ */
+
+static void freednsentry(void *freethis);
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void show_resolve_info(struct Curl_easy *data,
+                              struct Curl_dns_entry *dns);
+#else
+#define show_resolve_info(x,y) Curl_nop_stmt
+#endif
+
+/*
+ * Curl_printable_address() stores a printable version of the 1st address
+ * given in the 'ai' argument. The result will be stored in the buf that is
+ * bufsize bytes big.
+ *
+ * If the conversion fails, the target buffer is empty.
+ */
+void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf,
+                            size_t bufsize)
+{
+  DEBUGASSERT(bufsize);
+  buf[0] = 0;
+
+  switch(ai->ai_family) {
+  case AF_INET: {
+    const struct sockaddr_in *sa4 = (const void *)ai->ai_addr;
+    const struct in_addr *ipaddr4 = &sa4->sin_addr;
+    (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
+    break;
+  }
+#ifdef ENABLE_IPV6
+  case AF_INET6: {
+    const struct sockaddr_in6 *sa6 = (const void *)ai->ai_addr;
+    const struct in6_addr *ipaddr6 = &sa6->sin6_addr;
+    (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize);
+    break;
+  }
+#endif
+  default:
+    break;
+  }
+}
+
+/*
+ * Create a hostcache id string for the provided host + port, to be used by
+ * the DNS caching. Without alloc. Return length of the id string.
+ */
+static size_t
+create_hostcache_id(const char *name,
+                    size_t nlen, /* 0 or actual name length */
+                    int port, char *ptr, size_t buflen)
+{
+  size_t len = nlen ? nlen : strlen(name);
+  size_t olen = 0;
+  DEBUGASSERT(buflen >= MAX_HOSTCACHE_LEN);
+  if(len > (buflen - 7))
+    len = buflen - 7;
+  /* store and lower case the name */
+  while(len--) {
+    *ptr++ = Curl_raw_tolower(*name++);
+    olen++;
+  }
+  olen += msnprintf(ptr, 7, ":%u", port);
+  return olen;
+}
+
+struct hostcache_prune_data {
+  time_t now;
+  time_t oldest; /* oldest time in cache not pruned. */
+  int cache_timeout;
+};
+
+/*
+ * This function is set as a callback to be called for every entry in the DNS
+ * cache when we want to prune old unused entries.
+ *
+ * Returning non-zero means remove the entry, return 0 to keep it in the
+ * cache.
+ */
+static int
+hostcache_timestamp_remove(void *datap, void *hc)
+{
+  struct hostcache_prune_data *prune =
+    (struct hostcache_prune_data *) datap;
+  struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
+
+  if(c->timestamp) {
+    /* age in seconds */
+    time_t age = prune->now - c->timestamp;
+    if(age >= prune->cache_timeout)
+      return TRUE;
+    if(age > prune->oldest)
+      prune->oldest = age;
+  }
+  return FALSE;
+}
+
+/*
+ * Prune the DNS cache. This assumes that a lock has already been taken.
+ * Returns the 'age' of the oldest still kept entry.
+ */
+static time_t
+hostcache_prune(struct Curl_hash *hostcache, int cache_timeout,
+                time_t now)
+{
+  struct hostcache_prune_data user;
+
+  user.cache_timeout = cache_timeout;
+  user.now = now;
+  user.oldest = 0;
+
+  Curl_hash_clean_with_criterium(hostcache,
+                                 (void *) &user,
+                                 hostcache_timestamp_remove);
+
+  return user.oldest;
+}
+
+/*
+ * Library-wide function for pruning the DNS cache. This function takes and
+ * returns the appropriate locks.
+ */
+void Curl_hostcache_prune(struct Curl_easy *data)
+{
+  time_t now;
+  /* the timeout may be set -1 (forever) */
+  int timeout = data->set.dns_cache_timeout;
+
+  if(!data->dns.hostcache)
+    /* NULL hostcache means we can't do it */
+    return;
+
+  if(data->share)
+    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+  time(&now);
+
+  do {
+    /* Remove outdated and unused entries from the hostcache */
+    time_t oldest = hostcache_prune(data->dns.hostcache, timeout, now);
+
+    if(oldest < INT_MAX)
+      timeout = (int)oldest; /* we know it fits */
+    else
+      timeout = INT_MAX - 1;
+
+    /* if the cache size is still too big, use the oldest age as new
+       prune limit */
+  } while(timeout && (data->dns.hostcache->size > MAX_DNS_CACHE_SIZE));
+
+  if(data->share)
+    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+}
+
+#ifdef USE_ALARM_TIMEOUT
+/* Beware this is a global and unique instance. This is used to store the
+   return address that we can jump back to from inside a signal handler. This
+   is not thread-safe stuff. */
+static sigjmp_buf curl_jmpenv;
+static curl_simple_lock curl_jmpenv_lock;
+#endif
+
+/* lookup address, returns entry if found and not stale */
+static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
+                                         const char *hostname,
+                                         int port)
+{
+  struct Curl_dns_entry *dns = NULL;
+  char entry_id[MAX_HOSTCACHE_LEN];
+
+  /* Create an entry id, based upon the hostname and port */
+  size_t entry_len = create_hostcache_id(hostname, 0, port,
+                                         entry_id, sizeof(entry_id));
+
+  /* See if it's already in our dns cache */
+  dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
+
+  /* No entry found in cache, check if we might have a wildcard entry */
+  if(!dns && data->state.wildcard_resolve) {
+    entry_len = create_hostcache_id("*", 1, port, entry_id, sizeof(entry_id));
+
+    /* See if it's already in our dns cache */
+    dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
+  }
+
+  if(dns && (data->set.dns_cache_timeout != -1)) {
+    /* See whether the returned entry is stale. Done before we release lock */
+    struct hostcache_prune_data user;
+
+    time(&user.now);
+    user.cache_timeout = data->set.dns_cache_timeout;
+    user.oldest = 0;
+
+    if(hostcache_timestamp_remove(&user, dns)) {
+      infof(data, "Hostname in DNS cache was stale, zapped");
+      dns = NULL; /* the memory deallocation is being handled by the hash */
+      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
+    }
+  }
+
+  /* See if the returned entry matches the required resolve mode */
+  if(dns && data->conn->ip_version != CURL_IPRESOLVE_WHATEVER) {
+    int pf = PF_INET;
+    bool found = false;
+    struct Curl_addrinfo *addr = dns->addr;
+
+#ifdef PF_INET6
+    if(data->conn->ip_version == CURL_IPRESOLVE_V6)
+      pf = PF_INET6;
+#endif
+
+    while(addr) {
+      if(addr->ai_family == pf) {
+        found = true;
+        break;
+      }
+      addr = addr->ai_next;
+    }
+
+    if(!found) {
+      infof(data, "Hostname in DNS cache doesn't have needed family, zapped");
+      dns = NULL; /* the memory deallocation is being handled by the hash */
+      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
+    }
+  }
+  return dns;
+}
+
+/*
+ * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
+ *
+ * Curl_resolv() checks initially and multi_runsingle() checks each time
+ * it discovers the handle in the state WAITRESOLVE whether the hostname
+ * has already been resolved and the address has already been stored in
+ * the DNS cache. This short circuits waiting for a lot of pending
+ * lookups for the same hostname requested by different handles.
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
+ *
+ * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * use, or we'll leak memory!
+ */
+struct Curl_dns_entry *
+Curl_fetch_addr(struct Curl_easy *data,
+                const char *hostname,
+                int port)
+{
+  struct Curl_dns_entry *dns = NULL;
+
+  if(data->share)
+    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+  dns = fetch_addr(data, hostname, port);
+
+  if(dns)
+    dns->inuse++; /* we use it! */
+
+  if(data->share)
+    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+  return dns;
+}
+
+#ifndef CURL_DISABLE_SHUFFLE_DNS
+/*
+ * Return # of addresses in a Curl_addrinfo struct
+ */
+static int num_addresses(const struct Curl_addrinfo *addr)
+{
+  int i = 0;
+  while(addr) {
+    addr = addr->ai_next;
+    i++;
+  }
+  return i;
+}
+
+UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
+                                    struct Curl_addrinfo **addr);
+/*
+ * Curl_shuffle_addr() shuffles the order of addresses in a 'Curl_addrinfo'
+ * struct by re-linking its linked list.
+ *
+ * The addr argument should be the address of a pointer to the head node of a
+ * `Curl_addrinfo` list and it will be modified to point to the new head after
+ * shuffling.
+ *
+ * Not declared static only to make it easy to use in a unit test!
+ *
+ * @unittest: 1608
+ */
+UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
+                                    struct Curl_addrinfo **addr)
+{
+  CURLcode result = CURLE_OK;
+  const int num_addrs = num_addresses(*addr);
+
+  if(num_addrs > 1) {
+    struct Curl_addrinfo **nodes;
+    infof(data, "Shuffling %i addresses", num_addrs);
+
+    nodes = malloc(num_addrs*sizeof(*nodes));
+    if(nodes) {
+      int i;
+      unsigned int *rnd;
+      const size_t rnd_size = num_addrs * sizeof(*rnd);
+
+      /* build a plain array of Curl_addrinfo pointers */
+      nodes[0] = *addr;
+      for(i = 1; i < num_addrs; i++) {
+        nodes[i] = nodes[i-1]->ai_next;
+      }
+
+      rnd = malloc(rnd_size);
+      if(rnd) {
+        /* Fisher-Yates shuffle */
+        if(Curl_rand(data, (unsigned char *)rnd, rnd_size) == CURLE_OK) {
+          struct Curl_addrinfo *swap_tmp;
+          for(i = num_addrs - 1; i > 0; i--) {
+            swap_tmp = nodes[rnd[i] % (i + 1)];
+            nodes[rnd[i] % (i + 1)] = nodes[i];
+            nodes[i] = swap_tmp;
+          }
+
+          /* relink list in the new order */
+          for(i = 1; i < num_addrs; i++) {
+            nodes[i-1]->ai_next = nodes[i];
+          }
+
+          nodes[num_addrs-1]->ai_next = NULL;
+          *addr = nodes[0];
+        }
+        free(rnd);
+      }
+      else
+        result = CURLE_OUT_OF_MEMORY;
+      free(nodes);
+    }
+    else
+      result = CURLE_OUT_OF_MEMORY;
+  }
+  return result;
+}
+#endif
+
+/*
+ * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
+ *
+ * When calling Curl_resolv() has resulted in a response with a returned
+ * address, we call this function to store the information in the dns
+ * cache etc
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
+ */
+struct Curl_dns_entry *
+Curl_cache_addr(struct Curl_easy *data,
+                struct Curl_addrinfo *addr,
+                const char *hostname,
+                size_t hostlen, /* length or zero */
+                int port)
+{
+  char entry_id[MAX_HOSTCACHE_LEN];
+  size_t entry_len;
+  struct Curl_dns_entry *dns;
+  struct Curl_dns_entry *dns2;
+
+#ifndef CURL_DISABLE_SHUFFLE_DNS
+  /* shuffle addresses if requested */
+  if(data->set.dns_shuffle_addresses) {
+    CURLcode result = Curl_shuffle_addr(data, &addr);
+    if(result)
+      return NULL;
+  }
+#endif
+  if(!hostlen)
+    hostlen = strlen(hostname);
+
+  /* Create a new cache entry */
+  dns = calloc(1, sizeof(struct Curl_dns_entry) + hostlen);
+  if(!dns) {
+    return NULL;
+  }
+
+  /* Create an entry id, based upon the hostname and port */
+  entry_len = create_hostcache_id(hostname, hostlen, port,
+                                  entry_id, sizeof(entry_id));
+
+  dns->inuse = 1;   /* the cache has the first reference */
+  dns->addr = addr; /* this is the address(es) */
+  time(&dns->timestamp);
+  if(dns->timestamp == 0)
+    dns->timestamp = 1;   /* zero indicates permanent CURLOPT_RESOLVE entry */
+  dns->hostport = port;
+  if(hostlen)
+    memcpy(dns->hostname, hostname, hostlen);
+
+  /* Store the resolved data in our DNS cache. */
+  dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1,
+                       (void *)dns);
+  if(!dns2) {
+    free(dns);
+    return NULL;
+  }
+
+  dns = dns2;
+  dns->inuse++;         /* mark entry as in-use */
+  return dns;
+}
+
+#ifdef ENABLE_IPV6
+/* return a static IPv6 ::1 for the name */
+static struct Curl_addrinfo *get_localhost6(int port, const char *name)
+{
+  struct Curl_addrinfo *ca;
+  const size_t ss_size = sizeof(struct sockaddr_in6);
+  const size_t hostlen = strlen(name);
+  struct sockaddr_in6 sa6;
+  unsigned char ipv6[16];
+  unsigned short port16 = (unsigned short)(port & 0xffff);
+  ca = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1);
+  if(!ca)
+    return NULL;
+
+  sa6.sin6_family = AF_INET6;
+  sa6.sin6_port = htons(port16);
+  sa6.sin6_flowinfo = 0;
+  sa6.sin6_scope_id = 0;
+  if(Curl_inet_pton(AF_INET6, "::1", ipv6) < 1)
+    return NULL;
+  memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6));
+
+  ca->ai_flags     = 0;
+  ca->ai_family    = AF_INET6;
+  ca->ai_socktype  = SOCK_STREAM;
+  ca->ai_protocol  = IPPROTO_TCP;
+  ca->ai_addrlen   = (curl_socklen_t)ss_size;
+  ca->ai_next      = NULL;
+  ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
+  memcpy(ca->ai_addr, &sa6, ss_size);
+  ca->ai_canonname = (char *)ca->ai_addr + ss_size;
+  strcpy(ca->ai_canonname, name);
+  return ca;
+}
+#else
+#define get_localhost6(x,y) NULL
+#endif
+
+/* return a static IPv4 127.0.0.1 for the given name */
+static struct Curl_addrinfo *get_localhost(int port, const char *name)
+{
+  struct Curl_addrinfo *ca;
+  struct Curl_addrinfo *ca6;
+  const size_t ss_size = sizeof(struct sockaddr_in);
+  const size_t hostlen = strlen(name);
+  struct sockaddr_in sa;
+  unsigned int ipv4;
+  unsigned short port16 = (unsigned short)(port & 0xffff);
+
+  /* memset to clear the sa.sin_zero field */
+  memset(&sa, 0, sizeof(sa));
+  sa.sin_family = AF_INET;
+  sa.sin_port = htons(port16);
+  if(Curl_inet_pton(AF_INET, "127.0.0.1", (char *)&ipv4) < 1)
+    return NULL;
+  memcpy(&sa.sin_addr, &ipv4, sizeof(ipv4));
+
+  ca = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1);
+  if(!ca)
+    return NULL;
+  ca->ai_flags     = 0;
+  ca->ai_family    = AF_INET;
+  ca->ai_socktype  = SOCK_STREAM;
+  ca->ai_protocol  = IPPROTO_TCP;
+  ca->ai_addrlen   = (curl_socklen_t)ss_size;
+  ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
+  memcpy(ca->ai_addr, &sa, ss_size);
+  ca->ai_canonname = (char *)ca->ai_addr + ss_size;
+  strcpy(ca->ai_canonname, name);
+
+  ca6 = get_localhost6(port, name);
+  if(!ca6)
+    return ca;
+  ca6->ai_next = ca;
+  return ca6;
+}
+
+#ifdef ENABLE_IPV6
+/*
+ * Curl_ipv6works() returns TRUE if IPv6 seems to work.
+ */
+bool Curl_ipv6works(struct Curl_easy *data)
+{
+  if(data) {
+    /* the nature of most system is that IPv6 status doesn't come and go
+       during a program's lifetime so we only probe the first time and then we
+       have the info kept for fast reuse */
+    DEBUGASSERT(data);
+    DEBUGASSERT(data->multi);
+    if(data->multi->ipv6_up == IPV6_UNKNOWN) {
+      bool works = Curl_ipv6works(NULL);
+      data->multi->ipv6_up = works ? IPV6_WORKS : IPV6_DEAD;
+    }
+    return data->multi->ipv6_up == IPV6_WORKS;
+  }
+  else {
+    int ipv6_works = -1;
+    /* probe to see if we have a working IPv6 stack */
+    curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
+    if(s == CURL_SOCKET_BAD)
+      /* an IPv6 address was requested but we can't get/use one */
+      ipv6_works = 0;
+    else {
+      ipv6_works = 1;
+      sclose(s);
+    }
+    return (ipv6_works>0)?TRUE:FALSE;
+  }
+}
+#endif /* ENABLE_IPV6 */
+
+/*
+ * Curl_host_is_ipnum() returns TRUE if the given string is a numerical IPv4
+ * (or IPv6 if supported) address.
+ */
+bool Curl_host_is_ipnum(const char *hostname)
+{
+  struct in_addr in;
+#ifdef ENABLE_IPV6
+  struct in6_addr in6;
+#endif
+  if(Curl_inet_pton(AF_INET, hostname, &in) > 0
+#ifdef ENABLE_IPV6
+     || Curl_inet_pton(AF_INET6, hostname, &in6) > 0
+#endif
+    )
+    return TRUE;
+  return FALSE;
+}
+
+
+/* return TRUE if 'part' is a case insensitive tail of 'full' */
+static bool tailmatch(const char *full, const char *part)
+{
+  size_t plen = strlen(part);
+  size_t flen = strlen(full);
+  if(plen > flen)
+    return FALSE;
+  return strncasecompare(part, &full[flen - plen], plen);
+}
+
+/*
+ * Curl_resolv() is the main name resolve function within libcurl. It resolves
+ * a name and returns a pointer to the entry in the 'entry' argument (if one
+ * is provided). This function might return immediately if we're using asynch
+ * resolves. See the return codes.
+ *
+ * The cache entry we return will get its 'inuse' counter increased when this
+ * function is used. You MUST call Curl_resolv_unlock() later (when you're
+ * done using this struct) to decrease the counter again.
+ *
+ * Return codes:
+ *
+ * CURLRESOLV_ERROR   (-1) = error, no pointer
+ * CURLRESOLV_RESOLVED (0) = OK, pointer provided
+ * CURLRESOLV_PENDING  (1) = waiting for response, no pointer
+ */
+
+enum resolve_t Curl_resolv(struct Curl_easy *data,
+                           const char *hostname,
+                           int port,
+                           bool allowDOH,
+                           struct Curl_dns_entry **entry)
+{
+  struct Curl_dns_entry *dns = NULL;
+  CURLcode result;
+  enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */
+  struct connectdata *conn = data->conn;
+  /* We should intentionally error and not resolve .onion TLDs */
+  size_t hostname_len = strlen(hostname);
+  if(hostname_len >= 7 &&
+     (curl_strequal(&hostname[hostname_len - 6], ".onion") ||
+      curl_strequal(&hostname[hostname_len - 7], ".onion."))) {
+    failf(data, "Not resolving .onion address (RFC 7686)");
+    return CURLRESOLV_ERROR;
+  }
+  *entry = NULL;
+#ifndef CURL_DISABLE_DOH
+  conn->bits.doh = FALSE; /* default is not */
+#else
+  (void)allowDOH;
+#endif
+
+  if(data->share)
+    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+  dns = fetch_addr(data, hostname, port);
+
+  if(dns) {
+    infof(data, "Hostname %s was found in DNS cache", hostname);
+    dns->inuse++; /* we use it! */
+    rc = CURLRESOLV_RESOLVED;
+  }
+
+  if(data->share)
+    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+  if(!dns) {
+    /* The entry was not in the cache. Resolve it to IP address */
+
+    struct Curl_addrinfo *addr = NULL;
+    int respwait = 0;
+#if !defined(CURL_DISABLE_DOH) || !defined(USE_RESOLVE_ON_IPS)
+    struct in_addr in;
+#endif
+#ifndef CURL_DISABLE_DOH
+#ifndef USE_RESOLVE_ON_IPS
+    const
+#endif
+      bool ipnum = FALSE;
+#endif
+
+    /* notify the resolver start callback */
+    if(data->set.resolver_start) {
+      int st;
+      Curl_set_in_callback(data, true);
+      st = data->set.resolver_start(
+#ifdef USE_CURL_ASYNC
+        data->state.async.resolver,
+#else
+        NULL,
+#endif
+        NULL,
+        data->set.resolver_start_client);
+      Curl_set_in_callback(data, false);
+      if(st)
+        return CURLRESOLV_ERROR;
+    }
+
+#ifndef USE_RESOLVE_ON_IPS
+    /* First check if this is an IPv4 address string */
+    if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
+      /* This is a dotted IP address 123.123.123.123-style */
+      addr = Curl_ip2addr(AF_INET, &in, hostname, port);
+      if(!addr)
+        return CURLRESOLV_ERROR;
+    }
+#ifdef ENABLE_IPV6
+    else {
+      struct in6_addr in6;
+      /* check if this is an IPv6 address string */
+      if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) {
+        /* This is an IPv6 address literal */
+        addr = Curl_ip2addr(AF_INET6, &in6, hostname, port);
+        if(!addr)
+          return CURLRESOLV_ERROR;
+      }
+    }
+#endif /* ENABLE_IPV6 */
+
+#else /* if USE_RESOLVE_ON_IPS */
+#ifndef CURL_DISABLE_DOH
+    /* First check if this is an IPv4 address string */
+    if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+      /* This is a dotted IP address 123.123.123.123-style */
+      ipnum = TRUE;
+#ifdef ENABLE_IPV6
+    else {
+      struct in6_addr in6;
+      /* check if this is an IPv6 address string */
+      if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0)
+        /* This is an IPv6 address literal */
+        ipnum = TRUE;
+    }
+#endif /* ENABLE_IPV6 */
+#endif /* CURL_DISABLE_DOH */
+
+#endif /* !USE_RESOLVE_ON_IPS */
+
+    if(!addr) {
+      if(conn->ip_version == CURL_IPRESOLVE_V6 && !Curl_ipv6works(data))
+        return CURLRESOLV_ERROR;
+
+      if(strcasecompare(hostname, "localhost") ||
+         tailmatch(hostname, ".localhost"))
+        addr = get_localhost(port, hostname);
+#ifndef CURL_DISABLE_DOH
+      else if(allowDOH && data->set.doh && !ipnum)
+        addr = Curl_doh(data, hostname, port, &respwait);
+#endif
+      else {
+        /* Check what IP specifics the app has requested and if we can provide
+         * it. If not, bail out. */
+        if(!Curl_ipvalid(data, conn))
+          return CURLRESOLV_ERROR;
+        /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
+           non-zero value indicating that we need to wait for the response to
+           the resolve call */
+        addr = Curl_getaddrinfo(data, hostname, port, &respwait);
+      }
+    }
+    if(!addr) {
+      if(respwait) {
+        /* the response to our resolve call will come asynchronously at
+           a later time, good or bad */
+        /* First, check that we haven't received the info by now */
+        result = Curl_resolv_check(data, &dns);
+        if(result) /* error detected */
+          return CURLRESOLV_ERROR;
+        if(dns)
+          rc = CURLRESOLV_RESOLVED; /* pointer provided */
+        else
+          rc = CURLRESOLV_PENDING; /* no info yet */
+      }
+    }
+    else {
+      if(data->share)
+        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+      /* we got a response, store it in the cache */
+      dns = Curl_cache_addr(data, addr, hostname, 0, port);
+
+      if(data->share)
+        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+      if(!dns)
+        /* returned failure, bail out nicely */
+        Curl_freeaddrinfo(addr);
+      else {
+        rc = CURLRESOLV_RESOLVED;
+        show_resolve_info(data, dns);
+      }
+    }
+  }
+
+  *entry = dns;
+
+  return rc;
+}
+
+#ifdef USE_ALARM_TIMEOUT
+/*
+ * This signal handler jumps back into the main libcurl code and continues
+ * execution.  This effectively causes the remainder of the application to run
+ * within a signal handler which is nonportable and could lead to problems.
+ */
+CURL_NORETURN static
+void alarmfunc(int sig)
+{
+  (void)sig;
+  siglongjmp(curl_jmpenv, 1);
+}
+#endif /* USE_ALARM_TIMEOUT */
+
+/*
+ * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a
+ * timeout.  This function might return immediately if we're using asynch
+ * resolves. See the return codes.
+ *
+ * The cache entry we return will get its 'inuse' counter increased when this
+ * function is used. You MUST call Curl_resolv_unlock() later (when you're
+ * done using this struct) to decrease the counter again.
+ *
+ * If built with a synchronous resolver and use of signals is not
+ * disabled by the application, then a nonzero timeout will cause a
+ * timeout after the specified number of milliseconds. Otherwise, timeout
+ * is ignored.
+ *
+ * Return codes:
+ *
+ * CURLRESOLV_TIMEDOUT(-2) = warning, time too short or previous alarm expired
+ * CURLRESOLV_ERROR   (-1) = error, no pointer
+ * CURLRESOLV_RESOLVED (0) = OK, pointer provided
+ * CURLRESOLV_PENDING  (1) = waiting for response, no pointer
+ */
+
+enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
+                                   const char *hostname,
+                                   int port,
+                                   struct Curl_dns_entry **entry,
+                                   timediff_t timeoutms)
+{
+#ifdef USE_ALARM_TIMEOUT
+#ifdef HAVE_SIGACTION
+  struct sigaction keep_sigact;   /* store the old struct here */
+  volatile bool keep_copysig = FALSE; /* whether old sigact has been saved */
+  struct sigaction sigact;
+#else
+#ifdef HAVE_SIGNAL
+  void (*keep_sigact)(int);       /* store the old handler here */
+#endif /* HAVE_SIGNAL */
+#endif /* HAVE_SIGACTION */
+  volatile long timeout;
+  volatile unsigned int prev_alarm = 0;
+#endif /* USE_ALARM_TIMEOUT */
+  enum resolve_t rc;
+
+  *entry = NULL;
+
+  if(timeoutms < 0)
+    /* got an already expired timeout */
+    return CURLRESOLV_TIMEDOUT;
+
+#ifdef USE_ALARM_TIMEOUT
+  if(data->set.no_signal)
+    /* Ignore the timeout when signals are disabled */
+    timeout = 0;
+  else
+    timeout = (timeoutms > LONG_MAX) ? LONG_MAX : (long)timeoutms;
+
+  if(!timeout)
+    /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
+    return Curl_resolv(data, hostname, port, TRUE, entry);
+
+  if(timeout < 1000) {
+    /* The alarm() function only provides integer second resolution, so if
+       we want to wait less than one second we must bail out already now. */
+    failf(data,
+        "remaining timeout of %ld too small to resolve via SIGALRM method",
+        timeout);
+    return CURLRESOLV_TIMEDOUT;
+  }
+  /* This allows us to time-out from the name resolver, as the timeout
+     will generate a signal and we will siglongjmp() from that here.
+     This technique has problems (see alarmfunc).
+     This should be the last thing we do before calling Curl_resolv(),
+     as otherwise we'd have to worry about variables that get modified
+     before we invoke Curl_resolv() (and thus use "volatile"). */
+  curl_simple_lock_lock(&curl_jmpenv_lock);
+
+  if(sigsetjmp(curl_jmpenv, 1)) {
+    /* this is coming from a siglongjmp() after an alarm signal */
+    failf(data, "name lookup timed out");
+    rc = CURLRESOLV_ERROR;
+    goto clean_up;
+  }
+  else {
+    /*************************************************************
+     * Set signal handler to catch SIGALRM
+     * Store the old value to be able to set it back later!
+     *************************************************************/
+#ifdef HAVE_SIGACTION
+    sigaction(SIGALRM, NULL, &sigact);
+    keep_sigact = sigact;
+    keep_copysig = TRUE; /* yes, we have a copy */
+    sigact.sa_handler = alarmfunc;
+#ifdef SA_RESTART
+    /* HPUX doesn't have SA_RESTART but defaults to that behavior! */
+    sigact.sa_flags &= ~SA_RESTART;
+#endif
+    /* now set the new struct */
+    sigaction(SIGALRM, &sigact, NULL);
+#else /* HAVE_SIGACTION */
+    /* no sigaction(), revert to the much lamer signal() */
+#ifdef HAVE_SIGNAL
+    keep_sigact = signal(SIGALRM, alarmfunc);
+#endif
+#endif /* HAVE_SIGACTION */
+
+    /* alarm() makes a signal get sent when the timeout fires off, and that
+       will abort system calls */
+    prev_alarm = alarm(curlx_sltoui(timeout/1000L));
+  }
+
+#else
+#ifndef CURLRES_ASYNCH
+  if(timeoutms)
+    infof(data, "timeout on name lookup is not supported");
+#else
+  (void)timeoutms; /* timeoutms not used with an async resolver */
+#endif
+#endif /* USE_ALARM_TIMEOUT */
+
+  /* Perform the actual name resolution. This might be interrupted by an
+   * alarm if it takes too long.
+   */
+  rc = Curl_resolv(data, hostname, port, TRUE, entry);
+
+#ifdef USE_ALARM_TIMEOUT
+clean_up:
+
+  if(!prev_alarm)
+    /* deactivate a possibly active alarm before uninstalling the handler */
+    alarm(0);
+
+#ifdef HAVE_SIGACTION
+  if(keep_copysig) {
+    /* we got a struct as it looked before, now put that one back nice
+       and clean */
+    sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
+  }
+#else
+#ifdef HAVE_SIGNAL
+  /* restore the previous SIGALRM handler */
+  signal(SIGALRM, keep_sigact);
+#endif
+#endif /* HAVE_SIGACTION */
+
+  curl_simple_lock_unlock(&curl_jmpenv_lock);
+
+  /* switch back the alarm() to either zero or to what it was before minus
+     the time we spent until now! */
+  if(prev_alarm) {
+    /* there was an alarm() set before us, now put it back */
+    timediff_t elapsed_secs = Curl_timediff(Curl_now(),
+                                            data->conn->created) / 1000;
+
+    /* the alarm period is counted in even number of seconds */
+    unsigned long alarm_set = (unsigned long)(prev_alarm - elapsed_secs);
+
+    if(!alarm_set ||
+       ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
+      /* if the alarm time-left reached zero or turned "negative" (counted
+         with unsigned values), we should fire off a SIGALRM here, but we
+         won't, and zero would be to switch it off so we never set it to
+         less than 1! */
+      alarm(1);
+      rc = CURLRESOLV_TIMEDOUT;
+      failf(data, "Previous alarm fired off");
+    }
+    else
+      alarm((unsigned int)alarm_set);
+  }
+#endif /* USE_ALARM_TIMEOUT */
+
+  return rc;
+}
+
+/*
+ * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
+ * made, the struct may be destroyed due to pruning. It is important that only
+ * one unlock is made for each Curl_resolv() call.
+ *
+ * May be called with 'data' == NULL for global cache.
+ */
+void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns)
+{
+  if(data && data->share)
+    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+  freednsentry(dns);
+
+  if(data && data->share)
+    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+}
+
+/*
+ * File-internal: release cache dns entry reference, free if inuse drops to 0
+ */
+static void freednsentry(void *freethis)
+{
+  struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis;
+  DEBUGASSERT(dns && (dns->inuse>0));
+
+  dns->inuse--;
+  if(dns->inuse == 0) {
+    Curl_freeaddrinfo(dns->addr);
+    free(dns);
+  }
+}
+
+/*
+ * Curl_init_dnscache() inits a new DNS cache.
+ */
+void Curl_init_dnscache(struct Curl_hash *hash, int size)
+{
+  Curl_hash_init(hash, size, Curl_hash_str, Curl_str_key_compare,
+                 freednsentry);
+}
+
+/*
+ * Curl_hostcache_clean()
+ *
+ * This _can_ be called with 'data' == NULL but then of course no locking
+ * can be done!
+ */
+
+void Curl_hostcache_clean(struct Curl_easy *data,
+                          struct Curl_hash *hash)
+{
+  if(data && data->share)
+    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+  Curl_hash_clean(hash);
+
+  if(data && data->share)
+    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+}
+
+
+CURLcode Curl_loadhostpairs(struct Curl_easy *data)
+{
+  struct curl_slist *hostp;
+  char *host_end;
+
+  /* Default is no wildcard found */
+  data->state.wildcard_resolve = false;
+
+  for(hostp = data->state.resolve; hostp; hostp = hostp->next) {
+    char entry_id[MAX_HOSTCACHE_LEN];
+    if(!hostp->data)
+      continue;
+    if(hostp->data[0] == '-') {
+      unsigned long num = 0;
+      size_t entry_len;
+      size_t hlen = 0;
+      host_end = strchr(&hostp->data[1], ':');
+
+      if(host_end) {
+        hlen = host_end - &hostp->data[1];
+        num = strtoul(++host_end, NULL, 10);
+        if(!hlen || (num > 0xffff))
+          host_end = NULL;
+      }
+      if(!host_end) {
+        infof(data, "Bad syntax CURLOPT_RESOLVE removal entry '%s'",
+              hostp->data);
+        continue;
+      }
+      /* Create an entry id, based upon the hostname and port */
+      entry_len = create_hostcache_id(&hostp->data[1], hlen, (int)num,
+                                      entry_id, sizeof(entry_id));
+      if(data->share)
+        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+      /* delete entry, ignore if it didn't exist */
+      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
+
+      if(data->share)
+        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+    }
+    else {
+      struct Curl_dns_entry *dns;
+      struct Curl_addrinfo *head = NULL, *tail = NULL;
+      size_t entry_len;
+      char address[64];
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+      char *addresses = NULL;
+#endif
+      char *addr_begin;
+      char *addr_end;
+      char *port_ptr;
+      int port = 0;
+      char *end_ptr;
+      bool permanent = TRUE;
+      unsigned long tmp_port;
+      bool error = true;
+      char *host_begin = hostp->data;
+      size_t hlen = 0;
+
+      if(host_begin[0] == '+') {
+        host_begin++;
+        permanent = FALSE;
+      }
+      host_end = strchr(host_begin, ':');
+      if(!host_end)
+        goto err;
+      hlen = host_end - host_begin;
+
+      port_ptr = host_end + 1;
+      tmp_port = strtoul(port_ptr, &end_ptr, 10);
+      if(tmp_port > USHRT_MAX || end_ptr == port_ptr || *end_ptr != ':')
+        goto err;
+
+      port = (int)tmp_port;
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+      addresses = end_ptr + 1;
+#endif
+
+      while(*end_ptr) {
+        size_t alen;
+        struct Curl_addrinfo *ai;
+
+        addr_begin = end_ptr + 1;
+        addr_end = strchr(addr_begin, ',');
+        if(!addr_end)
+          addr_end = addr_begin + strlen(addr_begin);
+        end_ptr = addr_end;
+
+        /* allow IP(v6) address within [brackets] */
+        if(*addr_begin == '[') {
+          if(addr_end == addr_begin || *(addr_end - 1) != ']')
+            goto err;
+          ++addr_begin;
+          --addr_end;
+        }
+
+        alen = addr_end - addr_begin;
+        if(!alen)
+          continue;
+
+        if(alen >= sizeof(address))
+          goto err;
+
+        memcpy(address, addr_begin, alen);
+        address[alen] = '\0';
+
+#ifndef ENABLE_IPV6
+        if(strchr(address, ':')) {
+          infof(data, "Ignoring resolve address '%s', missing IPv6 support.",
+                address);
+          continue;
+        }
+#endif
+
+        ai = Curl_str2addr(address, port);
+        if(!ai) {
+          infof(data, "Resolve address '%s' found illegal", address);
+          goto err;
+        }
+
+        if(tail) {
+          tail->ai_next = ai;
+          tail = tail->ai_next;
+        }
+        else {
+          head = tail = ai;
+        }
+      }
+
+      if(!head)
+        goto err;
+
+      error = false;
+err:
+      if(error) {
+        failf(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'",
+              hostp->data);
+        Curl_freeaddrinfo(head);
+        return CURLE_SETOPT_OPTION_SYNTAX;
+      }
+
+      /* Create an entry id, based upon the hostname and port */
+      entry_len = create_hostcache_id(host_begin, hlen, port,
+                                      entry_id, sizeof(entry_id));
+
+      if(data->share)
+        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+      /* See if it's already in our dns cache */
+      dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
+
+      if(dns) {
+        infof(data, "RESOLVE %.*s:%d - old addresses discarded",
+              (int)hlen, host_begin, port);
+        /* delete old entry, there are two reasons for this
+         1. old entry may have different addresses.
+         2. even if entry with correct addresses is already in the cache,
+            but if it is close to expire, then by the time next http
+            request is made, it can get expired and pruned because old
+            entry is not necessarily marked as permanent.
+         3. when adding a non-permanent entry, we want it to remove and
+            replace an existing permanent entry.
+         4. when adding a non-permanent entry, we want it to get a "fresh"
+            timeout that starts _now_. */
+
+        Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
+      }
+
+      /* put this new host in the cache */
+      dns = Curl_cache_addr(data, head, host_begin, hlen, port);
+      if(dns) {
+        if(permanent)
+          dns->timestamp = 0; /* mark as permanent */
+        /* release the returned reference; the cache itself will keep the
+         * entry alive: */
+        dns->inuse--;
+      }
+
+      if(data->share)
+        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+      if(!dns) {
+        Curl_freeaddrinfo(head);
+        return CURLE_OUT_OF_MEMORY;
+      }
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+      infof(data, "Added %.*s:%d:%s to DNS cache%s",
+            (int)hlen, host_begin, port, addresses,
+            permanent ? "" : " (non-permanent)");
+#endif
+
+      /* Wildcard hostname */
+      if((hlen == 1) && (host_begin[0] == '*')) {
+        infof(data, "RESOLVE *:%d using wildcard", port);
+        data->state.wildcard_resolve = true;
+      }
+    }
+  }
+  data->state.resolve = NULL; /* dealt with now */
+
+  return CURLE_OK;
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void show_resolve_info(struct Curl_easy *data,
+                              struct Curl_dns_entry *dns)
+{
+  struct Curl_addrinfo *a;
+  CURLcode result = CURLE_OK;
+#ifdef CURLRES_IPV6
+  struct dynbuf out[2];
+#else
+  struct dynbuf out[1];
+#endif
+  DEBUGASSERT(data);
+  DEBUGASSERT(dns);
+
+  if(!data->set.verbose ||
+     /* ignore no name or numerical IP addresses */
+     !dns->hostname[0] || Curl_host_is_ipnum(dns->hostname))
+    return;
+
+  a = dns->addr;
+
+  infof(data, "Host %s:%d was resolved.",
+        (dns->hostname[0] ? dns->hostname : "(none)"), dns->hostport);
+
+  Curl_dyn_init(&out[0], 1024);
+#ifdef CURLRES_IPV6
+  Curl_dyn_init(&out[1], 1024);
+#endif
+
+  while(a) {
+    if(
+#ifdef CURLRES_IPV6
+       a->ai_family == PF_INET6 ||
+#endif
+       a->ai_family == PF_INET) {
+      char buf[MAX_IPADR_LEN];
+      struct dynbuf *d = &out[(a->ai_family != PF_INET)];
+      Curl_printable_address(a, buf, sizeof(buf));
+      if(Curl_dyn_len(d))
+        result = Curl_dyn_addn(d, ", ", 2);
+      if(!result)
+        result = Curl_dyn_add(d, buf);
+      if(result) {
+        infof(data, "too many IP, can't show");
+        goto fail;
+      }
+    }
+    a = a->ai_next;
+  }
+
+#ifdef CURLRES_IPV6
+  infof(data, "IPv6: %s",
+        (Curl_dyn_len(&out[1]) ? Curl_dyn_ptr(&out[1]) : "(none)"));
+#endif
+  infof(data, "IPv4: %s",
+        (Curl_dyn_len(&out[0]) ? Curl_dyn_ptr(&out[0]) : "(none)"));
+
+fail:
+  Curl_dyn_free(&out[0]);
+#ifdef CURLRES_IPV6
+  Curl_dyn_free(&out[1]);
+#endif
+}
+#endif
+
+CURLcode Curl_resolv_check(struct Curl_easy *data,
+                           struct Curl_dns_entry **dns)
+{
+  CURLcode result;
+#if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH)
+  (void)data;
+  (void)dns;
+#endif
+#ifndef CURL_DISABLE_DOH
+  if(data->conn->bits.doh) {
+    result = Curl_doh_is_resolved(data, dns);
+  }
+  else
+#endif
+  result = Curl_resolver_is_resolved(data, dns);
+  if(*dns)
+    show_resolve_info(data, *dns);
+  return result;
+}
+
+int Curl_resolv_getsock(struct Curl_easy *data,
+                        curl_socket_t *socks)
+{
+#ifdef CURLRES_ASYNCH
+#ifndef CURL_DISABLE_DOH
+  if(data->conn->bits.doh)
+    /* nothing to wait for during DoH resolve, those handles have their own
+       sockets */
+    return GETSOCK_BLANK;
+#endif
+  return Curl_resolver_getsock(data, socks);
+#else
+  (void)data;
+  (void)socks;
+  return GETSOCK_BLANK;
+#endif
+}
+
+/* Call this function after Curl_connect() has returned async=TRUE and
+   then a successful name resolve has been received.
+
+   Note: this function disconnects and frees the conn data in case of
+   resolve failure */
+CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
+{
+  CURLcode result;
+  struct connectdata *conn = data->conn;
+
+#ifdef USE_CURL_ASYNC
+  if(data->state.async.dns) {
+    conn->dns_entry = data->state.async.dns;
+    data->state.async.dns = NULL;
+  }
+#endif
+
+  result = Curl_setup_conn(data, protocol_done);
+
+  if(result) {
+    Curl_detach_connection(data);
+    Curl_conncache_remove_conn(data, conn, TRUE);
+    Curl_disconnect(data, conn, TRUE);
+  }
+  return result;
+}
+
+/*
+ * Curl_resolver_error() calls failf() with the appropriate message after a
+ * resolve error
+ */
+
+#ifdef USE_CURL_ASYNC
+CURLcode Curl_resolver_error(struct Curl_easy *data)
+{
+  const char *host_or_proxy;
+  CURLcode result;
+
+#ifndef CURL_DISABLE_PROXY
+  struct connectdata *conn = data->conn;
+  if(conn->bits.httpproxy) {
+    host_or_proxy = "proxy";
+    result = CURLE_COULDNT_RESOLVE_PROXY;
+  }
+  else
+#endif
+  {
+    host_or_proxy = "host";
+    result = CURLE_COULDNT_RESOLVE_HOST;
+  }
+
+  failf(data, "Could not resolve %s: %s", host_or_proxy,
+        data->state.async.hostname);
+
+  return result;
+}
+#endif /* USE_CURL_ASYNC */
Index: trunk/src/libs/curl-8.7.1/lib/hostip.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/hostip.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/hostip.h	(revision 104083)
@@ -0,0 +1,229 @@
+#ifndef HEADER_CURL_HOSTIP_H
+#define HEADER_CURL_HOSTIP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "hash.h"
+#include "curl_addrinfo.h"
+#include "timeval.h" /* for timediff_t */
+#include "asyn.h"
+
+#include <setjmp.h>
+
+/* Allocate enough memory to hold the full name information structs and
+ * everything. OSF1 is known to require at least 8872 bytes. The buffer
+ * required for storing all possible aliases and IP numbers is according to
+ * Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes!
+ */
+#define CURL_HOSTENT_SIZE 9000
+
+#define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this
+                                    many seconds for a name resolve */
+
+#define CURL_ASYNC_SUCCESS CURLE_OK
+
+struct addrinfo;
+struct hostent;
+struct Curl_easy;
+struct connectdata;
+
+/*
+ * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
+ * Global DNS cache is general badness. Do not use. This will be removed in
+ * a future version. Use the share interface instead!
+ *
+ * Returns a struct Curl_hash pointer on success, NULL on failure.
+ */
+struct Curl_hash *Curl_global_host_cache_init(void);
+
+struct Curl_dns_entry {
+  struct Curl_addrinfo *addr;
+  /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (doesn't time out) */
+  time_t timestamp;
+  /* use-counter, use Curl_resolv_unlock to release reference */
+  long inuse;
+  /* hostname port number that resolved to addr. */
+  int hostport;
+  /* hostname that resolved to addr. may be NULL (unix domain sockets). */
+  char hostname[1];
+};
+
+bool Curl_host_is_ipnum(const char *hostname);
+
+/*
+ * Curl_resolv() returns an entry with the info for the specified host
+ * and port.
+ *
+ * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * use, or we'll leak memory!
+ */
+/* return codes */
+enum resolve_t {
+  CURLRESOLV_TIMEDOUT = -2,
+  CURLRESOLV_ERROR    = -1,
+  CURLRESOLV_RESOLVED =  0,
+  CURLRESOLV_PENDING  =  1
+};
+enum resolve_t Curl_resolv(struct Curl_easy *data,
+                           const char *hostname,
+                           int port,
+                           bool allowDOH,
+                           struct Curl_dns_entry **dnsentry);
+enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
+                                   const char *hostname, int port,
+                                   struct Curl_dns_entry **dnsentry,
+                                   timediff_t timeoutms);
+
+#ifdef ENABLE_IPV6
+/*
+ * Curl_ipv6works() returns TRUE if IPv6 seems to work.
+ */
+bool Curl_ipv6works(struct Curl_easy *data);
+#else
+#define Curl_ipv6works(x) FALSE
+#endif
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn);
+
+
+/*
+ * Curl_getaddrinfo() is the generic low-level name resolve API within this
+ * source file. There are several versions of this function - for different
+ * name resolve layers (selected at build-time). They all take this same set
+ * of arguments
+ */
+struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
+                                       const char *hostname,
+                                       int port,
+                                       int *waitp);
+
+
+/* unlock a previously resolved dns entry */
+void Curl_resolv_unlock(struct Curl_easy *data,
+                        struct Curl_dns_entry *dns);
+
+/* init a new dns cache */
+void Curl_init_dnscache(struct Curl_hash *hash, int hashsize);
+
+/* prune old entries from the DNS cache */
+void Curl_hostcache_prune(struct Curl_easy *data);
+
+/* IPv4 threadsafe resolve function used for synch and asynch builds */
+struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
+
+CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_connect);
+
+/*
+ * Curl_addrinfo_callback() is used when we build with any asynch specialty.
+ * Handles end of async request processing. Inserts ai into hostcache when
+ * status is CURL_ASYNC_SUCCESS. Twiddles fields in conn to indicate async
+ * request completed whether successful or failed.
+ */
+CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
+                                int status,
+                                struct Curl_addrinfo *ai);
+
+/*
+ * Curl_printable_address() returns a printable version of the 1st address
+ * given in the 'ip' argument. The result will be stored in the buf that is
+ * bufsize bytes big.
+ */
+void Curl_printable_address(const struct Curl_addrinfo *ip,
+                            char *buf, size_t bufsize);
+
+/*
+ * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
+ *
+ * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * use, or we'll leak memory!
+ */
+struct Curl_dns_entry *
+Curl_fetch_addr(struct Curl_easy *data,
+                const char *hostname,
+                int port);
+
+/*
+ * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
+ */
+struct Curl_dns_entry *
+Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr,
+                const char *hostname, size_t hostlen, int port);
+
+#ifndef INADDR_NONE
+#define CURL_INADDR_NONE (in_addr_t) ~0
+#else
+#define CURL_INADDR_NONE INADDR_NONE
+#endif
+
+/*
+ * Function provided by the resolver backend to set DNS servers to use.
+ */
+CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers);
+
+/*
+ * Function provided by the resolver backend to set
+ * outgoing interface to use for DNS requests
+ */
+CURLcode Curl_set_dns_interface(struct Curl_easy *data,
+                                const char *interf);
+
+/*
+ * Function provided by the resolver backend to set
+ * local IPv4 address to use as source address for DNS requests
+ */
+CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
+                                const char *local_ip4);
+
+/*
+ * Function provided by the resolver backend to set
+ * local IPv6 address to use as source address for DNS requests
+ */
+CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
+                                const char *local_ip6);
+
+/*
+ * Clean off entries from the cache
+ */
+void Curl_hostcache_clean(struct Curl_easy *data, struct Curl_hash *hash);
+
+/*
+ * Populate the cache with specified entries from CURLOPT_RESOLVE.
+ */
+CURLcode Curl_loadhostpairs(struct Curl_easy *data);
+CURLcode Curl_resolv_check(struct Curl_easy *data,
+                           struct Curl_dns_entry **dns);
+int Curl_resolv_getsock(struct Curl_easy *data,
+                        curl_socket_t *socks);
+
+CURLcode Curl_resolver_error(struct Curl_easy *data);
+#endif /* HEADER_CURL_HOSTIP_H */
Index: trunk/src/libs/curl-8.7.1/lib/hostip4.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/hostip4.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/hostip4.c	(revision 104083)
@@ -0,0 +1,301 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+/***********************************************************************
+ * Only for plain IPv4 builds
+ **********************************************************************/
+#ifdef CURLRES_IPV4 /* plain IPv4 code coming up */
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "url.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
+{
+  (void)data;
+  if(conn->ip_version == CURL_IPRESOLVE_V6)
+    /* An IPv6 address was requested and we can't get/use one */
+    return FALSE;
+
+  return TRUE; /* OK, proceed */
+}
+
+#ifdef CURLRES_SYNCH
+
+/*
+ * Curl_getaddrinfo() - the IPv4 synchronous version.
+ *
+ * The original code to this function was from the Dancer source code, written
+ * by Bjorn Reese, it has since been patched and modified considerably.
+ *
+ * gethostbyname_r() is the thread-safe version of the gethostbyname()
+ * function. When we build for plain IPv4, we attempt to use this
+ * function. There are _three_ different gethostbyname_r() versions, and we
+ * detect which one this platform supports in the configure script and set up
+ * the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or
+ * HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME
+ * has the corresponding rules. This is primarily on *nix. Note that some unix
+ * flavours have thread-safe versions of the plain gethostbyname() etc.
+ *
+ */
+struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
+                                       const char *hostname,
+                                       int port,
+                                       int *waitp)
+{
+  struct Curl_addrinfo *ai = NULL;
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)data;
+#endif
+
+  *waitp = 0; /* synchronous response only */
+
+  ai = Curl_ipv4_resolve_r(hostname, port);
+  if(!ai)
+    infof(data, "Curl_ipv4_resolve_r failed for %s", hostname);
+
+  return ai;
+}
+#endif /* CURLRES_SYNCH */
+#endif /* CURLRES_IPV4 */
+
+#if defined(CURLRES_IPV4) && \
+   !defined(CURLRES_ARES) && !defined(CURLRES_AMIGA)
+
+/*
+ * Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function.
+ *
+ * This is used for both synchronous and asynchronous resolver builds,
+ * implying that only threadsafe code and function calls may be used.
+ *
+ */
+struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
+                                          int port)
+{
+#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE)) && \
+   defined(HAVE_GETHOSTBYNAME_R_3)
+  int res;
+#endif
+  struct Curl_addrinfo *ai = NULL;
+  struct hostent *h = NULL;
+  struct hostent *buf = NULL;
+
+#if defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE)
+  struct addrinfo hints;
+  char sbuf[12];
+  char *sbufptr = NULL;
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = PF_INET;
+  hints.ai_socktype = SOCK_STREAM;
+  if(port) {
+    msnprintf(sbuf, sizeof(sbuf), "%d", port);
+    sbufptr = sbuf;
+  }
+
+  (void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai);
+
+#elif defined(HAVE_GETHOSTBYNAME_R)
+  /*
+   * gethostbyname_r() is the preferred resolve function for many platforms.
+   * Since there are three different versions of it, the following code is
+   * somewhat #ifdef-ridden.
+   */
+  int h_errnop;
+
+  buf = calloc(1, CURL_HOSTENT_SIZE);
+  if(!buf)
+    return NULL; /* major failure */
+  /*
+   * The clearing of the buffer is a workaround for a gethostbyname_r bug in
+   * qnx nto and it is also _required_ for some of these functions on some
+   * platforms.
+   */
+
+#if defined(HAVE_GETHOSTBYNAME_R_5)
+  /* Solaris, IRIX and more */
+  h = gethostbyname_r(hostname,
+                      (struct hostent *)buf,
+                      (char *)buf + sizeof(struct hostent),
+                      CURL_HOSTENT_SIZE - sizeof(struct hostent),
+                      &h_errnop);
+
+  /* If the buffer is too small, it returns NULL and sets errno to
+   * ERANGE. The errno is thread safe if this is compiled with
+   * -D_REENTRANT as then the 'errno' variable is a macro defined to get
+   * used properly for threads.
+   */
+
+  if(h) {
+    ;
+  }
+  else
+#elif defined(HAVE_GETHOSTBYNAME_R_6)
+  /* Linux */
+
+  (void)gethostbyname_r(hostname,
+                      (struct hostent *)buf,
+                      (char *)buf + sizeof(struct hostent),
+                      CURL_HOSTENT_SIZE - sizeof(struct hostent),
+                      &h, /* DIFFERENCE */
+                      &h_errnop);
+  /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
+   * sudden this function returns EAGAIN if the given buffer size is too
+   * small. Previous versions are known to return ERANGE for the same
+   * problem.
+   *
+   * This wouldn't be such a big problem if older versions wouldn't
+   * sometimes return EAGAIN on a common failure case. Alas, we can't
+   * assume that EAGAIN *or* ERANGE means ERANGE for any given version of
+   * glibc.
+   *
+   * For now, we do that and thus we may call the function repeatedly and
+   * fail for older glibc versions that return EAGAIN, until we run out of
+   * buffer size (step_size grows beyond CURL_HOSTENT_SIZE).
+   *
+   * If anyone has a better fix, please tell us!
+   *
+   * -------------------------------------------------------------------
+   *
+   * On October 23rd 2003, Dan C dug up more details on the mysteries of
+   * gethostbyname_r() in glibc:
+   *
+   * In glibc 2.2.5 the interface is different (this has also been
+   * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
+   * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
+   * (shipped/upgraded by Redhat 7.2) don't show this behavior!
+   *
+   * In this "buggy" version, the return code is -1 on error and 'errno'
+   * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
+   * thread-safe variable.
+   */
+
+  if(!h) /* failure */
+#elif defined(HAVE_GETHOSTBYNAME_R_3)
+  /* AIX, Digital Unix/Tru64, HPUX 10, more? */
+
+  /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
+   * the plain fact that it does not return unique full buffers on each
+   * call, but instead several of the pointers in the hostent structs will
+   * point to the same actual data! This have the unfortunate down-side that
+   * our caching system breaks down horribly. Luckily for us though, AIX 4.3
+   * and more recent versions have a "completely thread-safe"[*] libc where
+   * all the data is stored in thread-specific memory areas making calls to
+   * the plain old gethostbyname() work fine even for multi-threaded
+   * programs.
+   *
+   * This AIX 4.3 or later detection is all made in the configure script.
+   *
+   * Troels Walsted Hansen helped us work this out on March 3rd, 2003.
+   *
+   * [*] = much later we've found out that it isn't at all "completely
+   * thread-safe", but at least the gethostbyname() function is.
+   */
+
+  if(CURL_HOSTENT_SIZE >=
+     (sizeof(struct hostent) + sizeof(struct hostent_data))) {
+
+    /* August 22nd, 2000: Albert Chin-A-Young brought an updated version
+     * that should work! September 20: Richard Prescott worked on the buffer
+     * size dilemma.
+     */
+
+    res = gethostbyname_r(hostname,
+                          (struct hostent *)buf,
+                          (struct hostent_data *)((char *)buf +
+                                                  sizeof(struct hostent)));
+    h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */
+  }
+  else
+    res = -1; /* failure, too smallish buffer size */
+
+  if(!res) { /* success */
+
+    h = buf; /* result expected in h */
+
+    /* This is the worst kind of the different gethostbyname_r() interfaces.
+     * Since we don't know how big buffer this particular lookup required,
+     * we can't realloc down the huge alloc without doing closer analysis of
+     * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
+     * name lookup. Fixing this would require an extra malloc() and then
+     * calling Curl_addrinfo_copy() that subsequent realloc()s down the new
+     * memory area to the actually used amount.
+     */
+  }
+  else
+#endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */
+  {
+    h = NULL; /* set return code to NULL */
+    free(buf);
+  }
+#else /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
+          HAVE_GETHOSTBYNAME_R */
+  /*
+   * Here is code for platforms that don't have a thread safe
+   * getaddrinfo() nor gethostbyname_r() function or for which
+   * gethostbyname() is the preferred one.
+   */
+  h = gethostbyname((void *)hostname);
+#endif /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
+           HAVE_GETHOSTBYNAME_R */
+
+  if(h) {
+    ai = Curl_he2ai(h, port);
+
+    if(buf) /* used a *_r() function */
+      free(buf);
+  }
+
+  return ai;
+}
+#endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) &&
+                                   !defined(CURLRES_AMIGA) */
Index: trunk/src/libs/curl-8.7.1/lib/hostip6.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/hostip6.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/hostip6.c	(revision 104083)
@@ -0,0 +1,157 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+/***********************************************************************
+ * Only for IPv6-enabled builds
+ **********************************************************************/
+#ifdef CURLRES_IPV6
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "url.h"
+#include "inet_pton.h"
+#include "connect.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
+{
+  if(conn->ip_version == CURL_IPRESOLVE_V6)
+    return Curl_ipv6works(data);
+
+  return TRUE;
+}
+
+#if defined(CURLRES_SYNCH)
+
+#ifdef DEBUG_ADDRINFO
+static void dump_addrinfo(const struct Curl_addrinfo *ai)
+{
+  printf("dump_addrinfo:\n");
+  for(; ai; ai = ai->ai_next) {
+    char buf[INET6_ADDRSTRLEN];
+    printf("    fam %2d, CNAME %s, ",
+           ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
+    Curl_printable_address(ai, buf, sizeof(buf));
+    printf("%s\n", buf);
+  }
+}
+#else
+#define dump_addrinfo(x) Curl_nop_stmt
+#endif
+
+/*
+ * Curl_getaddrinfo() when built IPv6-enabled (non-threading and
+ * non-ares version).
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'addrinfo' is returned and the fourth argument will point
+ * to memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ */
+struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
+                                       const char *hostname,
+                                       int port,
+                                       int *waitp)
+{
+  struct addrinfo hints;
+  struct Curl_addrinfo *res;
+  int error;
+  char sbuf[12];
+  char *sbufptr = NULL;
+#ifndef USE_RESOLVE_ON_IPS
+  char addrbuf[128];
+#endif
+  int pf = PF_INET;
+
+  *waitp = 0; /* synchronous response only */
+
+  if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data))
+    /* The stack seems to be IPv6-enabled */
+    pf = PF_UNSPEC;
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = pf;
+  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
+    SOCK_STREAM : SOCK_DGRAM;
+
+#ifndef USE_RESOLVE_ON_IPS
+  /*
+   * The AI_NUMERICHOST must not be set to get synthesized IPv6 address from
+   * an IPv4 address on iOS and Mac OS X.
+   */
+  if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) ||
+     (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) {
+    /* the given address is numerical only, prevent a reverse lookup */
+    hints.ai_flags = AI_NUMERICHOST;
+  }
+#endif
+
+  if(port) {
+    msnprintf(sbuf, sizeof(sbuf), "%d", port);
+    sbufptr = sbuf;
+  }
+
+  error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);
+  if(error) {
+    infof(data, "getaddrinfo(3) failed for %s:%d", hostname, port);
+    return NULL;
+  }
+
+  if(port) {
+    Curl_addrinfo_set_port(res, port);
+  }
+
+  dump_addrinfo(res);
+
+  return res;
+}
+#endif /* CURLRES_SYNCH */
+
+#endif /* CURLRES_IPV6 */
Index: trunk/src/libs/curl-8.7.1/lib/hostsyn.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/hostsyn.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/hostsyn.c	(revision 104083)
@@ -0,0 +1,104 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+/***********************************************************************
+ * Only for builds using synchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_SYNCH
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "url.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Function provided by the resolver backend to set DNS servers to use.
+ */
+CURLcode Curl_set_dns_servers(struct Curl_easy *data,
+                              char *servers)
+{
+  (void)data;
+  (void)servers;
+  return CURLE_NOT_BUILT_IN;
+
+}
+
+/*
+ * Function provided by the resolver backend to set
+ * outgoing interface to use for DNS requests
+ */
+CURLcode Curl_set_dns_interface(struct Curl_easy *data,
+                                const char *interf)
+{
+  (void)data;
+  (void)interf;
+  return CURLE_NOT_BUILT_IN;
+}
+
+/*
+ * Function provided by the resolver backend to set
+ * local IPv4 address to use as source address for DNS requests
+ */
+CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
+                                const char *local_ip4)
+{
+  (void)data;
+  (void)local_ip4;
+  return CURLE_NOT_BUILT_IN;
+}
+
+/*
+ * Function provided by the resolver backend to set
+ * local IPv6 address to use as source address for DNS requests
+ */
+CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
+                                const char *local_ip6)
+{
+  (void)data;
+  (void)local_ip6;
+  return CURLE_NOT_BUILT_IN;
+}
+
+#endif /* truly sync */
Index: trunk/src/libs/curl-8.7.1/lib/hsts.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/hsts.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/hsts.c	(revision 104083)
@@ -0,0 +1,578 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+/*
+ * The Strict-Transport-Security header is defined in RFC 6797:
+ * https://datatracker.ietf.org/doc/html/rfc6797
+ */
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS)
+#include <curl/curl.h>
+#include "urldata.h"
+#include "llist.h"
+#include "hsts.h"
+#include "curl_get_line.h"
+#include "strcase.h"
+#include "sendf.h"
+#include "strtoofft.h"
+#include "parsedate.h"
+#include "fopen.h"
+#include "rename.h"
+#include "share.h"
+#include "strdup.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define MAX_HSTS_LINE 4095
+#define MAX_HSTS_HOSTLEN 256
+#define MAX_HSTS_HOSTLENSTR "256"
+#define MAX_HSTS_DATELEN 64
+#define MAX_HSTS_DATELENSTR "64"
+#define UNLIMITED "unlimited"
+
+#ifdef DEBUGBUILD
+/* to play well with debug builds, we can *set* a fixed time this will
+   return */
+time_t deltatime; /* allow for "adjustments" for unit test purposes */
+static time_t hsts_debugtime(void *unused)
+{
+  char *timestr = getenv("CURL_TIME");
+  (void)unused;
+  if(timestr) {
+    curl_off_t val;
+    (void)curlx_strtoofft(timestr, NULL, 10, &val);
+
+    val += (curl_off_t)deltatime;
+    return (time_t)val;
+  }
+  return time(NULL);
+}
+#undef time
+#define time(x) hsts_debugtime(x)
+#endif
+
+struct hsts *Curl_hsts_init(void)
+{
+  struct hsts *h = calloc(1, sizeof(struct hsts));
+  if(h) {
+    Curl_llist_init(&h->list, NULL);
+  }
+  return h;
+}
+
+static void hsts_free(struct stsentry *e)
+{
+  free((char *)e->host);
+  free(e);
+}
+
+void Curl_hsts_cleanup(struct hsts **hp)
+{
+  struct hsts *h = *hp;
+  if(h) {
+    struct Curl_llist_element *e;
+    struct Curl_llist_element *n;
+    for(e = h->list.head; e; e = n) {
+      struct stsentry *sts = e->ptr;
+      n = e->next;
+      hsts_free(sts);
+    }
+    free(h->filename);
+    free(h);
+    *hp = NULL;
+  }
+}
+
+static struct stsentry *hsts_entry(void)
+{
+  return calloc(1, sizeof(struct stsentry));
+}
+
+static CURLcode hsts_create(struct hsts *h,
+                            const char *hostname,
+                            bool subdomains,
+                            curl_off_t expires)
+{
+  size_t hlen;
+  DEBUGASSERT(h);
+  DEBUGASSERT(hostname);
+
+  hlen = strlen(hostname);
+  if(hlen && (hostname[hlen - 1] == '.'))
+    /* strip off any trailing dot */
+    --hlen;
+  if(hlen) {
+    char *duphost;
+    struct stsentry *sts = hsts_entry();
+    if(!sts)
+      return CURLE_OUT_OF_MEMORY;
+
+    duphost = Curl_memdup0(hostname, hlen);
+    if(!duphost) {
+      free(sts);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    sts->host = duphost;
+    sts->expires = expires;
+    sts->includeSubDomains = subdomains;
+    Curl_llist_insert_next(&h->list, h->list.tail, sts, &sts->node);
+  }
+  return CURLE_OK;
+}
+
+CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
+                         const char *header)
+{
+  const char *p = header;
+  curl_off_t expires = 0;
+  bool gotma = FALSE;
+  bool gotinc = FALSE;
+  bool subdomains = FALSE;
+  struct stsentry *sts;
+  time_t now = time(NULL);
+
+  if(Curl_host_is_ipnum(hostname))
+    /* "explicit IP address identification of all forms is excluded."
+       / RFC 6797 */
+    return CURLE_OK;
+
+  do {
+    while(*p && ISBLANK(*p))
+      p++;
+    if(strncasecompare("max-age=", p, 8)) {
+      bool quoted = FALSE;
+      CURLofft offt;
+      char *endp;
+
+      if(gotma)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+
+      p += 8;
+      while(*p && ISBLANK(*p))
+        p++;
+      if(*p == '\"') {
+        p++;
+        quoted = TRUE;
+      }
+      offt = curlx_strtoofft(p, &endp, 10, &expires);
+      if(offt == CURL_OFFT_FLOW)
+        expires = CURL_OFF_T_MAX;
+      else if(offt)
+        /* invalid max-age */
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+      p = endp;
+      if(quoted) {
+        if(*p != '\"')
+          return CURLE_BAD_FUNCTION_ARGUMENT;
+        p++;
+      }
+      gotma = TRUE;
+    }
+    else if(strncasecompare("includesubdomains", p, 17)) {
+      if(gotinc)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+      subdomains = TRUE;
+      p += 17;
+      gotinc = TRUE;
+    }
+    else {
+      /* unknown directive, do a lame attempt to skip */
+      while(*p && (*p != ';'))
+        p++;
+    }
+
+    while(*p && ISBLANK(*p))
+      p++;
+    if(*p == ';')
+      p++;
+  } while(*p);
+
+  if(!gotma)
+    /* max-age is mandatory */
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  if(!expires) {
+    /* remove the entry if present verbatim (without subdomain match) */
+    sts = Curl_hsts(h, hostname, FALSE);
+    if(sts) {
+      Curl_llist_remove(&h->list, &sts->node, NULL);
+      hsts_free(sts);
+    }
+    return CURLE_OK;
+  }
+
+  if(CURL_OFF_T_MAX - now < expires)
+    /* would overflow, use maximum value */
+    expires = CURL_OFF_T_MAX;
+  else
+    expires += now;
+
+  /* check if it already exists */
+  sts = Curl_hsts(h, hostname, FALSE);
+  if(sts) {
+    /* just update these fields */
+    sts->expires = expires;
+    sts->includeSubDomains = subdomains;
+  }
+  else
+    return hsts_create(h, hostname, subdomains, expires);
+
+  return CURLE_OK;
+}
+
+/*
+ * Return TRUE if the given host name is currently an HSTS one.
+ *
+ * The 'subdomain' argument tells the function if subdomain matching should be
+ * attempted.
+ */
+struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
+                           bool subdomain)
+{
+  if(h) {
+    char buffer[MAX_HSTS_HOSTLEN + 1];
+    time_t now = time(NULL);
+    size_t hlen = strlen(hostname);
+    struct Curl_llist_element *e;
+    struct Curl_llist_element *n;
+
+    if((hlen > MAX_HSTS_HOSTLEN) || !hlen)
+      return NULL;
+    memcpy(buffer, hostname, hlen);
+    if(hostname[hlen-1] == '.')
+      /* remove the trailing dot */
+      --hlen;
+    buffer[hlen] = 0;
+    hostname = buffer;
+
+    for(e = h->list.head; e; e = n) {
+      struct stsentry *sts = e->ptr;
+      n = e->next;
+      if(sts->expires <= now) {
+        /* remove expired entries */
+        Curl_llist_remove(&h->list, &sts->node, NULL);
+        hsts_free(sts);
+        continue;
+      }
+      if(subdomain && sts->includeSubDomains) {
+        size_t ntail = strlen(sts->host);
+        if(ntail < hlen) {
+          size_t offs = hlen - ntail;
+          if((hostname[offs-1] == '.') &&
+             strncasecompare(&hostname[offs], sts->host, ntail))
+            return sts;
+        }
+      }
+      if(strcasecompare(hostname, sts->host))
+        return sts;
+    }
+  }
+  return NULL; /* no match */
+}
+
+/*
+ * Send this HSTS entry to the write callback.
+ */
+static CURLcode hsts_push(struct Curl_easy *data,
+                          struct curl_index *i,
+                          struct stsentry *sts,
+                          bool *stop)
+{
+  struct curl_hstsentry e;
+  CURLSTScode sc;
+  struct tm stamp;
+  CURLcode result;
+
+  e.name = (char *)sts->host;
+  e.namelen = strlen(sts->host);
+  e.includeSubDomains = sts->includeSubDomains;
+
+  if(sts->expires != TIME_T_MAX) {
+    result = Curl_gmtime((time_t)sts->expires, &stamp);
+    if(result)
+      return result;
+
+    msnprintf(e.expire, sizeof(e.expire), "%d%02d%02d %02d:%02d:%02d",
+              stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
+              stamp.tm_hour, stamp.tm_min, stamp.tm_sec);
+  }
+  else
+    strcpy(e.expire, UNLIMITED);
+
+  sc = data->set.hsts_write(data, &e, i,
+                            data->set.hsts_write_userp);
+  *stop = (sc != CURLSTS_OK);
+  return sc == CURLSTS_FAIL ? CURLE_BAD_FUNCTION_ARGUMENT : CURLE_OK;
+}
+
+/*
+ * Write this single hsts entry to a single output line
+ */
+static CURLcode hsts_out(struct stsentry *sts, FILE *fp)
+{
+  struct tm stamp;
+  if(sts->expires != TIME_T_MAX) {
+    CURLcode result = Curl_gmtime((time_t)sts->expires, &stamp);
+    if(result)
+      return result;
+    fprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n",
+            sts->includeSubDomains ? ".": "", sts->host,
+            stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
+            stamp.tm_hour, stamp.tm_min, stamp.tm_sec);
+  }
+  else
+    fprintf(fp, "%s%s \"%s\"\n",
+            sts->includeSubDomains ? ".": "", sts->host, UNLIMITED);
+  return CURLE_OK;
+}
+
+
+/*
+ * Curl_https_save() writes the HSTS cache to file and callback.
+ */
+CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
+                        const char *file)
+{
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *n;
+  CURLcode result = CURLE_OK;
+  FILE *out;
+  char *tempstore = NULL;
+
+  if(!h)
+    /* no cache activated */
+    return CURLE_OK;
+
+  /* if no new name is given, use the one we stored from the load */
+  if(!file && h->filename)
+    file = h->filename;
+
+  if((h->flags & CURLHSTS_READONLYFILE) || !file || !file[0])
+    /* marked as read-only, no file or zero length file name */
+    goto skipsave;
+
+  result = Curl_fopen(data, file, &out, &tempstore);
+  if(!result) {
+    fputs("# Your HSTS cache. https://curl.se/docs/hsts.html\n"
+          "# This file was generated by libcurl! Edit at your own risk.\n",
+          out);
+    for(e = h->list.head; e; e = n) {
+      struct stsentry *sts = e->ptr;
+      n = e->next;
+      result = hsts_out(sts, out);
+      if(result)
+        break;
+    }
+    fclose(out);
+    if(!result && tempstore && Curl_rename(tempstore, file))
+      result = CURLE_WRITE_ERROR;
+
+    if(result && tempstore)
+      unlink(tempstore);
+  }
+  free(tempstore);
+skipsave:
+  if(data->set.hsts_write) {
+    /* if there's a write callback */
+    struct curl_index i; /* count */
+    i.total = h->list.size;
+    i.index = 0;
+    for(e = h->list.head; e; e = n) {
+      struct stsentry *sts = e->ptr;
+      bool stop;
+      n = e->next;
+      result = hsts_push(data, &i, sts, &stop);
+      if(result || stop)
+        break;
+      i.index++;
+    }
+  }
+  return result;
+}
+
+/* only returns SERIOUS errors */
+static CURLcode hsts_add(struct hsts *h, char *line)
+{
+  /* Example lines:
+     example.com "20191231 10:00:00"
+     .example.net "20191231 10:00:00"
+   */
+  char host[MAX_HSTS_HOSTLEN + 1];
+  char date[MAX_HSTS_DATELEN + 1];
+  int rc;
+
+  rc = sscanf(line,
+              "%" MAX_HSTS_HOSTLENSTR "s \"%" MAX_HSTS_DATELENSTR "[^\"]\"",
+              host, date);
+  if(2 == rc) {
+    time_t expires = strcmp(date, UNLIMITED) ? Curl_getdate_capped(date) :
+      TIME_T_MAX;
+    CURLcode result = CURLE_OK;
+    char *p = host;
+    bool subdomain = FALSE;
+    struct stsentry *e;
+    if(p[0] == '.') {
+      p++;
+      subdomain = TRUE;
+    }
+    /* only add it if not already present */
+    e = Curl_hsts(h, p, subdomain);
+    if(!e)
+      result = hsts_create(h, p, subdomain, expires);
+    else {
+      /* the same host name, use the largest expire time */
+      if(expires > e->expires)
+        e->expires = expires;
+    }
+    if(result)
+      return result;
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Load HSTS data from callback.
+ *
+ */
+static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
+{
+  /* if the HSTS read callback is set, use it */
+  if(data->set.hsts_read) {
+    CURLSTScode sc;
+    DEBUGASSERT(h);
+    do {
+      char buffer[MAX_HSTS_HOSTLEN + 1];
+      struct curl_hstsentry e;
+      e.name = buffer;
+      e.namelen = sizeof(buffer)-1;
+      e.includeSubDomains = FALSE; /* default */
+      e.expire[0] = 0;
+      e.name[0] = 0; /* just to make it clean */
+      sc = data->set.hsts_read(data, &e, data->set.hsts_read_userp);
+      if(sc == CURLSTS_OK) {
+        time_t expires;
+        CURLcode result;
+        DEBUGASSERT(e.name[0]);
+        if(!e.name[0])
+          /* bail out if no name was stored */
+          return CURLE_BAD_FUNCTION_ARGUMENT;
+        if(e.expire[0])
+          expires = Curl_getdate_capped(e.expire);
+        else
+          expires = TIME_T_MAX; /* the end of time */
+        result = hsts_create(h, e.name,
+                             /* bitfield to bool conversion: */
+                             e.includeSubDomains ? TRUE : FALSE,
+                             expires);
+        if(result)
+          return result;
+      }
+      else if(sc == CURLSTS_FAIL)
+        return CURLE_ABORTED_BY_CALLBACK;
+    } while(sc == CURLSTS_OK);
+  }
+  return CURLE_OK;
+}
+
+/*
+ * Load the HSTS cache from the given file. The text based line-oriented file
+ * format is documented here: https://curl.se/docs/hsts.html
+ *
+ * This function only returns error on major problems that prevent hsts
+ * handling to work completely. It will ignore individual syntactical errors
+ * etc.
+ */
+static CURLcode hsts_load(struct hsts *h, const char *file)
+{
+  CURLcode result = CURLE_OK;
+  FILE *fp;
+
+  /* we need a private copy of the file name so that the hsts cache file
+     name survives an easy handle reset */
+  free(h->filename);
+  h->filename = strdup(file);
+  if(!h->filename)
+    return CURLE_OUT_OF_MEMORY;
+
+  fp = fopen(file, FOPEN_READTEXT);
+  if(fp) {
+    struct dynbuf buf;
+    Curl_dyn_init(&buf, MAX_HSTS_LINE);
+    while(Curl_get_line(&buf, fp)) {
+      char *lineptr = Curl_dyn_ptr(&buf);
+      while(*lineptr && ISBLANK(*lineptr))
+        lineptr++;
+      if(*lineptr == '#')
+        /* skip commented lines */
+        continue;
+
+      hsts_add(h, lineptr);
+    }
+    Curl_dyn_free(&buf); /* free the line buffer */
+    fclose(fp);
+  }
+  return result;
+}
+
+/*
+ * Curl_hsts_loadfile() loads HSTS from file
+ */
+CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
+                            struct hsts *h, const char *file)
+{
+  DEBUGASSERT(h);
+  (void)data;
+  return hsts_load(h, file);
+}
+
+/*
+ * Curl_hsts_loadcb() loads HSTS from callback
+ */
+CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h)
+{
+  if(h)
+    return hsts_pull(data, h);
+  return CURLE_OK;
+}
+
+void Curl_hsts_loadfiles(struct Curl_easy *data)
+{
+  struct curl_slist *l = data->state.hstslist;
+  if(l) {
+    Curl_share_lock(data, CURL_LOCK_DATA_HSTS, CURL_LOCK_ACCESS_SINGLE);
+
+    while(l) {
+      (void)Curl_hsts_loadfile(data, data->hsts, l->data);
+      l = l->next;
+    }
+    Curl_share_unlock(data, CURL_LOCK_DATA_HSTS);
+  }
+}
+
+#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
Index: trunk/src/libs/curl-8.7.1/lib/hsts.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/hsts.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/hsts.h	(revision 104083)
@@ -0,0 +1,69 @@
+#ifndef HEADER_CURL_HSTS_H
+#define HEADER_CURL_HSTS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS)
+#include <curl/curl.h>
+#include "llist.h"
+
+#ifdef DEBUGBUILD
+extern time_t deltatime;
+#endif
+
+struct stsentry {
+  struct Curl_llist_element node;
+  const char *host;
+  bool includeSubDomains;
+  curl_off_t expires; /* the timestamp of this entry's expiry */
+};
+
+/* The HSTS cache. Needs to be able to tailmatch host names. */
+struct hsts {
+  struct Curl_llist list;
+  char *filename;
+  unsigned int flags;
+};
+
+struct hsts *Curl_hsts_init(void);
+void Curl_hsts_cleanup(struct hsts **hp);
+CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
+                         const char *sts);
+struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
+                           bool subdomain);
+CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
+                        const char *file);
+CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
+                            struct hsts *h, const char *file);
+CURLcode Curl_hsts_loadcb(struct Curl_easy *data,
+                          struct hsts *h);
+void Curl_hsts_loadfiles(struct Curl_easy *data);
+#else
+#define Curl_hsts_cleanup(x)
+#define Curl_hsts_loadcb(x,y) CURLE_OK
+#define Curl_hsts_save(x,y,z)
+#define Curl_hsts_loadfiles(x)
+#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
+#endif /* HEADER_CURL_HSTS_H */
Index: trunk/src/libs/curl-8.7.1/lib/http.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http.c	(revision 104083)
@@ -0,0 +1,4514 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_HTTP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef USE_HYPER
+#include <hyper.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "formdata.h"
+#include "mime.h"
+#include "progress.h"
+#include "curl_base64.h"
+#include "cookie.h"
+#include "vauth/vauth.h"
+#include "vtls/vtls.h"
+#include "vquic/vquic.h"
+#include "http_digest.h"
+#include "http_ntlm.h"
+#include "curl_ntlm_wb.h"
+#include "http_negotiate.h"
+#include "http_aws_sigv4.h"
+#include "url.h"
+#include "share.h"
+#include "hostip.h"
+#include "dynhds.h"
+#include "http.h"
+#include "headers.h"
+#include "select.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "strtoofft.h"
+#include "multiif.h"
+#include "strcase.h"
+#include "content_encoding.h"
+#include "http_proxy.h"
+#include "warnless.h"
+#include "http2.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "strdup.h"
+#include "altsvc.h"
+#include "hsts.h"
+#include "ws.h"
+#include "c-hyper.h"
+#include "curl_ctype.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Forward declarations.
+ */
+
+static bool http_should_fail(struct Curl_easy *data);
+static bool http_exp100_is_waiting(struct Curl_easy *data);
+static CURLcode http_exp100_add_reader(struct Curl_easy *data);
+static void http_exp100_send_anyway(struct Curl_easy *data);
+
+/*
+ * HTTP handler interface.
+ */
+const struct Curl_handler Curl_handler_http = {
+  "HTTP",                               /* scheme */
+  Curl_http_setup_conn,                 /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  Curl_http_connect,                    /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  Curl_http_getsock_do,                 /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  Curl_http_write_resp,                 /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_HTTP,                            /* defport */
+  CURLPROTO_HTTP,                       /* protocol */
+  CURLPROTO_HTTP,                       /* family */
+  PROTOPT_CREDSPERREQUEST |             /* flags */
+  PROTOPT_USERPWDCTRL
+};
+
+#ifdef USE_SSL
+/*
+ * HTTPS handler interface.
+ */
+const struct Curl_handler Curl_handler_https = {
+  "HTTPS",                              /* scheme */
+  Curl_http_setup_conn,                 /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  Curl_http_connect,                    /* connect_it */
+  NULL,                                 /* connecting */
+  ZERO_NULL,                            /* doing */
+  NULL,                                 /* proto_getsock */
+  Curl_http_getsock_do,                 /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  Curl_http_write_resp,                 /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_HTTPS,                           /* defport */
+  CURLPROTO_HTTPS,                      /* protocol */
+  CURLPROTO_HTTP,                       /* family */
+  PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN | /* flags */
+  PROTOPT_USERPWDCTRL
+};
+
+#endif
+
+CURLcode Curl_http_setup_conn(struct Curl_easy *data,
+                              struct connectdata *conn)
+{
+  /* allocate the HTTP-specific struct for the Curl_easy, only to survive
+     during this request */
+  struct HTTP *http;
+  DEBUGASSERT(data->req.p.http == NULL);
+
+  http = calloc(1, sizeof(struct HTTP));
+  if(!http)
+    return CURLE_OUT_OF_MEMORY;
+
+  data->req.p.http = http;
+  connkeep(conn, "HTTP default");
+
+  if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
+    CURLcode result = Curl_conn_may_http3(data, conn);
+    if(result)
+      return result;
+  }
+
+  return CURLE_OK;
+}
+
+#ifndef CURL_DISABLE_PROXY
+/*
+ * checkProxyHeaders() checks the linked list of custom proxy headers
+ * if proxy headers are not available, then it will lookup into http header
+ * link list
+ *
+ * It takes a connectdata struct as input to see if this is a proxy request or
+ * not, as it then might check a different header list. Provide the header
+ * prefix without colon!
+ */
+char *Curl_checkProxyheaders(struct Curl_easy *data,
+                             const struct connectdata *conn,
+                             const char *thisheader,
+                             const size_t thislen)
+{
+  struct curl_slist *head;
+
+  for(head = (conn->bits.proxy && data->set.sep_headers) ?
+        data->set.proxyheaders : data->set.headers;
+      head; head = head->next) {
+    if(strncasecompare(head->data, thisheader, thislen) &&
+       Curl_headersep(head->data[thislen]))
+      return head->data;
+  }
+
+  return NULL;
+}
+#else
+/* disabled */
+#define Curl_checkProxyheaders(x,y,z,a) NULL
+#endif
+
+/*
+ * Strip off leading and trailing whitespace from the value in the
+ * given HTTP header line and return a strdupped copy. Returns NULL in
+ * case of allocation failure. Returns an empty string if the header value
+ * consists entirely of whitespace.
+ */
+char *Curl_copy_header_value(const char *header)
+{
+  const char *start;
+  const char *end;
+  size_t len;
+
+  /* Find the end of the header name */
+  while(*header && (*header != ':'))
+    ++header;
+
+  if(*header)
+    /* Skip over colon */
+    ++header;
+
+  /* Find the first non-space letter */
+  start = header;
+  while(*start && ISSPACE(*start))
+    start++;
+
+  /* data is in the host encoding so
+     use '\r' and '\n' instead of 0x0d and 0x0a */
+  end = strchr(start, '\r');
+  if(!end)
+    end = strchr(start, '\n');
+  if(!end)
+    end = strchr(start, '\0');
+  if(!end)
+    return NULL;
+
+  /* skip all trailing space letters */
+  while((end > start) && ISSPACE(*end))
+    end--;
+
+  /* get length of the type */
+  len = end - start + 1;
+
+  return Curl_memdup0(start, len);
+}
+
+#ifndef CURL_DISABLE_HTTP_AUTH
+
+#ifndef CURL_DISABLE_BASIC_AUTH
+/*
+ * http_output_basic() sets up an Authorization: header (or the proxy version)
+ * for HTTP Basic authentication.
+ *
+ * Returns CURLcode.
+ */
+static CURLcode http_output_basic(struct Curl_easy *data, bool proxy)
+{
+  size_t size = 0;
+  char *authorization = NULL;
+  char **userp;
+  const char *user;
+  const char *pwd;
+  CURLcode result;
+  char *out;
+
+  /* credentials are unique per transfer for HTTP, do not use the ones for the
+     connection */
+  if(proxy) {
+#ifndef CURL_DISABLE_PROXY
+    userp = &data->state.aptr.proxyuserpwd;
+    user = data->state.aptr.proxyuser;
+    pwd = data->state.aptr.proxypasswd;
+#else
+    return CURLE_NOT_BUILT_IN;
+#endif
+  }
+  else {
+    userp = &data->state.aptr.userpwd;
+    user = data->state.aptr.user;
+    pwd = data->state.aptr.passwd;
+  }
+
+  out = aprintf("%s:%s", user ? user : "", pwd ? pwd : "");
+  if(!out)
+    return CURLE_OUT_OF_MEMORY;
+
+  result = Curl_base64_encode(out, strlen(out), &authorization, &size);
+  if(result)
+    goto fail;
+
+  if(!authorization) {
+    result = CURLE_REMOTE_ACCESS_DENIED;
+    goto fail;
+  }
+
+  free(*userp);
+  *userp = aprintf("%sAuthorization: Basic %s\r\n",
+                   proxy ? "Proxy-" : "",
+                   authorization);
+  free(authorization);
+  if(!*userp) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto fail;
+  }
+
+fail:
+  free(out);
+  return result;
+}
+
+#endif
+
+#ifndef CURL_DISABLE_BEARER_AUTH
+/*
+ * http_output_bearer() sets up an Authorization: header
+ * for HTTP Bearer authentication.
+ *
+ * Returns CURLcode.
+ */
+static CURLcode http_output_bearer(struct Curl_easy *data)
+{
+  char **userp;
+  CURLcode result = CURLE_OK;
+
+  userp = &data->state.aptr.userpwd;
+  free(*userp);
+  *userp = aprintf("Authorization: Bearer %s\r\n",
+                   data->set.str[STRING_BEARER]);
+
+  if(!*userp) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto fail;
+  }
+
+fail:
+  return result;
+}
+
+#endif
+
+#endif
+
+/* pickoneauth() selects the most favourable authentication method from the
+ * ones available and the ones we want.
+ *
+ * return TRUE if one was picked
+ */
+static bool pickoneauth(struct auth *pick, unsigned long mask)
+{
+  bool picked;
+  /* only deal with authentication we want */
+  unsigned long avail = pick->avail & pick->want & mask;
+  picked = TRUE;
+
+  /* The order of these checks is highly relevant, as this will be the order
+     of preference in case of the existence of multiple accepted types. */
+  if(avail & CURLAUTH_NEGOTIATE)
+    pick->picked = CURLAUTH_NEGOTIATE;
+#ifndef CURL_DISABLE_BEARER_AUTH
+  else if(avail & CURLAUTH_BEARER)
+    pick->picked = CURLAUTH_BEARER;
+#endif
+#ifndef CURL_DISABLE_DIGEST_AUTH
+  else if(avail & CURLAUTH_DIGEST)
+    pick->picked = CURLAUTH_DIGEST;
+#endif
+  else if(avail & CURLAUTH_NTLM)
+    pick->picked = CURLAUTH_NTLM;
+  else if(avail & CURLAUTH_NTLM_WB)
+    pick->picked = CURLAUTH_NTLM_WB;
+#ifndef CURL_DISABLE_BASIC_AUTH
+  else if(avail & CURLAUTH_BASIC)
+    pick->picked = CURLAUTH_BASIC;
+#endif
+#ifndef CURL_DISABLE_AWS
+  else if(avail & CURLAUTH_AWS_SIGV4)
+    pick->picked = CURLAUTH_AWS_SIGV4;
+#endif
+  else {
+    pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
+    picked = FALSE;
+  }
+  pick->avail = CURLAUTH_NONE; /* clear it here */
+
+  return picked;
+}
+
+/*
+ * http_perhapsrewind()
+ *
+ * The current request needs to be done again - maybe due to a follow
+ * or authentication negotiation. Check if:
+ * 1) a rewind of the data sent to the server is necessary
+ * 2) the current transfer should continue or be stopped early
+ */
+static CURLcode http_perhapsrewind(struct Curl_easy *data,
+                                   struct connectdata *conn)
+{
+  curl_off_t bytessent = data->req.writebytecount;
+  curl_off_t expectsend = Curl_creader_total_length(data);
+  curl_off_t upload_remain = (expectsend >= 0)? (expectsend - bytessent) : -1;
+  bool little_upload_remains = (upload_remain >= 0 && upload_remain < 2000);
+  bool needs_rewind = Curl_creader_needs_rewind(data);
+  /* By default, we'd like to abort the transfer when little or
+   * unknown amount remains. But this may be overridden by authentications
+   * further below! */
+  bool abort_upload = (!data->req.upload_done && !little_upload_remains);
+  const char *ongoing_auth = NULL;
+
+  /* We need a rewind before uploading client read data again. The
+   * checks below just influence of the upload is to be continued
+   * or aborted early.
+   * This depends on how much remains to be sent and in what state
+   * the authentication is. Some auth schemes such as NTLM do not work
+   * for a new connection. */
+  if(needs_rewind) {
+    infof(data, "Need to rewind upload for next request");
+    Curl_creader_set_rewind(data, TRUE);
+  }
+
+  if(conn->bits.close)
+    /* If we already decided to close this connection, we cannot veto. */
+    return CURLE_OK;
+
+  if(abort_upload) {
+    /* We'd like to abort the upload - but should we? */
+#if defined(USE_NTLM)
+    if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
+       (data->state.authhost.picked == CURLAUTH_NTLM) ||
+       (data->state.authproxy.picked == CURLAUTH_NTLM_WB) ||
+       (data->state.authhost.picked == CURLAUTH_NTLM_WB)) {
+      ongoing_auth = "NTML";
+      if((conn->http_ntlm_state != NTLMSTATE_NONE) ||
+         (conn->proxy_ntlm_state != NTLMSTATE_NONE)) {
+        /* The NTLM-negotiation has started, keep on sending.
+         * Need to do further work on same connection */
+        abort_upload = FALSE;
+      }
+    }
+#endif
+#if defined(USE_SPNEGO)
+    /* There is still data left to send */
+    if((data->state.authproxy.picked == CURLAUTH_NEGOTIATE) ||
+       (data->state.authhost.picked == CURLAUTH_NEGOTIATE)) {
+      ongoing_auth = "NEGOTIATE";
+      if((conn->http_negotiate_state != GSS_AUTHNONE) ||
+         (conn->proxy_negotiate_state != GSS_AUTHNONE)) {
+        /* The NEGOTIATE-negotiation has started, keep on sending.
+         * Need to do further work on same connection */
+        abort_upload = FALSE;
+      }
+    }
+#endif
+  }
+
+  if(abort_upload) {
+    if(upload_remain >= 0)
+      infof(data, "%s%sclose instead of sending %"
+        CURL_FORMAT_CURL_OFF_T " more bytes",
+        ongoing_auth? ongoing_auth : "",
+        ongoing_auth? " send, " : "",
+        upload_remain);
+    else
+      infof(data, "%s%sclose instead of sending unknown amount "
+        "of more bytes",
+        ongoing_auth? ongoing_auth : "",
+        ongoing_auth? " send, " : "");
+    /* We decided to abort the ongoing transfer */
+    streamclose(conn, "Mid-auth HTTP and much data left to send");
+    /* FIXME: questionable manipulation here, can we do this differently? */
+    data->req.size = 0; /* don't download any more than 0 bytes */
+  }
+  return CURLE_OK;
+}
+
+/*
+ * Curl_http_auth_act() gets called when all HTTP headers have been received
+ * and it checks what authentication methods that are available and decides
+ * which one (if any) to use. It will set 'newurl' if an auth method was
+ * picked.
+ */
+
+CURLcode Curl_http_auth_act(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+  bool pickhost = FALSE;
+  bool pickproxy = FALSE;
+  CURLcode result = CURLE_OK;
+  unsigned long authmask = ~0ul;
+
+  if(!data->set.str[STRING_BEARER])
+    authmask &= (unsigned long)~CURLAUTH_BEARER;
+
+  if(100 <= data->req.httpcode && data->req.httpcode <= 199)
+    /* this is a transient response code, ignore */
+    return CURLE_OK;
+
+  if(data->state.authproblem)
+    return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
+
+  if((data->state.aptr.user || data->set.str[STRING_BEARER]) &&
+     ((data->req.httpcode == 401) ||
+      (data->req.authneg && data->req.httpcode < 300))) {
+    pickhost = pickoneauth(&data->state.authhost, authmask);
+    if(!pickhost)
+      data->state.authproblem = TRUE;
+    if(data->state.authhost.picked == CURLAUTH_NTLM &&
+       conn->httpversion > 11) {
+      infof(data, "Forcing HTTP/1.1 for NTLM");
+      connclose(conn, "Force HTTP/1.1 connection");
+      data->state.httpwant = CURL_HTTP_VERSION_1_1;
+    }
+  }
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.proxy_user_passwd &&
+     ((data->req.httpcode == 407) ||
+      (data->req.authneg && data->req.httpcode < 300))) {
+    pickproxy = pickoneauth(&data->state.authproxy,
+                            authmask & ~CURLAUTH_BEARER);
+    if(!pickproxy)
+      data->state.authproblem = TRUE;
+  }
+#endif
+
+  if(pickhost || pickproxy) {
+    result = http_perhapsrewind(data, conn);
+    if(result)
+      return result;
+
+    /* In case this is GSS auth, the newurl field is already allocated so
+       we must make sure to free it before allocating a new one. As figured
+       out in bug #2284386 */
+    Curl_safefree(data->req.newurl);
+    data->req.newurl = strdup(data->state.url); /* clone URL */
+    if(!data->req.newurl)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  else if((data->req.httpcode < 300) &&
+          (!data->state.authhost.done) &&
+          data->req.authneg) {
+    /* no (known) authentication available,
+       authentication is not "done" yet and
+       no authentication seems to be required and
+       we didn't try HEAD or GET */
+    if((data->state.httpreq != HTTPREQ_GET) &&
+       (data->state.httpreq != HTTPREQ_HEAD)) {
+      data->req.newurl = strdup(data->state.url); /* clone URL */
+      if(!data->req.newurl)
+        return CURLE_OUT_OF_MEMORY;
+      data->state.authhost.done = TRUE;
+    }
+  }
+  if(http_should_fail(data)) {
+    failf(data, "The requested URL returned error: %d",
+          data->req.httpcode);
+    result = CURLE_HTTP_RETURNED_ERROR;
+  }
+
+  return result;
+}
+
+#ifndef CURL_DISABLE_HTTP_AUTH
+/*
+ * Output the correct authentication header depending on the auth type
+ * and whether or not it is to a proxy.
+ */
+static CURLcode
+output_auth_headers(struct Curl_easy *data,
+                    struct connectdata *conn,
+                    struct auth *authstatus,
+                    const char *request,
+                    const char *path,
+                    bool proxy)
+{
+  const char *auth = NULL;
+  CURLcode result = CURLE_OK;
+  (void)conn;
+
+#ifdef CURL_DISABLE_DIGEST_AUTH
+  (void)request;
+  (void)path;
+#endif
+#ifndef CURL_DISABLE_AWS
+  if(authstatus->picked == CURLAUTH_AWS_SIGV4) {
+    auth = "AWS_SIGV4";
+    result = Curl_output_aws_sigv4(data, proxy);
+    if(result)
+      return result;
+  }
+  else
+#endif
+#ifdef USE_SPNEGO
+  if(authstatus->picked == CURLAUTH_NEGOTIATE) {
+    auth = "Negotiate";
+    result = Curl_output_negotiate(data, conn, proxy);
+    if(result)
+      return result;
+  }
+  else
+#endif
+#ifdef USE_NTLM
+  if(authstatus->picked == CURLAUTH_NTLM) {
+    auth = "NTLM";
+    result = Curl_output_ntlm(data, proxy);
+    if(result)
+      return result;
+  }
+  else
+#endif
+#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
+  if(authstatus->picked == CURLAUTH_NTLM_WB) {
+    auth = "NTLM_WB";
+    result = Curl_output_ntlm_wb(data, conn, proxy);
+    if(result)
+      return result;
+  }
+  else
+#endif
+#ifndef CURL_DISABLE_DIGEST_AUTH
+  if(authstatus->picked == CURLAUTH_DIGEST) {
+    auth = "Digest";
+    result = Curl_output_digest(data,
+                                proxy,
+                                (const unsigned char *)request,
+                                (const unsigned char *)path);
+    if(result)
+      return result;
+  }
+  else
+#endif
+#ifndef CURL_DISABLE_BASIC_AUTH
+  if(authstatus->picked == CURLAUTH_BASIC) {
+    /* Basic */
+    if(
+#ifndef CURL_DISABLE_PROXY
+      (proxy && conn->bits.proxy_user_passwd &&
+       !Curl_checkProxyheaders(data, conn, STRCONST("Proxy-authorization"))) ||
+#endif
+      (!proxy && data->state.aptr.user &&
+       !Curl_checkheaders(data, STRCONST("Authorization")))) {
+      auth = "Basic";
+      result = http_output_basic(data, proxy);
+      if(result)
+        return result;
+    }
+
+    /* NOTE: this function should set 'done' TRUE, as the other auth
+       functions work that way */
+    authstatus->done = TRUE;
+  }
+#endif
+#ifndef CURL_DISABLE_BEARER_AUTH
+  if(authstatus->picked == CURLAUTH_BEARER) {
+    /* Bearer */
+    if((!proxy && data->set.str[STRING_BEARER] &&
+        !Curl_checkheaders(data, STRCONST("Authorization")))) {
+      auth = "Bearer";
+      result = http_output_bearer(data);
+      if(result)
+        return result;
+    }
+
+    /* NOTE: this function should set 'done' TRUE, as the other auth
+       functions work that way */
+    authstatus->done = TRUE;
+  }
+#endif
+
+  if(auth) {
+#ifndef CURL_DISABLE_PROXY
+    infof(data, "%s auth using %s with user '%s'",
+          proxy ? "Proxy" : "Server", auth,
+          proxy ? (data->state.aptr.proxyuser ?
+                   data->state.aptr.proxyuser : "") :
+          (data->state.aptr.user ?
+           data->state.aptr.user : ""));
+#else
+    (void)proxy;
+    infof(data, "Server auth using %s with user '%s'",
+          auth, data->state.aptr.user ?
+          data->state.aptr.user : "");
+#endif
+    authstatus->multipass = (!authstatus->done) ? TRUE : FALSE;
+  }
+  else
+    authstatus->multipass = FALSE;
+
+  return result;
+}
+
+/**
+ * Curl_http_output_auth() setups the authentication headers for the
+ * host/proxy and the correct authentication
+ * method. data->state.authdone is set to TRUE when authentication is
+ * done.
+ *
+ * @param conn all information about the current connection
+ * @param request pointer to the request keyword
+ * @param path pointer to the requested path; should include query part
+ * @param proxytunnel boolean if this is the request setting up a "proxy
+ * tunnel"
+ *
+ * @returns CURLcode
+ */
+CURLcode
+Curl_http_output_auth(struct Curl_easy *data,
+                      struct connectdata *conn,
+                      const char *request,
+                      Curl_HttpReq httpreq,
+                      const char *path,
+                      bool proxytunnel) /* TRUE if this is the request setting
+                                           up the proxy tunnel */
+{
+  CURLcode result = CURLE_OK;
+  struct auth *authhost;
+  struct auth *authproxy;
+
+  DEBUGASSERT(data);
+
+  authhost = &data->state.authhost;
+  authproxy = &data->state.authproxy;
+
+  if(
+#ifndef CURL_DISABLE_PROXY
+    (conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
+#endif
+     data->state.aptr.user ||
+#ifdef USE_SPNEGO
+     authhost->want & CURLAUTH_NEGOTIATE ||
+     authproxy->want & CURLAUTH_NEGOTIATE ||
+#endif
+     data->set.str[STRING_BEARER])
+    /* continue please */;
+  else {
+    authhost->done = TRUE;
+    authproxy->done = TRUE;
+    return CURLE_OK; /* no authentication with no user or password */
+  }
+
+  if(authhost->want && !authhost->picked)
+    /* The app has selected one or more methods, but none has been picked
+       so far by a server round-trip. Then we set the picked one to the
+       want one, and if this is one single bit it'll be used instantly. */
+    authhost->picked = authhost->want;
+
+  if(authproxy->want && !authproxy->picked)
+    /* The app has selected one or more methods, but none has been picked so
+       far by a proxy round-trip. Then we set the picked one to the want one,
+       and if this is one single bit it'll be used instantly. */
+    authproxy->picked = authproxy->want;
+
+#ifndef CURL_DISABLE_PROXY
+  /* Send proxy authentication header if needed */
+  if(conn->bits.httpproxy &&
+     (conn->bits.tunnel_proxy == (bit)proxytunnel)) {
+    result = output_auth_headers(data, conn, authproxy, request, path, TRUE);
+    if(result)
+      return result;
+  }
+  else
+#else
+  (void)proxytunnel;
+#endif /* CURL_DISABLE_PROXY */
+    /* we have no proxy so let's pretend we're done authenticating
+       with it */
+    authproxy->done = TRUE;
+
+  /* To prevent the user+password to get sent to other than the original host
+     due to a location-follow */
+  if(Curl_auth_allowed_to_host(data)
+#ifndef CURL_DISABLE_NETRC
+     || conn->bits.netrc
+#endif
+    )
+    result = output_auth_headers(data, conn, authhost, request, path, FALSE);
+  else
+    authhost->done = TRUE;
+
+  if(((authhost->multipass && !authhost->done) ||
+      (authproxy->multipass && !authproxy->done)) &&
+     (httpreq != HTTPREQ_GET) &&
+     (httpreq != HTTPREQ_HEAD)) {
+    /* Auth is required and we are not authenticated yet. Make a PUT or POST
+       with content-length zero as a "probe". */
+    data->req.authneg = TRUE;
+  }
+  else
+    data->req.authneg = FALSE;
+
+  return result;
+}
+
+#else
+/* when disabled */
+CURLcode
+Curl_http_output_auth(struct Curl_easy *data,
+                      struct connectdata *conn,
+                      const char *request,
+                      Curl_HttpReq httpreq,
+                      const char *path,
+                      bool proxytunnel)
+{
+  (void)data;
+  (void)conn;
+  (void)request;
+  (void)httpreq;
+  (void)path;
+  (void)proxytunnel;
+  return CURLE_OK;
+}
+#endif
+
+#if defined(USE_SPNEGO) || defined(USE_NTLM) || \
+  !defined(CURL_DISABLE_DIGEST_AUTH) || \
+  !defined(CURL_DISABLE_BASIC_AUTH) || \
+  !defined(CURL_DISABLE_BEARER_AUTH)
+static int is_valid_auth_separator(char ch)
+{
+  return ch == '\0' || ch == ',' || ISSPACE(ch);
+}
+#endif
+
+/*
+ * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
+ * headers. They are dealt with both in the transfer.c main loop and in the
+ * proxy CONNECT loop.
+ */
+CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
+                              const char *auth) /* the first non-space */
+{
+  /*
+   * This resource requires authentication
+   */
+  struct connectdata *conn = data->conn;
+#ifdef USE_SPNEGO
+  curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state :
+                                    &conn->http_negotiate_state;
+#endif
+#if defined(USE_SPNEGO) || \
+  defined(USE_NTLM) || \
+  !defined(CURL_DISABLE_DIGEST_AUTH) || \
+  !defined(CURL_DISABLE_BASIC_AUTH) || \
+  !defined(CURL_DISABLE_BEARER_AUTH)
+
+  unsigned long *availp;
+  struct auth *authp;
+
+  if(proxy) {
+    availp = &data->info.proxyauthavail;
+    authp = &data->state.authproxy;
+  }
+  else {
+    availp = &data->info.httpauthavail;
+    authp = &data->state.authhost;
+  }
+#else
+  (void) proxy;
+#endif
+
+  (void) conn; /* In case conditionals make it unused. */
+
+  /*
+   * Here we check if we want the specific single authentication (using ==) and
+   * if we do, we initiate usage of it.
+   *
+   * If the provided authentication is wanted as one out of several accepted
+   * types (using &), we OR this authentication type to the authavail
+   * variable.
+   *
+   * Note:
+   *
+   * ->picked is first set to the 'want' value (one or more bits) before the
+   * request is sent, and then it is again set _after_ all response 401/407
+   * headers have been received but then only to a single preferred method
+   * (bit).
+   */
+
+  while(*auth) {
+#ifdef USE_SPNEGO
+    if(checkprefix("Negotiate", auth) && is_valid_auth_separator(auth[9])) {
+      if((authp->avail & CURLAUTH_NEGOTIATE) ||
+         Curl_auth_is_spnego_supported()) {
+        *availp |= CURLAUTH_NEGOTIATE;
+        authp->avail |= CURLAUTH_NEGOTIATE;
+
+        if(authp->picked == CURLAUTH_NEGOTIATE) {
+          CURLcode result = Curl_input_negotiate(data, conn, proxy, auth);
+          if(!result) {
+            free(data->req.newurl);
+            data->req.newurl = strdup(data->state.url);
+            if(!data->req.newurl)
+              return CURLE_OUT_OF_MEMORY;
+            data->state.authproblem = FALSE;
+            /* we received a GSS auth token and we dealt with it fine */
+            *negstate = GSS_AUTHRECV;
+          }
+          else
+            data->state.authproblem = TRUE;
+        }
+      }
+    }
+    else
+#endif
+#ifdef USE_NTLM
+      /* NTLM support requires the SSL crypto libs */
+      if(checkprefix("NTLM", auth) && is_valid_auth_separator(auth[4])) {
+        if((authp->avail & CURLAUTH_NTLM) ||
+           (authp->avail & CURLAUTH_NTLM_WB) ||
+           Curl_auth_is_ntlm_supported()) {
+          *availp |= CURLAUTH_NTLM;
+          authp->avail |= CURLAUTH_NTLM;
+
+          if(authp->picked == CURLAUTH_NTLM ||
+             authp->picked == CURLAUTH_NTLM_WB) {
+            /* NTLM authentication is picked and activated */
+            CURLcode result = Curl_input_ntlm(data, proxy, auth);
+            if(!result) {
+              data->state.authproblem = FALSE;
+#ifdef NTLM_WB_ENABLED
+              if(authp->picked == CURLAUTH_NTLM_WB) {
+                *availp &= ~CURLAUTH_NTLM;
+                authp->avail &= ~CURLAUTH_NTLM;
+                *availp |= CURLAUTH_NTLM_WB;
+                authp->avail |= CURLAUTH_NTLM_WB;
+
+                result = Curl_input_ntlm_wb(data, conn, proxy, auth);
+                if(result) {
+                  infof(data, "Authentication problem. Ignoring this.");
+                  data->state.authproblem = TRUE;
+                }
+              }
+#endif
+            }
+            else {
+              infof(data, "Authentication problem. Ignoring this.");
+              data->state.authproblem = TRUE;
+            }
+          }
+        }
+      }
+      else
+#endif
+#ifndef CURL_DISABLE_DIGEST_AUTH
+        if(checkprefix("Digest", auth) && is_valid_auth_separator(auth[6])) {
+          if((authp->avail & CURLAUTH_DIGEST) != 0)
+            infof(data, "Ignoring duplicate digest auth header.");
+          else if(Curl_auth_is_digest_supported()) {
+            CURLcode result;
+
+            *availp |= CURLAUTH_DIGEST;
+            authp->avail |= CURLAUTH_DIGEST;
+
+            /* We call this function on input Digest headers even if Digest
+             * authentication isn't activated yet, as we need to store the
+             * incoming data from this header in case we are going to use
+             * Digest */
+            result = Curl_input_digest(data, proxy, auth);
+            if(result) {
+              infof(data, "Authentication problem. Ignoring this.");
+              data->state.authproblem = TRUE;
+            }
+          }
+        }
+        else
+#endif
+#ifndef CURL_DISABLE_BASIC_AUTH
+          if(checkprefix("Basic", auth) &&
+             is_valid_auth_separator(auth[5])) {
+            *availp |= CURLAUTH_BASIC;
+            authp->avail |= CURLAUTH_BASIC;
+            if(authp->picked == CURLAUTH_BASIC) {
+              /* We asked for Basic authentication but got a 40X back
+                 anyway, which basically means our name+password isn't
+                 valid. */
+              authp->avail = CURLAUTH_NONE;
+              infof(data, "Authentication problem. Ignoring this.");
+              data->state.authproblem = TRUE;
+            }
+          }
+          else
+#endif
+#ifndef CURL_DISABLE_BEARER_AUTH
+            if(checkprefix("Bearer", auth) &&
+               is_valid_auth_separator(auth[6])) {
+              *availp |= CURLAUTH_BEARER;
+              authp->avail |= CURLAUTH_BEARER;
+              if(authp->picked == CURLAUTH_BEARER) {
+                /* We asked for Bearer authentication but got a 40X back
+                  anyway, which basically means our token isn't valid. */
+                authp->avail = CURLAUTH_NONE;
+                infof(data, "Authentication problem. Ignoring this.");
+                data->state.authproblem = TRUE;
+              }
+            }
+#else
+            {
+              /*
+               * Empty block to terminate the if-else chain correctly.
+               *
+               * A semicolon would yield the same result here, but can cause a
+               * compiler warning when -Wextra is enabled.
+               */
+            }
+#endif
+
+    /* there may be multiple methods on one line, so keep reading */
+    while(*auth && *auth != ',') /* read up to the next comma */
+      auth++;
+    if(*auth == ',') /* if we're on a comma, skip it */
+      auth++;
+    while(*auth && ISSPACE(*auth))
+      auth++;
+  }
+
+  return CURLE_OK;
+}
+
+/**
+ * http_should_fail() determines whether an HTTP response has gotten us
+ * into an error state or not.
+ *
+ * @retval FALSE communications should continue
+ *
+ * @retval TRUE communications should not continue
+ */
+static bool http_should_fail(struct Curl_easy *data)
+{
+  int httpcode;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+
+  httpcode = data->req.httpcode;
+
+  /*
+  ** If we haven't been asked to fail on error,
+  ** don't fail.
+  */
+  if(!data->set.http_fail_on_error)
+    return FALSE;
+
+  /*
+  ** Any code < 400 is never terminal.
+  */
+  if(httpcode < 400)
+    return FALSE;
+
+  /*
+  ** A 416 response to a resume request is presumably because the file is
+  ** already completely downloaded and thus not actually a fail.
+  */
+  if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
+     httpcode == 416)
+    return FALSE;
+
+  /*
+  ** Any code >= 400 that's not 401 or 407 is always
+  ** a terminal error
+  */
+  if((httpcode != 401) && (httpcode != 407))
+    return TRUE;
+
+  /*
+  ** All we have left to deal with is 401 and 407
+  */
+  DEBUGASSERT((httpcode == 401) || (httpcode == 407));
+
+  /*
+  ** Examine the current authentication state to see if this
+  ** is an error.  The idea is for this function to get
+  ** called after processing all the headers in a response
+  ** message.  So, if we've been to asked to authenticate a
+  ** particular stage, and we've done it, we're OK.  But, if
+  ** we're already completely authenticated, it's not OK to
+  ** get another 401 or 407.
+  **
+  ** It is possible for authentication to go stale such that
+  ** the client needs to reauthenticate.  Once that info is
+  ** available, use it here.
+  */
+
+  /*
+  ** Either we're not authenticating, or we're supposed to
+  ** be authenticating something else.  This is an error.
+  */
+  if((httpcode == 401) && !data->state.aptr.user)
+    return TRUE;
+#ifndef CURL_DISABLE_PROXY
+  if((httpcode == 407) && !data->conn->bits.proxy_user_passwd)
+    return TRUE;
+#endif
+
+  return data->state.authproblem;
+}
+
+/*
+ * Curl_compareheader()
+ *
+ * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
+ * Pass headers WITH the colon.
+ */
+bool
+Curl_compareheader(const char *headerline, /* line to check */
+                   const char *header,  /* header keyword _with_ colon */
+                   const size_t hlen,   /* len of the keyword in bytes */
+                   const char *content, /* content string to find */
+                   const size_t clen)   /* len of the content in bytes */
+{
+  /* RFC2616, section 4.2 says: "Each header field consists of a name followed
+   * by a colon (":") and the field value. Field names are case-insensitive.
+   * The field value MAY be preceded by any amount of LWS, though a single SP
+   * is preferred." */
+
+  size_t len;
+  const char *start;
+  const char *end;
+  DEBUGASSERT(hlen);
+  DEBUGASSERT(clen);
+  DEBUGASSERT(header);
+  DEBUGASSERT(content);
+
+  if(!strncasecompare(headerline, header, hlen))
+    return FALSE; /* doesn't start with header */
+
+  /* pass the header */
+  start = &headerline[hlen];
+
+  /* pass all whitespace */
+  while(*start && ISSPACE(*start))
+    start++;
+
+  /* find the end of the header line */
+  end = strchr(start, '\r'); /* lines end with CRLF */
+  if(!end) {
+    /* in case there's a non-standard compliant line here */
+    end = strchr(start, '\n');
+
+    if(!end)
+      /* hm, there's no line ending here, use the zero byte! */
+      end = strchr(start, '\0');
+  }
+
+  len = end-start; /* length of the content part of the input line */
+
+  /* find the content string in the rest of the line */
+  for(; len >= clen; len--, start++) {
+    if(strncasecompare(start, content, clen))
+      return TRUE; /* match! */
+  }
+
+  return FALSE; /* no match */
+}
+
+/*
+ * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
+ * the generic Curl_connect().
+ */
+CURLcode Curl_http_connect(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+
+  /* We default to persistent connections. We set this already in this connect
+     function to make the reuse checks properly be able to check this bit. */
+  connkeep(conn, "HTTP default");
+
+  return Curl_conn_connect(data, FIRSTSOCKET, FALSE, done);
+}
+
+/* this returns the socket to wait for in the DO and DOING state for the multi
+   interface and then we're always _sending_ a request and thus we wait for
+   the single socket to become writable only */
+int Curl_http_getsock_do(struct Curl_easy *data,
+                         struct connectdata *conn,
+                         curl_socket_t *socks)
+{
+  /* write mode */
+  (void)conn;
+  socks[0] = Curl_conn_get_socket(data, FIRSTSOCKET);
+  return GETSOCK_WRITESOCK(0);
+}
+
+/*
+ * Curl_http_done() gets called after a single HTTP request has been
+ * performed.
+ */
+
+CURLcode Curl_http_done(struct Curl_easy *data,
+                        CURLcode status, bool premature)
+{
+  struct connectdata *conn = data->conn;
+  struct HTTP *http = data->req.p.http;
+
+  /* Clear multipass flag. If authentication isn't done yet, then it will get
+   * a chance to be set back to true when we output the next auth header */
+  data->state.authhost.multipass = FALSE;
+  data->state.authproxy.multipass = FALSE;
+
+  if(!http)
+    return CURLE_OK;
+
+  Curl_dyn_reset(&data->state.headerb);
+  Curl_hyper_done(data);
+
+  if(status)
+    return status;
+
+  if(!premature && /* this check is pointless when DONE is called before the
+                      entire operation is complete */
+     !conn->bits.retry &&
+     !data->set.connect_only &&
+     (data->req.bytecount +
+      data->req.headerbytecount -
+      data->req.deductheadercount) <= 0) {
+    /* If this connection isn't simply closed to be retried, AND nothing was
+       read from the HTTP server (that counts), this can't be right so we
+       return an error here */
+    failf(data, "Empty reply from server");
+    /* Mark it as closed to avoid the "left intact" message */
+    streamclose(conn, "Empty reply from server");
+    return CURLE_GOT_NOTHING;
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons
+ * to avoid it include:
+ *
+ * - if the user specifically requested HTTP 1.0
+ * - if the server we are connected to only supports 1.0
+ * - if any server previously contacted to handle this request only supports
+ * 1.0.
+ */
+bool Curl_use_http_1_1plus(const struct Curl_easy *data,
+                           const struct connectdata *conn)
+{
+  if((data->state.httpversion == 10) || (conn->httpversion == 10))
+    return FALSE;
+  if((data->state.httpwant == CURL_HTTP_VERSION_1_0) &&
+     (conn->httpversion <= 10))
+    return FALSE;
+  return ((data->state.httpwant == CURL_HTTP_VERSION_NONE) ||
+          (data->state.httpwant >= CURL_HTTP_VERSION_1_1));
+}
+
+#ifndef USE_HYPER
+static const char *get_http_string(const struct Curl_easy *data,
+                                   const struct connectdata *conn)
+{
+  if(Curl_conn_is_http3(data, conn, FIRSTSOCKET))
+    return "3";
+  if(Curl_conn_is_http2(data, conn, FIRSTSOCKET))
+    return "2";
+  if(Curl_use_http_1_1plus(data, conn))
+    return "1.1";
+
+  return "1.0";
+}
+#endif
+
+enum proxy_use {
+  HEADER_SERVER,  /* direct to server */
+  HEADER_PROXY,   /* regular request to proxy */
+  HEADER_CONNECT  /* sending CONNECT to a proxy */
+};
+
+static bool hd_name_eq(const char *n1, size_t n1len,
+                       const char *n2, size_t n2len)
+{
+  if(n1len == n2len) {
+    return strncasecompare(n1, n2, n1len);
+  }
+  return FALSE;
+}
+
+CURLcode Curl_dynhds_add_custom(struct Curl_easy *data,
+                                bool is_connect,
+                                struct dynhds *hds)
+{
+  struct connectdata *conn = data->conn;
+  char *ptr;
+  struct curl_slist *h[2];
+  struct curl_slist *headers;
+  int numlists = 1; /* by default */
+  int i;
+
+#ifndef CURL_DISABLE_PROXY
+  enum proxy_use proxy;
+
+  if(is_connect)
+    proxy = HEADER_CONNECT;
+  else
+    proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy?
+      HEADER_PROXY:HEADER_SERVER;
+
+  switch(proxy) {
+  case HEADER_SERVER:
+    h[0] = data->set.headers;
+    break;
+  case HEADER_PROXY:
+    h[0] = data->set.headers;
+    if(data->set.sep_headers) {
+      h[1] = data->set.proxyheaders;
+      numlists++;
+    }
+    break;
+  case HEADER_CONNECT:
+    if(data->set.sep_headers)
+      h[0] = data->set.proxyheaders;
+    else
+      h[0] = data->set.headers;
+    break;
+  }
+#else
+  (void)is_connect;
+  h[0] = data->set.headers;
+#endif
+
+  /* loop through one or two lists */
+  for(i = 0; i < numlists; i++) {
+    for(headers = h[i]; headers; headers = headers->next) {
+      const char *name, *value;
+      size_t namelen, valuelen;
+
+      /* There are 2 quirks in place for custom headers:
+       * 1. setting only 'name:' to suppress a header from being sent
+       * 2. setting only 'name;' to send an empty (illegal) header
+       */
+      ptr = strchr(headers->data, ':');
+      if(ptr) {
+        name = headers->data;
+        namelen = ptr - headers->data;
+        ptr++; /* pass the colon */
+        while(*ptr && ISSPACE(*ptr))
+          ptr++;
+        if(*ptr) {
+          value = ptr;
+          valuelen = strlen(value);
+        }
+        else {
+          /* quirk #1, suppress this header */
+          continue;
+        }
+      }
+      else {
+        ptr = strchr(headers->data, ';');
+
+        if(!ptr) {
+          /* neither : nor ; in provided header value. We seem
+           * to ignore this silently */
+          continue;
+        }
+
+        name = headers->data;
+        namelen = ptr - headers->data;
+        ptr++; /* pass the semicolon */
+        while(*ptr && ISSPACE(*ptr))
+          ptr++;
+        if(!*ptr) {
+          /* quirk #2, send an empty header */
+          value = "";
+          valuelen = 0;
+        }
+        else {
+          /* this may be used for something else in the future,
+           * ignore this for now */
+          continue;
+        }
+      }
+
+      DEBUGASSERT(name && value);
+      if(data->state.aptr.host &&
+         /* a Host: header was sent already, don't pass on any custom Host:
+            header as that will produce *two* in the same request! */
+         hd_name_eq(name, namelen, STRCONST("Host:")))
+        ;
+      else if(data->state.httpreq == HTTPREQ_POST_FORM &&
+              /* this header (extended by formdata.c) is sent later */
+              hd_name_eq(name, namelen, STRCONST("Content-Type:")))
+        ;
+      else if(data->state.httpreq == HTTPREQ_POST_MIME &&
+              /* this header is sent later */
+              hd_name_eq(name, namelen, STRCONST("Content-Type:")))
+        ;
+      else if(data->req.authneg &&
+              /* while doing auth neg, don't allow the custom length since
+                 we will force length zero then */
+              hd_name_eq(name, namelen, STRCONST("Content-Length:")))
+        ;
+      else if(data->state.aptr.te &&
+              /* when asking for Transfer-Encoding, don't pass on a custom
+                 Connection: */
+              hd_name_eq(name, namelen, STRCONST("Connection:")))
+        ;
+      else if((conn->httpversion >= 20) &&
+              hd_name_eq(name, namelen, STRCONST("Transfer-Encoding:")))
+        /* HTTP/2 doesn't support chunked requests */
+        ;
+      else if((hd_name_eq(name, namelen, STRCONST("Authorization:")) ||
+               hd_name_eq(name, namelen, STRCONST("Cookie:"))) &&
+              /* be careful of sending this potentially sensitive header to
+                 other hosts */
+              !Curl_auth_allowed_to_host(data))
+        ;
+      else {
+        CURLcode result;
+
+        result = Curl_dynhds_add(hds, name, namelen, value, valuelen);
+        if(result)
+          return result;
+      }
+    }
+  }
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_add_custom_headers(struct Curl_easy *data,
+                                 bool is_connect,
+#ifndef USE_HYPER
+                                 struct dynbuf *req
+#else
+                                 void *req
+#endif
+  )
+{
+  struct connectdata *conn = data->conn;
+  char *ptr;
+  struct curl_slist *h[2];
+  struct curl_slist *headers;
+  int numlists = 1; /* by default */
+  int i;
+
+#ifndef CURL_DISABLE_PROXY
+  enum proxy_use proxy;
+
+  if(is_connect)
+    proxy = HEADER_CONNECT;
+  else
+    proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy?
+      HEADER_PROXY:HEADER_SERVER;
+
+  switch(proxy) {
+  case HEADER_SERVER:
+    h[0] = data->set.headers;
+    break;
+  case HEADER_PROXY:
+    h[0] = data->set.headers;
+    if(data->set.sep_headers) {
+      h[1] = data->set.proxyheaders;
+      numlists++;
+    }
+    break;
+  case HEADER_CONNECT:
+    if(data->set.sep_headers)
+      h[0] = data->set.proxyheaders;
+    else
+      h[0] = data->set.headers;
+    break;
+  }
+#else
+  (void)is_connect;
+  h[0] = data->set.headers;
+#endif
+
+  /* loop through one or two lists */
+  for(i = 0; i < numlists; i++) {
+    headers = h[i];
+
+    while(headers) {
+      char *semicolonp = NULL;
+      ptr = strchr(headers->data, ':');
+      if(!ptr) {
+        char *optr;
+        /* no colon, semicolon? */
+        ptr = strchr(headers->data, ';');
+        if(ptr) {
+          optr = ptr;
+          ptr++; /* pass the semicolon */
+          while(*ptr && ISSPACE(*ptr))
+            ptr++;
+
+          if(*ptr) {
+            /* this may be used for something else in the future */
+            optr = NULL;
+          }
+          else {
+            if(*(--ptr) == ';') {
+              /* copy the source */
+              semicolonp = strdup(headers->data);
+              if(!semicolonp) {
+#ifndef USE_HYPER
+                Curl_dyn_free(req);
+#endif
+                return CURLE_OUT_OF_MEMORY;
+              }
+              /* put a colon where the semicolon is */
+              semicolonp[ptr - headers->data] = ':';
+              /* point at the colon */
+              optr = &semicolonp [ptr - headers->data];
+            }
+          }
+          ptr = optr;
+        }
+      }
+      if(ptr && (ptr != headers->data)) {
+        /* we require a colon for this to be a true header */
+
+        ptr++; /* pass the colon */
+        while(*ptr && ISSPACE(*ptr))
+          ptr++;
+
+        if(*ptr || semicolonp) {
+          /* only send this if the contents was non-blank or done special */
+          CURLcode result = CURLE_OK;
+          char *compare = semicolonp ? semicolonp : headers->data;
+
+          if(data->state.aptr.host &&
+             /* a Host: header was sent already, don't pass on any custom Host:
+                header as that will produce *two* in the same request! */
+             checkprefix("Host:", compare))
+            ;
+          else if(data->state.httpreq == HTTPREQ_POST_FORM &&
+                  /* this header (extended by formdata.c) is sent later */
+                  checkprefix("Content-Type:", compare))
+            ;
+          else if(data->state.httpreq == HTTPREQ_POST_MIME &&
+                  /* this header is sent later */
+                  checkprefix("Content-Type:", compare))
+            ;
+          else if(data->req.authneg &&
+                  /* while doing auth neg, don't allow the custom length since
+                     we will force length zero then */
+                  checkprefix("Content-Length:", compare))
+            ;
+          else if(data->state.aptr.te &&
+                  /* when asking for Transfer-Encoding, don't pass on a custom
+                     Connection: */
+                  checkprefix("Connection:", compare))
+            ;
+          else if((conn->httpversion >= 20) &&
+                  checkprefix("Transfer-Encoding:", compare))
+            /* HTTP/2 doesn't support chunked requests */
+            ;
+          else if((checkprefix("Authorization:", compare) ||
+                   checkprefix("Cookie:", compare)) &&
+                  /* be careful of sending this potentially sensitive header to
+                     other hosts */
+                  !Curl_auth_allowed_to_host(data))
+            ;
+          else {
+#ifdef USE_HYPER
+            result = Curl_hyper_header(data, req, compare);
+#else
+            result = Curl_dyn_addf(req, "%s\r\n", compare);
+#endif
+          }
+          if(semicolonp)
+            free(semicolonp);
+          if(result)
+            return result;
+        }
+      }
+      headers = headers->next;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+#ifndef CURL_DISABLE_PARSEDATE
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
+#ifndef USE_HYPER
+                                struct dynbuf *req
+#else
+                                void *req
+#endif
+  )
+{
+  const struct tm *tm;
+  struct tm keeptime;
+  CURLcode result;
+  char datestr[80];
+  const char *condp;
+  size_t len;
+
+  if(data->set.timecondition == CURL_TIMECOND_NONE)
+    /* no condition was asked for */
+    return CURLE_OK;
+
+  result = Curl_gmtime(data->set.timevalue, &keeptime);
+  if(result) {
+    failf(data, "Invalid TIMEVALUE");
+    return result;
+  }
+  tm = &keeptime;
+
+  switch(data->set.timecondition) {
+  default:
+    DEBUGF(infof(data, "invalid time condition"));
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  case CURL_TIMECOND_IFMODSINCE:
+    condp = "If-Modified-Since";
+    len = 17;
+    break;
+  case CURL_TIMECOND_IFUNMODSINCE:
+    condp = "If-Unmodified-Since";
+    len = 19;
+    break;
+  case CURL_TIMECOND_LASTMOD:
+    condp = "Last-Modified";
+    len = 13;
+    break;
+  }
+
+  if(Curl_checkheaders(data, condp, len)) {
+    /* A custom header was specified; it will be sent instead. */
+    return CURLE_OK;
+  }
+
+  /* The If-Modified-Since header family should have their times set in
+   * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be
+   * represented in Greenwich Mean Time (GMT), without exception. For the
+   * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal
+   * Time)." (see page 20 of RFC2616).
+   */
+
+  /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+  msnprintf(datestr, sizeof(datestr),
+            "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+            condp,
+            Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+            tm->tm_mday,
+            Curl_month[tm->tm_mon],
+            tm->tm_year + 1900,
+            tm->tm_hour,
+            tm->tm_min,
+            tm->tm_sec);
+
+#ifndef USE_HYPER
+  result = Curl_dyn_add(req, datestr);
+#else
+  result = Curl_hyper_header(data, req, datestr);
+#endif
+
+  return result;
+}
+#else
+/* disabled */
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
+                                struct dynbuf *req)
+{
+  (void)data;
+  (void)req;
+  return CURLE_OK;
+}
+#endif
+
+void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
+                      const char **method, Curl_HttpReq *reqp)
+{
+  Curl_HttpReq httpreq = (Curl_HttpReq)data->state.httpreq;
+  const char *request;
+  if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) &&
+     data->state.upload)
+    httpreq = HTTPREQ_PUT;
+
+  /* Now set the 'request' pointer to the proper request string */
+  if(data->set.str[STRING_CUSTOMREQUEST])
+    request = data->set.str[STRING_CUSTOMREQUEST];
+  else {
+    if(data->req.no_body)
+      request = "HEAD";
+    else {
+      DEBUGASSERT((httpreq >= HTTPREQ_GET) && (httpreq <= HTTPREQ_HEAD));
+      switch(httpreq) {
+      case HTTPREQ_POST:
+      case HTTPREQ_POST_FORM:
+      case HTTPREQ_POST_MIME:
+        request = "POST";
+        break;
+      case HTTPREQ_PUT:
+        request = "PUT";
+        break;
+      default: /* this should never happen */
+      case HTTPREQ_GET:
+        request = "GET";
+        break;
+      case HTTPREQ_HEAD:
+        request = "HEAD";
+        break;
+      }
+    }
+  }
+  *method = request;
+  *reqp = httpreq;
+}
+
+CURLcode Curl_http_useragent(struct Curl_easy *data)
+{
+  /* The User-Agent string might have been allocated in url.c already, because
+     it might have been used in the proxy connect, but if we have got a header
+     with the user-agent string specified, we erase the previously made string
+     here. */
+  if(Curl_checkheaders(data, STRCONST("User-Agent"))) {
+    free(data->state.aptr.uagent);
+    data->state.aptr.uagent = NULL;
+  }
+  return CURLE_OK;
+}
+
+
+CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
+{
+  const char *ptr;
+  struct dynamically_allocated_data *aptr = &data->state.aptr;
+  if(!data->state.this_is_a_follow) {
+    /* Free to avoid leaking memory on multiple requests */
+    free(data->state.first_host);
+
+    data->state.first_host = strdup(conn->host.name);
+    if(!data->state.first_host)
+      return CURLE_OUT_OF_MEMORY;
+
+    data->state.first_remote_port = conn->remote_port;
+    data->state.first_remote_protocol = conn->handler->protocol;
+  }
+  Curl_safefree(aptr->host);
+
+  ptr = Curl_checkheaders(data, STRCONST("Host"));
+  if(ptr && (!data->state.this_is_a_follow ||
+             strcasecompare(data->state.first_host, conn->host.name))) {
+#if !defined(CURL_DISABLE_COOKIES)
+    /* If we have a given custom Host: header, we extract the host name in
+       order to possibly use it for cookie reasons later on. We only allow the
+       custom Host: header if this is NOT a redirect, as setting Host: in the
+       redirected request is being out on thin ice. Except if the host name
+       is the same as the first one! */
+    char *cookiehost = Curl_copy_header_value(ptr);
+    if(!cookiehost)
+      return CURLE_OUT_OF_MEMORY;
+    if(!*cookiehost)
+      /* ignore empty data */
+      free(cookiehost);
+    else {
+      /* If the host begins with '[', we start searching for the port after
+         the bracket has been closed */
+      if(*cookiehost == '[') {
+        char *closingbracket;
+        /* since the 'cookiehost' is an allocated memory area that will be
+           freed later we cannot simply increment the pointer */
+        memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1);
+        closingbracket = strchr(cookiehost, ']');
+        if(closingbracket)
+          *closingbracket = 0;
+      }
+      else {
+        int startsearch = 0;
+        char *colon = strchr(cookiehost + startsearch, ':');
+        if(colon)
+          *colon = 0; /* The host must not include an embedded port number */
+      }
+      Curl_safefree(aptr->cookiehost);
+      aptr->cookiehost = cookiehost;
+    }
+#endif
+
+    if(!strcasecompare("Host:", ptr)) {
+      aptr->host = aprintf("Host:%s\r\n", &ptr[5]);
+      if(!aptr->host)
+        return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  else {
+    /* When building Host: headers, we must put the host name within
+       [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
+    const char *host = conn->host.name;
+
+    if(((conn->given->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS)) &&
+        (conn->remote_port == PORT_HTTPS)) ||
+       ((conn->given->protocol&(CURLPROTO_HTTP|CURLPROTO_WS)) &&
+        (conn->remote_port == PORT_HTTP)) )
+      /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include
+         the port number in the host string */
+      aptr->host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip?"[":"",
+                           host, conn->bits.ipv6_ip?"]":"");
+    else
+      aptr->host = aprintf("Host: %s%s%s:%d\r\n", conn->bits.ipv6_ip?"[":"",
+                           host, conn->bits.ipv6_ip?"]":"",
+                           conn->remote_port);
+
+    if(!aptr->host)
+      /* without Host: we can't make a nice request */
+      return CURLE_OUT_OF_MEMORY;
+  }
+  return CURLE_OK;
+}
+
+/*
+ * Append the request-target to the HTTP request
+ */
+CURLcode Curl_http_target(struct Curl_easy *data,
+                          struct connectdata *conn,
+                          struct dynbuf *r)
+{
+  CURLcode result = CURLE_OK;
+  const char *path = data->state.up.path;
+  const char *query = data->state.up.query;
+
+  if(data->set.str[STRING_TARGET]) {
+    path = data->set.str[STRING_TARGET];
+    query = NULL;
+  }
+
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
+    /* Using a proxy but does not tunnel through it */
+
+    /* The path sent to the proxy is in fact the entire URL. But if the remote
+       host is a IDN-name, we must make sure that the request we produce only
+       uses the encoded host name! */
+
+    /* and no fragment part */
+    CURLUcode uc;
+    char *url;
+    CURLU *h = curl_url_dup(data->state.uh);
+    if(!h)
+      return CURLE_OUT_OF_MEMORY;
+
+    if(conn->host.dispname != conn->host.name) {
+      uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0);
+      if(uc) {
+        curl_url_cleanup(h);
+        return CURLE_OUT_OF_MEMORY;
+      }
+    }
+    uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0);
+    if(uc) {
+      curl_url_cleanup(h);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    if(strcasecompare("http", data->state.up.scheme)) {
+      /* when getting HTTP, we don't want the userinfo the URL */
+      uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
+      if(uc) {
+        curl_url_cleanup(h);
+        return CURLE_OUT_OF_MEMORY;
+      }
+      uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0);
+      if(uc) {
+        curl_url_cleanup(h);
+        return CURLE_OUT_OF_MEMORY;
+      }
+    }
+    /* Extract the URL to use in the request. */
+    uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
+    if(uc) {
+      curl_url_cleanup(h);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    curl_url_cleanup(h);
+
+    /* target or url */
+    result = Curl_dyn_add(r, data->set.str[STRING_TARGET]?
+      data->set.str[STRING_TARGET]:url);
+    free(url);
+    if(result)
+      return (result);
+
+    if(strcasecompare("ftp", data->state.up.scheme)) {
+      if(data->set.proxy_transfer_mode) {
+        /* when doing ftp, append ;type=<a|i> if not present */
+        char *type = strstr(path, ";type=");
+        if(type && type[6] && type[7] == 0) {
+          switch(Curl_raw_toupper(type[6])) {
+          case 'A':
+          case 'D':
+          case 'I':
+            break;
+          default:
+            type = NULL;
+          }
+        }
+        if(!type) {
+          result = Curl_dyn_addf(r, ";type=%c",
+                                 data->state.prefer_ascii ? 'a' : 'i');
+          if(result)
+            return result;
+        }
+      }
+    }
+  }
+
+  else
+#else
+    (void)conn; /* not used in disabled-proxy builds */
+#endif
+  {
+    result = Curl_dyn_add(r, path);
+    if(result)
+      return result;
+    if(query)
+      result = Curl_dyn_addf(r, "?%s", query);
+  }
+
+  return result;
+}
+
+#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
+static CURLcode set_post_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
+{
+  CURLcode result;
+
+  switch(httpreq) {
+#ifndef CURL_DISABLE_MIME
+  case HTTPREQ_POST_MIME:
+    data->state.mimepost = &data->set.mimepost;
+    break;
+#endif
+#ifndef CURL_DISABLE_FORM_API
+  case HTTPREQ_POST_FORM:
+    /* Convert the form structure into a mime structure, then keep
+       the conversion */
+    if(!data->state.formp) {
+      data->state.formp = calloc(1, sizeof(curl_mimepart));
+      if(!data->state.formp)
+        return CURLE_OUT_OF_MEMORY;
+      Curl_mime_cleanpart(data->state.formp);
+      result = Curl_getformdata(data, data->state.formp, data->set.httppost,
+                                data->state.fread_func);
+      if(result) {
+        Curl_safefree(data->state.formp);
+        return result;
+      }
+      data->state.mimepost = data->state.formp;
+    }
+    break;
+#endif
+  default:
+    data->state.mimepost = NULL;
+    break;
+  }
+
+  switch(httpreq) {
+  case HTTPREQ_POST_FORM:
+  case HTTPREQ_POST_MIME:
+    /* This is form posting using mime data. */
+#ifndef CURL_DISABLE_MIME
+    if(data->state.mimepost) {
+      const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type"));
+
+      /* Read and seek body only. */
+      data->state.mimepost->flags |= MIME_BODY_ONLY;
+
+      /* Prepare the mime structure headers & set content type. */
+
+      if(cthdr)
+        for(cthdr += 13; *cthdr == ' '; cthdr++)
+          ;
+      else if(data->state.mimepost->kind == MIMEKIND_MULTIPART)
+        cthdr = "multipart/form-data";
+
+      curl_mime_headers(data->state.mimepost, data->set.headers, 0);
+      result = Curl_mime_prepare_headers(data, data->state.mimepost, cthdr,
+                                         NULL, MIMESTRATEGY_FORM);
+      if(result)
+        return result;
+      curl_mime_headers(data->state.mimepost, NULL, 0);
+      result = Curl_creader_set_mime(data, data->state.mimepost);
+      if(result)
+        return result;
+    }
+    else
+#endif
+    {
+      result = Curl_creader_set_null(data);
+    }
+    data->state.infilesize = Curl_creader_total_length(data);
+    return result;
+
+  default:
+    return Curl_creader_set_null(data);
+  }
+  /* never reached */
+}
+#endif
+
+static CURLcode set_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
+{
+  CURLcode result = CURLE_OK;
+  curl_off_t postsize = data->state.infilesize;
+
+  DEBUGASSERT(data->conn);
+
+  if(data->req.authneg) {
+    return Curl_creader_set_null(data);
+  }
+
+  switch(httpreq) {
+  case HTTPREQ_PUT: /* Let's PUT the data to the server! */
+    if(!postsize)
+      result = Curl_creader_set_null(data);
+    else
+      result = Curl_creader_set_fread(data, postsize);
+    return result;
+
+#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
+  case HTTPREQ_POST_FORM:
+  case HTTPREQ_POST_MIME:
+    return set_post_reader(data, httpreq);
+#endif
+
+  case HTTPREQ_POST:
+    /* this is the simple POST, using x-www-form-urlencoded style */
+    /* the size of the post body */
+    if(!postsize) {
+      result = Curl_creader_set_null(data);
+    }
+    else if(data->set.postfields) {
+      if(postsize > 0)
+        result = Curl_creader_set_buf(data, data->set.postfields,
+                                      (size_t)postsize);
+      else
+        result = Curl_creader_set_null(data);
+    }
+    else { /* we read the bytes from the callback */
+      result = Curl_creader_set_fread(data, postsize);
+    }
+    return result;
+
+  default:
+    /* HTTP GET/HEAD download, has no body, needs no Content-Length */
+    data->state.infilesize = 0;
+    return Curl_creader_set_null(data);
+  }
+  /* not reached */
+}
+
+static CURLcode http_resume(struct Curl_easy *data, Curl_HttpReq httpreq)
+{
+  if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
+     data->state.resume_from) {
+    /**********************************************************************
+     * Resuming upload in HTTP means that we PUT or POST and that we have
+     * got a resume_from value set. The resume value has already created
+     * a Range: header that will be passed along. We need to "fast forward"
+     * the file the given number of bytes and decrease the assume upload
+     * file size before we continue this venture in the dark lands of HTTP.
+     * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
+     *********************************************************************/
+
+    if(data->state.resume_from < 0) {
+      /*
+       * This is meant to get the size of the present remote-file by itself.
+       * We don't support this now. Bail out!
+       */
+      data->state.resume_from = 0;
+    }
+
+    if(data->state.resume_from && !data->req.authneg) {
+      /* only act on the first request */
+      CURLcode result;
+      result = Curl_creader_resume_from(data, data->state.resume_from);
+      if(result) {
+        failf(data, "Unable to resume from offset %" CURL_FORMAT_CURL_OFF_T,
+              data->state.resume_from);
+        return result;
+      }
+    }
+  }
+  return CURLE_OK;
+}
+
+CURLcode Curl_http_req_set_reader(struct Curl_easy *data,
+                                  Curl_HttpReq httpreq,
+                                  const char **tep)
+{
+  CURLcode result = CURLE_OK;
+  const char *ptr;
+
+  result = set_reader(data, httpreq);
+  if(result)
+    return result;
+
+  result = http_resume(data, httpreq);
+  if(result)
+    return result;
+
+  ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
+  if(ptr) {
+    /* Some kind of TE is requested, check if 'chunked' is chosen */
+    data->req.upload_chunky =
+      Curl_compareheader(ptr,
+                         STRCONST("Transfer-Encoding:"), STRCONST("chunked"));
+  }
+  else {
+    curl_off_t req_clen = Curl_creader_total_length(data);
+
+    if(req_clen < 0) {
+      /* indeterminate request content length */
+      if(Curl_use_http_1_1plus(data, data->conn)) {
+        /* On HTTP/1.1, enable chunked, on HTTP/2 and later we do not
+         * need it */
+        data->req.upload_chunky = (data->conn->httpversion < 20);
+      }
+      else {
+        failf(data, "Chunky upload is not supported by HTTP 1.0");
+        return CURLE_UPLOAD_FAILED;
+      }
+    }
+    else {
+      /* else, no chunky upload */
+      data->req.upload_chunky = FALSE;
+    }
+
+    if(data->req.upload_chunky)
+      *tep = "Transfer-Encoding: chunked\r\n";
+  }
+  return result;
+}
+
+static CURLcode addexpect(struct Curl_easy *data, struct dynbuf *r,
+                          bool *announced_exp100)
+{
+  CURLcode result;
+  char *ptr;
+
+  *announced_exp100 = FALSE;
+  /* Avoid Expect: 100-continue if Upgrade: is used */
+  if(data->req.upgr101 != UPGR101_INIT)
+    return CURLE_OK;
+
+  /* For really small puts we don't use Expect: headers at all, and for
+     the somewhat bigger ones we allow the app to disable it. Just make
+     sure that the expect100header is always set to the preferred value
+     here. */
+  ptr = Curl_checkheaders(data, STRCONST("Expect"));
+  if(ptr) {
+    *announced_exp100 =
+      Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
+  }
+  else if(!data->state.disableexpect &&
+          Curl_use_http_1_1plus(data, data->conn) &&
+          (data->conn->httpversion < 20)) {
+    /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
+       Expect: 100-continue to the headers which actually speeds up post
+       operations (as there is one packet coming back from the web server) */
+    curl_off_t client_len = Curl_creader_client_length(data);
+    if(client_len > EXPECT_100_THRESHOLD || client_len < 0) {
+      result = Curl_dyn_addn(r, STRCONST("Expect: 100-continue\r\n"));
+      if(result)
+        return result;
+      *announced_exp100 = TRUE;
+    }
+  }
+  return CURLE_OK;
+}
+
+CURLcode Curl_http_req_complete(struct Curl_easy *data,
+                                struct dynbuf *r, Curl_HttpReq httpreq)
+{
+  CURLcode result = CURLE_OK;
+  curl_off_t req_clen;
+  bool announced_exp100 = FALSE;
+
+  DEBUGASSERT(data->conn);
+#ifndef USE_HYPER
+  if(data->req.upload_chunky) {
+    result = Curl_httpchunk_add_reader(data);
+    if(result)
+      return result;
+  }
+#endif
+
+  /* Get the request body length that has been set up */
+  req_clen = Curl_creader_total_length(data);
+  switch(httpreq) {
+  case HTTPREQ_PUT:
+  case HTTPREQ_POST:
+#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
+  case HTTPREQ_POST_FORM:
+  case HTTPREQ_POST_MIME:
+#endif
+    /* We only set Content-Length and allow a custom Content-Length if
+       we don't upload data chunked, as RFC2616 forbids us to set both
+       kinds of headers (Transfer-Encoding: chunked and Content-Length).
+       We do not override a custom "Content-Length" header, but during
+       authentication negotiation that header is suppressed.
+     */
+    if(req_clen >= 0 && !data->req.upload_chunky &&
+       (data->req.authneg ||
+        !Curl_checkheaders(data, STRCONST("Content-Length")))) {
+      /* we allow replacing this header if not during auth negotiation,
+         although it isn't very wise to actually set your own */
+      result = Curl_dyn_addf(r,
+                             "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+                             "\r\n", req_clen);
+    }
+    if(result)
+      goto out;
+
+#ifndef CURL_DISABLE_MIME
+    /* Output mime-generated headers. */
+    if(data->state.mimepost &&
+       ((httpreq == HTTPREQ_POST_FORM) || (httpreq == HTTPREQ_POST_MIME))) {
+      struct curl_slist *hdr;
+
+      for(hdr = data->state.mimepost->curlheaders; hdr; hdr = hdr->next) {
+        result = Curl_dyn_addf(r, "%s\r\n", hdr->data);
+        if(result)
+          goto out;
+      }
+    }
+#endif
+    if(httpreq == HTTPREQ_POST) {
+      if(!Curl_checkheaders(data, STRCONST("Content-Type"))) {
+        result = Curl_dyn_addn(r, STRCONST("Content-Type: application/"
+                                           "x-www-form-urlencoded\r\n"));
+        if(result)
+          goto out;
+      }
+    }
+    result = addexpect(data, r, &announced_exp100);
+    if(result)
+      goto out;
+    break;
+  default:
+    break;
+  }
+
+  /* end of headers */
+  result = Curl_dyn_addn(r, STRCONST("\r\n"));
+  Curl_pgrsSetUploadSize(data, req_clen);
+  if(announced_exp100)
+    result = http_exp100_add_reader(data);
+
+out:
+  if(!result) {
+    /* setup variables for the upcoming transfer */
+    Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
+  }
+  return result;
+}
+
+#if !defined(CURL_DISABLE_COOKIES)
+
+CURLcode Curl_http_cookies(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           struct dynbuf *r)
+{
+  CURLcode result = CURLE_OK;
+  char *addcookies = NULL;
+  bool linecap = FALSE;
+  if(data->set.str[STRING_COOKIE] &&
+     !Curl_checkheaders(data, STRCONST("Cookie")))
+    addcookies = data->set.str[STRING_COOKIE];
+
+  if(data->cookies || addcookies) {
+    struct Cookie *co = NULL; /* no cookies from start */
+    int count = 0;
+
+    if(data->cookies && data->state.cookie_engine) {
+      const char *host = data->state.aptr.cookiehost ?
+        data->state.aptr.cookiehost : conn->host.name;
+      const bool secure_context =
+        conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
+        strcasecompare("localhost", host) ||
+        !strcmp(host, "127.0.0.1") ||
+        !strcmp(host, "::1") ? TRUE : FALSE;
+      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+      co = Curl_cookie_getlist(data, data->cookies, host, data->state.up.path,
+                               secure_context);
+      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+    }
+    if(co) {
+      struct Cookie *store = co;
+      size_t clen = 8; /* hold the size of the generated Cookie: header */
+      /* now loop through all cookies that matched */
+      while(co) {
+        if(co->value) {
+          size_t add;
+          if(!count) {
+            result = Curl_dyn_addn(r, STRCONST("Cookie: "));
+            if(result)
+              break;
+          }
+          add = strlen(co->name) + strlen(co->value) + 1;
+          if(clen + add >= MAX_COOKIE_HEADER_LEN) {
+            infof(data, "Restricted outgoing cookies due to header size, "
+                  "'%s' not sent", co->name);
+            linecap = TRUE;
+            break;
+          }
+          result = Curl_dyn_addf(r, "%s%s=%s", count?"; ":"",
+                                 co->name, co->value);
+          if(result)
+            break;
+          clen += add + (count ? 2 : 0);
+          count++;
+        }
+        co = co->next; /* next cookie please */
+      }
+      Curl_cookie_freelist(store);
+    }
+    if(addcookies && !result && !linecap) {
+      if(!count)
+        result = Curl_dyn_addn(r, STRCONST("Cookie: "));
+      if(!result) {
+        result = Curl_dyn_addf(r, "%s%s", count?"; ":"", addcookies);
+        count++;
+      }
+    }
+    if(count && !result)
+      result = Curl_dyn_addn(r, STRCONST("\r\n"));
+
+    if(result)
+      return result;
+  }
+  return result;
+}
+#endif
+
+CURLcode Curl_http_range(struct Curl_easy *data,
+                         Curl_HttpReq httpreq)
+{
+  if(data->state.use_range) {
+    /*
+     * A range is selected. We use different headers whether we're downloading
+     * or uploading and we always let customized headers override our internal
+     * ones if any such are specified.
+     */
+    if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
+       !Curl_checkheaders(data, STRCONST("Range"))) {
+      /* if a line like this was already allocated, free the previous one */
+      free(data->state.aptr.rangeline);
+      data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n",
+                                           data->state.range);
+    }
+    else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
+            !Curl_checkheaders(data, STRCONST("Content-Range"))) {
+      curl_off_t req_clen = Curl_creader_total_length(data);
+      /* if a line like this was already allocated, free the previous one */
+      free(data->state.aptr.rangeline);
+
+      if(data->set.set_resume_from < 0) {
+        /* Upload resume was asked for, but we don't know the size of the
+           remote part so we tell the server (and act accordingly) that we
+           upload the whole file (again) */
+        data->state.aptr.rangeline =
+          aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T
+                  "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
+                  req_clen - 1, req_clen);
+
+      }
+      else if(data->state.resume_from) {
+        /* This is because "resume" was selected */
+        /* TODO: not sure if we want to send this header during authentication
+         * negotiation, but test1084 checks for it. In which case we have a
+         * "null" client reader installed that gives an unexpected length. */
+        curl_off_t total_len = data->req.authneg?
+                               data->state.infilesize :
+                               (data->state.resume_from + req_clen);
+        data->state.aptr.rangeline =
+          aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
+                  "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
+                  data->state.range, total_len-1, total_len);
+      }
+      else {
+        /* Range was selected and then we just pass the incoming range and
+           append total size */
+        data->state.aptr.rangeline =
+          aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n",
+                  data->state.range, req_clen);
+      }
+      if(!data->state.aptr.rangeline)
+        return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  return CURLE_OK;
+}
+
+CURLcode Curl_http_firstwrite(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+  struct SingleRequest *k = &data->req;
+
+  if(data->req.newurl) {
+    if(conn->bits.close) {
+      /* Abort after the headers if "follow Location" is set
+         and we're set to close anyway. */
+      k->keepon &= ~KEEP_RECV;
+      k->done = TRUE;
+      return CURLE_OK;
+    }
+    /* We have a new url to load, but since we want to be able to reuse this
+       connection properly, we read the full response in "ignore more" */
+    k->ignorebody = TRUE;
+    infof(data, "Ignoring the response-body");
+  }
+  if(data->state.resume_from && !k->content_range &&
+     (data->state.httpreq == HTTPREQ_GET) &&
+     !k->ignorebody) {
+
+    if(k->size == data->state.resume_from) {
+      /* The resume point is at the end of file, consider this fine even if it
+         doesn't allow resume from here. */
+      infof(data, "The entire document is already downloaded");
+      streamclose(conn, "already downloaded");
+      /* Abort download */
+      k->keepon &= ~KEEP_RECV;
+      k->done = TRUE;
+      return CURLE_OK;
+    }
+
+    /* we wanted to resume a download, although the server doesn't seem to
+     * support this and we did this with a GET (if it wasn't a GET we did a
+     * POST or PUT resume) */
+    failf(data, "HTTP server doesn't seem to support "
+          "byte ranges. Cannot resume.");
+    return CURLE_RANGE_ERROR;
+  }
+
+  if(data->set.timecondition && !data->state.range) {
+    /* A time condition has been set AND no ranges have been requested. This
+       seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct
+       action for an HTTP/1.1 client */
+
+    if(!Curl_meets_timecondition(data, k->timeofdoc)) {
+      k->done = TRUE;
+      /* We're simulating an HTTP 304 from server so we return
+         what should have been returned from the server */
+      data->info.httpcode = 304;
+      infof(data, "Simulate an HTTP 304 response");
+      /* we abort the transfer before it is completed == we ruin the
+         reuse ability. Close the connection */
+      streamclose(conn, "Simulated 304 handling");
+      return CURLE_OK;
+    }
+  } /* we have a time condition */
+
+  return CURLE_OK;
+}
+
+#ifdef HAVE_LIBZ
+CURLcode Curl_transferencode(struct Curl_easy *data)
+{
+  if(!Curl_checkheaders(data, STRCONST("TE")) &&
+     data->set.http_transfer_encoding) {
+    /* When we are to insert a TE: header in the request, we must also insert
+       TE in a Connection: header, so we need to merge the custom provided
+       Connection: header and prevent the original to get sent. Note that if
+       the user has inserted his/her own TE: header we don't do this magic
+       but then assume that the user will handle it all! */
+    char *cptr = Curl_checkheaders(data, STRCONST("Connection"));
+#define TE_HEADER "TE: gzip\r\n"
+
+    Curl_safefree(data->state.aptr.te);
+
+    if(cptr) {
+      cptr = Curl_copy_header_value(cptr);
+      if(!cptr)
+        return CURLE_OUT_OF_MEMORY;
+    }
+
+    /* Create the (updated) Connection: header */
+    data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
+                                cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
+
+    free(cptr);
+    if(!data->state.aptr.te)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  return CURLE_OK;
+}
+#endif
+
+#ifndef USE_HYPER
+/*
+ * Curl_http() gets called from the generic multi_do() function when an HTTP
+ * request is to be performed. This creates and sends a properly constructed
+ * HTTP request.
+ */
+CURLcode Curl_http(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  CURLcode result = CURLE_OK;
+  Curl_HttpReq httpreq;
+  const char *te = ""; /* transfer-encoding */
+  const char *request;
+  const char *httpstring;
+  struct dynbuf req;
+  char *altused = NULL;
+  const char *p_accept;      /* Accept: string */
+
+  /* Always consider the DO phase done after this function call, even if there
+     may be parts of the request that are not yet sent, since we can deal with
+     the rest of the request in the PERFORM phase. */
+  *done = TRUE;
+
+  switch(conn->alpn) {
+  case CURL_HTTP_VERSION_3:
+    DEBUGASSERT(Curl_conn_is_http3(data, conn, FIRSTSOCKET));
+    break;
+  case CURL_HTTP_VERSION_2:
+#ifndef CURL_DISABLE_PROXY
+    if(!Curl_conn_is_http2(data, conn, FIRSTSOCKET) &&
+       conn->bits.proxy && !conn->bits.tunnel_proxy
+      ) {
+      result = Curl_http2_switch(data, conn, FIRSTSOCKET);
+      if(result)
+        goto fail;
+    }
+    else
+#endif
+      DEBUGASSERT(Curl_conn_is_http2(data, conn, FIRSTSOCKET));
+    break;
+  case CURL_HTTP_VERSION_1_1:
+    /* continue with HTTP/1.x when explicitly requested */
+    break;
+  default:
+    /* Check if user wants to use HTTP/2 with clear TCP */
+    if(Curl_http2_may_switch(data, conn, FIRSTSOCKET)) {
+      DEBUGF(infof(data, "HTTP/2 over clean TCP"));
+      result = Curl_http2_switch(data, conn, FIRSTSOCKET);
+      if(result)
+        goto fail;
+    }
+    break;
+  }
+
+  /* Add collecting of headers written to client. For a new connection,
+   * we might have done that already, but reuse
+   * or multiplex needs it here as well. */
+  result = Curl_headers_init(data);
+  if(result)
+    goto fail;
+
+  result = Curl_http_host(data, conn);
+  if(result)
+    goto fail;
+
+  result = Curl_http_useragent(data);
+  if(result)
+    goto fail;
+
+  Curl_http_method(data, conn, &request, &httpreq);
+
+  /* setup the authentication headers */
+  {
+    char *pq = NULL;
+    if(data->state.up.query) {
+      pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
+      if(!pq)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    result = Curl_http_output_auth(data, conn, request, httpreq,
+                                   (pq ? pq : data->state.up.path), FALSE);
+    free(pq);
+    if(result)
+      goto fail;
+  }
+
+  Curl_safefree(data->state.aptr.ref);
+  if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) {
+    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
+    if(!data->state.aptr.ref)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
+     data->set.str[STRING_ENCODING]) {
+    Curl_safefree(data->state.aptr.accept_encoding);
+    data->state.aptr.accept_encoding =
+      aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
+    if(!data->state.aptr.accept_encoding)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  else
+    Curl_safefree(data->state.aptr.accept_encoding);
+
+#ifdef HAVE_LIBZ
+  /* we only consider transfer-encoding magic if libz support is built-in */
+  result = Curl_transferencode(data);
+  if(result)
+    goto fail;
+#endif
+
+  result = Curl_http_req_set_reader(data, httpreq, &te);
+  if(result)
+    goto fail;
+
+  p_accept = Curl_checkheaders(data,
+                               STRCONST("Accept"))?NULL:"Accept: */*\r\n";
+
+  result = Curl_http_range(data, httpreq);
+  if(result)
+    goto fail;
+
+  httpstring = get_http_string(data, conn);
+
+  /* initialize a dynamic send-buffer */
+  Curl_dyn_init(&req, DYN_HTTP_REQUEST);
+
+  /* make sure the header buffer is reset - if there are leftovers from a
+     previous transfer */
+  Curl_dyn_reset(&data->state.headerb);
+
+  /* add the main request stuff */
+  /* GET/HEAD/POST/PUT */
+  result = Curl_dyn_addf(&req, "%s ", request);
+  if(!result)
+    result = Curl_http_target(data, conn, &req);
+  if(result) {
+    Curl_dyn_free(&req);
+    goto fail;
+  }
+
+#ifndef CURL_DISABLE_ALTSVC
+  if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) {
+    altused = aprintf("Alt-Used: %s:%d\r\n",
+                      conn->conn_to_host.name, conn->conn_to_port);
+    if(!altused) {
+      Curl_dyn_free(&req);
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+#endif
+  result =
+    Curl_dyn_addf(&req,
+                  " HTTP/%s\r\n" /* HTTP version */
+                  "%s" /* host */
+                  "%s" /* proxyuserpwd */
+                  "%s" /* userpwd */
+                  "%s" /* range */
+                  "%s" /* user agent */
+                  "%s" /* accept */
+                  "%s" /* TE: */
+                  "%s" /* accept-encoding */
+                  "%s" /* referer */
+                  "%s" /* Proxy-Connection */
+                  "%s" /* transfer-encoding */
+                  "%s",/* Alt-Used */
+
+                  httpstring,
+                  (data->state.aptr.host?data->state.aptr.host:""),
+                  data->state.aptr.proxyuserpwd?
+                  data->state.aptr.proxyuserpwd:"",
+                  data->state.aptr.userpwd?data->state.aptr.userpwd:"",
+                  (data->state.use_range && data->state.aptr.rangeline)?
+                  data->state.aptr.rangeline:"",
+                  (data->set.str[STRING_USERAGENT] &&
+                   *data->set.str[STRING_USERAGENT] &&
+                   data->state.aptr.uagent)?
+                  data->state.aptr.uagent:"",
+                  p_accept?p_accept:"",
+                  data->state.aptr.te?data->state.aptr.te:"",
+                  (data->set.str[STRING_ENCODING] &&
+                   *data->set.str[STRING_ENCODING] &&
+                   data->state.aptr.accept_encoding)?
+                  data->state.aptr.accept_encoding:"",
+                  (data->state.referer && data->state.aptr.ref)?
+                  data->state.aptr.ref:"" /* Referer: <data> */,
+#ifndef CURL_DISABLE_PROXY
+                  (conn->bits.httpproxy &&
+                   !conn->bits.tunnel_proxy &&
+                   !Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
+                   !Curl_checkProxyheaders(data,
+                                           conn,
+                                           STRCONST("Proxy-Connection")))?
+                  "Proxy-Connection: Keep-Alive\r\n":"",
+#else
+                  "",
+#endif
+                  te,
+                  altused ? altused : ""
+      );
+
+  /* clear userpwd and proxyuserpwd to avoid reusing old credentials
+   * from reused connections */
+  Curl_safefree(data->state.aptr.userpwd);
+  Curl_safefree(data->state.aptr.proxyuserpwd);
+  free(altused);
+
+  if(result) {
+    Curl_dyn_free(&req);
+    goto fail;
+  }
+
+  if(!(conn->handler->flags&PROTOPT_SSL) &&
+     conn->httpversion < 20 &&
+     (data->state.httpwant == CURL_HTTP_VERSION_2)) {
+    /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
+       over SSL */
+    result = Curl_http2_request_upgrade(&req, data);
+    if(result) {
+      Curl_dyn_free(&req);
+      return result;
+    }
+  }
+
+  result = Curl_http_cookies(data, conn, &req);
+#ifdef USE_WEBSOCKETS
+  if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
+    result = Curl_ws_request(data, &req);
+#endif
+  if(!result)
+    result = Curl_add_timecondition(data, &req);
+  if(!result)
+    result = Curl_add_custom_headers(data, FALSE, &req);
+
+  if(!result) {
+    /* req_send takes ownership of the 'req' memory on success */
+    result = Curl_http_req_complete(data, &req, httpreq);
+    if(!result)
+      result = Curl_req_send(data, &req);
+  }
+  Curl_dyn_free(&req);
+  if(result)
+    goto fail;
+
+  if((conn->httpversion >= 20) && data->req.upload_chunky)
+    /* upload_chunky was set above to set up the request in a chunky fashion,
+       but is disabled here again to avoid that the chunked encoded version is
+       actually used when sending the request body over h2 */
+    data->req.upload_chunky = FALSE;
+fail:
+  if(CURLE_TOO_LARGE == result)
+    failf(data, "HTTP request too large");
+  return result;
+}
+
+#endif /* USE_HYPER */
+
+typedef enum {
+  STATUS_UNKNOWN, /* not enough data to tell yet */
+  STATUS_DONE, /* a status line was read */
+  STATUS_BAD /* not a status line */
+} statusline;
+
+
+/* Check a string for a prefix. Check no more than 'len' bytes */
+static bool checkprefixmax(const char *prefix, const char *buffer, size_t len)
+{
+  size_t ch = CURLMIN(strlen(prefix), len);
+  return curl_strnequal(prefix, buffer, ch);
+}
+
+/*
+ * checkhttpprefix()
+ *
+ * Returns TRUE if member of the list matches prefix of string
+ */
+static statusline
+checkhttpprefix(struct Curl_easy *data,
+                const char *s, size_t len)
+{
+  struct curl_slist *head = data->set.http200aliases;
+  statusline rc = STATUS_BAD;
+  statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
+
+  while(head) {
+    if(checkprefixmax(head->data, s, len)) {
+      rc = onmatch;
+      break;
+    }
+    head = head->next;
+  }
+
+  if((rc != STATUS_DONE) && (checkprefixmax("HTTP/", s, len)))
+    rc = onmatch;
+
+  return rc;
+}
+
+#ifndef CURL_DISABLE_RTSP
+static statusline
+checkrtspprefix(struct Curl_easy *data,
+                const char *s, size_t len)
+{
+  statusline result = STATUS_BAD;
+  statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
+  (void)data; /* unused */
+  if(checkprefixmax("RTSP/", s, len))
+    result = onmatch;
+
+  return result;
+}
+#endif /* CURL_DISABLE_RTSP */
+
+static statusline
+checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
+                 const char *s, size_t len)
+{
+#ifndef CURL_DISABLE_RTSP
+  if(conn->handler->protocol & CURLPROTO_RTSP)
+    return checkrtspprefix(data, s, len);
+#else
+  (void)conn;
+#endif /* CURL_DISABLE_RTSP */
+
+  return checkhttpprefix(data, s, len);
+}
+
+/* HTTP header has field name `n` (a string constant) */
+#define HD_IS(hd, hdlen, n) \
+  (((hdlen) >= (sizeof(n)-1)) && curl_strnequal((n), (hd), (sizeof(n)-1)))
+
+#define HD_VAL(hd, hdlen, n) \
+  ((((hdlen) >= (sizeof(n)-1)) && \
+    curl_strnequal((n), (hd), (sizeof(n)-1)))? (hd + (sizeof(n)-1)) : NULL)
+
+/* HTTP header has field name `n` (a string constant) and contains `v`
+ * (a string constant) in its value(s) */
+#define HD_IS_AND_SAYS(hd, hdlen, n, v) \
+  (HD_IS(hd, hdlen, n) && \
+   ((hdlen) > ((sizeof(n)-1) + (sizeof(v)-1))) && \
+   Curl_compareheader(hd, STRCONST(n), STRCONST(v)))
+
+/*
+ * Curl_http_header() parses a single response header.
+ */
+CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
+                          char *hd, size_t hdlen)
+{
+  CURLcode result;
+  struct SingleRequest *k = &data->req;
+  const char *v;
+
+  switch(hd[0]) {
+  case 'a':
+  case 'A':
+#ifndef CURL_DISABLE_ALTSVC
+    v = (data->asi &&
+         ((conn->handler->flags & PROTOPT_SSL) ||
+#ifdef CURLDEBUG
+          /* allow debug builds to circumvent the HTTPS restriction */
+          getenv("CURL_ALTSVC_HTTP")
+#else
+          0
+#endif
+        ))? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
+    if(v) {
+      /* the ALPN of the current request */
+      enum alpnid id = (conn->httpversion == 30)? ALPN_h3 :
+                         (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
+      return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name,
+                               curlx_uitous((unsigned int)conn->remote_port));
+    }
+#endif
+    break;
+  case 'c':
+  case 'C':
+    /* Check for Content-Length: header lines to get size */
+    v = (!k->http_bodyless && !data->set.ignorecl)?
+        HD_VAL(hd, hdlen, "Content-Length:") : NULL;
+    if(v) {
+      curl_off_t contentlength;
+      CURLofft offt = curlx_strtoofft(v, NULL, 10, &contentlength);
+
+      if(offt == CURL_OFFT_OK) {
+        k->size = contentlength;
+        k->maxdownload = k->size;
+      }
+      else if(offt == CURL_OFFT_FLOW) {
+        /* out of range */
+        if(data->set.max_filesize) {
+          failf(data, "Maximum file size exceeded");
+          return CURLE_FILESIZE_EXCEEDED;
+        }
+        streamclose(conn, "overflow content-length");
+        infof(data, "Overflow Content-Length: value");
+      }
+      else {
+        /* negative or just rubbish - bad HTTP */
+        failf(data, "Invalid Content-Length: value");
+        return CURLE_WEIRD_SERVER_REPLY;
+      }
+      return CURLE_OK;
+    }
+    v = (!k->http_bodyless && data->set.str[STRING_ENCODING])?
+        HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
+    if(v) {
+      /*
+       * Process Content-Encoding. Look for the values: identity,
+       * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
+       * x-compress are the same as gzip and compress. (Sec 3.5 RFC
+       * 2616). zlib cannot handle compress.  However, errors are
+       * handled further down when the response body is processed
+       */
+      return Curl_build_unencoding_stack(data, v, FALSE);
+    }
+    /* check for Content-Type: header lines to get the MIME-type */
+    v = HD_VAL(hd, hdlen, "Content-Type:");
+    if(v) {
+      char *contenttype = Curl_copy_header_value(hd);
+      if(!contenttype)
+        return CURLE_OUT_OF_MEMORY;
+      if(!*contenttype)
+        /* ignore empty data */
+        free(contenttype);
+      else {
+        Curl_safefree(data->info.contenttype);
+        data->info.contenttype = contenttype;
+      }
+      return CURLE_OK;
+    }
+    if(HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) {
+      /*
+       * [RFC 2616, section 8.1.2.1]
+       * "Connection: close" is HTTP/1.1 language and means that
+       * the connection will close when this request has been
+       * served.
+       */
+      streamclose(conn, "Connection: close used");
+      return CURLE_OK;
+    }
+    if((conn->httpversion == 10) &&
+       HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) {
+      /*
+       * An HTTP/1.0 reply with the 'Connection: keep-alive' line
+       * tells us the connection will be kept alive for our
+       * pleasure.  Default action for 1.0 is to close.
+       *
+       * [RFC2068, section 19.7.1] */
+      connkeep(conn, "Connection keep-alive");
+      infof(data, "HTTP/1.0 connection set to keep alive");
+      return CURLE_OK;
+    }
+    v = !k->http_bodyless? HD_VAL(hd, hdlen, "Content-Range:") : NULL;
+    if(v) {
+      /* Content-Range: bytes [num]-
+         Content-Range: bytes: [num]-
+         Content-Range: [num]-
+         Content-Range: [asterisk]/[total]
+
+         The second format was added since Sun's webserver
+         JavaWebServer/1.1.1 obviously sends the header this way!
+         The third added since some servers use that!
+         The fourth means the requested range was unsatisfied.
+      */
+
+      const char *ptr = v;
+
+      /* Move forward until first digit or asterisk */
+      while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
+        ptr++;
+
+      /* if it truly stopped on a digit */
+      if(ISDIGIT(*ptr)) {
+        if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
+          if(data->state.resume_from == k->offset)
+            /* we asked for a resume and we got it */
+            k->content_range = TRUE;
+        }
+      }
+      else if(k->httpcode < 300)
+        data->state.resume_from = 0; /* get everything */
+    }
+    break;
+  case 'l':
+  case 'L':
+    v = (!k->http_bodyless &&
+         (data->set.timecondition || data->set.get_filetime))?
+        HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
+    if(v) {
+      k->timeofdoc = Curl_getdate_capped(v);
+      if(data->set.get_filetime)
+        data->info.filetime = k->timeofdoc;
+      return CURLE_OK;
+    }
+    if((k->httpcode >= 300 && k->httpcode < 400) &&
+            HD_IS(hd, hdlen, "Location:") &&
+            !data->req.location) {
+      /* this is the URL that the server advises us to use instead */
+      char *location = Curl_copy_header_value(hd);
+      if(!location)
+        return CURLE_OUT_OF_MEMORY;
+      if(!*location)
+        /* ignore empty data */
+        free(location);
+      else {
+        data->req.location = location;
+
+        if(data->set.http_follow_location) {
+          DEBUGASSERT(!data->req.newurl);
+          data->req.newurl = strdup(data->req.location); /* clone */
+          if(!data->req.newurl)
+            return CURLE_OUT_OF_MEMORY;
+
+          /* some cases of POST and PUT etc needs to rewind the data
+             stream at this point */
+          result = http_perhapsrewind(data, conn);
+          if(result)
+            return result;
+
+          /* mark the next request as a followed location: */
+          data->state.this_is_a_follow = TRUE;
+        }
+      }
+    }
+    break;
+  case 'p':
+  case 'P':
+#ifndef CURL_DISABLE_PROXY
+    v = HD_VAL(hd, hdlen, "Proxy-Connection:");
+    if(v) {
+      if((conn->httpversion == 10) && conn->bits.httpproxy &&
+         HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) {
+        /*
+         * When an HTTP/1.0 reply comes when using a proxy, the
+         * 'Proxy-Connection: keep-alive' line tells us the
+         * connection will be kept alive for our pleasure.
+         * Default action for 1.0 is to close.
+         */
+        connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
+        infof(data, "HTTP/1.0 proxy connection set to keep alive");
+      }
+      else if((conn->httpversion == 11) && conn->bits.httpproxy &&
+              HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
+        /*
+         * We get an HTTP/1.1 response from a proxy and it says it'll
+         * close down after this transfer.
+         */
+        connclose(conn, "Proxy-Connection: asked to close after done");
+        infof(data, "HTTP/1.1 proxy connection set close");
+      }
+      return CURLE_OK;
+    }
+#endif
+    if((407 == k->httpcode) && HD_IS(hd, hdlen, "Proxy-authenticate:")) {
+      char *auth = Curl_copy_header_value(hd);
+      if(!auth)
+        return CURLE_OUT_OF_MEMORY;
+      result = Curl_http_input_auth(data, TRUE, auth);
+      free(auth);
+      return result;
+    }
+#ifdef USE_SPNEGO
+    if(HD_IS(hd, hdlen, "Persistent-Auth:")) {
+      struct negotiatedata *negdata = &conn->negotiate;
+      struct auth *authp = &data->state.authhost;
+      if(authp->picked == CURLAUTH_NEGOTIATE) {
+        char *persistentauth = Curl_copy_header_value(hd);
+        if(!persistentauth)
+          return CURLE_OUT_OF_MEMORY;
+        negdata->noauthpersist = checkprefix("false", persistentauth)?
+          TRUE:FALSE;
+        negdata->havenoauthpersist = TRUE;
+        infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
+              negdata->noauthpersist, persistentauth);
+        free(persistentauth);
+      }
+    }
+#endif
+    break;
+  case 'r':
+  case 'R':
+    v = HD_VAL(hd, hdlen, "Retry-After:");
+    if(v) {
+      /* Retry-After = HTTP-date / delay-seconds */
+      curl_off_t retry_after = 0; /* zero for unknown or "now" */
+      /* Try it as a decimal number, if it works it is not a date */
+      (void)curlx_strtoofft(v, NULL, 10, &retry_after);
+      if(!retry_after) {
+        time_t date = Curl_getdate_capped(v);
+        if(-1 != date)
+          /* convert date to number of seconds into the future */
+          retry_after = date - time(NULL);
+      }
+      data->info.retry_after = retry_after; /* store it */
+      return CURLE_OK;
+    }
+    break;
+  case 's':
+  case 'S':
+#if !defined(CURL_DISABLE_COOKIES)
+    v = (data->cookies && data->state.cookie_engine)?
+        HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
+    if(v) {
+      /* If there is a custom-set Host: name, use it here, or else use
+       * real peer host name. */
+      const char *host = data->state.aptr.cookiehost?
+        data->state.aptr.cookiehost:conn->host.name;
+      const bool secure_context =
+        conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
+        strcasecompare("localhost", host) ||
+        !strcmp(host, "127.0.0.1") ||
+        !strcmp(host, "::1") ? TRUE : FALSE;
+
+      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
+                      CURL_LOCK_ACCESS_SINGLE);
+      Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host,
+                      data->state.up.path, secure_context);
+      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+      return CURLE_OK;
+    }
+#endif
+#ifndef CURL_DISABLE_HSTS
+    /* If enabled, the header is incoming and this is over HTTPS */
+    v = (data->hsts &&
+         ((conn->handler->flags & PROTOPT_SSL) ||
+#ifdef CURLDEBUG
+           /* allow debug builds to circumvent the HTTPS restriction */
+           getenv("CURL_HSTS_HTTP")
+#else
+           0
+#endif
+            )
+        )? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
+    if(v) {
+      CURLcode check =
+        Curl_hsts_parse(data->hsts, conn->host.name, v);
+      if(check)
+        infof(data, "Illegal STS header skipped");
+#ifdef DEBUGBUILD
+      else
+        infof(data, "Parsed STS header fine (%zu entries)",
+              data->hsts->list.size);
+#endif
+    }
+#endif
+    break;
+  case 't':
+  case 'T':
+    v = !k->http_bodyless? HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
+    if(v) {
+      /* One or more encodings. We check for chunked and/or a compression
+         algorithm. */
+      /*
+       * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
+       * means that the server will send a series of "chunks". Each
+       * chunk starts with line with info (including size of the
+       * coming block) (terminated with CRLF), then a block of data
+       * with the previously mentioned size. There can be any amount
+       * of chunks, and a chunk-data set to zero signals the
+       * end-of-chunks. */
+
+      result = Curl_build_unencoding_stack(data, v, TRUE);
+      if(result)
+        return result;
+      if(!k->chunk && data->set.http_transfer_encoding) {
+        /* if this isn't chunked, only close can signal the end of this
+         * transfer as Content-Length is said not to be trusted for
+         * transfer-encoding! */
+        connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
+        k->ignore_cl = TRUE;
+      }
+      return CURLE_OK;
+    }
+    break;
+  case 'w':
+  case 'W':
+    if((401 == k->httpcode) && HD_IS(hd, hdlen, "WWW-Authenticate:")) {
+      char *auth = Curl_copy_header_value(hd);
+      if(!auth)
+        return CURLE_OUT_OF_MEMORY;
+      result = Curl_http_input_auth(data, FALSE, auth);
+      free(auth);
+      return result;
+    }
+    break;
+  }
+
+  if(conn->handler->protocol & CURLPROTO_RTSP) {
+    result = Curl_rtsp_parseheader(data, hd);
+    if(result)
+      return result;
+  }
+  return CURLE_OK;
+}
+
+/*
+ * Called after the first HTTP response line (the status line) has been
+ * received and parsed.
+ */
+CURLcode Curl_http_statusline(struct Curl_easy *data,
+                              struct connectdata *conn)
+{
+  struct SingleRequest *k = &data->req;
+
+  switch(k->httpversion) {
+  case 10:
+  case 11:
+#ifdef USE_HTTP2
+  case 20:
+#endif
+#ifdef ENABLE_QUIC
+  case 30:
+#endif
+    /* TODO: we should verify that responses do not switch major
+     * HTTP version of the connection. Now, it seems we might accept
+     * a HTTP/2 response on a HTTP/1.1 connection, which is wrong. */
+    conn->httpversion = (unsigned char)k->httpversion;
+    break;
+  default:
+    failf(data, "Unsupported HTTP version (%u.%d) in response",
+          k->httpversion/10, k->httpversion%10);
+    return CURLE_UNSUPPORTED_PROTOCOL;
+  }
+
+  data->info.httpcode = k->httpcode;
+  data->info.httpversion = k->httpversion;
+  conn->httpversion = (unsigned char)k->httpversion;
+
+  if(!data->state.httpversion || data->state.httpversion > k->httpversion)
+    /* store the lowest server version we encounter */
+    data->state.httpversion = (unsigned char)k->httpversion;
+
+  /*
+   * This code executes as part of processing the header.  As a
+   * result, it's not totally clear how to interpret the
+   * response code yet as that depends on what other headers may
+   * be present.  401 and 407 may be errors, but may be OK
+   * depending on how authentication is working.  Other codes
+   * are definitely errors, so give up here.
+   */
+  if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
+     k->httpcode == 416) {
+    /* "Requested Range Not Satisfiable", just proceed and
+       pretend this is no error */
+    k->ignorebody = TRUE; /* Avoid appending error msg to good data. */
+  }
+
+  if(k->httpversion == 10) {
+    /* Default action for HTTP/1.0 must be to close, unless
+       we get one of those fancy headers that tell us the
+       server keeps it open for us! */
+    infof(data, "HTTP 1.0, assume close after body");
+    connclose(conn, "HTTP/1.0 close after body");
+  }
+  else if(k->httpversion == 20 ||
+          (k->upgr101 == UPGR101_H2 && k->httpcode == 101)) {
+    DEBUGF(infof(data, "HTTP/2 found, allow multiplexing"));
+    /* HTTP/2 cannot avoid multiplexing since it is a core functionality
+       of the protocol */
+    conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+  }
+  else if(k->httpversion >= 11 && !conn->bits.close) {
+    /* If HTTP version is >= 1.1 and connection is persistent */
+    DEBUGF(infof(data, "HTTP 1.1 or later with persistent connection"));
+  }
+
+  k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
+  switch(k->httpcode) {
+  case 304:
+    /* (quote from RFC2616, section 10.3.5): The 304 response
+     * MUST NOT contain a message-body, and thus is always
+     * terminated by the first empty line after the header
+     * fields.  */
+    if(data->set.timecondition)
+      data->info.timecond = TRUE;
+    FALLTHROUGH();
+  case 204:
+    /* (quote from RFC2616, section 10.2.5): The server has
+     * fulfilled the request but does not need to return an
+     * entity-body ... The 204 response MUST NOT include a
+     * message-body, and thus is always terminated by the first
+     * empty line after the header fields. */
+    k->size = 0;
+    k->maxdownload = 0;
+    k->http_bodyless = TRUE;
+    break;
+  default:
+    break;
+  }
+  return CURLE_OK;
+}
+
+/* Content-Length must be ignored if any Transfer-Encoding is present in the
+   response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4.  This is
+   figured out here after all headers have been received but before the final
+   call to the user's header callback, so that a valid content length can be
+   retrieved by the user in the final call. */
+CURLcode Curl_http_size(struct Curl_easy *data)
+{
+  struct SingleRequest *k = &data->req;
+  if(data->req.ignore_cl || k->chunk) {
+    k->size = k->maxdownload = -1;
+  }
+  else if(k->size != -1) {
+    if(data->set.max_filesize &&
+       k->size > data->set.max_filesize) {
+      failf(data, "Maximum file size exceeded");
+      return CURLE_FILESIZE_EXCEEDED;
+    }
+    Curl_pgrsSetDownloadSize(data, k->size);
+    k->maxdownload = k->size;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode verify_header(struct Curl_easy *data)
+{
+  struct SingleRequest *k = &data->req;
+  const char *header = Curl_dyn_ptr(&data->state.headerb);
+  size_t hlen = Curl_dyn_len(&data->state.headerb);
+  char *ptr = memchr(header, 0x00, hlen);
+  if(ptr) {
+    /* this is bad, bail out */
+    failf(data, "Nul byte in header");
+    return CURLE_WEIRD_SERVER_REPLY;
+  }
+  if(k->headerline < 2)
+    /* the first "header" is the status-line and it has no colon */
+    return CURLE_OK;
+  if(((header[0] == ' ') || (header[0] == '\t')) && k->headerline > 2)
+    /* line folding, can't happen on line 2 */
+    ;
+  else {
+    ptr = memchr(header, ':', hlen);
+    if(!ptr) {
+      /* this is bad, bail out */
+      failf(data, "Header without colon");
+      return CURLE_WEIRD_SERVER_REPLY;
+    }
+  }
+  return CURLE_OK;
+}
+
+CURLcode Curl_bump_headersize(struct Curl_easy *data,
+                              size_t delta,
+                              bool connect_only)
+{
+  size_t bad = 0;
+  unsigned int max = MAX_HTTP_RESP_HEADER_SIZE;
+  if(delta < MAX_HTTP_RESP_HEADER_SIZE) {
+    data->info.header_size += (unsigned int)delta;
+    data->req.allheadercount += (unsigned int)delta;
+    if(!connect_only)
+      data->req.headerbytecount += (unsigned int)delta;
+    if(data->req.allheadercount > max)
+      bad = data->req.allheadercount;
+    else if(data->info.header_size > (max * 20)) {
+      bad = data->info.header_size;
+      max *= 20;
+    }
+  }
+  else
+    bad = data->req.allheadercount + delta;
+  if(bad) {
+    failf(data, "Too large response headers: %zu > %u", bad, max);
+    return CURLE_RECV_ERROR;
+  }
+  return CURLE_OK;
+}
+
+
+static CURLcode http_on_response(struct Curl_easy *data,
+                                 const char *buf, size_t blen,
+                                 size_t *pconsumed)
+{
+  struct connectdata *conn = data->conn;
+  CURLcode result = CURLE_OK;
+  struct SingleRequest *k = &data->req;
+  bool switch_to_h2 = FALSE;
+
+  (void)buf; /* not used without HTTP2 enabled */
+  *pconsumed = 0;
+
+  if(k->upgr101 == UPGR101_RECEIVED) {
+    /* supposedly upgraded to http2 now */
+    if(conn->httpversion != 20)
+      infof(data, "Lying server, not serving HTTP/2");
+  }
+  if(conn->httpversion < 20) {
+    conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
+  }
+
+  if(k->httpcode < 100) {
+    failf(data, "Unsupported response code in HTTP response");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+  }
+  else if(k->httpcode < 200) {
+    /* "A user agent MAY ignore unexpected 1xx status responses." */
+    switch(k->httpcode) {
+    case 100:
+      /*
+       * We have made an HTTP PUT or POST and this is 1.1-lingo
+       * that tells us that the server is OK with this and ready
+       * to receive the data.
+       * However, we'll get more headers now so we must get
+       * back into the header-parsing state!
+       */
+      k->header = TRUE;
+      k->headerline = 0; /* restart the header line counter */
+
+      /* if we did wait for this do enable write now! */
+      Curl_http_exp100_got100(data);
+      break;
+    case 101:
+      if(conn->httpversion == 11) {
+        /* Switching Protocols only allowed from HTTP/1.1 */
+        if(k->upgr101 == UPGR101_H2) {
+          /* Switching to HTTP/2 */
+          infof(data, "Received 101, Switching to HTTP/2");
+          k->upgr101 = UPGR101_RECEIVED;
+
+          /* we'll get more headers (HTTP/2 response) */
+          k->header = TRUE;
+          k->headerline = 0; /* restart the header line counter */
+          switch_to_h2 = TRUE;
+        }
+#ifdef USE_WEBSOCKETS
+        else if(k->upgr101 == UPGR101_WS) {
+          /* verify the response */
+          result = Curl_ws_accept(data, buf, blen);
+          if(result)
+            return result;
+          k->header = FALSE; /* no more header to parse! */
+          *pconsumed += blen; /* ws accept handled the data */
+          blen = 0;
+          if(data->set.connect_only)
+            k->keepon &= ~KEEP_RECV; /* read no more content */
+        }
+#endif
+        else {
+          /* Not switching to another protocol */
+          k->header = FALSE; /* no more header to parse! */
+        }
+      }
+      else {
+        /* invalid for other HTTP versions */
+        failf(data, "unexpected 101 response code");
+        return CURLE_WEIRD_SERVER_REPLY;
+      }
+      break;
+    default:
+      /* the status code 1xx indicates a provisional response, so
+         we'll get another set of headers */
+      k->header = TRUE;
+      k->headerline = 0; /* restart the header line counter */
+      break;
+    }
+  }
+  else {
+    /* k->httpcode >= 200, final response */
+    k->header = FALSE;
+
+    if(k->upgr101 == UPGR101_H2) {
+      /* A requested upgrade was denied, poke the multi handle to possibly
+         allow a pending pipewait to continue */
+      Curl_multi_connchanged(data->multi);
+    }
+
+    if((k->size == -1) && !k->chunk && !conn->bits.close &&
+       (conn->httpversion == 11) &&
+       !(conn->handler->protocol & CURLPROTO_RTSP) &&
+       data->state.httpreq != HTTPREQ_HEAD) {
+      /* On HTTP 1.1, when connection is not to get closed, but no
+         Content-Length nor Transfer-Encoding chunked have been
+         received, according to RFC2616 section 4.4 point 5, we
+         assume that the server will close the connection to
+         signal the end of the document. */
+      infof(data, "no chunk, no close, no size. Assume close to "
+            "signal end");
+      streamclose(conn, "HTTP: No end-of-message indicator");
+    }
+  }
+
+  if(!k->header) {
+    result = Curl_http_size(data);
+    if(result)
+      return result;
+  }
+
+  /* At this point we have some idea about the fate of the connection.
+     If we are closing the connection it may result auth failure. */
+#if defined(USE_NTLM)
+  if(conn->bits.close &&
+     (((data->req.httpcode == 401) &&
+       (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
+      ((data->req.httpcode == 407) &&
+       (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
+    infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
+    data->state.authproblem = TRUE;
+  }
+#endif
+#if defined(USE_SPNEGO)
+  if(conn->bits.close &&
+    (((data->req.httpcode == 401) &&
+      (conn->http_negotiate_state == GSS_AUTHRECV)) ||
+     ((data->req.httpcode == 407) &&
+      (conn->proxy_negotiate_state == GSS_AUTHRECV)))) {
+    infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
+    data->state.authproblem = TRUE;
+  }
+  if((conn->http_negotiate_state == GSS_AUTHDONE) &&
+     (data->req.httpcode != 401)) {
+    conn->http_negotiate_state = GSS_AUTHSUCC;
+  }
+  if((conn->proxy_negotiate_state == GSS_AUTHDONE) &&
+     (data->req.httpcode != 407)) {
+    conn->proxy_negotiate_state = GSS_AUTHSUCC;
+  }
+#endif
+
+  /*
+   * When all the headers have been parsed, see if we should give
+   * up and return an error.
+   */
+  if(http_should_fail(data)) {
+    failf(data, "The requested URL returned error: %d",
+          k->httpcode);
+    return CURLE_HTTP_RETURNED_ERROR;
+  }
+
+#ifdef USE_WEBSOCKETS
+  /* All non-101 HTTP status codes are bad when wanting to upgrade to
+     websockets */
+  if(data->req.upgr101 == UPGR101_WS) {
+    failf(data, "Refused WebSockets upgrade: %d", k->httpcode);
+    return CURLE_HTTP_RETURNED_ERROR;
+  }
+#endif
+
+
+  /* Curl_http_auth_act() checks what authentication methods
+   * that are available and decides which one (if any) to
+   * use. It will set 'newurl' if an auth method was picked. */
+  result = Curl_http_auth_act(data);
+
+  if(result)
+    return result;
+
+  if(k->httpcode >= 300) {
+    if((!data->req.authneg) && !conn->bits.close &&
+       !Curl_creader_will_rewind(data)) {
+      /*
+       * General treatment of errors when about to send data. Including :
+       * "417 Expectation Failed", while waiting for 100-continue.
+       *
+       * The check for close above is done simply because of something
+       * else has already deemed the connection to get closed then
+       * something else should've considered the big picture and we
+       * avoid this check.
+       *
+       */
+
+      switch(data->state.httpreq) {
+      case HTTPREQ_PUT:
+      case HTTPREQ_POST:
+      case HTTPREQ_POST_FORM:
+      case HTTPREQ_POST_MIME:
+        /* We got an error response. If this happened before the whole
+         * request body has been sent we stop sending and mark the
+         * connection for closure after we've read the entire response.
+         */
+        if(!Curl_req_done_sending(data)) {
+          if((k->httpcode == 417) && Curl_http_exp100_is_selected(data)) {
+            /* 417 Expectation Failed - try again without the Expect
+               header */
+            if(!k->writebytecount && http_exp100_is_waiting(data)) {
+              infof(data, "Got HTTP failure 417 while waiting for a 100");
+            }
+            else {
+              infof(data, "Got HTTP failure 417 while sending data");
+              streamclose(conn,
+                          "Stop sending data before everything sent");
+              result = http_perhapsrewind(data, conn);
+              if(result)
+                return result;
+            }
+            data->state.disableexpect = TRUE;
+            DEBUGASSERT(!data->req.newurl);
+            data->req.newurl = strdup(data->state.url);
+            Curl_req_abort_sending(data);
+          }
+          else if(data->set.http_keep_sending_on_error) {
+            infof(data, "HTTP error before end of send, keep sending");
+            http_exp100_send_anyway(data);
+          }
+          else {
+            infof(data, "HTTP error before end of send, stop sending");
+            streamclose(conn, "Stop sending data before everything sent");
+            result = Curl_req_abort_sending(data);
+            if(result)
+              return result;
+          }
+        }
+        break;
+
+      default: /* default label present to avoid compiler warnings */
+        break;
+      }
+    }
+
+    if(Curl_creader_will_rewind(data) && !Curl_req_done_sending(data)) {
+      /* We rewind before next send, continue sending now */
+      infof(data, "Keep sending data to get tossed away");
+      k->keepon |= KEEP_SEND;
+    }
+  }
+
+  if(!k->header) {
+    /*
+     * really end-of-headers.
+     *
+     * If we requested a "no body", this is a good time to get
+     * out and return home.
+     */
+    if(data->req.no_body)
+      k->download_done = TRUE;
+
+    /* If max download size is *zero* (nothing) we already have
+       nothing and can safely return ok now!  But for HTTP/2, we'd
+       like to call http2_handle_stream_close to properly close a
+       stream.  In order to do this, we keep reading until we
+       close the stream. */
+    if(0 == k->maxdownload
+       && !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
+       && !Curl_conn_is_http3(data, conn, FIRSTSOCKET))
+      k->download_done = TRUE;
+  }
+
+  if(switch_to_h2) {
+    /* Having handled the headers, we can do the HTTP/2 switch.
+     * Any remaining `buf` bytes are already HTTP/2 and passed to
+     * be processed. */
+    result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
+    if(result)
+      return result;
+    *pconsumed += blen;
+  }
+
+  return CURLE_OK;
+}
+/*
+ * Read any HTTP header lines from the server and pass them to the client app.
+ */
+static CURLcode http_rw_headers(struct Curl_easy *data,
+                                const char *buf, size_t blen,
+                                size_t *pconsumed)
+{
+  struct connectdata *conn = data->conn;
+  CURLcode result = CURLE_OK;
+  struct SingleRequest *k = &data->req;
+  char *hd;
+  size_t hdlen;
+  char *end_ptr;
+  bool leftover_body = FALSE;
+
+  /* header line within buffer loop */
+  *pconsumed = 0;
+  do {
+    size_t line_length;
+    int writetype;
+
+    /* data is in network encoding so use 0x0a instead of '\n' */
+    end_ptr = memchr(buf, 0x0a, blen);
+
+    if(!end_ptr) {
+      /* Not a complete header line within buffer, append the data to
+         the end of the headerbuff. */
+      result = Curl_dyn_addn(&data->state.headerb, buf, blen);
+      if(result)
+        return result;
+      *pconsumed += blen;
+
+      if(!k->headerline) {
+        /* check if this looks like a protocol header */
+        statusline st =
+          checkprotoprefix(data, conn,
+                           Curl_dyn_ptr(&data->state.headerb),
+                           Curl_dyn_len(&data->state.headerb));
+
+        if(st == STATUS_BAD) {
+          /* this is not the beginning of a protocol first header line */
+          k->header = FALSE;
+          streamclose(conn, "bad HTTP: No end-of-message indicator");
+          if(conn->httpversion >= 10) {
+            failf(data, "Invalid status line");
+            return CURLE_WEIRD_SERVER_REPLY;
+          }
+          if(!data->set.http09_allowed) {
+            failf(data, "Received HTTP/0.9 when not allowed");
+            return CURLE_UNSUPPORTED_PROTOCOL;
+          }
+          leftover_body = TRUE;
+          goto out;
+        }
+      }
+      goto out; /* read more and try again */
+    }
+
+    /* decrease the size of the remaining (supposed) header line */
+    line_length = (end_ptr - buf) + 1;
+    result = Curl_dyn_addn(&data->state.headerb, buf, line_length);
+    if(result)
+      return result;
+
+    blen -= line_length;
+    buf += line_length;
+    *pconsumed += line_length;
+
+    /****
+     * We now have a FULL header line in 'headerb'.
+     *****/
+
+    if(!k->headerline) {
+      /* the first read header */
+      statusline st = checkprotoprefix(data, conn,
+                                       Curl_dyn_ptr(&data->state.headerb),
+                                       Curl_dyn_len(&data->state.headerb));
+      if(st == STATUS_BAD) {
+        streamclose(conn, "bad HTTP: No end-of-message indicator");
+        /* this is not the beginning of a protocol first header line */
+        if(conn->httpversion >= 10) {
+          failf(data, "Invalid status line");
+          return CURLE_WEIRD_SERVER_REPLY;
+        }
+        if(!data->set.http09_allowed) {
+          failf(data, "Received HTTP/0.9 when not allowed");
+          return CURLE_UNSUPPORTED_PROTOCOL;
+        }
+        k->header = FALSE;
+        leftover_body = TRUE;
+        goto out;
+      }
+    }
+
+    /* headers are in network encoding so use 0x0a and 0x0d instead of '\n'
+       and '\r' */
+    hd = Curl_dyn_ptr(&data->state.headerb);
+    hdlen = Curl_dyn_len(&data->state.headerb);
+    if((0x0a == *hd) || (0x0d == *hd)) {
+      /* Empty header line means end of headers! */
+      size_t consumed;
+
+      /* now, only output this if the header AND body are requested:
+       */
+      Curl_debug(data, CURLINFO_HEADER_IN, hd, hdlen);
+
+      writetype = CLIENTWRITE_HEADER |
+        ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
+
+      result = Curl_client_write(data, writetype, hd, hdlen);
+      if(result)
+        return result;
+
+      result = Curl_bump_headersize(data, hdlen, FALSE);
+      if(result)
+        return result;
+      /* We are done with this line. We reset because response
+       * processing might switch to HTTP/2 and that might call us
+       * directly again. */
+      Curl_dyn_reset(&data->state.headerb);
+
+      data->req.deductheadercount =
+        (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
+
+      /* analyze the response to find out what to do */
+      result = http_on_response(data, buf, blen, &consumed);
+      if(result)
+        return result;
+      *pconsumed += consumed;
+      blen -= consumed;
+      buf += consumed;
+
+      if(!k->header || !blen)
+        goto out; /* exit header line loop */
+
+      continue;
+    }
+
+    /*
+     * Checks for special headers coming up.
+     */
+
+    writetype = CLIENTWRITE_HEADER;
+    if(!k->headerline++) {
+      /* This is the first header, it MUST be the error code line
+         or else we consider this to be the body right away! */
+      bool fine_statusline = FALSE;
+
+      k->httpversion = 0; /* Don't know yet */
+      if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
+        /*
+         * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
+         *
+         * The response code is always a three-digit number in HTTP as the spec
+         * says. We allow any three-digit number here, but we cannot make
+         * guarantees on future behaviors since it isn't within the protocol.
+         */
+        char *p = hd;
+
+        while(*p && ISBLANK(*p))
+          p++;
+        if(!strncmp(p, "HTTP/", 5)) {
+          p += 5;
+          switch(*p) {
+          case '1':
+            p++;
+            if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) {
+              if(ISBLANK(p[2])) {
+                k->httpversion = 10 + (p[1] - '0');
+                p += 3;
+                if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
+                  k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
+                    (p[2] - '0');
+                  p += 3;
+                  if(ISSPACE(*p))
+                    fine_statusline = TRUE;
+                }
+              }
+            }
+            if(!fine_statusline) {
+              failf(data, "Unsupported HTTP/1 subversion in response");
+              return CURLE_UNSUPPORTED_PROTOCOL;
+            }
+            break;
+          case '2':
+          case '3':
+            if(!ISBLANK(p[1]))
+              break;
+            k->httpversion = (*p - '0') * 10;
+            p += 2;
+            if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
+              k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
+                (p[2] - '0');
+              p += 3;
+              if(!ISSPACE(*p))
+                break;
+              fine_statusline = TRUE;
+            }
+            break;
+          default: /* unsupported */
+            failf(data, "Unsupported HTTP version in response");
+            return CURLE_UNSUPPORTED_PROTOCOL;
+          }
+        }
+
+        if(!fine_statusline) {
+          /* If user has set option HTTP200ALIASES,
+             compare header line against list of aliases
+          */
+          statusline check = checkhttpprefix(data, hd, hdlen);
+          if(check == STATUS_DONE) {
+            fine_statusline = TRUE;
+            k->httpcode = 200;
+            k->httpversion = 10;
+          }
+        }
+      }
+      else if(conn->handler->protocol & CURLPROTO_RTSP) {
+        char *p = hd;
+        while(*p && ISBLANK(*p))
+          p++;
+        if(!strncmp(p, "RTSP/", 5)) {
+          p += 5;
+          if(ISDIGIT(*p)) {
+            p++;
+            if((p[0] == '.') && ISDIGIT(p[1])) {
+              if(ISBLANK(p[2])) {
+                p += 3;
+                if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
+                  k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
+                    (p[2] - '0');
+                  p += 3;
+                  if(ISSPACE(*p)) {
+                    fine_statusline = TRUE;
+                    k->httpversion = 11; /* RTSP acts like HTTP 1.1 */
+                  }
+                }
+              }
+            }
+          }
+          if(!fine_statusline)
+            return CURLE_WEIRD_SERVER_REPLY;
+        }
+      }
+
+      if(fine_statusline) {
+        result = Curl_http_statusline(data, conn);
+        if(result)
+          return result;
+        writetype |= CLIENTWRITE_STATUS;
+      }
+      else {
+        k->header = FALSE;   /* this is not a header line */
+        break;
+      }
+    }
+
+    result = verify_header(data);
+    if(result)
+      return result;
+
+    result = Curl_http_header(data, conn, hd, hdlen);
+    if(result)
+      return result;
+
+    /*
+     * Taken in one (more) header. Write it to the client.
+     */
+    Curl_debug(data, CURLINFO_HEADER_IN, hd, hdlen);
+
+    if(k->httpcode/100 == 1)
+      writetype |= CLIENTWRITE_1XX;
+    result = Curl_client_write(data, writetype, hd, hdlen);
+    if(result)
+      return result;
+
+    result = Curl_bump_headersize(data, hdlen, FALSE);
+    if(result)
+      return result;
+
+    Curl_dyn_reset(&data->state.headerb);
+  }
+  while(blen);
+
+  /* We might have reached the end of the header part here, but
+     there might be a non-header part left in the end of the read
+     buffer. */
+out:
+  if(!k->header && !leftover_body) {
+    Curl_dyn_free(&data->state.headerb);
+  }
+  return CURLE_OK;
+}
+
+/*
+ * HTTP protocol `write_resp` implementation. Will parse headers
+ * when not done yet and otherwise return without consuming data.
+ */
+CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
+                                  const char *buf, size_t blen,
+                                  size_t *pconsumed)
+{
+  if(!data->req.header) {
+    *pconsumed = 0;
+    return CURLE_OK;
+  }
+  else {
+    CURLcode result;
+
+    result = http_rw_headers(data, buf, blen, pconsumed);
+    if(!result && !data->req.header) {
+      /* we have successfully finished parsing the HEADERs */
+      result = Curl_http_firstwrite(data);
+
+      if(!data->req.no_body && Curl_dyn_len(&data->state.headerb)) {
+        /* leftover from parsing something that turned out not
+         * to be a header, only happens if we allow for
+         * HTTP/0.9 like responses */
+        result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                   Curl_dyn_ptr(&data->state.headerb),
+                                   Curl_dyn_len(&data->state.headerb));
+      }
+      Curl_dyn_free(&data->state.headerb);
+    }
+    return result;
+  }
+}
+
+CURLcode Curl_http_write_resp(struct Curl_easy *data,
+                              const char *buf, size_t blen,
+                              bool is_eos)
+{
+  CURLcode result;
+  size_t consumed;
+  int flags;
+
+  result = Curl_http_write_resp_hds(data, buf, blen, &consumed);
+  if(result || data->req.done)
+    goto out;
+
+  DEBUGASSERT(consumed <= blen);
+  blen -= consumed;
+  buf += consumed;
+  /* either all was consumed in header parsing, or we have data left
+   * and are done with headers, e.g. it is BODY data */
+  DEBUGASSERT(!blen || !data->req.header);
+  if(!data->req.header && (blen || is_eos)) {
+    /* BODY data after header been parsed, write and consume */
+    flags = CLIENTWRITE_BODY;
+    if(is_eos)
+      flags |= CLIENTWRITE_EOS;
+    result = Curl_client_write(data, flags, (char *)buf, blen);
+  }
+out:
+  return result;
+}
+
+/* Decode HTTP status code string. */
+CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len)
+{
+  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
+  int status = 0;
+  int i;
+
+  if(len != 3)
+    goto out;
+
+  for(i = 0; i < 3; ++i) {
+    char c = s[i];
+
+    if(c < '0' || c > '9')
+      goto out;
+
+    status *= 10;
+    status += c - '0';
+  }
+  result = CURLE_OK;
+out:
+  *pstatus = result? -1 : status;
+  return result;
+}
+
+CURLcode Curl_http_req_make(struct httpreq **preq,
+                            const char *method, size_t m_len,
+                            const char *scheme, size_t s_len,
+                            const char *authority, size_t a_len,
+                            const char *path, size_t p_len)
+{
+  struct httpreq *req;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+
+  DEBUGASSERT(method);
+  if(m_len + 1 > sizeof(req->method))
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  req = calloc(1, sizeof(*req));
+  if(!req)
+    goto out;
+  memcpy(req->method, method, m_len);
+  if(scheme) {
+    req->scheme = Curl_memdup0(scheme, s_len);
+    if(!req->scheme)
+      goto out;
+  }
+  if(authority) {
+    req->authority = Curl_memdup0(authority, a_len);
+    if(!req->authority)
+      goto out;
+  }
+  if(path) {
+    req->path = Curl_memdup0(path, p_len);
+    if(!req->path)
+      goto out;
+  }
+  Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST);
+  Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST);
+  result = CURLE_OK;
+
+out:
+  if(result && req)
+    Curl_http_req_free(req);
+  *preq = result? NULL : req;
+  return result;
+}
+
+static CURLcode req_assign_url_authority(struct httpreq *req, CURLU *url)
+{
+  char *user, *pass, *host, *port;
+  struct dynbuf buf;
+  CURLUcode uc;
+  CURLcode result = CURLE_URL_MALFORMAT;
+
+  user = pass = host = port = NULL;
+  Curl_dyn_init(&buf, DYN_HTTP_REQUEST);
+
+  uc = curl_url_get(url, CURLUPART_HOST, &host, 0);
+  if(uc && uc != CURLUE_NO_HOST)
+    goto out;
+  if(!host) {
+    req->authority = NULL;
+    result = CURLE_OK;
+    goto out;
+  }
+
+  uc = curl_url_get(url, CURLUPART_PORT, &port, CURLU_NO_DEFAULT_PORT);
+  if(uc && uc != CURLUE_NO_PORT)
+    goto out;
+  uc = curl_url_get(url, CURLUPART_USER, &user, 0);
+  if(uc && uc != CURLUE_NO_USER)
+    goto out;
+  if(user) {
+    uc = curl_url_get(url, CURLUPART_PASSWORD, &pass, 0);
+    if(uc && uc != CURLUE_NO_PASSWORD)
+      goto out;
+  }
+
+  if(user) {
+    result = Curl_dyn_add(&buf, user);
+    if(result)
+      goto out;
+    if(pass) {
+      result = Curl_dyn_addf(&buf, ":%s", pass);
+      if(result)
+        goto out;
+    }
+    result = Curl_dyn_add(&buf, "@");
+    if(result)
+      goto out;
+  }
+  result = Curl_dyn_add(&buf, host);
+  if(result)
+    goto out;
+  if(port) {
+    result = Curl_dyn_addf(&buf, ":%s", port);
+    if(result)
+      goto out;
+  }
+  req->authority = strdup(Curl_dyn_ptr(&buf));
+  if(!req->authority)
+    goto out;
+  result = CURLE_OK;
+
+out:
+  free(user);
+  free(pass);
+  free(host);
+  free(port);
+  Curl_dyn_free(&buf);
+  return result;
+}
+
+static CURLcode req_assign_url_path(struct httpreq *req, CURLU *url)
+{
+  char *path, *query;
+  struct dynbuf buf;
+  CURLUcode uc;
+  CURLcode result = CURLE_URL_MALFORMAT;
+
+  path = query = NULL;
+  Curl_dyn_init(&buf, DYN_HTTP_REQUEST);
+
+  uc = curl_url_get(url, CURLUPART_PATH, &path, CURLU_PATH_AS_IS);
+  if(uc)
+    goto out;
+  uc = curl_url_get(url, CURLUPART_QUERY, &query, 0);
+  if(uc && uc != CURLUE_NO_QUERY)
+    goto out;
+
+  if(!path && !query) {
+    req->path = NULL;
+  }
+  else if(path && !query) {
+    req->path = path;
+    path = NULL;
+  }
+  else {
+    if(path) {
+      result = Curl_dyn_add(&buf, path);
+      if(result)
+        goto out;
+    }
+    if(query) {
+      result = Curl_dyn_addf(&buf, "?%s", query);
+      if(result)
+        goto out;
+    }
+    req->path = strdup(Curl_dyn_ptr(&buf));
+    if(!req->path)
+      goto out;
+  }
+  result = CURLE_OK;
+
+out:
+  free(path);
+  free(query);
+  Curl_dyn_free(&buf);
+  return result;
+}
+
+CURLcode Curl_http_req_make2(struct httpreq **preq,
+                             const char *method, size_t m_len,
+                             CURLU *url, const char *scheme_default)
+{
+  struct httpreq *req;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  CURLUcode uc;
+
+  DEBUGASSERT(method);
+  if(m_len + 1 > sizeof(req->method))
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  req = calloc(1, sizeof(*req));
+  if(!req)
+    goto out;
+  memcpy(req->method, method, m_len);
+
+  uc = curl_url_get(url, CURLUPART_SCHEME, &req->scheme, 0);
+  if(uc && uc != CURLUE_NO_SCHEME)
+    goto out;
+  if(!req->scheme && scheme_default) {
+    req->scheme = strdup(scheme_default);
+    if(!req->scheme)
+      goto out;
+  }
+
+  result = req_assign_url_authority(req, url);
+  if(result)
+    goto out;
+  result = req_assign_url_path(req, url);
+  if(result)
+    goto out;
+
+  Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST);
+  Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST);
+  result = CURLE_OK;
+
+out:
+  if(result && req)
+    Curl_http_req_free(req);
+  *preq = result? NULL : req;
+  return result;
+}
+
+void Curl_http_req_free(struct httpreq *req)
+{
+  if(req) {
+    free(req->scheme);
+    free(req->authority);
+    free(req->path);
+    Curl_dynhds_free(&req->headers);
+    Curl_dynhds_free(&req->trailers);
+    free(req);
+  }
+}
+
+struct name_const {
+  const char *name;
+  size_t namelen;
+};
+
+static struct name_const H2_NON_FIELD[] = {
+  { STRCONST("Host") },
+  { STRCONST("Upgrade") },
+  { STRCONST("Connection") },
+  { STRCONST("Keep-Alive") },
+  { STRCONST("Proxy-Connection") },
+  { STRCONST("Transfer-Encoding") },
+};
+
+static bool h2_non_field(const char *name, size_t namelen)
+{
+  size_t i;
+  for(i = 0; i < sizeof(H2_NON_FIELD)/sizeof(H2_NON_FIELD[0]); ++i) {
+    if(namelen < H2_NON_FIELD[i].namelen)
+      return FALSE;
+    if(namelen == H2_NON_FIELD[i].namelen &&
+       strcasecompare(H2_NON_FIELD[i].name, name))
+      return TRUE;
+  }
+  return FALSE;
+}
+
+CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers,
+                             struct httpreq *req, struct Curl_easy *data)
+{
+  const char *scheme = NULL, *authority = NULL;
+  struct dynhds_entry *e;
+  size_t i;
+  CURLcode result;
+
+  DEBUGASSERT(req);
+  DEBUGASSERT(h2_headers);
+
+  if(req->scheme) {
+    scheme = req->scheme;
+  }
+  else if(strcmp("CONNECT", req->method)) {
+    scheme = Curl_checkheaders(data, STRCONST(HTTP_PSEUDO_SCHEME));
+    if(scheme) {
+      scheme += sizeof(HTTP_PSEUDO_SCHEME);
+      while(*scheme && ISBLANK(*scheme))
+        scheme++;
+      infof(data, "set pseudo header %s to %s", HTTP_PSEUDO_SCHEME, scheme);
+    }
+    else {
+      scheme = (data->conn && data->conn->handler->flags & PROTOPT_SSL)?
+                "https" : "http";
+    }
+  }
+
+  if(req->authority) {
+    authority = req->authority;
+  }
+  else {
+    e = Curl_dynhds_get(&req->headers, STRCONST("Host"));
+    if(e)
+      authority = e->value;
+  }
+
+  Curl_dynhds_reset(h2_headers);
+  Curl_dynhds_set_opts(h2_headers, DYNHDS_OPT_LOWERCASE);
+  result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD),
+                           req->method, strlen(req->method));
+  if(!result && scheme) {
+    result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME),
+                             scheme, strlen(scheme));
+  }
+  if(!result && authority) {
+    result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY),
+                             authority, strlen(authority));
+  }
+  if(!result && req->path) {
+    result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH),
+                             req->path, strlen(req->path));
+  }
+  for(i = 0; !result && i < Curl_dynhds_count(&req->headers); ++i) {
+    e = Curl_dynhds_getn(&req->headers, i);
+    if(!h2_non_field(e->name, e->namelen)) {
+      result = Curl_dynhds_add(h2_headers, e->name, e->namelen,
+                               e->value, e->valuelen);
+    }
+  }
+
+  return result;
+}
+
+CURLcode Curl_http_resp_make(struct http_resp **presp,
+                             int status,
+                             const char *description)
+{
+  struct http_resp *resp;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+
+  resp = calloc(1, sizeof(*resp));
+  if(!resp)
+    goto out;
+
+  resp->status = status;
+  if(description) {
+    resp->description = strdup(description);
+    if(!resp->description)
+      goto out;
+  }
+  Curl_dynhds_init(&resp->headers, 0, DYN_HTTP_REQUEST);
+  Curl_dynhds_init(&resp->trailers, 0, DYN_HTTP_REQUEST);
+  result = CURLE_OK;
+
+out:
+  if(result && resp)
+    Curl_http_resp_free(resp);
+  *presp = result? NULL : resp;
+  return result;
+}
+
+void Curl_http_resp_free(struct http_resp *resp)
+{
+  if(resp) {
+    free(resp->description);
+    Curl_dynhds_free(&resp->headers);
+    Curl_dynhds_free(&resp->trailers);
+    if(resp->prev)
+      Curl_http_resp_free(resp->prev);
+    free(resp);
+  }
+}
+
+struct cr_exp100_ctx {
+  struct Curl_creader super;
+  struct curltime start; /* time started waiting */
+  enum expect100 state;
+};
+
+/* Expect: 100-continue client reader, blocking uploads */
+
+static void http_exp100_continue(struct Curl_easy *data,
+                                 struct Curl_creader *reader)
+{
+  struct cr_exp100_ctx *ctx = reader->ctx;
+  if(ctx->state > EXP100_SEND_DATA) {
+    ctx->state = EXP100_SEND_DATA;
+    data->req.keepon |= KEEP_SEND;
+    data->req.keepon &= ~KEEP_SEND_TIMED;
+    Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+  }
+}
+
+static CURLcode cr_exp100_read(struct Curl_easy *data,
+                               struct Curl_creader *reader,
+                               char *buf, size_t blen,
+                               size_t *nread, bool *eos)
+{
+  struct cr_exp100_ctx *ctx = reader->ctx;
+  timediff_t ms;
+
+  switch(ctx->state) {
+  case EXP100_SENDING_REQUEST:
+    /* We are now waiting for a reply from the server or
+     * a timeout on our side */
+    DEBUGF(infof(data, "cr_exp100_read, start AWAITING_CONTINUE"));
+    ctx->state = EXP100_AWAITING_CONTINUE;
+    ctx->start = Curl_now();
+    Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
+    data->req.keepon &= ~KEEP_SEND;
+    data->req.keepon |= KEEP_SEND_TIMED;
+    *nread = 0;
+    *eos = FALSE;
+    return CURLE_OK;
+  case EXP100_FAILED:
+    DEBUGF(infof(data, "cr_exp100_read, expectation failed, error"));
+    *nread = 0;
+    *eos = FALSE;
+    return CURLE_READ_ERROR;
+  case EXP100_AWAITING_CONTINUE:
+    ms = Curl_timediff(Curl_now(), ctx->start);
+    if(ms < data->set.expect_100_timeout) {
+      DEBUGF(infof(data, "cr_exp100_read, AWAITING_CONTINUE, not expired"));
+      data->req.keepon &= ~KEEP_SEND;
+      data->req.keepon |= KEEP_SEND_TIMED;
+      *nread = 0;
+      *eos = FALSE;
+      return CURLE_OK;
+    }
+    /* we've waited long enough, continue anyway */
+    http_exp100_continue(data, reader);
+    infof(data, "Done waiting for 100-continue");
+    FALLTHROUGH();
+  default:
+    DEBUGF(infof(data, "cr_exp100_read, pass through"));
+    return Curl_creader_read(data, reader->next, buf, blen, nread, eos);
+  }
+}
+
+static void cr_exp100_done(struct Curl_easy *data,
+                           struct Curl_creader *reader, int premature)
+{
+  struct cr_exp100_ctx *ctx = reader->ctx;
+  ctx->state = premature? EXP100_FAILED : EXP100_SEND_DATA;
+  data->req.keepon &= ~KEEP_SEND_TIMED;
+  Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+}
+
+static const struct Curl_crtype cr_exp100 = {
+  "cr-exp100",
+  Curl_creader_def_init,
+  cr_exp100_read,
+  Curl_creader_def_close,
+  Curl_creader_def_needs_rewind,
+  Curl_creader_def_total_length,
+  Curl_creader_def_resume_from,
+  Curl_creader_def_rewind,
+  Curl_creader_def_unpause,
+  cr_exp100_done,
+  sizeof(struct cr_exp100_ctx)
+};
+
+static CURLcode http_exp100_add_reader(struct Curl_easy *data)
+{
+  struct Curl_creader *reader = NULL;
+  CURLcode result;
+
+  result = Curl_creader_create(&reader, data, &cr_exp100,
+                               CURL_CR_PROTOCOL);
+  if(!result)
+    result = Curl_creader_add(data, reader);
+  if(!result) {
+    struct cr_exp100_ctx *ctx = reader->ctx;
+    ctx->state = EXP100_SENDING_REQUEST;
+  }
+
+  if(result && reader)
+    Curl_creader_free(data, reader);
+  return result;
+}
+
+void Curl_http_exp100_got100(struct Curl_easy *data)
+{
+  struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
+  if(r)
+    http_exp100_continue(data, r);
+}
+
+static bool http_exp100_is_waiting(struct Curl_easy *data)
+{
+  struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
+  if(r) {
+    struct cr_exp100_ctx *ctx = r->ctx;
+    return (ctx->state == EXP100_AWAITING_CONTINUE);
+  }
+  return FALSE;
+}
+
+static void http_exp100_send_anyway(struct Curl_easy *data)
+{
+  struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
+  if(r)
+    http_exp100_continue(data, r);
+}
+
+bool Curl_http_exp100_is_selected(struct Curl_easy *data)
+{
+  struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
+  return r? TRUE : FALSE;
+}
+
+#endif /* CURL_DISABLE_HTTP */
Index: trunk/src/libs/curl-8.7.1/lib/http.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http.h	(revision 104083)
@@ -0,0 +1,302 @@
+#ifndef HEADER_CURL_HTTP_H
+#define HEADER_CURL_HTTP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(USE_MSH3) && !defined(_WIN32)
+#include <pthread.h>
+#endif
+
+#include "bufq.h"
+#include "dynhds.h"
+#include "ws.h"
+
+typedef enum {
+  HTTPREQ_GET,
+  HTTPREQ_POST,
+  HTTPREQ_POST_FORM, /* we make a difference internally */
+  HTTPREQ_POST_MIME, /* we make a difference internally */
+  HTTPREQ_PUT,
+  HTTPREQ_HEAD
+} Curl_HttpReq;
+
+#ifndef CURL_DISABLE_HTTP
+
+#if defined(ENABLE_QUIC)
+#include <stdint.h>
+#endif
+
+extern const struct Curl_handler Curl_handler_http;
+
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_https;
+#endif
+
+struct dynhds;
+
+CURLcode Curl_bump_headersize(struct Curl_easy *data,
+                              size_t delta,
+                              bool connect_only);
+
+/* Header specific functions */
+bool Curl_compareheader(const char *headerline,  /* line to check */
+                        const char *header,   /* header keyword _with_ colon */
+                        const size_t hlen,   /* len of the keyword in bytes */
+                        const char *content, /* content string to find */
+                        const size_t clen);   /* len of the content in bytes */
+
+char *Curl_copy_header_value(const char *header);
+
+char *Curl_checkProxyheaders(struct Curl_easy *data,
+                             const struct connectdata *conn,
+                             const char *thisheader,
+                             const size_t thislen);
+struct HTTP; /* see below */
+
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
+#ifndef USE_HYPER
+                                struct dynbuf *req
+#else
+                                void *headers
+#endif
+  );
+CURLcode Curl_add_custom_headers(struct Curl_easy *data,
+                                 bool is_connect,
+#ifndef USE_HYPER
+                                 struct dynbuf *req
+#else
+                                 void *headers
+#endif
+  );
+CURLcode Curl_dynhds_add_custom(struct Curl_easy *data,
+                                bool is_connect,
+                                struct dynhds *hds);
+
+void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
+                      const char **method, Curl_HttpReq *);
+CURLcode Curl_http_useragent(struct Curl_easy *data);
+CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn);
+CURLcode Curl_http_target(struct Curl_easy *data, struct connectdata *conn,
+                          struct dynbuf *req);
+CURLcode Curl_http_statusline(struct Curl_easy *data,
+                              struct connectdata *conn);
+CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
+                          char *headp, size_t hdlen);
+CURLcode Curl_transferencode(struct Curl_easy *data);
+CURLcode Curl_http_req_set_reader(struct Curl_easy *data,
+                                  Curl_HttpReq httpreq,
+                                  const char **tep);
+CURLcode Curl_http_req_complete(struct Curl_easy *data,
+                                struct dynbuf *r, Curl_HttpReq httpreq);
+bool Curl_use_http_1_1plus(const struct Curl_easy *data,
+                           const struct connectdata *conn);
+#ifndef CURL_DISABLE_COOKIES
+CURLcode Curl_http_cookies(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           struct dynbuf *r);
+#else
+#define Curl_http_cookies(a,b,c) CURLE_OK
+#endif
+CURLcode Curl_http_range(struct Curl_easy *data,
+                         Curl_HttpReq httpreq);
+CURLcode Curl_http_firstwrite(struct Curl_easy *data);
+
+/* protocol-specific functions set up to be called by the main engine */
+CURLcode Curl_http_setup_conn(struct Curl_easy *data,
+                              struct connectdata *conn);
+CURLcode Curl_http(struct Curl_easy *data, bool *done);
+CURLcode Curl_http_done(struct Curl_easy *data, CURLcode, bool premature);
+CURLcode Curl_http_connect(struct Curl_easy *data, bool *done);
+int Curl_http_getsock_do(struct Curl_easy *data, struct connectdata *conn,
+                         curl_socket_t *socks);
+CURLcode Curl_http_write_resp(struct Curl_easy *data,
+                              const char *buf, size_t blen,
+                              bool is_eos);
+
+/* These functions are in http.c */
+CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
+                              const char *auth);
+CURLcode Curl_http_auth_act(struct Curl_easy *data);
+
+/* If only the PICKNONE bit is set, there has been a round-trip and we
+   selected to use no auth at all. Ie, we actively select no auth, as opposed
+   to not having one selected. The other CURLAUTH_* defines are present in the
+   public curl/curl.h header. */
+#define CURLAUTH_PICKNONE (1<<30) /* don't use auth */
+
+/* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST
+   data get included in the initial data chunk sent to the server. If the
+   data is larger than this, it will automatically get split up in multiple
+   system calls.
+
+   This value used to be fairly big (100K), but we must take into account that
+   if the server rejects the POST due for authentication reasons, this data
+   will always be unconditionally sent and thus it may not be larger than can
+   always be afforded to send twice.
+
+   It must not be greater than 64K to work on VMS.
+*/
+#ifndef MAX_INITIAL_POST_SIZE
+#define MAX_INITIAL_POST_SIZE (64*1024)
+#endif
+
+/* EXPECT_100_THRESHOLD is the request body size limit for when libcurl will
+ * automatically add an "Expect: 100-continue" header in HTTP requests. When
+ * the size is unknown, it will always add it.
+ *
+ */
+#ifndef EXPECT_100_THRESHOLD
+#define EXPECT_100_THRESHOLD (1024*1024)
+#endif
+
+/* MAX_HTTP_RESP_HEADER_SIZE is the maximum size of all response headers
+   combined that libcurl allows for a single HTTP response, any HTTP
+   version. This count includes CONNECT response headers. */
+#define MAX_HTTP_RESP_HEADER_SIZE (300*1024)
+
+bool Curl_http_exp100_is_selected(struct Curl_easy *data);
+void Curl_http_exp100_got100(struct Curl_easy *data);
+
+#endif /* CURL_DISABLE_HTTP */
+
+/****************************************************************************
+ * HTTP unique setup
+ ***************************************************************************/
+struct HTTP {
+#ifndef CURL_DISABLE_HTTP
+  void *h2_ctx;              /* HTTP/2 implementation context */
+  void *h3_ctx;              /* HTTP/3 implementation context */
+#else
+  char unused;
+#endif
+};
+
+CURLcode Curl_http_size(struct Curl_easy *data);
+
+CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
+                                  const char *buf, size_t blen,
+                                  size_t *pconsumed);
+
+/**
+ * Curl_http_output_auth() setups the authentication headers for the
+ * host/proxy and the correct authentication
+ * method. data->state.authdone is set to TRUE when authentication is
+ * done.
+ *
+ * @param data all information about the current transfer
+ * @param conn all information about the current connection
+ * @param request pointer to the request keyword
+ * @param httpreq is the request type
+ * @param path pointer to the requested path
+ * @param proxytunnel boolean if this is the request setting up a "proxy
+ * tunnel"
+ *
+ * @returns CURLcode
+ */
+CURLcode
+Curl_http_output_auth(struct Curl_easy *data,
+                      struct connectdata *conn,
+                      const char *request,
+                      Curl_HttpReq httpreq,
+                      const char *path,
+                      bool proxytunnel); /* TRUE if this is the request setting
+                                            up the proxy tunnel */
+
+/* Decode HTTP status code string. */
+CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len);
+
+
+/**
+ * All about a core HTTP request, excluding body and trailers
+ */
+struct httpreq {
+  char method[24];
+  char *scheme;
+  char *authority;
+  char *path;
+  struct dynhds headers;
+  struct dynhds trailers;
+};
+
+/**
+ * Create a HTTP request struct.
+ */
+CURLcode Curl_http_req_make(struct httpreq **preq,
+                            const char *method, size_t m_len,
+                            const char *scheme, size_t s_len,
+                            const char *authority, size_t a_len,
+                            const char *path, size_t p_len);
+
+CURLcode Curl_http_req_make2(struct httpreq **preq,
+                             const char *method, size_t m_len,
+                             CURLU *url, const char *scheme_default);
+
+void Curl_http_req_free(struct httpreq *req);
+
+#define HTTP_PSEUDO_METHOD ":method"
+#define HTTP_PSEUDO_SCHEME ":scheme"
+#define HTTP_PSEUDO_AUTHORITY ":authority"
+#define HTTP_PSEUDO_PATH ":path"
+#define HTTP_PSEUDO_STATUS ":status"
+
+/**
+ * Create the list of HTTP/2 headers which represent the request,
+ * using HTTP/2 pseudo headers preceding the `req->headers`.
+ *
+ * Applies the following transformations:
+ * - if `authority` is set, any "Host" header is removed.
+ * - if `authority` is unset and a "Host" header is present, use
+ *   that as `authority` and remove "Host"
+ * - removes and Connection header fields as defined in rfc9113 ch. 8.2.2
+ * - lower-cases the header field names
+ *
+ * @param h2_headers will contain the HTTP/2 headers on success
+ * @param req        the request to transform
+ * @param data       the handle to lookup defaults like ' :scheme' from
+ */
+CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers,
+                             struct httpreq *req, struct Curl_easy *data);
+
+/**
+ * All about a core HTTP response, excluding body and trailers
+ */
+struct http_resp {
+  int status;
+  char *description;
+  struct dynhds headers;
+  struct dynhds trailers;
+  struct http_resp *prev;
+};
+
+/**
+ * Create a HTTP response struct.
+ */
+CURLcode Curl_http_resp_make(struct http_resp **presp,
+                             int status,
+                             const char *description);
+
+void Curl_http_resp_free(struct http_resp *resp);
+
+#endif /* HEADER_CURL_HTTP_H */
Index: trunk/src/libs/curl-8.7.1/lib/http1.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http1.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http1.c	(revision 104083)
@@ -0,0 +1,346 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_HTTP
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "http.h"
+#include "http1.h"
+#include "urlapi-int.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+#define H1_MAX_URL_LEN   (8*1024)
+
+void Curl_h1_req_parse_init(struct h1_req_parser *parser, size_t max_line_len)
+{
+  memset(parser, 0, sizeof(*parser));
+  parser->max_line_len = max_line_len;
+  Curl_dyn_init(&parser->scratch, max_line_len);
+}
+
+void Curl_h1_req_parse_free(struct h1_req_parser *parser)
+{
+  if(parser) {
+    Curl_http_req_free(parser->req);
+    Curl_dyn_free(&parser->scratch);
+    parser->req = NULL;
+    parser->done = FALSE;
+  }
+}
+
+static CURLcode trim_line(struct h1_req_parser *parser, int options)
+{
+  DEBUGASSERT(parser->line);
+  if(parser->line_len) {
+    if(parser->line[parser->line_len - 1] == '\n')
+      --parser->line_len;
+    if(parser->line_len) {
+      if(parser->line[parser->line_len - 1] == '\r')
+        --parser->line_len;
+      else if(options & H1_PARSE_OPT_STRICT)
+        return CURLE_URL_MALFORMAT;
+    }
+    else if(options & H1_PARSE_OPT_STRICT)
+      return CURLE_URL_MALFORMAT;
+  }
+  else if(options & H1_PARSE_OPT_STRICT)
+    return CURLE_URL_MALFORMAT;
+
+  if(parser->line_len > parser->max_line_len) {
+    return CURLE_URL_MALFORMAT;
+  }
+  return CURLE_OK;
+}
+
+static ssize_t detect_line(struct h1_req_parser *parser,
+                           const char *buf, const size_t buflen,
+                           CURLcode *err)
+{
+  const char  *line_end;
+
+  DEBUGASSERT(!parser->line);
+  line_end = memchr(buf, '\n', buflen);
+  if(!line_end) {
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+  parser->line = buf;
+  parser->line_len = line_end - buf + 1;
+  *err = CURLE_OK;
+  return (ssize_t)parser->line_len;
+}
+
+static ssize_t next_line(struct h1_req_parser *parser,
+                         const char *buf, const size_t buflen, int options,
+                         CURLcode *err)
+{
+  ssize_t nread = 0;
+
+  if(parser->line) {
+    parser->line = NULL;
+    parser->line_len = 0;
+    Curl_dyn_reset(&parser->scratch);
+  }
+
+  nread = detect_line(parser, buf, buflen, err);
+  if(nread >= 0) {
+    if(Curl_dyn_len(&parser->scratch)) {
+      /* append detected line to scratch to have the complete line */
+      *err = Curl_dyn_addn(&parser->scratch, parser->line, parser->line_len);
+      if(*err)
+        return -1;
+      parser->line = Curl_dyn_ptr(&parser->scratch);
+      parser->line_len = Curl_dyn_len(&parser->scratch);
+    }
+    *err = trim_line(parser, options);
+    if(*err)
+      return -1;
+  }
+  else if(*err == CURLE_AGAIN) {
+    /* no line end in `buf`, add it to our scratch */
+    *err = Curl_dyn_addn(&parser->scratch, (const unsigned char *)buf, buflen);
+    nread = (*err)? -1 : (ssize_t)buflen;
+  }
+  return nread;
+}
+
+static CURLcode start_req(struct h1_req_parser *parser,
+                          const char *scheme_default, int options)
+{
+  const char  *p, *m, *target, *hv, *scheme, *authority, *path;
+  size_t m_len, target_len, hv_len, scheme_len, authority_len, path_len;
+  size_t i;
+  CURLU *url = NULL;
+  CURLcode result = CURLE_URL_MALFORMAT; /* Use this as default fail */
+
+  DEBUGASSERT(!parser->req);
+  /* line must match: "METHOD TARGET HTTP_VERSION" */
+  p = memchr(parser->line, ' ', parser->line_len);
+  if(!p || p == parser->line)
+    goto out;
+
+  m = parser->line;
+  m_len = p - parser->line;
+  target = p + 1;
+  target_len = hv_len = 0;
+  hv = NULL;
+
+  /* URL may contain spaces so scan backwards */
+  for(i = parser->line_len; i > m_len; --i) {
+    if(parser->line[i] == ' ') {
+      hv = &parser->line[i + 1];
+      hv_len = parser->line_len - i;
+      target_len = (hv - target) - 1;
+      break;
+    }
+  }
+  /* no SPACE found or empty TARGET or empty HTTP_VERSION */
+  if(!target_len || !hv_len)
+    goto out;
+
+  /* TODO: we do not check HTTP_VERSION for conformity, should
+   + do that when STRICT option is supplied. */
+  (void)hv;
+
+  /* The TARGET can be (rfc 9112, ch. 3.2):
+   * origin-form:     path + optional query
+   * absolute-form:   absolute URI
+   * authority-form:  host+port for CONNECT
+   * asterisk-form:   '*' for OPTIONS
+   *
+   * from TARGET, we derive `scheme` `authority` `path`
+   * origin-form            --        --          TARGET
+   * absolute-form          URL*      URL*        URL*
+   * authority-form         --        TARGET      --
+   * asterisk-form          --        --          TARGET
+   */
+  scheme = authority = path = NULL;
+  scheme_len = authority_len = path_len = 0;
+
+  if(target_len == 1 && target[0] == '*') {
+    /* asterisk-form */
+    path = target;
+    path_len = target_len;
+  }
+  else if(!strncmp("CONNECT", m, m_len)) {
+    /* authority-form */
+    authority = target;
+    authority_len = target_len;
+  }
+  else if(target[0] == '/') {
+    /* origin-form */
+    path = target;
+    path_len = target_len;
+  }
+  else {
+    /* origin-form OR absolute-form */
+    CURLUcode uc;
+    char tmp[H1_MAX_URL_LEN];
+
+    /* default, unless we see an absolute URL */
+    path = target;
+    path_len = target_len;
+
+    /* URL parser wants 0-termination */
+    if(target_len >= sizeof(tmp))
+      goto out;
+    memcpy(tmp, target, target_len);
+    tmp[target_len] = '\0';
+    /* See if treating TARGET as an absolute URL makes sense */
+    if(Curl_is_absolute_url(tmp, NULL, 0, FALSE)) {
+      int url_options;
+
+      url = curl_url();
+      if(!url) {
+        result = CURLE_OUT_OF_MEMORY;
+        goto out;
+      }
+      url_options = (CURLU_NON_SUPPORT_SCHEME|
+                     CURLU_PATH_AS_IS|
+                     CURLU_NO_DEFAULT_PORT);
+      if(!(options & H1_PARSE_OPT_STRICT))
+        url_options |= CURLU_ALLOW_SPACE;
+      uc = curl_url_set(url, CURLUPART_URL, tmp, url_options);
+      if(uc) {
+        goto out;
+      }
+    }
+
+    if(!url && (options & H1_PARSE_OPT_STRICT)) {
+      /* we should have an absolute URL or have seen `/` earlier */
+      goto out;
+    }
+  }
+
+  if(url) {
+    result = Curl_http_req_make2(&parser->req, m, m_len, url, scheme_default);
+  }
+  else {
+    if(!scheme && scheme_default) {
+      scheme = scheme_default;
+      scheme_len = strlen(scheme_default);
+    }
+    result = Curl_http_req_make(&parser->req, m, m_len, scheme, scheme_len,
+                                authority, authority_len, path, path_len);
+  }
+
+out:
+  curl_url_cleanup(url);
+  return result;
+}
+
+ssize_t Curl_h1_req_parse_read(struct h1_req_parser *parser,
+                               const char *buf, size_t buflen,
+                               const char *scheme_default, int options,
+                               CURLcode *err)
+{
+  ssize_t nread = 0, n;
+
+  *err = CURLE_OK;
+  while(!parser->done) {
+    n = next_line(parser, buf, buflen, options, err);
+    if(n < 0) {
+      if(*err != CURLE_AGAIN) {
+        nread = -1;
+      }
+      *err = CURLE_OK;
+      goto out;
+    }
+
+    /* Consume this line */
+    nread += (size_t)n;
+    buf += (size_t)n;
+    buflen -= (size_t)n;
+
+    if(!parser->line) {
+      /* consumed bytes, but line not complete */
+      if(!buflen)
+        goto out;
+    }
+    else if(!parser->req) {
+      *err = start_req(parser, scheme_default, options);
+      if(*err) {
+        nread = -1;
+        goto out;
+      }
+    }
+    else if(parser->line_len == 0) {
+      /* last, empty line, we are finished */
+      if(!parser->req) {
+        *err = CURLE_URL_MALFORMAT;
+        nread = -1;
+        goto out;
+      }
+      parser->done = TRUE;
+      Curl_dyn_reset(&parser->scratch);
+      /* last chance adjustments */
+    }
+    else {
+      *err = Curl_dynhds_h1_add_line(&parser->req->headers,
+                                     parser->line, parser->line_len);
+      if(*err) {
+        nread = -1;
+        goto out;
+      }
+    }
+  }
+
+out:
+  return nread;
+}
+
+CURLcode Curl_h1_req_write_head(struct httpreq *req, int http_minor,
+                                struct dynbuf *dbuf)
+{
+  CURLcode result;
+
+  result = Curl_dyn_addf(dbuf, "%s %s%s%s%s HTTP/1.%d\r\n",
+                         req->method,
+                         req->scheme? req->scheme : "",
+                         req->scheme? "://" : "",
+                         req->authority? req->authority : "",
+                         req->path? req->path : "",
+                         http_minor);
+  if(result)
+    goto out;
+
+  result = Curl_dynhds_h1_dprint(&req->headers, dbuf);
+  if(result)
+    goto out;
+
+  result = Curl_dyn_addn(dbuf, STRCONST("\r\n"));
+
+out:
+  return result;
+}
+
+#endif /* !CURL_DISABLE_HTTP */
Index: trunk/src/libs/curl-8.7.1/lib/http1.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http1.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http1.h	(revision 104083)
@@ -0,0 +1,63 @@
+#ifndef HEADER_CURL_HTTP1_H
+#define HEADER_CURL_HTTP1_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_HTTP
+#include "bufq.h"
+#include "http.h"
+
+#define H1_PARSE_OPT_NONE       (0)
+#define H1_PARSE_OPT_STRICT     (1 << 0)
+
+#define H1_PARSE_DEFAULT_MAX_LINE_LEN   DYN_HTTP_REQUEST
+
+struct h1_req_parser {
+  struct httpreq *req;
+  struct dynbuf scratch;
+  size_t scratch_skip;
+  const char *line;
+  size_t max_line_len;
+  size_t line_len;
+  bool done;
+};
+
+void Curl_h1_req_parse_init(struct h1_req_parser *parser, size_t max_line_len);
+void Curl_h1_req_parse_free(struct h1_req_parser *parser);
+
+ssize_t Curl_h1_req_parse_read(struct h1_req_parser *parser,
+                               const char *buf, size_t buflen,
+                               const char *scheme_default, int options,
+                               CURLcode *err);
+
+CURLcode Curl_h1_req_dprint(const struct httpreq *req,
+                            struct dynbuf *dbuf);
+
+CURLcode Curl_h1_req_write_head(struct httpreq *req, int http_minor,
+                                struct dynbuf *dbuf);
+
+#endif /* !CURL_DISABLE_HTTP */
+#endif /* HEADER_CURL_HTTP1_H */
Index: trunk/src/libs/curl-8.7.1/lib/http2.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http2.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http2.c	(revision 104083)
@@ -0,0 +1,2794 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_NGHTTP2
+#include <stdint.h>
+#include <nghttp2/nghttp2.h>
+#include "urldata.h"
+#include "bufq.h"
+#include "http1.h"
+#include "http2.h"
+#include "http.h"
+#include "sendf.h"
+#include "select.h"
+#include "curl_base64.h"
+#include "strcase.h"
+#include "multiif.h"
+#include "url.h"
+#include "urlapi-int.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "rand.h"
+#include "strtoofft.h"
+#include "strdup.h"
+#include "transfer.h"
+#include "dynbuf.h"
+#include "headers.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if (NGHTTP2_VERSION_NUM < 0x010c00)
+#error too old nghttp2 version, upgrade!
+#endif
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+#define nghttp2_session_callbacks_set_error_callback(x,y)
+#endif
+
+#if (NGHTTP2_VERSION_NUM >= 0x010c00)
+#define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1
+#endif
+
+
+/* buffer dimensioning:
+ * use 16K as chunk size, as that fits H2 DATA frames well */
+#define H2_CHUNK_SIZE           (16 * 1024)
+/* this is how much we want "in flight" for a stream */
+#define H2_STREAM_WINDOW_SIZE   (10 * 1024 * 1024)
+/* on receiving from TLS, we prep for holding a full stream window */
+#define H2_NW_RECV_CHUNKS       (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE)
+/* on send into TLS, we just want to accumulate small frames */
+#define H2_NW_SEND_CHUNKS       1
+/* stream recv/send chunks are a result of window / chunk sizes */
+#define H2_STREAM_RECV_CHUNKS   (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE)
+/* keep smaller stream upload buffer (default h2 window size) to have
+ * our progress bars and "upload done" reporting closer to reality */
+#define H2_STREAM_SEND_CHUNKS   ((64 * 1024) / H2_CHUNK_SIZE)
+/* spare chunks we keep for a full window */
+#define H2_STREAM_POOL_SPARES   (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE)
+
+/* We need to accommodate the max number of streams with their window
+ * sizes on the overall connection. Streams might become PAUSED which
+ * will block their received QUOTA in the connection window. And if we
+ * run out of space, the server is blocked from sending us any data.
+ * See #10988 for an issue with this. */
+#define HTTP2_HUGE_WINDOW_SIZE (100 * H2_STREAM_WINDOW_SIZE)
+
+#define H2_SETTINGS_IV_LEN  3
+#define H2_BINSETTINGS_LEN 80
+
+static int populate_settings(nghttp2_settings_entry *iv,
+                             struct Curl_easy *data)
+{
+  iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
+  iv[0].value = Curl_multi_max_concurrent_streams(data->multi);
+
+  iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
+  iv[1].value = H2_STREAM_WINDOW_SIZE;
+
+  iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
+  iv[2].value = data->multi->push_cb != NULL;
+
+  return 3;
+}
+
+static ssize_t populate_binsettings(uint8_t *binsettings,
+                                    struct Curl_easy *data)
+{
+  nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
+  int ivlen;
+
+  ivlen = populate_settings(iv, data);
+  /* this returns number of bytes it wrote or a negative number on error. */
+  return nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
+                                       iv, ivlen);
+}
+
+struct cf_h2_ctx {
+  nghttp2_session *h2;
+  /* The easy handle used in the current filter call, cleared at return */
+  struct cf_call_data call_data;
+
+  struct bufq inbufq;           /* network input */
+  struct bufq outbufq;          /* network output */
+  struct bufc_pool stream_bufcp; /* spares for stream buffers */
+
+  size_t drain_total; /* sum of all stream's UrlState drain */
+  uint32_t max_concurrent_streams;
+  int32_t goaway_error;
+  int32_t last_stream_id;
+  BIT(conn_closed);
+  BIT(goaway);
+  BIT(enable_push);
+  BIT(nw_out_blocked);
+};
+
+/* How to access `call_data` from a cf_h2 filter */
+#undef CF_CTX_CALL_DATA
+#define CF_CTX_CALL_DATA(cf)  \
+  ((struct cf_h2_ctx *)(cf)->ctx)->call_data
+
+static void cf_h2_ctx_clear(struct cf_h2_ctx *ctx)
+{
+  struct cf_call_data save = ctx->call_data;
+
+  if(ctx->h2) {
+    nghttp2_session_del(ctx->h2);
+  }
+  Curl_bufq_free(&ctx->inbufq);
+  Curl_bufq_free(&ctx->outbufq);
+  Curl_bufcp_free(&ctx->stream_bufcp);
+  memset(ctx, 0, sizeof(*ctx));
+  ctx->call_data = save;
+}
+
+static void cf_h2_ctx_free(struct cf_h2_ctx *ctx)
+{
+  if(ctx) {
+    cf_h2_ctx_clear(ctx);
+    free(ctx);
+  }
+}
+
+static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data);
+
+/**
+ * All about the H2 internals of a stream
+ */
+struct h2_stream_ctx {
+  struct bufq recvbuf; /* response buffer */
+  struct bufq sendbuf; /* request buffer */
+  struct h1_req_parser h1; /* parsing the request */
+  struct dynhds resp_trailers; /* response trailer fields */
+  size_t resp_hds_len; /* amount of response header bytes in recvbuf */
+  size_t upload_blocked_len;
+  curl_off_t upload_left; /* number of request bytes left to upload */
+  curl_off_t nrcvd_data;  /* number of DATA bytes received */
+
+  char **push_headers;       /* allocated array */
+  size_t push_headers_used;  /* number of entries filled in */
+  size_t push_headers_alloc; /* number of entries allocated */
+
+  int status_code; /* HTTP response status code */
+  uint32_t error; /* stream error code */
+  uint32_t local_window_size; /* the local recv window size */
+  int32_t id; /* HTTP/2 protocol identifier for stream */
+  BIT(resp_hds_complete); /* we have a complete, final response */
+  BIT(closed); /* TRUE on stream close */
+  BIT(reset);  /* TRUE on stream reset */
+  BIT(close_handled); /* TRUE if stream closure is handled by libcurl */
+  BIT(bodystarted);
+  BIT(send_closed); /* transfer is done sending, we might have still
+                       buffered data in stream->sendbuf to upload. */
+};
+
+#define H2_STREAM_CTX(d)    ((struct h2_stream_ctx *)(((d) && \
+                              (d)->req.p.http)? \
+                             ((struct HTTP *)(d)->req.p.http)->h2_ctx \
+                               : NULL))
+#define H2_STREAM_LCTX(d)   ((struct HTTP *)(d)->req.p.http)->h2_ctx
+#define H2_STREAM_ID(d)     (H2_STREAM_CTX(d)? \
+                             H2_STREAM_CTX(d)->id : -2)
+
+/*
+ * Mark this transfer to get "drained".
+ */
+static void drain_stream(struct Curl_cfilter *cf,
+                         struct Curl_easy *data,
+                         struct h2_stream_ctx *stream)
+{
+  unsigned char bits;
+
+  (void)cf;
+  bits = CURL_CSELECT_IN;
+  if(!stream->send_closed &&
+     (stream->upload_left || stream->upload_blocked_len))
+    bits |= CURL_CSELECT_OUT;
+  if(data->state.select_bits != bits) {
+    CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x",
+                stream->id, bits);
+    data->state.select_bits = bits;
+    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+  }
+}
+
+static CURLcode http2_data_setup(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 struct h2_stream_ctx **pstream)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream;
+
+  (void)cf;
+  DEBUGASSERT(data);
+  if(!data->req.p.http) {
+    failf(data, "initialization failure, transfer not http initialized");
+    return CURLE_FAILED_INIT;
+  }
+  stream = H2_STREAM_CTX(data);
+  if(stream) {
+    *pstream = stream;
+    return CURLE_OK;
+  }
+
+  stream = calloc(1, sizeof(*stream));
+  if(!stream)
+    return CURLE_OUT_OF_MEMORY;
+
+  stream->id = -1;
+  Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
+                  H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
+  Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
+  Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST);
+  stream->resp_hds_len = 0;
+  stream->bodystarted = FALSE;
+  stream->status_code = -1;
+  stream->closed = FALSE;
+  stream->close_handled = FALSE;
+  stream->error = NGHTTP2_NO_ERROR;
+  stream->local_window_size = H2_STREAM_WINDOW_SIZE;
+  stream->upload_left = 0;
+  stream->nrcvd_data = 0;
+
+  H2_STREAM_LCTX(data) = stream;
+  *pstream = stream;
+  return CURLE_OK;
+}
+
+static void free_push_headers(struct h2_stream_ctx *stream)
+{
+  size_t i;
+  for(i = 0; i<stream->push_headers_used; i++)
+    free(stream->push_headers[i]);
+  Curl_safefree(stream->push_headers);
+  stream->push_headers_used = 0;
+}
+
+static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+
+  DEBUGASSERT(ctx);
+  if(!stream)
+    return;
+
+  if(ctx->h2) {
+    bool flush_egress = FALSE;
+    /* returns error if stream not known, which is fine here */
+    (void)nghttp2_session_set_stream_user_data(ctx->h2, stream->id, NULL);
+
+    if(!stream->closed && stream->id > 0) {
+      /* RST_STREAM */
+      CURL_TRC_CF(data, cf, "[%d] premature DATA_DONE, RST stream",
+                  stream->id);
+      stream->closed = TRUE;
+      stream->reset = TRUE;
+      stream->send_closed = TRUE;
+      nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
+                                stream->id, NGHTTP2_STREAM_CLOSED);
+      flush_egress = TRUE;
+    }
+
+    if(flush_egress)
+      nghttp2_session_send(ctx->h2);
+  }
+
+  Curl_bufq_free(&stream->sendbuf);
+  Curl_h1_req_parse_free(&stream->h1);
+  Curl_dynhds_free(&stream->resp_trailers);
+  free_push_headers(stream);
+  free(stream);
+  H2_STREAM_LCTX(data) = NULL;
+}
+
+static int h2_client_new(struct Curl_cfilter *cf,
+                         nghttp2_session_callbacks *cbs)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  nghttp2_option *o;
+
+  int rc = nghttp2_option_new(&o);
+  if(rc)
+    return rc;
+  /* We handle window updates ourself to enforce buffer limits */
+  nghttp2_option_set_no_auto_window_update(o, 1);
+#if NGHTTP2_VERSION_NUM >= 0x013200
+  /* with 1.50.0 */
+  /* turn off RFC 9113 leading and trailing white spaces validation against
+     HTTP field value. */
+  nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(o, 1);
+#endif
+  rc = nghttp2_session_client_new2(&ctx->h2, cbs, cf, o);
+  nghttp2_option_del(o);
+  return rc;
+}
+
+static ssize_t nw_in_reader(void *reader_ctx,
+                              unsigned char *buf, size_t buflen,
+                              CURLcode *err)
+{
+  struct Curl_cfilter *cf = reader_ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+
+  return Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err);
+}
+
+static ssize_t nw_out_writer(void *writer_ctx,
+                             const unsigned char *buf, size_t buflen,
+                             CURLcode *err)
+{
+  struct Curl_cfilter *cf = writer_ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+
+  if(data) {
+    ssize_t nwritten = Curl_conn_cf_send(cf->next, data,
+                                         (const char *)buf, buflen, err);
+    if(nwritten > 0)
+      CURL_TRC_CF(data, cf, "[0] egress: wrote %zd bytes", nwritten);
+    return nwritten;
+  }
+  return 0;
+}
+
+static ssize_t send_callback(nghttp2_session *h2,
+                             const uint8_t *mem, size_t length, int flags,
+                             void *userp);
+static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
+                         void *userp);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame,
+                         void *userp);
+#endif
+static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
+                              int32_t stream_id,
+                              const uint8_t *mem, size_t len, void *userp);
+static int on_stream_close(nghttp2_session *session, int32_t stream_id,
+                           uint32_t error_code, void *userp);
+static int on_begin_headers(nghttp2_session *session,
+                            const nghttp2_frame *frame, void *userp);
+static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
+                     const uint8_t *name, size_t namelen,
+                     const uint8_t *value, size_t valuelen,
+                     uint8_t flags,
+                     void *userp);
+static int error_callback(nghttp2_session *session, const char *msg,
+                          size_t len, void *userp);
+
+/*
+ * Initialize the cfilter context
+ */
+static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               bool via_h1_upgrade)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  int rc;
+  nghttp2_session_callbacks *cbs = NULL;
+
+  DEBUGASSERT(!ctx->h2);
+  Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES);
+  Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0);
+  Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0);
+  ctx->last_stream_id = 2147483647;
+
+  rc = nghttp2_session_callbacks_new(&cbs);
+  if(rc) {
+    failf(data, "Couldn't initialize nghttp2 callbacks");
+    goto out;
+  }
+
+  nghttp2_session_callbacks_set_send_callback(cbs, send_callback);
+  nghttp2_session_callbacks_set_on_frame_recv_callback(cbs, on_frame_recv);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  nghttp2_session_callbacks_set_on_frame_send_callback(cbs, on_frame_send);
+#endif
+  nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
+    cbs, on_data_chunk_recv);
+  nghttp2_session_callbacks_set_on_stream_close_callback(cbs, on_stream_close);
+  nghttp2_session_callbacks_set_on_begin_headers_callback(
+    cbs, on_begin_headers);
+  nghttp2_session_callbacks_set_on_header_callback(cbs, on_header);
+  nghttp2_session_callbacks_set_error_callback(cbs, error_callback);
+
+  /* The nghttp2 session is not yet setup, do it */
+  rc = h2_client_new(cf, cbs);
+  if(rc) {
+    failf(data, "Couldn't initialize nghttp2");
+    goto out;
+  }
+  ctx->max_concurrent_streams = DEFAULT_MAX_CONCURRENT_STREAMS;
+
+  if(via_h1_upgrade) {
+    /* HTTP/1.1 Upgrade issued. H2 Settings have already been submitted
+     * in the H1 request and we upgrade from there. This stream
+     * is opened implicitly as #1. */
+    uint8_t binsettings[H2_BINSETTINGS_LEN];
+    ssize_t binlen; /* length of the binsettings data */
+
+    binlen = populate_binsettings(binsettings, data);
+    if(binlen <= 0) {
+      failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
+      result = CURLE_FAILED_INIT;
+      goto out;
+    }
+
+    result = http2_data_setup(cf, data, &stream);
+    if(result)
+      goto out;
+    DEBUGASSERT(stream);
+    stream->id = 1;
+    /* queue SETTINGS frame (again) */
+    rc = nghttp2_session_upgrade2(ctx->h2, binsettings, binlen,
+                                  data->state.httpreq == HTTPREQ_HEAD,
+                                  NULL);
+    if(rc) {
+      failf(data, "nghttp2_session_upgrade2() failed: %s(%d)",
+            nghttp2_strerror(rc), rc);
+      result = CURLE_HTTP2;
+      goto out;
+    }
+
+    rc = nghttp2_session_set_stream_user_data(ctx->h2, stream->id,
+                                              data);
+    if(rc) {
+      infof(data, "http/2: failed to set user_data for stream %u",
+            stream->id);
+      DEBUGASSERT(0);
+    }
+    CURL_TRC_CF(data, cf, "created session via Upgrade");
+  }
+  else {
+    nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
+    int ivlen;
+
+    ivlen = populate_settings(iv, data);
+    rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE,
+                                 iv, ivlen);
+    if(rc) {
+      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
+            nghttp2_strerror(rc), rc);
+      result = CURLE_HTTP2;
+      goto out;
+    }
+  }
+
+  rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0,
+                                             HTTP2_HUGE_WINDOW_SIZE);
+  if(rc) {
+    failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
+          nghttp2_strerror(rc), rc);
+    result = CURLE_HTTP2;
+    goto out;
+  }
+
+  /* all set, traffic will be send on connect */
+  result = CURLE_OK;
+  CURL_TRC_CF(data, cf, "[0] created h2 session%s",
+              via_h1_upgrade? " (via h1 upgrade)" : "");
+
+out:
+  if(cbs)
+    nghttp2_session_callbacks_del(cbs);
+  return result;
+}
+
+/*
+ * Returns nonzero if current HTTP/2 session should be closed.
+ */
+static int should_close_session(struct cf_h2_ctx *ctx)
+{
+  return ctx->drain_total == 0 && !nghttp2_session_want_read(ctx->h2) &&
+    !nghttp2_session_want_write(ctx->h2);
+}
+
+/*
+ * Processes pending input left in network input buffer.
+ * This function returns 0 if it succeeds, or -1 and error code will
+ * be assigned to *err.
+ */
+static int h2_process_pending_input(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    CURLcode *err)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  const unsigned char *buf;
+  size_t blen;
+  ssize_t rv;
+
+  while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) {
+
+    rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen);
+    if(rv < 0) {
+      failf(data,
+            "process_pending_input: nghttp2_session_mem_recv() returned "
+            "%zd:%s", rv, nghttp2_strerror((int)rv));
+      *err = CURLE_RECV_ERROR;
+      return -1;
+    }
+    Curl_bufq_skip(&ctx->inbufq, (size_t)rv);
+    if(Curl_bufq_is_empty(&ctx->inbufq)) {
+      break;
+    }
+    else {
+      CURL_TRC_CF(data, cf, "process_pending_input: %zu bytes left "
+                  "in connection buffer", Curl_bufq_len(&ctx->inbufq));
+    }
+  }
+
+  if(nghttp2_session_check_request_allowed(ctx->h2) == 0) {
+    /* No more requests are allowed in the current session, so
+       the connection may not be reused. This is set when a
+       GOAWAY frame has been received or when the limit of stream
+       identifiers has been reached. */
+    connclose(cf->conn, "http/2: No new requests allowed");
+  }
+
+  return 0;
+}
+
+/*
+ * The server may send us data at any point (e.g. PING frames). Therefore,
+ * we cannot assume that an HTTP/2 socket is dead just because it is readable.
+ *
+ * Check the lower filters first and, if successful, peek at the socket
+ * and distinguish between closed and data.
+ */
+static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              bool *input_pending)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  bool alive = TRUE;
+
+  *input_pending = FALSE;
+  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
+    return FALSE;
+
+  if(*input_pending) {
+    /* This happens before we've sent off a request and the connection is
+       not in use by any other transfer, there shouldn't be any data here,
+       only "protocol frames" */
+    CURLcode result;
+    ssize_t nread = -1;
+
+    *input_pending = FALSE;
+    nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result);
+    if(nread != -1) {
+      CURL_TRC_CF(data, cf, "%zd bytes stray data read before trying "
+                  "h2 connection", nread);
+      if(h2_process_pending_input(cf, data, &result) < 0)
+        /* immediate error, considered dead */
+        alive = FALSE;
+      else {
+        alive = !should_close_session(ctx);
+      }
+    }
+    else if(result != CURLE_AGAIN) {
+      /* the read failed so let's say this is dead anyway */
+      alive = FALSE;
+    }
+  }
+
+  return alive;
+}
+
+static CURLcode http2_send_ping(struct Curl_cfilter *cf,
+                                struct Curl_easy *data)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  int rc;
+
+  rc = nghttp2_submit_ping(ctx->h2, 0, ZERO_NULL);
+  if(rc) {
+    failf(data, "nghttp2_submit_ping() failed: %s(%d)",
+          nghttp2_strerror(rc), rc);
+   return CURLE_HTTP2;
+  }
+
+  rc = nghttp2_session_send(ctx->h2);
+  if(rc) {
+    failf(data, "nghttp2_session_send() failed: %s(%d)",
+          nghttp2_strerror(rc), rc);
+    return CURLE_SEND_ERROR;
+  }
+  return CURLE_OK;
+}
+
+/*
+ * Store nghttp2 version info in this buffer.
+ */
+void Curl_http2_ver(char *p, size_t len)
+{
+  nghttp2_info *h2 = nghttp2_version(0);
+  (void)msnprintf(p, len, "nghttp2/%s", h2->version_str);
+}
+
+static CURLcode nw_out_flush(struct Curl_cfilter *cf,
+                             struct Curl_easy *data)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  ssize_t nwritten;
+  CURLcode result;
+
+  (void)data;
+  if(Curl_bufq_is_empty(&ctx->outbufq))
+    return CURLE_OK;
+
+  nwritten = Curl_bufq_pass(&ctx->outbufq, nw_out_writer, cf, &result);
+  if(nwritten < 0) {
+    if(result == CURLE_AGAIN) {
+      CURL_TRC_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN",
+                  Curl_bufq_len(&ctx->outbufq));
+      ctx->nw_out_blocked = 1;
+    }
+    return result;
+  }
+  return Curl_bufq_is_empty(&ctx->outbufq)? CURLE_OK: CURLE_AGAIN;
+}
+
+/*
+ * The implementation of nghttp2_send_callback type. Here we write |data| with
+ * size |length| to the network and return the number of bytes actually
+ * written. See the documentation of nghttp2_send_callback for the details.
+ */
+static ssize_t send_callback(nghttp2_session *h2,
+                             const uint8_t *buf, size_t blen, int flags,
+                             void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  ssize_t nwritten;
+  CURLcode result = CURLE_OK;
+
+  (void)h2;
+  (void)flags;
+  DEBUGASSERT(data);
+
+  nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
+                                  nw_out_writer, cf, &result);
+  if(nwritten < 0) {
+    if(result == CURLE_AGAIN) {
+      ctx->nw_out_blocked = 1;
+      return NGHTTP2_ERR_WOULDBLOCK;
+    }
+    failf(data, "Failed sending HTTP2 data");
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  }
+
+  if(!nwritten) {
+    ctx->nw_out_blocked = 1;
+    return NGHTTP2_ERR_WOULDBLOCK;
+  }
+  return nwritten;
+}
+
+
+/* We pass a pointer to this struct in the push callback, but the contents of
+   the struct are hidden from the user. */
+struct curl_pushheaders {
+  struct Curl_easy *data;
+  const nghttp2_push_promise *frame;
+};
+
+/*
+ * push header access function. Only to be used from within the push callback
+ */
+char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
+{
+  /* Verify that we got a good easy handle in the push header struct, mostly to
+     detect rubbish input fast(er). */
+  if(!h || !GOOD_EASY_HANDLE(h->data))
+    return NULL;
+  else {
+    struct h2_stream_ctx *stream = H2_STREAM_CTX(h->data);
+    if(stream && num < stream->push_headers_used)
+      return stream->push_headers[num];
+  }
+  return NULL;
+}
+
+/*
+ * push header access function. Only to be used from within the push callback
+ */
+char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
+{
+  struct h2_stream_ctx *stream;
+  size_t len;
+  size_t i;
+  /* Verify that we got a good easy handle in the push header struct,
+     mostly to detect rubbish input fast(er). Also empty header name
+     is just a rubbish too. We have to allow ":" at the beginning of
+     the header, but header == ":" must be rejected. If we have ':' in
+     the middle of header, it could be matched in middle of the value,
+     this is because we do prefix match.*/
+  if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] ||
+     !strcmp(header, ":") || strchr(header + 1, ':'))
+    return NULL;
+
+  stream = H2_STREAM_CTX(h->data);
+  if(!stream)
+    return NULL;
+
+  len = strlen(header);
+  for(i = 0; i<stream->push_headers_used; i++) {
+    if(!strncmp(header, stream->push_headers[i], len)) {
+      /* sub-match, make sure that it is followed by a colon */
+      if(stream->push_headers[i][len] != ':')
+        continue;
+      return &stream->push_headers[i][len + 1];
+    }
+  }
+  return NULL;
+}
+
+static struct Curl_easy *h2_duphandle(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data)
+{
+  struct Curl_easy *second = curl_easy_duphandle(data);
+  if(second) {
+    /* setup the request struct */
+    struct HTTP *http = calloc(1, sizeof(struct HTTP));
+    if(!http) {
+      (void)Curl_close(&second);
+    }
+    else {
+      struct h2_stream_ctx *second_stream;
+
+      second->req.p.http = http;
+      http2_data_setup(cf, second, &second_stream);
+      second->state.priority.weight = data->state.priority.weight;
+    }
+  }
+  return second;
+}
+
+static int set_transfer_url(struct Curl_easy *data,
+                            struct curl_pushheaders *hp)
+{
+  const char *v;
+  CURLUcode uc;
+  char *url = NULL;
+  int rc = 0;
+  CURLU *u = curl_url();
+
+  if(!u)
+    return 5;
+
+  v = curl_pushheader_byname(hp, HTTP_PSEUDO_SCHEME);
+  if(v) {
+    uc = curl_url_set(u, CURLUPART_SCHEME, v, 0);
+    if(uc) {
+      rc = 1;
+      goto fail;
+    }
+  }
+
+  v = curl_pushheader_byname(hp, HTTP_PSEUDO_AUTHORITY);
+  if(v) {
+    uc = Curl_url_set_authority(u, v, CURLU_DISALLOW_USER);
+    if(uc) {
+      rc = 2;
+      goto fail;
+    }
+  }
+
+  v = curl_pushheader_byname(hp, HTTP_PSEUDO_PATH);
+  if(v) {
+    uc = curl_url_set(u, CURLUPART_PATH, v, 0);
+    if(uc) {
+      rc = 3;
+      goto fail;
+    }
+  }
+
+  uc = curl_url_get(u, CURLUPART_URL, &url, 0);
+  if(uc)
+    rc = 4;
+fail:
+  curl_url_cleanup(u);
+  if(rc)
+    return rc;
+
+  if(data->state.url_alloc)
+    free(data->state.url);
+  data->state.url_alloc = TRUE;
+  data->state.url = url;
+  return 0;
+}
+
+static void discard_newhandle(struct Curl_cfilter *cf,
+                              struct Curl_easy *newhandle)
+{
+  if(newhandle->req.p.http) {
+    http2_data_done(cf, newhandle);
+  }
+  (void)Curl_close(&newhandle);
+}
+
+static int push_promise(struct Curl_cfilter *cf,
+                        struct Curl_easy *data,
+                        const nghttp2_push_promise *frame)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  int rv; /* one of the CURL_PUSH_* defines */
+
+  CURL_TRC_CF(data, cf, "[%d] PUSH_PROMISE received",
+              frame->promised_stream_id);
+  if(data->multi->push_cb) {
+    struct h2_stream_ctx *stream;
+    struct h2_stream_ctx *newstream;
+    struct curl_pushheaders heads;
+    CURLMcode rc;
+    CURLcode result;
+    /* clone the parent */
+    struct Curl_easy *newhandle = h2_duphandle(cf, data);
+    if(!newhandle) {
+      infof(data, "failed to duplicate handle");
+      rv = CURL_PUSH_DENY; /* FAIL HARD */
+      goto fail;
+    }
+
+    heads.data = data;
+    heads.frame = frame;
+    /* ask the application */
+    CURL_TRC_CF(data, cf, "Got PUSH_PROMISE, ask application");
+
+    stream = H2_STREAM_CTX(data);
+    if(!stream) {
+      failf(data, "Internal NULL stream");
+      discard_newhandle(cf, newhandle);
+      rv = CURL_PUSH_DENY;
+      goto fail;
+    }
+
+    rv = set_transfer_url(newhandle, &heads);
+    if(rv) {
+      discard_newhandle(cf, newhandle);
+      rv = CURL_PUSH_DENY;
+      goto fail;
+    }
+
+    result = http2_data_setup(cf, newhandle, &newstream);
+    if(result) {
+      failf(data, "error setting up stream: %d", result);
+      discard_newhandle(cf, newhandle);
+      rv = CURL_PUSH_DENY;
+      goto fail;
+    }
+    DEBUGASSERT(stream);
+
+    Curl_set_in_callback(data, true);
+    rv = data->multi->push_cb(data, newhandle,
+                              stream->push_headers_used, &heads,
+                              data->multi->push_userp);
+    Curl_set_in_callback(data, false);
+
+    /* free the headers again */
+    free_push_headers(stream);
+
+    if(rv) {
+      DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
+      /* denied, kill off the new handle again */
+      discard_newhandle(cf, newhandle);
+      goto fail;
+    }
+
+    newstream->id = frame->promised_stream_id;
+    newhandle->req.maxdownload = -1;
+    newhandle->req.size = -1;
+
+    /* approved, add to the multi handle and immediately switch to PERFORM
+       state with the given connection !*/
+    rc = Curl_multi_add_perform(data->multi, newhandle, cf->conn);
+    if(rc) {
+      infof(data, "failed to add handle to multi");
+      discard_newhandle(cf, newhandle);
+      rv = CURL_PUSH_DENY;
+      goto fail;
+    }
+
+    rv = nghttp2_session_set_stream_user_data(ctx->h2,
+                                              newstream->id,
+                                              newhandle);
+    if(rv) {
+      infof(data, "failed to set user_data for stream %u",
+            newstream->id);
+      DEBUGASSERT(0);
+      rv = CURL_PUSH_DENY;
+      goto fail;
+    }
+  }
+  else {
+    CURL_TRC_CF(data, cf, "Got PUSH_PROMISE, ignore it");
+    rv = CURL_PUSH_DENY;
+  }
+fail:
+  return rv;
+}
+
+static CURLcode recvbuf_write_hds(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  const char *buf, size_t blen)
+{
+  (void)cf;
+  return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
+}
+
+static CURLcode on_stream_frame(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                const nghttp2_frame *frame)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+  int32_t stream_id = frame->hd.stream_id;
+  CURLcode result;
+  int rv;
+
+  if(!stream) {
+    CURL_TRC_CF(data, cf, "[%d] No stream_ctx set", stream_id);
+    return CURLE_FAILED_INIT;
+  }
+
+  switch(frame->hd.type) {
+  case NGHTTP2_DATA:
+    CURL_TRC_CF(data, cf, "[%d] DATA, window=%d/%d",
+                stream_id,
+                nghttp2_session_get_stream_effective_recv_data_length(
+                  ctx->h2, stream->id),
+                nghttp2_session_get_stream_effective_local_window_size(
+                  ctx->h2, stream->id));
+    /* If !body started on this stream, then receiving DATA is illegal. */
+    if(!stream->bodystarted) {
+      rv = nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
+                                     stream_id, NGHTTP2_PROTOCOL_ERROR);
+
+      if(nghttp2_is_fatal(rv)) {
+        return CURLE_RECV_ERROR;
+      }
+    }
+    if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
+      drain_stream(cf, data, stream);
+    }
+    break;
+  case NGHTTP2_HEADERS:
+    if(stream->bodystarted) {
+      /* Only valid HEADERS after body started is trailer HEADERS.  We
+         buffer them in on_header callback. */
+      break;
+    }
+
+    /* nghttp2 guarantees that :status is received, and we store it to
+       stream->status_code. Fuzzing has proven this can still be reached
+       without status code having been set. */
+    if(stream->status_code == -1)
+      return CURLE_RECV_ERROR;
+
+    /* Only final status code signals the end of header */
+    if(stream->status_code / 100 != 1) {
+      stream->bodystarted = TRUE;
+      stream->status_code = -1;
+    }
+
+    result = recvbuf_write_hds(cf, data, STRCONST("\r\n"));
+    if(result)
+      return result;
+
+    if(stream->status_code / 100 != 1) {
+      stream->resp_hds_complete = TRUE;
+    }
+    drain_stream(cf, data, stream);
+    break;
+  case NGHTTP2_PUSH_PROMISE:
+    rv = push_promise(cf, data, &frame->push_promise);
+    if(rv) { /* deny! */
+      DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
+      rv = nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
+                                     frame->push_promise.promised_stream_id,
+                                     NGHTTP2_CANCEL);
+      if(nghttp2_is_fatal(rv))
+        return CURLE_SEND_ERROR;
+      else if(rv == CURL_PUSH_ERROROUT) {
+        CURL_TRC_CF(data, cf, "[%d] fail in PUSH_PROMISE received",
+                    stream_id);
+        return CURLE_RECV_ERROR;
+      }
+    }
+    break;
+  case NGHTTP2_RST_STREAM:
+    stream->closed = TRUE;
+    if(frame->rst_stream.error_code) {
+      stream->reset = TRUE;
+    }
+    stream->send_closed = TRUE;
+    drain_stream(cf, data, stream);
+    break;
+  case NGHTTP2_WINDOW_UPDATE:
+    if(CURL_WANT_SEND(data)) {
+      drain_stream(cf, data, stream);
+    }
+    break;
+  default:
+    break;
+  }
+  return CURLE_OK;
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static int fr_print(const nghttp2_frame *frame, char *buffer, size_t blen)
+{
+  switch(frame->hd.type) {
+    case NGHTTP2_DATA: {
+      return msnprintf(buffer, blen,
+                       "FRAME[DATA, len=%d, eos=%d, padlen=%d]",
+                       (int)frame->hd.length,
+                       !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM),
+                       (int)frame->data.padlen);
+    }
+    case NGHTTP2_HEADERS: {
+      return msnprintf(buffer, blen,
+                       "FRAME[HEADERS, len=%d, hend=%d, eos=%d]",
+                       (int)frame->hd.length,
+                       !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS),
+                       !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM));
+    }
+    case NGHTTP2_PRIORITY: {
+      return msnprintf(buffer, blen,
+                       "FRAME[PRIORITY, len=%d, flags=%d]",
+                       (int)frame->hd.length, frame->hd.flags);
+    }
+    case NGHTTP2_RST_STREAM: {
+      return msnprintf(buffer, blen,
+                       "FRAME[RST_STREAM, len=%d, flags=%d, error=%u]",
+                       (int)frame->hd.length, frame->hd.flags,
+                       frame->rst_stream.error_code);
+    }
+    case NGHTTP2_SETTINGS: {
+      if(frame->hd.flags & NGHTTP2_FLAG_ACK) {
+        return msnprintf(buffer, blen, "FRAME[SETTINGS, ack=1]");
+      }
+      return msnprintf(buffer, blen,
+                       "FRAME[SETTINGS, len=%d]", (int)frame->hd.length);
+    }
+    case NGHTTP2_PUSH_PROMISE: {
+      return msnprintf(buffer, blen,
+                       "FRAME[PUSH_PROMISE, len=%d, hend=%d]",
+                       (int)frame->hd.length,
+                       !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS));
+    }
+    case NGHTTP2_PING: {
+      return msnprintf(buffer, blen,
+                       "FRAME[PING, len=%d, ack=%d]",
+                       (int)frame->hd.length,
+                       frame->hd.flags&NGHTTP2_FLAG_ACK);
+    }
+    case NGHTTP2_GOAWAY: {
+      char scratch[128];
+      size_t s_len = sizeof(scratch)/sizeof(scratch[0]);
+        size_t len = (frame->goaway.opaque_data_len < s_len)?
+                      frame->goaway.opaque_data_len : s_len-1;
+        if(len)
+          memcpy(scratch, frame->goaway.opaque_data, len);
+        scratch[len] = '\0';
+        return msnprintf(buffer, blen, "FRAME[GOAWAY, error=%d, reason='%s', "
+                         "last_stream=%d]", frame->goaway.error_code,
+                         scratch, frame->goaway.last_stream_id);
+    }
+    case NGHTTP2_WINDOW_UPDATE: {
+      return msnprintf(buffer, blen,
+                       "FRAME[WINDOW_UPDATE, incr=%d]",
+                       frame->window_update.window_size_increment);
+    }
+    default:
+      return msnprintf(buffer, blen, "FRAME[%d, len=%d, flags=%d]",
+                       frame->hd.type, (int)frame->hd.length,
+                       frame->hd.flags);
+  }
+}
+
+static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame,
+                         void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+
+  (void)session;
+  DEBUGASSERT(data);
+  if(data && Curl_trc_cf_is_verbose(cf, data)) {
+    char buffer[256];
+    int len;
+    len = fr_print(frame, buffer, sizeof(buffer)-1);
+    buffer[len] = 0;
+    CURL_TRC_CF(data, cf, "[%d] -> %s", frame->hd.stream_id, buffer);
+  }
+  return 0;
+}
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+
+static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
+                         void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf), *data_s;
+  int32_t stream_id = frame->hd.stream_id;
+
+  DEBUGASSERT(data);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  if(Curl_trc_cf_is_verbose(cf, data)) {
+    char buffer[256];
+    int len;
+    len = fr_print(frame, buffer, sizeof(buffer)-1);
+    buffer[len] = 0;
+    CURL_TRC_CF(data, cf, "[%d] <- %s",frame->hd.stream_id, buffer);
+  }
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+
+  if(!stream_id) {
+    /* stream ID zero is for connection-oriented stuff */
+    DEBUGASSERT(data);
+    switch(frame->hd.type) {
+    case NGHTTP2_SETTINGS: {
+      if(!(frame->hd.flags & NGHTTP2_FLAG_ACK)) {
+        uint32_t max_conn = ctx->max_concurrent_streams;
+        ctx->max_concurrent_streams = nghttp2_session_get_remote_settings(
+            session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
+        ctx->enable_push = nghttp2_session_get_remote_settings(
+            session, NGHTTP2_SETTINGS_ENABLE_PUSH) != 0;
+        CURL_TRC_CF(data, cf, "[0] MAX_CONCURRENT_STREAMS: %d",
+                    ctx->max_concurrent_streams);
+        CURL_TRC_CF(data, cf, "[0] ENABLE_PUSH: %s",
+                    ctx->enable_push ? "TRUE" : "false");
+        if(data && max_conn != ctx->max_concurrent_streams) {
+          /* only signal change if the value actually changed */
+          CURL_TRC_CF(data, cf, "[0] notify MAX_CONCURRENT_STREAMS: %u",
+                      ctx->max_concurrent_streams);
+          Curl_multi_connchanged(data->multi);
+        }
+        /* Since the initial stream window is 64K, a request might be on HOLD,
+         * due to exhaustion. The (initial) SETTINGS may announce a much larger
+         * window and *assume* that we treat this like a WINDOW_UPDATE. Some
+         * servers send an explicit WINDOW_UPDATE, but not all seem to do that.
+         * To be safe, we UNHOLD a stream in order not to stall. */
+        if(CURL_WANT_SEND(data)) {
+          struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+          if(stream)
+            drain_stream(cf, data, stream);
+        }
+      }
+      break;
+    }
+    case NGHTTP2_GOAWAY:
+      ctx->goaway = TRUE;
+      ctx->goaway_error = frame->goaway.error_code;
+      ctx->last_stream_id = frame->goaway.last_stream_id;
+      if(data) {
+        infof(data, "received GOAWAY, error=%d, last_stream=%u",
+                    ctx->goaway_error, ctx->last_stream_id);
+        Curl_multi_connchanged(data->multi);
+      }
+      break;
+    default:
+      break;
+    }
+    return 0;
+  }
+
+  data_s = nghttp2_session_get_stream_user_data(session, stream_id);
+  if(!data_s) {
+    CURL_TRC_CF(data, cf, "[%d] No Curl_easy associated", stream_id);
+    return 0;
+  }
+
+  return on_stream_frame(cf, data_s, frame)? NGHTTP2_ERR_CALLBACK_FAILURE : 0;
+}
+
+static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
+                              int32_t stream_id,
+                              const uint8_t *mem, size_t len, void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream;
+  struct Curl_easy *data_s;
+  CURLcode result;
+  (void)flags;
+
+  DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
+  DEBUGASSERT(CF_DATA_CURRENT(cf));
+
+  /* get the stream from the hash based on Stream ID */
+  data_s = nghttp2_session_get_stream_user_data(session, stream_id);
+  if(!data_s) {
+    /* Receiving a Stream ID not in the hash should not happen - unless
+       we have aborted a transfer artificially and there were more data
+       in the pipeline. Silently ignore. */
+    CURL_TRC_CF(CF_DATA_CURRENT(cf), cf, "[%d] Data for unknown",
+                stream_id);
+    /* consumed explicitly as no one will read it */
+    nghttp2_session_consume(session, stream_id, len);
+    return 0;
+  }
+
+  stream = H2_STREAM_CTX(data_s);
+  if(!stream)
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+  result = Curl_xfer_write_resp(data_s, (char *)mem, len, FALSE);
+  if(result && result != CURLE_AGAIN)
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+  nghttp2_session_consume(ctx->h2, stream_id, len);
+  stream->nrcvd_data += (curl_off_t)len;
+
+  /* if we receive data for another handle, wake that up */
+  drain_stream(cf, data_s, stream);
+  return 0;
+}
+
+static int on_stream_close(nghttp2_session *session, int32_t stream_id,
+                           uint32_t error_code, void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct Curl_easy *data_s, *call_data = CF_DATA_CURRENT(cf);
+  struct h2_stream_ctx *stream;
+  int rv;
+  (void)session;
+
+  DEBUGASSERT(call_data);
+  /* get the stream from the hash based on Stream ID, stream ID zero is for
+     connection-oriented stuff */
+  data_s = stream_id?
+             nghttp2_session_get_stream_user_data(session, stream_id) : NULL;
+  if(!data_s) {
+    CURL_TRC_CF(call_data, cf,
+                "[%d] on_stream_close, no easy set on stream", stream_id);
+    return 0;
+  }
+  if(!GOOD_EASY_HANDLE(data_s)) {
+    /* nghttp2 still has an easy registered for the stream which has
+     * been freed be libcurl. This points to a code path that does not
+     * trigger DONE or DETACH events as it must. */
+    CURL_TRC_CF(call_data, cf,
+                "[%d] on_stream_close, not a GOOD easy on stream", stream_id);
+    (void)nghttp2_session_set_stream_user_data(session, stream_id, 0);
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  }
+  stream = H2_STREAM_CTX(data_s);
+  if(!stream) {
+    CURL_TRC_CF(data_s, cf,
+                "[%d] on_stream_close, GOOD easy but no stream", stream_id);
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  }
+
+  stream->closed = TRUE;
+  stream->error = error_code;
+  if(stream->error) {
+    stream->reset = TRUE;
+    stream->send_closed = TRUE;
+  }
+
+  if(stream->error)
+    CURL_TRC_CF(data_s, cf, "[%d] RESET: %s (err %d)",
+              stream_id, nghttp2_http2_strerror(error_code), error_code);
+  else
+    CURL_TRC_CF(data_s, cf, "[%d] CLOSED", stream_id);
+  drain_stream(cf, data_s, stream);
+
+  /* remove `data_s` from the nghttp2 stream */
+  rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
+  if(rv) {
+    infof(data_s, "http/2: failed to clear user_data for stream %u",
+          stream_id);
+    DEBUGASSERT(0);
+  }
+  return 0;
+}
+
+static int on_begin_headers(nghttp2_session *session,
+                            const nghttp2_frame *frame, void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct h2_stream_ctx *stream;
+  struct Curl_easy *data_s = NULL;
+
+  (void)cf;
+  data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
+  if(!data_s) {
+    return 0;
+  }
+
+  if(frame->hd.type != NGHTTP2_HEADERS) {
+    return 0;
+  }
+
+  stream = H2_STREAM_CTX(data_s);
+  if(!stream || !stream->bodystarted) {
+    return 0;
+  }
+
+  return 0;
+}
+
+/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
+static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
+                     const uint8_t *name, size_t namelen,
+                     const uint8_t *value, size_t valuelen,
+                     uint8_t flags,
+                     void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct h2_stream_ctx *stream;
+  struct Curl_easy *data_s;
+  int32_t stream_id = frame->hd.stream_id;
+  CURLcode result;
+  (void)flags;
+
+  DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
+
+  /* get the stream from the hash based on Stream ID */
+  data_s = nghttp2_session_get_stream_user_data(session, stream_id);
+  if(!data_s)
+    /* Receiving a Stream ID not in the hash should not happen, this is an
+       internal error more than anything else! */
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+  stream = H2_STREAM_CTX(data_s);
+  if(!stream) {
+    failf(data_s, "Internal NULL stream");
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  }
+
+  /* Store received PUSH_PROMISE headers to be used when the subsequent
+     PUSH_PROMISE callback comes */
+  if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
+    char *h;
+
+    if(!strcmp(HTTP_PSEUDO_AUTHORITY, (const char *)name)) {
+      /* pseudo headers are lower case */
+      int rc = 0;
+      char *check = aprintf("%s:%d", cf->conn->host.name,
+                            cf->conn->remote_port);
+      if(!check)
+        /* no memory */
+        return NGHTTP2_ERR_CALLBACK_FAILURE;
+      if(!strcasecompare(check, (const char *)value) &&
+         ((cf->conn->remote_port != cf->conn->given->defport) ||
+          !strcasecompare(cf->conn->host.name, (const char *)value))) {
+        /* This is push is not for the same authority that was asked for in
+         * the URL. RFC 7540 section 8.2 says: "A client MUST treat a
+         * PUSH_PROMISE for which the server is not authoritative as a stream
+         * error of type PROTOCOL_ERROR."
+         */
+        (void)nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
+                                        stream_id, NGHTTP2_PROTOCOL_ERROR);
+        rc = NGHTTP2_ERR_CALLBACK_FAILURE;
+      }
+      free(check);
+      if(rc)
+        return rc;
+    }
+
+    if(!stream->push_headers) {
+      stream->push_headers_alloc = 10;
+      stream->push_headers = malloc(stream->push_headers_alloc *
+                                    sizeof(char *));
+      if(!stream->push_headers)
+        return NGHTTP2_ERR_CALLBACK_FAILURE;
+      stream->push_headers_used = 0;
+    }
+    else if(stream->push_headers_used ==
+            stream->push_headers_alloc) {
+      char **headp;
+      if(stream->push_headers_alloc > 1000) {
+        /* this is beyond crazy many headers, bail out */
+        failf(data_s, "Too many PUSH_PROMISE headers");
+        free_push_headers(stream);
+        return NGHTTP2_ERR_CALLBACK_FAILURE;
+      }
+      stream->push_headers_alloc *= 2;
+      headp = realloc(stream->push_headers,
+                      stream->push_headers_alloc * sizeof(char *));
+      if(!headp) {
+        free_push_headers(stream);
+        return NGHTTP2_ERR_CALLBACK_FAILURE;
+      }
+      stream->push_headers = headp;
+    }
+    h = aprintf("%s:%s", name, value);
+    if(h)
+      stream->push_headers[stream->push_headers_used++] = h;
+    return 0;
+  }
+
+  if(stream->bodystarted) {
+    /* This is a trailer */
+    CURL_TRC_CF(data_s, cf, "[%d] trailer: %.*s: %.*s",
+                stream->id, (int)namelen, name, (int)valuelen, value);
+    result = Curl_dynhds_add(&stream->resp_trailers,
+                             (const char *)name, namelen,
+                             (const char *)value, valuelen);
+    if(result)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+    return 0;
+  }
+
+  if(namelen == sizeof(HTTP_PSEUDO_STATUS) - 1 &&
+     memcmp(HTTP_PSEUDO_STATUS, name, namelen) == 0) {
+    /* nghttp2 guarantees :status is received first and only once. */
+    char buffer[32];
+    result = Curl_http_decode_status(&stream->status_code,
+                                     (const char *)value, valuelen);
+    if(result)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+    msnprintf(buffer, sizeof(buffer), HTTP_PSEUDO_STATUS ":%u\r",
+              stream->status_code);
+    result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO);
+    if(result)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+    result = recvbuf_write_hds(cf, data_s, STRCONST("HTTP/2 "));
+    if(result)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+    result = recvbuf_write_hds(cf, data_s, (const char *)value, valuelen);
+    if(result)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+    /* the space character after the status code is mandatory */
+    result = recvbuf_write_hds(cf, data_s, STRCONST(" \r\n"));
+    if(result)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+    /* if we receive data for another handle, wake that up */
+    if(CF_DATA_CURRENT(cf) != data_s)
+      Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
+
+    CURL_TRC_CF(data_s, cf, "[%d] status: HTTP/2 %03d",
+                stream->id, stream->status_code);
+    return 0;
+  }
+
+  /* nghttp2 guarantees that namelen > 0, and :status was already
+     received, and this is not pseudo-header field . */
+  /* convert to an HTTP1-style header */
+  result = recvbuf_write_hds(cf, data_s, (const char *)name, namelen);
+  if(result)
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  result = recvbuf_write_hds(cf, data_s, STRCONST(": "));
+  if(result)
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  result = recvbuf_write_hds(cf, data_s, (const char *)value, valuelen);
+  if(result)
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  result = recvbuf_write_hds(cf, data_s, STRCONST("\r\n"));
+  if(result)
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  /* if we receive data for another handle, wake that up */
+  if(CF_DATA_CURRENT(cf) != data_s)
+    Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
+
+  CURL_TRC_CF(data_s, cf, "[%d] header: %.*s: %.*s",
+              stream->id, (int)namelen, name, (int)valuelen, value);
+
+  return 0; /* 0 is successful */
+}
+
+static ssize_t req_body_read_callback(nghttp2_session *session,
+                                      int32_t stream_id,
+                                      uint8_t *buf, size_t length,
+                                      uint32_t *data_flags,
+                                      nghttp2_data_source *source,
+                                      void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct Curl_easy *data_s;
+  struct h2_stream_ctx *stream = NULL;
+  CURLcode result;
+  ssize_t nread;
+  (void)source;
+
+  (void)cf;
+  if(stream_id) {
+    /* get the stream from the hash based on Stream ID, stream ID zero is for
+       connection-oriented stuff */
+    data_s = nghttp2_session_get_stream_user_data(session, stream_id);
+    if(!data_s)
+      /* Receiving a Stream ID not in the hash should not happen, this is an
+         internal error more than anything else! */
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+    stream = H2_STREAM_CTX(data_s);
+    if(!stream)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+  }
+  else
+    return NGHTTP2_ERR_INVALID_ARGUMENT;
+
+  nread = Curl_bufq_read(&stream->sendbuf, buf, length, &result);
+  if(nread < 0) {
+    if(result != CURLE_AGAIN)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+    nread = 0;
+  }
+
+  if(nread > 0 && stream->upload_left != -1)
+    stream->upload_left -= nread;
+
+  CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) left=%"
+              CURL_FORMAT_CURL_OFF_T " -> %zd, %d",
+              stream_id, length, stream->upload_left, nread, result);
+
+  if(stream->upload_left == 0)
+    *data_flags = NGHTTP2_DATA_FLAG_EOF;
+  else if(nread == 0)
+    return NGHTTP2_ERR_DEFERRED;
+
+  return nread;
+}
+
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+static int error_callback(nghttp2_session *session,
+                          const char *msg,
+                          size_t len,
+                          void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  (void)session;
+  failf(data, "%.*s", (int)len, msg);
+  return 0;
+}
+#endif
+
+/*
+ * Append headers to ask for an HTTP1.1 to HTTP2 upgrade.
+ */
+CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
+                                    struct Curl_easy *data)
+{
+  CURLcode result;
+  char *base64;
+  size_t blen;
+  struct SingleRequest *k = &data->req;
+  uint8_t binsettings[H2_BINSETTINGS_LEN];
+  ssize_t binlen; /* length of the binsettings data */
+
+  binlen = populate_binsettings(binsettings, data);
+  if(binlen <= 0) {
+    failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
+    Curl_dyn_free(req);
+    return CURLE_FAILED_INIT;
+  }
+
+  result = Curl_base64url_encode((const char *)binsettings, binlen,
+                                 &base64, &blen);
+  if(result) {
+    Curl_dyn_free(req);
+    return result;
+  }
+
+  result = Curl_dyn_addf(req,
+                         "Connection: Upgrade, HTTP2-Settings\r\n"
+                         "Upgrade: %s\r\n"
+                         "HTTP2-Settings: %s\r\n",
+                         NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
+  free(base64);
+
+  k->upgr101 = UPGR101_H2;
+
+  return result;
+}
+
+static CURLcode http2_data_done_send(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
+  struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+
+  if(!ctx || !ctx->h2 || !stream)
+    goto out;
+
+  CURL_TRC_CF(data, cf, "[%d] data done send", stream->id);
+  if(!stream->send_closed) {
+    stream->send_closed = TRUE;
+    if(stream->upload_left) {
+      /* we now know that everything that is buffered is all there is. */
+      stream->upload_left = Curl_bufq_len(&stream->sendbuf);
+      /* resume sending here to trigger the callback to get called again so
+         that it can signal EOF to nghttp2 */
+      (void)nghttp2_session_resume_data(ctx->h2, stream->id);
+      drain_stream(cf, data, stream);
+    }
+  }
+
+out:
+  return result;
+}
+
+static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
+                                         struct Curl_easy *data,
+                                         struct h2_stream_ctx *stream,
+                                         CURLcode *err)
+{
+  ssize_t rv = 0;
+
+  if(stream->error == NGHTTP2_REFUSED_STREAM) {
+    CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
+                "connection", stream->id);
+    connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */
+    data->state.refused_stream = TRUE;
+    *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
+    return -1;
+  }
+  else if(stream->error != NGHTTP2_NO_ERROR) {
+    failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
+          stream->id, nghttp2_http2_strerror(stream->error),
+          stream->error);
+    *err = CURLE_HTTP2_STREAM;
+    return -1;
+  }
+  else if(stream->reset) {
+    failf(data, "HTTP/2 stream %u was reset", stream->id);
+    *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP2;
+    return -1;
+  }
+
+  if(!stream->bodystarted) {
+    failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
+          " all response header fields, treated as error",
+          stream->id);
+    *err = CURLE_HTTP2_STREAM;
+    return -1;
+  }
+
+  if(Curl_dynhds_count(&stream->resp_trailers)) {
+    struct dynhds_entry *e;
+    struct dynbuf dbuf;
+    size_t i;
+
+    *err = CURLE_OK;
+    Curl_dyn_init(&dbuf, DYN_TRAILERS);
+    for(i = 0; i < Curl_dynhds_count(&stream->resp_trailers); ++i) {
+      e = Curl_dynhds_getn(&stream->resp_trailers, i);
+      if(!e)
+        break;
+      Curl_dyn_reset(&dbuf);
+      *err = Curl_dyn_addf(&dbuf, "%.*s: %.*s\x0d\x0a",
+                          (int)e->namelen, e->name,
+                          (int)e->valuelen, e->value);
+      if(*err)
+        break;
+      Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&dbuf),
+                 Curl_dyn_len(&dbuf));
+      *err = Curl_client_write(data, CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER,
+                               Curl_dyn_ptr(&dbuf), Curl_dyn_len(&dbuf));
+      if(*err)
+        break;
+    }
+    Curl_dyn_free(&dbuf);
+    if(*err)
+      goto out;
+  }
+
+  stream->close_handled = TRUE;
+  *err = CURLE_OK;
+  rv = 0;
+
+out:
+  CURL_TRC_CF(data, cf, "handle_stream_close -> %zd, %d", rv, *err);
+  return rv;
+}
+
+static int sweight_wanted(const struct Curl_easy *data)
+{
+  /* 0 weight is not set by user and we take the nghttp2 default one */
+  return data->set.priority.weight?
+    data->set.priority.weight : NGHTTP2_DEFAULT_WEIGHT;
+}
+
+static int sweight_in_effect(const struct Curl_easy *data)
+{
+  /* 0 weight is not set by user and we take the nghttp2 default one */
+  return data->state.priority.weight?
+    data->state.priority.weight : NGHTTP2_DEFAULT_WEIGHT;
+}
+
+/*
+ * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight
+ * and dependency to the peer. It also stores the updated values in the state
+ * struct.
+ */
+
+static void h2_pri_spec(struct Curl_easy *data,
+                        nghttp2_priority_spec *pri_spec)
+{
+  struct Curl_data_priority *prio = &data->set.priority;
+  struct h2_stream_ctx *depstream = H2_STREAM_CTX(prio->parent);
+  int32_t depstream_id = depstream? depstream->id:0;
+  nghttp2_priority_spec_init(pri_spec, depstream_id,
+                             sweight_wanted(data),
+                             data->set.priority.exclusive);
+  data->state.priority = *prio;
+}
+
+/*
+ * Check if there's been an update in the priority /
+ * dependency settings and if so it submits a PRIORITY frame with the updated
+ * info.
+ * Flush any out data pending in the network buffer.
+ */
+static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+  int rv = 0;
+
+  if(stream && stream->id > 0 &&
+     ((sweight_wanted(data) != sweight_in_effect(data)) ||
+      (data->set.priority.exclusive != data->state.priority.exclusive) ||
+      (data->set.priority.parent != data->state.priority.parent)) ) {
+    /* send new weight and/or dependency */
+    nghttp2_priority_spec pri_spec;
+
+    h2_pri_spec(data, &pri_spec);
+    CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id);
+    DEBUGASSERT(stream->id != -1);
+    rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE,
+                                 stream->id, &pri_spec);
+    if(rv)
+      goto out;
+  }
+
+  ctx->nw_out_blocked = 0;
+  while(!rv && !ctx->nw_out_blocked && nghttp2_session_want_write(ctx->h2))
+    rv = nghttp2_session_send(ctx->h2);
+
+out:
+  if(nghttp2_is_fatal(rv)) {
+    CURL_TRC_CF(data, cf, "nghttp2_session_send error (%s)%d",
+                nghttp2_strerror(rv), rv);
+    return CURLE_SEND_ERROR;
+  }
+  return nw_out_flush(cf, data);
+}
+
+static ssize_t stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                           struct h2_stream_ctx *stream,
+                           char *buf, size_t len, CURLcode *err)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  ssize_t nread = -1;
+
+  (void)buf;
+  *err = CURLE_AGAIN;
+  if(stream->closed) {
+    CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id);
+    nread = http2_handle_stream_close(cf, data, stream, err);
+  }
+  else if(stream->reset ||
+          (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
+          (ctx->goaway && ctx->last_stream_id < stream->id)) {
+    CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id);
+    *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP2;
+    nread = -1;
+  }
+
+  if(nread < 0 && *err != CURLE_AGAIN)
+    CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %zd, %d",
+                stream->id, len, nread, *err);
+  return nread;
+}
+
+static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    size_t data_max_bytes)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream;
+  CURLcode result = CURLE_OK;
+  ssize_t nread;
+
+  /* Process network input buffer fist */
+  if(!Curl_bufq_is_empty(&ctx->inbufq)) {
+    CURL_TRC_CF(data, cf, "Process %zu bytes in connection buffer",
+                Curl_bufq_len(&ctx->inbufq));
+    if(h2_process_pending_input(cf, data, &result) < 0)
+      return result;
+  }
+
+  /* Receive data from the "lower" filters, e.g. network until
+   * it is time to stop due to connection close or us not processing
+   * all network input */
+  while(!ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) {
+    stream = H2_STREAM_CTX(data);
+    if(stream && (stream->closed || !data_max_bytes)) {
+      /* We would like to abort here and stop processing, so that
+       * the transfer loop can handle the data/close here. However,
+       * this may leave data in underlying buffers that will not
+       * be consumed. */
+      if(!cf->next || !cf->next->cft->has_data_pending(cf->next, data))
+        drain_stream(cf, data, stream);
+      break;
+    }
+
+    nread = Curl_bufq_sipn(&ctx->inbufq, 0, nw_in_reader, cf, &result);
+    if(nread < 0) {
+      if(result != CURLE_AGAIN) {
+        failf(data, "Failed receiving HTTP2 data: %d(%s)", result,
+              curl_easy_strerror(result));
+        return result;
+      }
+      break;
+    }
+    else if(nread == 0) {
+      CURL_TRC_CF(data, cf, "[0] ingress: connection closed");
+      ctx->conn_closed = TRUE;
+      break;
+    }
+    else {
+      CURL_TRC_CF(data, cf, "[0] ingress: read %zd bytes", nread);
+      data_max_bytes = (data_max_bytes > (size_t)nread)?
+                        (data_max_bytes - (size_t)nread) : 0;
+    }
+
+    if(h2_process_pending_input(cf, data, &result))
+      return result;
+  }
+
+  if(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) {
+    connclose(cf->conn, "GOAWAY received");
+  }
+
+  return CURLE_OK;
+}
+
+static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          char *buf, size_t len, CURLcode *err)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+  ssize_t nread = -1;
+  CURLcode result;
+  struct cf_call_data save;
+
+  if(!stream) {
+    /* Abnormal call sequence: either this transfer has never opened a stream
+     * (unlikely) or the transfer has been done, cleaned up its resources, but
+     * a read() is called anyway. It is not clear what the calling sequence
+     * is for such a case. */
+    failf(data, "[%zd-%zd], http/2 recv on a transfer never opened "
+          "or already cleared", (ssize_t)data->id,
+          (ssize_t)cf->conn->connection_id);
+    *err = CURLE_HTTP2;
+    return -1;
+  }
+
+  CF_DATA_SAVE(save, cf, data);
+
+  nread = stream_recv(cf, data, stream, buf, len, err);
+  if(nread < 0 && *err != CURLE_AGAIN)
+    goto out;
+
+  if(nread < 0) {
+    *err = h2_progress_ingress(cf, data, len);
+    if(*err)
+      goto out;
+
+    nread = stream_recv(cf, data, stream, buf, len, err);
+  }
+
+  if(nread > 0) {
+    size_t data_consumed = (size_t)nread;
+    /* Now that we transferred this to the upper layer, we report
+     * the actual amount of DATA consumed to the H2 session, so
+     * that it adjusts stream flow control */
+    if(stream->resp_hds_len >= data_consumed) {
+      stream->resp_hds_len -= data_consumed;  /* no DATA */
+    }
+    else {
+      if(stream->resp_hds_len) {
+        data_consumed -= stream->resp_hds_len;
+        stream->resp_hds_len = 0;
+      }
+      if(data_consumed) {
+        nghttp2_session_consume(ctx->h2, stream->id, data_consumed);
+      }
+    }
+
+    if(stream->closed) {
+      CURL_TRC_CF(data, cf, "[%d] DRAIN closed stream", stream->id);
+      drain_stream(cf, data, stream);
+    }
+  }
+
+out:
+  result = h2_progress_egress(cf, data);
+  if(result == CURLE_AGAIN) {
+    /* pending data to send, need to be called again. Ideally, we'd
+     * monitor the socket for POLLOUT, but we might not be in SENDING
+     * transfer state any longer and are unable to make this happen.
+     */
+    drain_stream(cf, data, stream);
+  }
+  else if(result) {
+    *err = result;
+    nread = -1;
+  }
+  CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d, "
+              "window=%d/%d, connection %d/%d",
+              stream->id, len, nread, *err,
+              nghttp2_session_get_stream_effective_recv_data_length(
+                ctx->h2, stream->id),
+              nghttp2_session_get_stream_effective_local_window_size(
+                ctx->h2, stream->id),
+              nghttp2_session_get_local_window_size(ctx->h2),
+              HTTP2_HUGE_WINDOW_SIZE);
+
+  CF_DATA_RESTORE(cf, save);
+  return nread;
+}
+
+static ssize_t h2_submit(struct h2_stream_ctx **pstream,
+                         struct Curl_cfilter *cf, struct Curl_easy *data,
+                         const void *buf, size_t len,
+                         size_t *phdslen, CURLcode *err)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream = NULL;
+  struct dynhds h2_headers;
+  nghttp2_nv *nva = NULL;
+  const void *body = NULL;
+  size_t nheader, bodylen, i;
+  nghttp2_data_provider data_prd;
+  int32_t stream_id;
+  nghttp2_priority_spec pri_spec;
+  ssize_t nwritten;
+
+  *phdslen = 0;
+  Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
+
+  *err = http2_data_setup(cf, data, &stream);
+  if(*err) {
+    nwritten = -1;
+    goto out;
+  }
+
+  nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
+  if(nwritten < 0)
+    goto out;
+  *phdslen = (size_t)nwritten;
+  if(!stream->h1.done) {
+    /* need more data */
+    goto out;
+  }
+  DEBUGASSERT(stream->h1.req);
+
+  *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
+  if(*err) {
+    nwritten = -1;
+    goto out;
+  }
+  /* no longer needed */
+  Curl_h1_req_parse_free(&stream->h1);
+
+  nva = Curl_dynhds_to_nva(&h2_headers, &nheader);
+  if(!nva) {
+    *err = CURLE_OUT_OF_MEMORY;
+    nwritten = -1;
+    goto out;
+  }
+
+  h2_pri_spec(data, &pri_spec);
+  if(!nghttp2_session_check_request_allowed(ctx->h2))
+    CURL_TRC_CF(data, cf, "send request NOT allowed (via nghttp2)");
+
+  switch(data->state.httpreq) {
+  case HTTPREQ_POST:
+  case HTTPREQ_POST_FORM:
+  case HTTPREQ_POST_MIME:
+  case HTTPREQ_PUT:
+    if(data->state.infilesize != -1)
+      stream->upload_left = data->state.infilesize;
+    else
+      /* data sending without specifying the data amount up front */
+      stream->upload_left = -1; /* unknown */
+
+    data_prd.read_callback = req_body_read_callback;
+    data_prd.source.ptr = NULL;
+    stream_id = nghttp2_submit_request(ctx->h2, &pri_spec, nva, nheader,
+                                       &data_prd, data);
+    break;
+  default:
+    stream->upload_left = 0; /* no request body */
+    stream_id = nghttp2_submit_request(ctx->h2, &pri_spec, nva, nheader,
+                                       NULL, data);
+  }
+
+  if(stream_id < 0) {
+    CURL_TRC_CF(data, cf, "send: nghttp2_submit_request error (%s)%u",
+                nghttp2_strerror(stream_id), stream_id);
+    *err = CURLE_SEND_ERROR;
+    nwritten = -1;
+    goto out;
+  }
+
+#define MAX_ACC 60000  /* <64KB to account for some overhead */
+  if(Curl_trc_is_verbose(data)) {
+    size_t acc = 0;
+
+    infof(data, "[HTTP/2] [%d] OPENED stream for %s",
+          stream_id, data->state.url);
+    for(i = 0; i < nheader; ++i) {
+      acc += nva[i].namelen + nva[i].valuelen;
+
+      infof(data, "[HTTP/2] [%d] [%.*s: %.*s]", stream_id,
+            (int)nva[i].namelen, nva[i].name,
+            (int)nva[i].valuelen, nva[i].value);
+    }
+
+    if(acc > MAX_ACC) {
+      infof(data, "[HTTP/2] Warning: The cumulative length of all "
+            "headers exceeds %d bytes and that could cause the "
+            "stream to be rejected.", MAX_ACC);
+    }
+  }
+
+  stream->id = stream_id;
+  stream->local_window_size = H2_STREAM_WINDOW_SIZE;
+  if(data->set.max_recv_speed) {
+    /* We are asked to only receive `max_recv_speed` bytes per second.
+     * Let's limit our stream window size around that, otherwise the server
+     * will send in large bursts only. We make the window 50% larger to
+     * allow for data in flight and avoid stalling. */
+    curl_off_t n = (((data->set.max_recv_speed - 1) / H2_CHUNK_SIZE) + 1);
+    n += CURLMAX((n/2), 1);
+    if(n < (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE) &&
+       n < (UINT_MAX / H2_CHUNK_SIZE)) {
+      stream->local_window_size = (uint32_t)n * H2_CHUNK_SIZE;
+    }
+  }
+
+  body = (const char *)buf + nwritten;
+  bodylen = len - nwritten;
+
+  if(bodylen) {
+    /* We have request body to send in DATA frame */
+    ssize_t n = Curl_bufq_write(&stream->sendbuf, body, bodylen, err);
+    if(n < 0) {
+      *err = CURLE_SEND_ERROR;
+      nwritten = -1;
+      goto out;
+    }
+    nwritten += n;
+  }
+
+out:
+  CURL_TRC_CF(data, cf, "[%d] submit -> %zd, %d",
+              stream? stream->id : -1, nwritten, *err);
+  Curl_safefree(nva);
+  *pstream = stream;
+  Curl_dynhds_free(&h2_headers);
+  return nwritten;
+}
+
+static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          const void *buf, size_t len, CURLcode *err)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+  struct cf_call_data save;
+  int rv;
+  ssize_t nwritten;
+  size_t hdslen = 0;
+  CURLcode result;
+  int blocked = 0, was_blocked = 0;
+
+  CF_DATA_SAVE(save, cf, data);
+
+  if(stream && stream->id != -1) {
+    if(stream->upload_blocked_len) {
+      /* the data in `buf` has already been submitted or added to the
+       * buffers, but have been EAGAINed on the last invocation. */
+      /* TODO: this assertion triggers in OSSFuzz runs and it is not
+       * clear why. Disable for now to let OSSFuzz continue its tests. */
+      DEBUGASSERT(len >= stream->upload_blocked_len);
+      if(len < stream->upload_blocked_len) {
+        /* Did we get called again with a smaller `len`? This should not
+         * happen. We are not prepared to handle that. */
+        failf(data, "HTTP/2 send again with decreased length (%zd vs %zd)",
+              len, stream->upload_blocked_len);
+        *err = CURLE_HTTP2;
+        nwritten = -1;
+        goto out;
+      }
+      nwritten = (ssize_t)stream->upload_blocked_len;
+      stream->upload_blocked_len = 0;
+      was_blocked = 1;
+    }
+    else if(stream->closed) {
+      if(stream->resp_hds_complete) {
+        /* Server decided to close the stream after having sent us a findl
+         * response. This is valid if it is not interested in the request
+         * body. This happens on 30x or 40x responses.
+         * We silently discard the data sent, since this is not a transport
+         * error situation. */
+        CURL_TRC_CF(data, cf, "[%d] discarding data"
+                    "on closed stream with response", stream->id);
+        *err = CURLE_OK;
+        nwritten = (ssize_t)len;
+        goto out;
+      }
+      infof(data, "stream %u closed", stream->id);
+      *err = CURLE_SEND_ERROR;
+      nwritten = -1;
+      goto out;
+    }
+    else {
+      /* If stream_id != -1, we have dispatched request HEADERS and
+       * optionally request body, and now are going to send or sending
+       * more request body in DATA frame */
+      nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err);
+      if(nwritten < 0 && *err != CURLE_AGAIN)
+        goto out;
+    }
+
+    if(!Curl_bufq_is_empty(&stream->sendbuf)) {
+      /* req body data is buffered, resume the potentially suspended stream */
+      rv = nghttp2_session_resume_data(ctx->h2, stream->id);
+      if(nghttp2_is_fatal(rv)) {
+        *err = CURLE_SEND_ERROR;
+        nwritten = -1;
+        goto out;
+      }
+    }
+  }
+  else {
+    nwritten = h2_submit(&stream, cf, data, buf, len, &hdslen, err);
+    if(nwritten < 0) {
+      goto out;
+    }
+    DEBUGASSERT(stream);
+    DEBUGASSERT(hdslen <= (size_t)nwritten);
+  }
+
+  /* Call the nghttp2 send loop and flush to write ALL buffered data,
+   * headers and/or request body completely out to the network */
+  result = h2_progress_egress(cf, data);
+  /* if the stream has been closed in egress handling (nghttp2 does that
+   * when it does not like the headers, for example */
+  if(stream && stream->closed && !was_blocked) {
+    infof(data, "stream %u closed", stream->id);
+    *err = CURLE_SEND_ERROR;
+    nwritten = -1;
+    goto out;
+  }
+  else if(result == CURLE_AGAIN) {
+    blocked = 1;
+  }
+  else if(result) {
+    *err = result;
+    nwritten = -1;
+    goto out;
+  }
+  else if(stream && !Curl_bufq_is_empty(&stream->sendbuf)) {
+    /* although we wrote everything that nghttp2 wants to send now,
+     * there is data left in our stream send buffer unwritten. This may
+     * be due to the stream's HTTP/2 flow window being exhausted. */
+    blocked = 1;
+  }
+
+  if(stream && blocked && nwritten > 0) {
+    /* Unable to send all data, due to connection blocked or H2 window
+     * exhaustion. Data is left in our stream buffer, or nghttp2's internal
+     * frame buffer or our network out buffer. */
+    size_t rwin = nghttp2_session_get_stream_remote_window_size(ctx->h2,
+                                                                stream->id);
+    /* At the start of a stream, we are called with request headers
+     * and, possibly, parts of the body. Later, only body data.
+     * If we cannot send pure body data, we EAGAIN. If there had been
+     * header, we return that *they* have been written and remember the
+     * block on the data length only. */
+    stream->upload_blocked_len = ((size_t)nwritten) - hdslen;
+    CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) BLOCK: win %u/%zu "
+                "hds_len=%zu blocked_len=%zu",
+                stream->id, len,
+                nghttp2_session_get_remote_window_size(ctx->h2), rwin,
+                hdslen, stream->upload_blocked_len);
+    if(hdslen) {
+      *err = CURLE_OK;
+      nwritten = hdslen;
+    }
+    else {
+      *err = CURLE_AGAIN;
+      nwritten = -1;
+      goto out;
+    }
+  }
+  else if(should_close_session(ctx)) {
+    /* nghttp2 thinks this session is done. If the stream has not been
+     * closed, this is an error state for out transfer */
+    if(stream->closed) {
+      nwritten = http2_handle_stream_close(cf, data, stream, err);
+    }
+    else {
+      CURL_TRC_CF(data, cf, "send: nothing to do in this session");
+      *err = CURLE_HTTP2;
+      nwritten = -1;
+    }
+  }
+
+out:
+  if(stream) {
+    CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, "
+                "upload_left=%" CURL_FORMAT_CURL_OFF_T ", "
+                "h2 windows %d-%d (stream-conn), "
+                "buffers %zu-%zu (stream-conn)",
+                stream->id, len, nwritten, *err,
+                stream->upload_left,
+                nghttp2_session_get_stream_remote_window_size(
+                  ctx->h2, stream->id),
+                nghttp2_session_get_remote_window_size(ctx->h2),
+                Curl_bufq_len(&stream->sendbuf),
+                Curl_bufq_len(&ctx->outbufq));
+  }
+  else {
+    CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %zd, %d, "
+                "connection-window=%d, nw_send_buffer(%zu)",
+                len, nwritten, *err,
+                nghttp2_session_get_remote_window_size(ctx->h2),
+                Curl_bufq_len(&ctx->outbufq));
+  }
+  CF_DATA_RESTORE(cf, save);
+  return nwritten;
+}
+
+static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 struct easy_pollset *ps)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  curl_socket_t sock;
+  bool want_recv, want_send;
+
+  if(!ctx->h2)
+    return;
+
+  sock = Curl_conn_cf_get_socket(cf, data);
+  Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
+  if(want_recv || want_send) {
+    struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+    struct cf_call_data save;
+    bool c_exhaust, s_exhaust;
+
+    CF_DATA_SAVE(save, cf, data);
+    c_exhaust = want_send && !nghttp2_session_get_remote_window_size(ctx->h2);
+    s_exhaust = want_send && stream && stream->id >= 0 &&
+                !nghttp2_session_get_stream_remote_window_size(ctx->h2,
+                                                               stream->id);
+    want_recv = (want_recv || c_exhaust || s_exhaust);
+    want_send = (!s_exhaust && want_send) ||
+                (!c_exhaust && nghttp2_session_want_write(ctx->h2));
+
+    Curl_pollset_set(data, ps, sock, want_recv, want_send);
+    CF_DATA_RESTORE(cf, save);
+  }
+}
+
+static CURLcode cf_h2_connect(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              bool blocking, bool *done)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
+  struct cf_call_data save;
+
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  /* Connect the lower filters first */
+  if(!cf->next->connected) {
+    result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+    if(result || !*done)
+      return result;
+  }
+
+  *done = FALSE;
+
+  CF_DATA_SAVE(save, cf, data);
+  if(!ctx->h2) {
+    result = cf_h2_ctx_init(cf, data, FALSE);
+    if(result)
+      goto out;
+  }
+
+  result = h2_progress_ingress(cf, data, H2_CHUNK_SIZE);
+  if(result)
+    goto out;
+
+  /* Send out our SETTINGS and ACKs and such. If that blocks, we
+   * have it buffered and  can count this filter as being connected */
+  result = h2_progress_egress(cf, data);
+  if(result == CURLE_AGAIN)
+    result = CURLE_OK;
+  else if(result)
+    goto out;
+
+  *done = TRUE;
+  cf->connected = TRUE;
+  result = CURLE_OK;
+
+out:
+  CURL_TRC_CF(data, cf, "cf_connect() -> %d, %d, ", result, *done);
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
+static void cf_h2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+
+  if(ctx) {
+    struct cf_call_data save;
+
+    CF_DATA_SAVE(save, cf, data);
+    cf_h2_ctx_clear(ctx);
+    CF_DATA_RESTORE(cf, save);
+  }
+  if(cf->next)
+    cf->next->cft->do_close(cf->next, data);
+}
+
+static void cf_h2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+
+  (void)data;
+  if(ctx) {
+    cf_h2_ctx_free(ctx);
+    cf->ctx = NULL;
+  }
+}
+
+static CURLcode http2_data_pause(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 bool pause)
+{
+#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+
+  DEBUGASSERT(data);
+  if(ctx && ctx->h2 && stream) {
+    uint32_t window = pause? 0 : stream->local_window_size;
+
+    int rv = nghttp2_session_set_local_window_size(ctx->h2,
+                                                   NGHTTP2_FLAG_NONE,
+                                                   stream->id,
+                                                   window);
+    if(rv) {
+      failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
+            nghttp2_strerror(rv), rv);
+      return CURLE_HTTP2;
+    }
+
+    if(!pause)
+      drain_stream(cf, data, stream);
+
+    /* attempt to send the window update */
+    (void)h2_progress_egress(cf, data);
+
+    if(!pause) {
+      /* Unpausing a h2 transfer, requires it to be run again. The server
+       * may send new DATA on us increasing the flow window, and it may
+       * not. We may have already buffered and exhausted the new window
+       * by operating on things in flight during the handling of other
+       * transfers. */
+      drain_stream(cf, data, stream);
+      Curl_expire(data, 0, EXPIRE_RUN_NOW);
+    }
+    DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u",
+                 window, stream->id));
+
+#ifdef DEBUGBUILD
+    {
+      /* read out the stream local window again */
+      uint32_t window2 =
+        nghttp2_session_get_stream_local_window_size(ctx->h2,
+                                                     stream->id);
+      DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u",
+                   window2, stream->id));
+    }
+#endif
+  }
+#endif
+  return CURLE_OK;
+}
+
+static CURLcode cf_h2_cntrl(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            int event, int arg1, void *arg2)
+{
+  CURLcode result = CURLE_OK;
+  struct cf_call_data save;
+
+  (void)arg2;
+
+  CF_DATA_SAVE(save, cf, data);
+  switch(event) {
+  case CF_CTRL_DATA_SETUP:
+    break;
+  case CF_CTRL_DATA_PAUSE:
+    result = http2_data_pause(cf, data, (arg1 != 0));
+    break;
+  case CF_CTRL_DATA_DONE_SEND:
+    result = http2_data_done_send(cf, data);
+    break;
+  case CF_CTRL_DATA_DETACH:
+    http2_data_done(cf, data);
+    break;
+  case CF_CTRL_DATA_DONE:
+    http2_data_done(cf, data);
+    break;
+  default:
+    break;
+  }
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
+static bool cf_h2_data_pending(struct Curl_cfilter *cf,
+                               const struct Curl_easy *data)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+
+  if(ctx && (!Curl_bufq_is_empty(&ctx->inbufq)
+            || (stream && !Curl_bufq_is_empty(&stream->sendbuf))))
+    return TRUE;
+  return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
+}
+
+static bool cf_h2_is_alive(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           bool *input_pending)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  CURLcode result;
+  struct cf_call_data save;
+
+  CF_DATA_SAVE(save, cf, data);
+  result = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending));
+  CURL_TRC_CF(data, cf, "conn alive -> %d, input_pending=%d",
+              result, *input_pending);
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
+static CURLcode cf_h2_keep_alive(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data)
+{
+  CURLcode result;
+  struct cf_call_data save;
+
+  CF_DATA_SAVE(save, cf, data);
+  result = http2_send_ping(cf, data);
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
+static CURLcode cf_h2_query(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            int query, int *pres1, void *pres2)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct cf_call_data save;
+  size_t effective_max;
+
+  switch(query) {
+  case CF_QUERY_MAX_CONCURRENT:
+    DEBUGASSERT(pres1);
+
+    CF_DATA_SAVE(save, cf, data);
+    if(nghttp2_session_check_request_allowed(ctx->h2) == 0) {
+      /* the limit is what we have in use right now */
+      effective_max = CONN_INUSE(cf->conn);
+    }
+    else {
+      effective_max = ctx->max_concurrent_streams;
+    }
+    *pres1 = (effective_max > INT_MAX)? INT_MAX : (int)effective_max;
+    CF_DATA_RESTORE(cf, save);
+    return CURLE_OK;
+  default:
+    break;
+  }
+  return cf->next?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
+}
+
+struct Curl_cftype Curl_cft_nghttp2 = {
+  "HTTP/2",
+  CF_TYPE_MULTIPLEX,
+  CURL_LOG_LVL_NONE,
+  cf_h2_destroy,
+  cf_h2_connect,
+  cf_h2_close,
+  Curl_cf_def_get_host,
+  cf_h2_adjust_pollset,
+  cf_h2_data_pending,
+  cf_h2_send,
+  cf_h2_recv,
+  cf_h2_cntrl,
+  cf_h2_is_alive,
+  cf_h2_keep_alive,
+  cf_h2_query,
+};
+
+static CURLcode http2_cfilter_add(struct Curl_cfilter **pcf,
+                                  struct Curl_easy *data,
+                                  struct connectdata *conn,
+                                  int sockindex,
+                                  bool via_h1_upgrade)
+{
+  struct Curl_cfilter *cf = NULL;
+  struct cf_h2_ctx *ctx;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+
+  DEBUGASSERT(data->conn);
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx)
+    goto out;
+
+  result = Curl_cf_create(&cf, &Curl_cft_nghttp2, ctx);
+  if(result)
+    goto out;
+
+  ctx = NULL;
+  Curl_conn_cf_add(data, conn, sockindex, cf);
+  result = cf_h2_ctx_init(cf, data, via_h1_upgrade);
+
+out:
+  if(result)
+    cf_h2_ctx_free(ctx);
+  *pcf = result? NULL : cf;
+  return result;
+}
+
+static CURLcode http2_cfilter_insert_after(struct Curl_cfilter *cf,
+                                           struct Curl_easy *data,
+                                           bool via_h1_upgrade)
+{
+  struct Curl_cfilter *cf_h2 = NULL;
+  struct cf_h2_ctx *ctx;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+
+  (void)data;
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx)
+    goto out;
+
+  result = Curl_cf_create(&cf_h2, &Curl_cft_nghttp2, ctx);
+  if(result)
+    goto out;
+
+  ctx = NULL;
+  Curl_conn_cf_insert_after(cf, cf_h2);
+  result = cf_h2_ctx_init(cf_h2, data, via_h1_upgrade);
+
+out:
+  if(result)
+    cf_h2_ctx_free(ctx);
+  return result;
+}
+
+static bool Curl_cf_is_http2(struct Curl_cfilter *cf,
+                             const struct Curl_easy *data)
+{
+  (void)data;
+  for(; cf; cf = cf->next) {
+    if(cf->cft == &Curl_cft_nghttp2)
+      return TRUE;
+    if(cf->cft->flags & CF_TYPE_IP_CONNECT)
+      return FALSE;
+  }
+  return FALSE;
+}
+
+bool Curl_conn_is_http2(const struct Curl_easy *data,
+                        const struct connectdata *conn,
+                        int sockindex)
+{
+  return conn? Curl_cf_is_http2(conn->cfilter[sockindex], data) : FALSE;
+}
+
+bool Curl_http2_may_switch(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           int sockindex)
+{
+  (void)sockindex;
+  if(!Curl_conn_is_http2(data, conn, sockindex) &&
+     data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
+#ifndef CURL_DISABLE_PROXY
+    if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
+      /* We don't support HTTP/2 proxies yet. Also it's debatable
+         whether or not this setting should apply to HTTP/2 proxies. */
+      infof(data, "Ignoring HTTP/2 prior knowledge due to proxy");
+      return FALSE;
+    }
+#endif
+    return TRUE;
+  }
+  return FALSE;
+}
+
+CURLcode Curl_http2_switch(struct Curl_easy *data,
+                           struct connectdata *conn, int sockindex)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result;
+
+  DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex));
+  DEBUGF(infof(data, "switching to HTTP/2"));
+
+  result = http2_cfilter_add(&cf, data, conn, sockindex, FALSE);
+  if(result)
+    return result;
+
+  conn->httpversion = 20; /* we know we're on HTTP/2 now */
+  conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+  conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+  Curl_multi_connchanged(data->multi);
+
+  if(cf->next) {
+    bool done;
+    return Curl_conn_cf_connect(cf, data, FALSE, &done);
+  }
+  return CURLE_OK;
+}
+
+CURLcode Curl_http2_switch_at(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct Curl_cfilter *cf_h2;
+  CURLcode result;
+
+  DEBUGASSERT(!Curl_cf_is_http2(cf, data));
+
+  result = http2_cfilter_insert_after(cf, data, FALSE);
+  if(result)
+    return result;
+
+  cf_h2 = cf->next;
+  cf->conn->httpversion = 20; /* we know we're on HTTP/2 now */
+  cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+  cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+  Curl_multi_connchanged(data->multi);
+
+  if(cf_h2->next) {
+    bool done;
+    return Curl_conn_cf_connect(cf_h2, data, FALSE, &done);
+  }
+  return CURLE_OK;
+}
+
+CURLcode Curl_http2_upgrade(struct Curl_easy *data,
+                            struct connectdata *conn, int sockindex,
+                            const char *mem, size_t nread)
+{
+  struct Curl_cfilter *cf;
+  struct cf_h2_ctx *ctx;
+  CURLcode result;
+
+  DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex));
+  DEBUGF(infof(data, "upgrading to HTTP/2"));
+  DEBUGASSERT(data->req.upgr101 == UPGR101_RECEIVED);
+
+  result = http2_cfilter_add(&cf, data, conn, sockindex, TRUE);
+  if(result)
+    return result;
+
+  DEBUGASSERT(cf->cft == &Curl_cft_nghttp2);
+  ctx = cf->ctx;
+
+  if(nread > 0) {
+    /* Remaining data from the protocol switch reply is already using
+     * the switched protocol, ie. HTTP/2. We add that to the network
+     * inbufq. */
+    ssize_t copied;
+
+    copied = Curl_bufq_write(&ctx->inbufq,
+                             (const unsigned char *)mem, nread, &result);
+    if(copied < 0) {
+      failf(data, "error on copying HTTP Upgrade response: %d", result);
+      return CURLE_RECV_ERROR;
+    }
+    if((size_t)copied < nread) {
+      failf(data, "connection buffer size could not take all data "
+            "from HTTP Upgrade response header: copied=%zd, datalen=%zu",
+            copied, nread);
+      return CURLE_HTTP2;
+    }
+    infof(data, "Copied HTTP/2 data in stream buffer to connection buffer"
+          " after upgrade: len=%zu", nread);
+  }
+
+  conn->httpversion = 20; /* we know we're on HTTP/2 now */
+  conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+  conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+  Curl_multi_connchanged(data->multi);
+
+  if(cf->next) {
+    bool done;
+    return Curl_conn_cf_connect(cf, data, FALSE, &done);
+  }
+  return CURLE_OK;
+}
+
+/* Only call this function for a transfer that already got an HTTP/2
+   CURLE_HTTP2_STREAM error! */
+bool Curl_h2_http_1_1_error(struct Curl_easy *data)
+{
+  struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+  return (stream && stream->error == NGHTTP2_HTTP_1_1_REQUIRED);
+}
+
+#else /* !USE_NGHTTP2 */
+
+/* Satisfy external references even if http2 is not compiled in. */
+#include <curl/curl.h>
+
+char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
+{
+  (void) h;
+  (void) num;
+  return NULL;
+}
+
+char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
+{
+  (void) h;
+  (void) header;
+  return NULL;
+}
+
+#endif /* USE_NGHTTP2 */
Index: trunk/src/libs/curl-8.7.1/lib/http2.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http2.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http2.h	(revision 104083)
@@ -0,0 +1,77 @@
+#ifndef HEADER_CURL_HTTP2_H
+#define HEADER_CURL_HTTP2_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_NGHTTP2
+#include "http.h"
+
+/* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting
+   from the peer */
+#define DEFAULT_MAX_CONCURRENT_STREAMS 100
+
+/*
+ * Store nghttp2 version info in this buffer.
+ */
+void Curl_http2_ver(char *p, size_t len);
+
+CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
+                                    struct Curl_easy *data);
+
+/* returns true if the HTTP/2 stream error was HTTP_1_1_REQUIRED */
+bool Curl_h2_http_1_1_error(struct Curl_easy *data);
+
+bool Curl_conn_is_http2(const struct Curl_easy *data,
+                        const struct connectdata *conn,
+                        int sockindex);
+bool Curl_http2_may_switch(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           int sockindex);
+
+CURLcode Curl_http2_switch(struct Curl_easy *data,
+                           struct connectdata *conn, int sockindex);
+
+CURLcode Curl_http2_switch_at(struct Curl_cfilter *cf, struct Curl_easy *data);
+
+CURLcode Curl_http2_upgrade(struct Curl_easy *data,
+                            struct connectdata *conn, int sockindex,
+                            const char *ptr, size_t nread);
+
+extern struct Curl_cftype Curl_cft_nghttp2;
+
+#else /* USE_NGHTTP2 */
+
+#define Curl_cf_is_http2(a,b) FALSE
+#define Curl_conn_is_http2(a,b,c) FALSE
+#define Curl_http2_may_switch(a,b,c) FALSE
+
+#define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL
+#define Curl_http2_switch(a,b,c)        CURLE_UNSUPPORTED_PROTOCOL
+#define Curl_http2_upgrade(a,b,c,d,e)   CURLE_UNSUPPORTED_PROTOCOL
+#define Curl_h2_http_1_1_error(x) 0
+#endif
+
+#endif /* HEADER_CURL_HTTP2_H */
Index: trunk/src/libs/curl-8.7.1/lib/http_aws_sigv4.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http_aws_sigv4.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http_aws_sigv4.c	(revision 104083)
@@ -0,0 +1,817 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS)
+
+#include "urldata.h"
+#include "strcase.h"
+#include "strdup.h"
+#include "http_aws_sigv4.h"
+#include "curl_sha256.h"
+#include "transfer.h"
+#include "parsedate.h"
+#include "sendf.h"
+#include "escape.h"
+
+#include <time.h>
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#include "slist.h"
+
+#define HMAC_SHA256(k, kl, d, dl, o)           \
+  do {                                         \
+    result = Curl_hmacit(Curl_HMAC_SHA256,     \
+                         (unsigned char *)k,   \
+                         kl,                   \
+                         (unsigned char *)d,   \
+                         dl, o);               \
+    if(result) {                               \
+      goto fail;                               \
+    }                                          \
+  } while(0)
+
+#define TIMESTAMP_SIZE 17
+
+/* hex-encoded with trailing null */
+#define SHA256_HEX_LENGTH (2 * SHA256_DIGEST_LENGTH + 1)
+
+static void sha256_to_hex(char *dst, unsigned char *sha)
+{
+  Curl_hexencode(sha, SHA256_DIGEST_LENGTH,
+                 (unsigned char *)dst, SHA256_HEX_LENGTH);
+}
+
+static char *find_date_hdr(struct Curl_easy *data, const char *sig_hdr)
+{
+  char *tmp = Curl_checkheaders(data, sig_hdr, strlen(sig_hdr));
+
+  if(tmp)
+    return tmp;
+  return Curl_checkheaders(data, STRCONST("Date"));
+}
+
+/* remove whitespace, and lowercase all headers */
+static void trim_headers(struct curl_slist *head)
+{
+  struct curl_slist *l;
+  for(l = head; l; l = l->next) {
+    char *value; /* to read from */
+    char *store;
+    size_t colon = strcspn(l->data, ":");
+    Curl_strntolower(l->data, l->data, colon);
+
+    value = &l->data[colon];
+    if(!*value)
+      continue;
+    ++value;
+    store = value;
+
+    /* skip leading whitespace */
+    while(*value && ISBLANK(*value))
+      value++;
+
+    while(*value) {
+      int space = 0;
+      while(*value && ISBLANK(*value)) {
+        value++;
+        space++;
+      }
+      if(space) {
+        /* replace any number of consecutive whitespace with a single space,
+           unless at the end of the string, then nothing */
+        if(*value)
+          *store++ = ' ';
+      }
+      else
+        *store++ = *value++;
+    }
+    *store = 0; /* null terminate */
+  }
+}
+
+/* maximum length for the aws sivg4 parts */
+#define MAX_SIGV4_LEN 64
+#define MAX_SIGV4_LEN_TXT "64"
+
+#define DATE_HDR_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Date"))
+
+#define MAX_HOST_LEN 255
+/* FQDN + host: */
+#define FULL_HOST_LEN (MAX_HOST_LEN + sizeof("host:"))
+
+/* string been x-PROVIDER-date:TIMESTAMP, I need +1 for ':' */
+#define DATE_FULL_HDR_LEN (DATE_HDR_KEY_LEN + TIMESTAMP_SIZE + 1)
+
+/* timestamp should point to a buffer of at last TIMESTAMP_SIZE bytes */
+static CURLcode make_headers(struct Curl_easy *data,
+                             const char *hostname,
+                             char *timestamp,
+                             char *provider1,
+                             char **date_header,
+                             char *content_sha256_header,
+                             struct dynbuf *canonical_headers,
+                             struct dynbuf *signed_headers)
+{
+  char date_hdr_key[DATE_HDR_KEY_LEN];
+  char date_full_hdr[DATE_FULL_HDR_LEN];
+  struct curl_slist *head = NULL;
+  struct curl_slist *tmp_head = NULL;
+  CURLcode ret = CURLE_OUT_OF_MEMORY;
+  struct curl_slist *l;
+  int again = 1;
+
+  /* provider1 mid */
+  Curl_strntolower(provider1, provider1, strlen(provider1));
+  provider1[0] = Curl_raw_toupper(provider1[0]);
+
+  msnprintf(date_hdr_key, DATE_HDR_KEY_LEN, "X-%s-Date", provider1);
+
+  /* provider1 lowercase */
+  Curl_strntolower(provider1, provider1, 1); /* first byte only */
+  msnprintf(date_full_hdr, DATE_FULL_HDR_LEN,
+            "x-%s-date:%s", provider1, timestamp);
+
+  if(Curl_checkheaders(data, STRCONST("Host"))) {
+    head = NULL;
+  }
+  else {
+    char full_host[FULL_HOST_LEN + 1];
+
+    if(data->state.aptr.host) {
+      size_t pos;
+
+      if(strlen(data->state.aptr.host) > FULL_HOST_LEN) {
+        ret = CURLE_URL_MALFORMAT;
+        goto fail;
+      }
+      strcpy(full_host, data->state.aptr.host);
+      /* remove /r/n as the separator for canonical request must be '\n' */
+      pos = strcspn(full_host, "\n\r");
+      full_host[pos] = 0;
+    }
+    else {
+      if(strlen(hostname) > MAX_HOST_LEN) {
+        ret = CURLE_URL_MALFORMAT;
+        goto fail;
+      }
+      msnprintf(full_host, FULL_HOST_LEN, "host:%s", hostname);
+    }
+
+    head = curl_slist_append(NULL, full_host);
+    if(!head)
+      goto fail;
+  }
+
+
+  if(*content_sha256_header) {
+    tmp_head = curl_slist_append(head, content_sha256_header);
+    if(!tmp_head)
+      goto fail;
+    head = tmp_head;
+  }
+
+  /* copy user headers to our header list. the logic is based on how http.c
+     handles user headers.
+
+     user headers in format 'name:' with no value are used to signal that an
+     internal header of that name should be removed. those user headers are not
+     added to this list.
+
+     user headers in format 'name;' with no value are used to signal that a
+     header of that name with no value should be sent. those user headers are
+     added to this list but in the format that they will be sent, ie the
+     semi-colon is changed to a colon for format 'name:'.
+
+     user headers with a value of whitespace only, or without a colon or
+     semi-colon, are not added to this list.
+     */
+  for(l = data->set.headers; l; l = l->next) {
+    char *dupdata, *ptr;
+    char *sep = strchr(l->data, ':');
+    if(!sep)
+      sep = strchr(l->data, ';');
+    if(!sep || (*sep == ':' && !*(sep + 1)))
+      continue;
+    for(ptr = sep + 1; ISSPACE(*ptr); ++ptr)
+      ;
+    if(!*ptr && ptr != sep + 1) /* a value of whitespace only */
+      continue;
+    dupdata = strdup(l->data);
+    if(!dupdata)
+      goto fail;
+    dupdata[sep - l->data] = ':';
+    tmp_head = Curl_slist_append_nodup(head, dupdata);
+    if(!tmp_head) {
+      free(dupdata);
+      goto fail;
+    }
+    head = tmp_head;
+  }
+
+  trim_headers(head);
+
+  *date_header = find_date_hdr(data, date_hdr_key);
+  if(!*date_header) {
+    tmp_head = curl_slist_append(head, date_full_hdr);
+    if(!tmp_head)
+      goto fail;
+    head = tmp_head;
+    *date_header = curl_maprintf("%s: %s\r\n", date_hdr_key, timestamp);
+  }
+  else {
+    char *value;
+    char *endp;
+    value = strchr(*date_header, ':');
+    if(!value) {
+      *date_header = NULL;
+      goto fail;
+    }
+    ++value;
+    while(ISBLANK(*value))
+      ++value;
+    endp = value;
+    while(*endp && ISALNUM(*endp))
+      ++endp;
+    /* 16 bytes => "19700101T000000Z" */
+    if((endp - value) == TIMESTAMP_SIZE - 1) {
+      memcpy(timestamp, value, TIMESTAMP_SIZE - 1);
+      timestamp[TIMESTAMP_SIZE - 1] = 0;
+    }
+    else
+      /* bad timestamp length */
+      timestamp[0] = 0;
+    *date_header = NULL;
+  }
+
+  /* alpha-sort in a case sensitive manner */
+  do {
+    again = 0;
+    for(l = head; l; l = l->next) {
+      struct curl_slist *next = l->next;
+
+      if(next && strcmp(l->data, next->data) > 0) {
+        char *tmp = l->data;
+
+        l->data = next->data;
+        next->data = tmp;
+        again = 1;
+      }
+    }
+  } while(again);
+
+  for(l = head; l; l = l->next) {
+    char *tmp;
+
+    if(Curl_dyn_add(canonical_headers, l->data))
+      goto fail;
+    if(Curl_dyn_add(canonical_headers, "\n"))
+      goto fail;
+
+    tmp = strchr(l->data, ':');
+    if(tmp)
+      *tmp = 0;
+
+    if(l != head) {
+      if(Curl_dyn_add(signed_headers, ";"))
+        goto fail;
+    }
+    if(Curl_dyn_add(signed_headers, l->data))
+      goto fail;
+  }
+
+  ret = CURLE_OK;
+fail:
+  curl_slist_free_all(head);
+
+  return ret;
+}
+
+#define CONTENT_SHA256_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Content-Sha256"))
+/* add 2 for ": " between header name and value */
+#define CONTENT_SHA256_HDR_LEN (CONTENT_SHA256_KEY_LEN + 2 + \
+                                SHA256_HEX_LENGTH)
+
+/* try to parse a payload hash from the content-sha256 header */
+static char *parse_content_sha_hdr(struct Curl_easy *data,
+                                   const char *provider1,
+                                   size_t *value_len)
+{
+  char key[CONTENT_SHA256_KEY_LEN];
+  size_t key_len;
+  char *value;
+  size_t len;
+
+  key_len = msnprintf(key, sizeof(key), "x-%s-content-sha256", provider1);
+
+  value = Curl_checkheaders(data, key, key_len);
+  if(!value)
+    return NULL;
+
+  value = strchr(value, ':');
+  if(!value)
+    return NULL;
+  ++value;
+
+  while(*value && ISBLANK(*value))
+    ++value;
+
+  len = strlen(value);
+  while(len > 0 && ISBLANK(value[len-1]))
+    --len;
+
+  *value_len = len;
+  return value;
+}
+
+static CURLcode calc_payload_hash(struct Curl_easy *data,
+                                  unsigned char *sha_hash, char *sha_hex)
+{
+  const char *post_data = data->set.postfields;
+  size_t post_data_len = 0;
+  CURLcode result;
+
+  if(post_data) {
+    if(data->set.postfieldsize < 0)
+      post_data_len = strlen(post_data);
+    else
+      post_data_len = (size_t)data->set.postfieldsize;
+  }
+  result = Curl_sha256it(sha_hash, (const unsigned char *) post_data,
+                         post_data_len);
+  if(!result)
+    sha256_to_hex(sha_hex, sha_hash);
+  return result;
+}
+
+#define S3_UNSIGNED_PAYLOAD "UNSIGNED-PAYLOAD"
+
+static CURLcode calc_s3_payload_hash(struct Curl_easy *data,
+                                     Curl_HttpReq httpreq, char *provider1,
+                                     unsigned char *sha_hash,
+                                     char *sha_hex, char *header)
+{
+  bool empty_method = (httpreq == HTTPREQ_GET || httpreq == HTTPREQ_HEAD);
+  /* The request method or filesize indicate no request payload */
+  bool empty_payload = (empty_method || data->set.filesize == 0);
+  /* The POST payload is in memory */
+  bool post_payload = (httpreq == HTTPREQ_POST && data->set.postfields);
+  CURLcode ret = CURLE_OUT_OF_MEMORY;
+
+  if(empty_payload || post_payload) {
+    /* Calculate a real hash when we know the request payload */
+    ret = calc_payload_hash(data, sha_hash, sha_hex);
+    if(ret)
+      goto fail;
+  }
+  else {
+    /* Fall back to s3's UNSIGNED-PAYLOAD */
+    size_t len = sizeof(S3_UNSIGNED_PAYLOAD) - 1;
+    DEBUGASSERT(len < SHA256_HEX_LENGTH); /* 16 < 65 */
+    memcpy(sha_hex, S3_UNSIGNED_PAYLOAD, len);
+    sha_hex[len] = 0;
+  }
+
+  /* format the required content-sha256 header */
+  msnprintf(header, CONTENT_SHA256_HDR_LEN,
+            "x-%s-content-sha256: %s", provider1, sha_hex);
+
+  ret = CURLE_OK;
+fail:
+  return ret;
+}
+
+struct pair {
+  const char *p;
+  size_t len;
+};
+
+static int compare_func(const void *a, const void *b)
+{
+  const struct pair *aa = a;
+  const struct pair *bb = b;
+  /* If one element is empty, the other is always sorted higher */
+  if(aa->len == 0)
+    return -1;
+  if(bb->len == 0)
+    return 1;
+  return strncmp(aa->p, bb->p, aa->len < bb->len ? aa->len : bb->len);
+}
+
+#define MAX_QUERYPAIRS 64
+
+static CURLcode canon_query(struct Curl_easy *data,
+                            const char *query, struct dynbuf *dq)
+{
+  CURLcode result = CURLE_OK;
+  int entry = 0;
+  int i;
+  const char *p = query;
+  struct pair array[MAX_QUERYPAIRS];
+  struct pair *ap = &array[0];
+  if(!query)
+    return result;
+
+  /* sort the name=value pairs first */
+  do {
+    char *amp;
+    entry++;
+    ap->p = p;
+    amp = strchr(p, '&');
+    if(amp)
+      ap->len = amp - p; /* excluding the ampersand */
+    else {
+      ap->len = strlen(p);
+      break;
+    }
+    ap++;
+    p = amp + 1;
+  } while(entry < MAX_QUERYPAIRS);
+  if(entry == MAX_QUERYPAIRS) {
+    /* too many query pairs for us */
+    failf(data, "aws-sigv4: too many query pairs in URL");
+    return CURLE_URL_MALFORMAT;
+  }
+
+  qsort(&array[0], entry, sizeof(struct pair), compare_func);
+
+  ap = &array[0];
+  for(i = 0; !result && (i < entry); i++, ap++) {
+    size_t len;
+    const char *q = ap->p;
+    bool found_equals = false;
+    if(!ap->len)
+      continue;
+    for(len = ap->len; len && !result; q++, len--) {
+      if(ISALNUM(*q))
+        result = Curl_dyn_addn(dq, q, 1);
+      else {
+        switch(*q) {
+        case '-':
+        case '.':
+        case '_':
+        case '~':
+          /* allowed as-is */
+          result = Curl_dyn_addn(dq, q, 1);
+          break;
+        case '=':
+          /* allowed as-is */
+          result = Curl_dyn_addn(dq, q, 1);
+          found_equals = true;
+          break;
+        case '%':
+          /* uppercase the following if hexadecimal */
+          if(ISXDIGIT(q[1]) && ISXDIGIT(q[2])) {
+            char tmp[3]="%";
+            tmp[1] = Curl_raw_toupper(q[1]);
+            tmp[2] = Curl_raw_toupper(q[2]);
+            result = Curl_dyn_addn(dq, tmp, 3);
+            q += 2;
+            len -= 2;
+          }
+          else
+            /* '%' without a following two-digit hex, encode it */
+            result = Curl_dyn_addn(dq, "%25", 3);
+          break;
+        default: {
+          /* URL encode */
+          const char hex[] = "0123456789ABCDEF";
+          char out[3]={'%'};
+          out[1] = hex[((unsigned char)*q)>>4];
+          out[2] = hex[*q & 0xf];
+          result = Curl_dyn_addn(dq, out, 3);
+          break;
+        }
+        }
+      }
+    }
+    if(!result && !found_equals) {
+      /* queries without value still need an equals */
+      result = Curl_dyn_addn(dq, "=", 1);
+    }
+    if(!result && i < entry - 1) {
+      /* insert ampersands between query pairs */
+      result = Curl_dyn_addn(dq, "&", 1);
+    }
+  }
+  return result;
+}
+
+
+CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
+{
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  struct connectdata *conn = data->conn;
+  size_t len;
+  const char *arg;
+  char provider0[MAX_SIGV4_LEN + 1]="";
+  char provider1[MAX_SIGV4_LEN + 1]="";
+  char region[MAX_SIGV4_LEN + 1]="";
+  char service[MAX_SIGV4_LEN + 1]="";
+  bool sign_as_s3 = false;
+  const char *hostname = conn->host.name;
+  time_t clock;
+  struct tm tm;
+  char timestamp[TIMESTAMP_SIZE];
+  char date[9];
+  struct dynbuf canonical_headers;
+  struct dynbuf signed_headers;
+  struct dynbuf canonical_query;
+  char *date_header = NULL;
+  Curl_HttpReq httpreq;
+  const char *method = NULL;
+  char *payload_hash = NULL;
+  size_t payload_hash_len = 0;
+  unsigned char sha_hash[SHA256_DIGEST_LENGTH];
+  char sha_hex[SHA256_HEX_LENGTH];
+  char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */
+  char *canonical_request = NULL;
+  char *request_type = NULL;
+  char *credential_scope = NULL;
+  char *str_to_sign = NULL;
+  const char *user = data->state.aptr.user ? data->state.aptr.user : "";
+  char *secret = NULL;
+  unsigned char sign0[SHA256_DIGEST_LENGTH] = {0};
+  unsigned char sign1[SHA256_DIGEST_LENGTH] = {0};
+  char *auth_headers = NULL;
+
+  DEBUGASSERT(!proxy);
+  (void)proxy;
+
+  if(Curl_checkheaders(data, STRCONST("Authorization"))) {
+    /* Authorization already present, Bailing out */
+    return CURLE_OK;
+  }
+
+  /* we init those buffers here, so goto fail will free initialized dynbuf */
+  Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
+  Curl_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER);
+  Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);
+
+  /*
+   * Parameters parsing
+   * Google and Outscale use the same OSC or GOOG,
+   * but Amazon uses AWS and AMZ for header arguments.
+   * AWS is the default because most of non-amazon providers
+   * are still using aws:amz as a prefix.
+   */
+  arg = data->set.str[STRING_AWS_SIGV4] ?
+    data->set.str[STRING_AWS_SIGV4] : "aws:amz";
+
+  /* provider1[:provider2[:region[:service]]]
+
+     No string can be longer than N bytes of non-whitespace
+  */
+  (void)sscanf(arg, "%" MAX_SIGV4_LEN_TXT "[^:]"
+               ":%" MAX_SIGV4_LEN_TXT "[^:]"
+               ":%" MAX_SIGV4_LEN_TXT "[^:]"
+               ":%" MAX_SIGV4_LEN_TXT "s",
+               provider0, provider1, region, service);
+  if(!provider0[0]) {
+    failf(data, "first aws-sigv4 provider can't be empty");
+    result = CURLE_BAD_FUNCTION_ARGUMENT;
+    goto fail;
+  }
+  else if(!provider1[0])
+    strcpy(provider1, provider0);
+
+  if(!service[0]) {
+    char *hostdot = strchr(hostname, '.');
+    if(!hostdot) {
+      failf(data, "aws-sigv4: service missing in parameters and hostname");
+      result = CURLE_URL_MALFORMAT;
+      goto fail;
+    }
+    len = hostdot - hostname;
+    if(len > MAX_SIGV4_LEN) {
+      failf(data, "aws-sigv4: service too long in hostname");
+      result = CURLE_URL_MALFORMAT;
+      goto fail;
+    }
+    memcpy(service, hostname, len);
+    service[len] = '\0';
+
+    infof(data, "aws_sigv4: picked service %s from host", service);
+
+    if(!region[0]) {
+      const char *reg = hostdot + 1;
+      const char *hostreg = strchr(reg, '.');
+      if(!hostreg) {
+        failf(data, "aws-sigv4: region missing in parameters and hostname");
+        result = CURLE_URL_MALFORMAT;
+        goto fail;
+      }
+      len = hostreg - reg;
+      if(len > MAX_SIGV4_LEN) {
+        failf(data, "aws-sigv4: region too long in hostname");
+        result = CURLE_URL_MALFORMAT;
+        goto fail;
+      }
+      memcpy(region, reg, len);
+      region[len] = '\0';
+      infof(data, "aws_sigv4: picked region %s from host", region);
+    }
+  }
+
+  Curl_http_method(data, conn, &method, &httpreq);
+
+  /* AWS S3 requires a x-amz-content-sha256 header, and supports special
+   * values like UNSIGNED-PAYLOAD */
+  sign_as_s3 = (strcasecompare(provider0, "aws") &&
+                strcasecompare(service, "s3"));
+
+  payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len);
+
+  if(!payload_hash) {
+    if(sign_as_s3)
+      result = calc_s3_payload_hash(data, httpreq, provider1, sha_hash,
+                                    sha_hex, content_sha256_hdr);
+    else
+      result = calc_payload_hash(data, sha_hash, sha_hex);
+    if(result)
+      goto fail;
+
+    payload_hash = sha_hex;
+    /* may be shorter than SHA256_HEX_LENGTH, like S3_UNSIGNED_PAYLOAD */
+    payload_hash_len = strlen(sha_hex);
+  }
+
+#ifdef DEBUGBUILD
+  {
+    char *force_timestamp = getenv("CURL_FORCETIME");
+    if(force_timestamp)
+      clock = 0;
+    else
+      time(&clock);
+  }
+#else
+  time(&clock);
+#endif
+  result = Curl_gmtime(clock, &tm);
+  if(result) {
+    goto fail;
+  }
+  if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto fail;
+  }
+
+  result = make_headers(data, hostname, timestamp, provider1,
+                        &date_header, content_sha256_hdr,
+                        &canonical_headers, &signed_headers);
+  if(result)
+    goto fail;
+
+  if(*content_sha256_hdr) {
+    /* make_headers() needed this without the \r\n for canonicalization */
+    size_t hdrlen = strlen(content_sha256_hdr);
+    DEBUGASSERT(hdrlen + 3 < sizeof(content_sha256_hdr));
+    memcpy(content_sha256_hdr + hdrlen, "\r\n", 3);
+  }
+
+  memcpy(date, timestamp, sizeof(date));
+  date[sizeof(date) - 1] = 0;
+
+  result = canon_query(data, data->state.up.query, &canonical_query);
+  if(result)
+    goto fail;
+  result = CURLE_OUT_OF_MEMORY;
+
+  canonical_request =
+    curl_maprintf("%s\n" /* HTTPRequestMethod */
+                  "%s\n" /* CanonicalURI */
+                  "%s\n" /* CanonicalQueryString */
+                  "%s\n" /* CanonicalHeaders */
+                  "%s\n" /* SignedHeaders */
+                  "%.*s",  /* HashedRequestPayload in hex */
+                  method,
+                  data->state.up.path,
+                  Curl_dyn_ptr(&canonical_query) ?
+                  Curl_dyn_ptr(&canonical_query) : "",
+                  Curl_dyn_ptr(&canonical_headers),
+                  Curl_dyn_ptr(&signed_headers),
+                  (int)payload_hash_len, payload_hash);
+  if(!canonical_request)
+    goto fail;
+
+  DEBUGF(infof(data, "Canonical request: %s", canonical_request));
+
+  /* provider 0 lowercase */
+  Curl_strntolower(provider0, provider0, strlen(provider0));
+  request_type = curl_maprintf("%s4_request", provider0);
+  if(!request_type)
+    goto fail;
+
+  credential_scope = curl_maprintf("%s/%s/%s/%s",
+                                   date, region, service, request_type);
+  if(!credential_scope)
+    goto fail;
+
+  if(Curl_sha256it(sha_hash, (unsigned char *) canonical_request,
+                   strlen(canonical_request)))
+    goto fail;
+
+  sha256_to_hex(sha_hex, sha_hash);
+
+  /* provider 0 uppercase */
+  Curl_strntoupper(provider0, provider0, strlen(provider0));
+
+  /*
+   * Google allows using RSA key instead of HMAC, so this code might change
+   * in the future. For now we only support HMAC.
+   */
+  str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */
+                              "%s\n" /* RequestDateTime */
+                              "%s\n" /* CredentialScope */
+                              "%s",  /* HashedCanonicalRequest in hex */
+                              provider0,
+                              timestamp,
+                              credential_scope,
+                              sha_hex);
+  if(!str_to_sign) {
+    goto fail;
+  }
+
+  /* provider 0 uppercase */
+  secret = curl_maprintf("%s4%s", provider0,
+                         data->state.aptr.passwd ?
+                         data->state.aptr.passwd : "");
+  if(!secret)
+    goto fail;
+
+  HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0);
+  HMAC_SHA256(sign0, sizeof(sign0), region, strlen(region), sign1);
+  HMAC_SHA256(sign1, sizeof(sign1), service, strlen(service), sign0);
+  HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1);
+  HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0);
+
+  sha256_to_hex(sha_hex, sign0);
+
+  /* provider 0 uppercase */
+  auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 "
+                               "Credential=%s/%s, "
+                               "SignedHeaders=%s, "
+                               "Signature=%s\r\n"
+                               /*
+                                * date_header is added here, only if it wasn't
+                                * user-specified (using CURLOPT_HTTPHEADER).
+                                * date_header includes \r\n
+                                */
+                               "%s"
+                               "%s", /* optional sha256 header includes \r\n */
+                               provider0,
+                               user,
+                               credential_scope,
+                               Curl_dyn_ptr(&signed_headers),
+                               sha_hex,
+                               date_header ? date_header : "",
+                               content_sha256_hdr);
+  if(!auth_headers) {
+    goto fail;
+  }
+
+  Curl_safefree(data->state.aptr.userpwd);
+  data->state.aptr.userpwd = auth_headers;
+  data->state.authhost.done = TRUE;
+  result = CURLE_OK;
+
+fail:
+  Curl_dyn_free(&canonical_query);
+  Curl_dyn_free(&canonical_headers);
+  Curl_dyn_free(&signed_headers);
+  free(canonical_request);
+  free(request_type);
+  free(credential_scope);
+  free(str_to_sign);
+  free(secret);
+  free(date_header);
+  return result;
+}
+
+#endif /* !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS) */
Index: trunk/src/libs/curl-8.7.1/lib/http_aws_sigv4.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http_aws_sigv4.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http_aws_sigv4.h	(revision 104083)
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_HTTP_AWS_SIGV4_H
+#define HEADER_CURL_HTTP_AWS_SIGV4_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+/* this is for creating aws_sigv4 header output */
+CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy);
+
+#endif /* HEADER_CURL_HTTP_AWS_SIGV4_H */
Index: trunk/src/libs/curl-8.7.1/lib/http_chunks.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http_chunks.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http_chunks.c	(revision 104083)
@@ -0,0 +1,666 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_HTTP
+
+#include "urldata.h" /* it includes http_chunks.h */
+#include "curl_printf.h"
+#include "sendf.h"   /* for the client write stuff */
+#include "dynbuf.h"
+#include "content_encoding.h"
+#include "http.h"
+#include "multiif.h"
+#include "strtoofft.h"
+#include "warnless.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Chunk format (simplified):
+ *
+ * <HEX SIZE>[ chunk extension ] CRLF
+ * <DATA> CRLF
+ *
+ * Highlights from RFC2616 section 3.6 say:
+
+   The chunked encoding modifies the body of a message in order to
+   transfer it as a series of chunks, each with its own size indicator,
+   followed by an OPTIONAL trailer containing entity-header fields. This
+   allows dynamically produced content to be transferred along with the
+   information necessary for the recipient to verify that it has
+   received the full message.
+
+       Chunked-Body   = *chunk
+                        last-chunk
+                        trailer
+                        CRLF
+
+       chunk          = chunk-size [ chunk-extension ] CRLF
+                        chunk-data CRLF
+       chunk-size     = 1*HEX
+       last-chunk     = 1*("0") [ chunk-extension ] CRLF
+
+       chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
+       chunk-ext-name = token
+       chunk-ext-val  = token | quoted-string
+       chunk-data     = chunk-size(OCTET)
+       trailer        = *(entity-header CRLF)
+
+   The chunk-size field is a string of hex digits indicating the size of
+   the chunk. The chunked encoding is ended by any chunk whose size is
+   zero, followed by the trailer, which is terminated by an empty line.
+
+ */
+
+void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch,
+                         bool ignore_body)
+{
+  (void)data;
+  ch->hexindex = 0;      /* start at 0 */
+  ch->state = CHUNK_HEX; /* we get hex first! */
+  ch->last_code = CHUNKE_OK;
+  Curl_dyn_init(&ch->trailer, DYN_H1_TRAILER);
+  ch->ignore_body = ignore_body;
+}
+
+void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch,
+                          bool ignore_body)
+{
+  (void)data;
+  ch->hexindex = 0;      /* start at 0 */
+  ch->state = CHUNK_HEX; /* we get hex first! */
+  ch->last_code = CHUNKE_OK;
+  Curl_dyn_reset(&ch->trailer);
+  ch->ignore_body = ignore_body;
+}
+
+void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch)
+{
+  (void)data;
+  Curl_dyn_free(&ch->trailer);
+}
+
+bool Curl_httpchunk_is_done(struct Curl_easy *data, struct Curl_chunker *ch)
+{
+  (void)data;
+  return ch->state == CHUNK_DONE;
+}
+
+static CURLcode httpchunk_readwrite(struct Curl_easy *data,
+                                    struct Curl_chunker *ch,
+                                    struct Curl_cwriter *cw_next,
+                                    const char *buf, size_t blen,
+                                    size_t *pconsumed)
+{
+  CURLcode result = CURLE_OK;
+  size_t piece;
+
+  *pconsumed = 0; /* nothing's written yet */
+  /* first check terminal states that will not progress anywhere */
+  if(ch->state == CHUNK_DONE)
+    return CURLE_OK;
+  if(ch->state == CHUNK_FAILED)
+    return CURLE_RECV_ERROR;
+
+  /* the original data is written to the client, but we go on with the
+     chunk read process, to properly calculate the content length */
+  if(data->set.http_te_skip && !ch->ignore_body) {
+    if(cw_next)
+      result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_BODY, buf, blen);
+    else
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen);
+    if(result) {
+      ch->state = CHUNK_FAILED;
+      ch->last_code = CHUNKE_PASSTHRU_ERROR;
+      return result;
+    }
+  }
+
+  while(blen) {
+    switch(ch->state) {
+    case CHUNK_HEX:
+      if(ISXDIGIT(*buf)) {
+        if(ch->hexindex >= CHUNK_MAXNUM_LEN) {
+          failf(data, "chunk hex-length longer than %d", CHUNK_MAXNUM_LEN);
+          ch->state = CHUNK_FAILED;
+          ch->last_code = CHUNKE_TOO_LONG_HEX; /* longer than we support */
+          return CURLE_RECV_ERROR;
+        }
+        ch->hexbuffer[ch->hexindex++] = *buf;
+        buf++;
+        blen--;
+        (*pconsumed)++;
+      }
+      else {
+        if(0 == ch->hexindex) {
+          /* This is illegal data, we received junk where we expected
+             a hexadecimal digit. */
+          failf(data, "chunk hex-length char not a hex digit: 0x%x", *buf);
+          ch->state = CHUNK_FAILED;
+          ch->last_code = CHUNKE_ILLEGAL_HEX;
+          return CURLE_RECV_ERROR;
+        }
+
+        /* blen and buf are unmodified */
+        ch->hexbuffer[ch->hexindex] = 0;
+        if(curlx_strtoofft(ch->hexbuffer, NULL, 16, &ch->datasize)) {
+          failf(data, "chunk hex-length not valid: '%s'", ch->hexbuffer);
+          ch->state = CHUNK_FAILED;
+          ch->last_code = CHUNKE_ILLEGAL_HEX;
+          return CURLE_RECV_ERROR;
+        }
+        ch->state = CHUNK_LF; /* now wait for the CRLF */
+      }
+      break;
+
+    case CHUNK_LF:
+      /* waiting for the LF after a chunk size */
+      if(*buf == 0x0a) {
+        /* we're now expecting data to come, unless size was zero! */
+        if(0 == ch->datasize) {
+          ch->state = CHUNK_TRAILER; /* now check for trailers */
+        }
+        else
+          ch->state = CHUNK_DATA;
+      }
+
+      buf++;
+      blen--;
+      (*pconsumed)++;
+      break;
+
+    case CHUNK_DATA:
+      /* We expect 'datasize' of data. We have 'blen' right now, it can be
+         more or less than 'datasize'. Get the smallest piece.
+      */
+      piece = blen;
+      if(ch->datasize < (curl_off_t)blen)
+        piece = curlx_sotouz(ch->datasize);
+
+      /* Write the data portion available */
+      if(!data->set.http_te_skip && !ch->ignore_body) {
+        if(cw_next)
+          result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_BODY,
+                                      buf, piece);
+        else
+          result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                    (char *)buf, piece);
+        if(result) {
+          ch->state = CHUNK_FAILED;
+          ch->last_code = CHUNKE_PASSTHRU_ERROR;
+          return result;
+        }
+      }
+
+      *pconsumed += piece;
+      ch->datasize -= piece; /* decrease amount left to expect */
+      buf += piece;    /* move read pointer forward */
+      blen -= piece;   /* decrease space left in this round */
+
+      if(0 == ch->datasize)
+        /* end of data this round, we now expect a trailing CRLF */
+        ch->state = CHUNK_POSTLF;
+      break;
+
+    case CHUNK_POSTLF:
+      if(*buf == 0x0a) {
+        /* The last one before we go back to hex state and start all over. */
+        Curl_httpchunk_reset(data, ch, ch->ignore_body);
+      }
+      else if(*buf != 0x0d) {
+        ch->state = CHUNK_FAILED;
+        ch->last_code = CHUNKE_BAD_CHUNK;
+        return CURLE_RECV_ERROR;
+      }
+      buf++;
+      blen--;
+      (*pconsumed)++;
+      break;
+
+    case CHUNK_TRAILER:
+      if((*buf == 0x0d) || (*buf == 0x0a)) {
+        char *tr = Curl_dyn_ptr(&ch->trailer);
+        /* this is the end of a trailer, but if the trailer was zero bytes
+           there was no trailer and we move on */
+
+        if(tr) {
+          size_t trlen;
+          result = Curl_dyn_addn(&ch->trailer, (char *)STRCONST("\x0d\x0a"));
+          if(result) {
+            ch->state = CHUNK_FAILED;
+            ch->last_code = CHUNKE_OUT_OF_MEMORY;
+            return result;
+          }
+          tr = Curl_dyn_ptr(&ch->trailer);
+          trlen = Curl_dyn_len(&ch->trailer);
+          if(!data->set.http_te_skip) {
+            if(cw_next)
+              result = Curl_cwriter_write(data, cw_next,
+                                          CLIENTWRITE_HEADER|
+                                          CLIENTWRITE_TRAILER,
+                                          tr, trlen);
+            else
+              result = Curl_client_write(data,
+                                         CLIENTWRITE_HEADER|
+                                         CLIENTWRITE_TRAILER,
+                                         tr, trlen);
+            if(result) {
+              ch->state = CHUNK_FAILED;
+              ch->last_code = CHUNKE_PASSTHRU_ERROR;
+              return result;
+            }
+          }
+          Curl_dyn_reset(&ch->trailer);
+          ch->state = CHUNK_TRAILER_CR;
+          if(*buf == 0x0a)
+            /* already on the LF */
+            break;
+        }
+        else {
+          /* no trailer, we're on the final CRLF pair */
+          ch->state = CHUNK_TRAILER_POSTCR;
+          break; /* don't advance the pointer */
+        }
+      }
+      else {
+        result = Curl_dyn_addn(&ch->trailer, buf, 1);
+        if(result) {
+          ch->state = CHUNK_FAILED;
+          ch->last_code = CHUNKE_OUT_OF_MEMORY;
+          return result;
+        }
+      }
+      buf++;
+      blen--;
+      (*pconsumed)++;
+      break;
+
+    case CHUNK_TRAILER_CR:
+      if(*buf == 0x0a) {
+        ch->state = CHUNK_TRAILER_POSTCR;
+        buf++;
+        blen--;
+        (*pconsumed)++;
+      }
+      else {
+        ch->state = CHUNK_FAILED;
+        ch->last_code = CHUNKE_BAD_CHUNK;
+        return CURLE_RECV_ERROR;
+      }
+      break;
+
+    case CHUNK_TRAILER_POSTCR:
+      /* We enter this state when a CR should arrive so we expect to
+         have to first pass a CR before we wait for LF */
+      if((*buf != 0x0d) && (*buf != 0x0a)) {
+        /* not a CR then it must be another header in the trailer */
+        ch->state = CHUNK_TRAILER;
+        break;
+      }
+      if(*buf == 0x0d) {
+        /* skip if CR */
+        buf++;
+        blen--;
+        (*pconsumed)++;
+      }
+      /* now wait for the final LF */
+      ch->state = CHUNK_STOP;
+      break;
+
+    case CHUNK_STOP:
+      if(*buf == 0x0a) {
+        blen--;
+        (*pconsumed)++;
+        /* Record the length of any data left in the end of the buffer
+           even if there's no more chunks to read */
+        ch->datasize = blen;
+        ch->state = CHUNK_DONE;
+        return CURLE_OK;
+      }
+      else {
+        ch->state = CHUNK_FAILED;
+        ch->last_code = CHUNKE_BAD_CHUNK;
+        return CURLE_RECV_ERROR;
+      }
+    case CHUNK_DONE:
+      return CURLE_OK;
+
+    case CHUNK_FAILED:
+      return CURLE_RECV_ERROR;
+    }
+
+  }
+  return CURLE_OK;
+}
+
+static const char *Curl_chunked_strerror(CHUNKcode code)
+{
+  switch(code) {
+  default:
+    return "OK";
+  case CHUNKE_TOO_LONG_HEX:
+    return "Too long hexadecimal number";
+  case CHUNKE_ILLEGAL_HEX:
+    return "Illegal or missing hexadecimal sequence";
+  case CHUNKE_BAD_CHUNK:
+    return "Malformed encoding found";
+  case CHUNKE_PASSTHRU_ERROR:
+    return "Error writing data to client";
+  case CHUNKE_BAD_ENCODING:
+    return "Bad content-encoding found";
+  case CHUNKE_OUT_OF_MEMORY:
+    return "Out of memory";
+  }
+}
+
+CURLcode Curl_httpchunk_read(struct Curl_easy *data,
+                             struct Curl_chunker *ch,
+                             char *buf, size_t blen,
+                             size_t *pconsumed)
+{
+  return httpchunk_readwrite(data, ch, NULL, buf, blen, pconsumed);
+}
+
+struct chunked_writer {
+  struct Curl_cwriter super;
+  struct Curl_chunker ch;
+};
+
+static CURLcode cw_chunked_init(struct Curl_easy *data,
+                                struct Curl_cwriter *writer)
+{
+  struct chunked_writer *ctx = writer->ctx;
+
+  data->req.chunk = TRUE;      /* chunks coming our way. */
+  Curl_httpchunk_init(data, &ctx->ch, FALSE);
+  return CURLE_OK;
+}
+
+static void cw_chunked_close(struct Curl_easy *data,
+                             struct Curl_cwriter *writer)
+{
+  struct chunked_writer *ctx = writer->ctx;
+  Curl_httpchunk_free(data, &ctx->ch);
+}
+
+static CURLcode cw_chunked_write(struct Curl_easy *data,
+                                 struct Curl_cwriter *writer, int type,
+                                 const char *buf, size_t blen)
+{
+  struct chunked_writer *ctx = writer->ctx;
+  CURLcode result;
+  size_t consumed;
+
+  if(!(type & CLIENTWRITE_BODY))
+    return Curl_cwriter_write(data, writer->next, type, buf, blen);
+
+  consumed = 0;
+  result = httpchunk_readwrite(data, &ctx->ch, writer->next, buf, blen,
+                               &consumed);
+
+  if(result) {
+    if(CHUNKE_PASSTHRU_ERROR == ctx->ch.last_code) {
+      failf(data, "Failed reading the chunked-encoded stream");
+    }
+    else {
+      failf(data, "%s in chunked-encoding",
+            Curl_chunked_strerror(ctx->ch.last_code));
+    }
+    return result;
+  }
+
+  blen -= consumed;
+  if(CHUNK_DONE == ctx->ch.state) {
+    /* chunks read successfully, download is complete */
+    data->req.download_done = TRUE;
+    if(blen) {
+      infof(data, "Leftovers after chunking: %zu bytes", blen);
+    }
+  }
+  else if((type & CLIENTWRITE_EOS) && !data->req.no_body) {
+    failf(data, "transfer closed with outstanding read data remaining");
+    return CURLE_PARTIAL_FILE;
+  }
+
+  return CURLE_OK;
+}
+
+/* HTTP chunked Transfer-Encoding decoder */
+const struct Curl_cwtype Curl_httpchunk_unencoder = {
+  "chunked",
+  NULL,
+  cw_chunked_init,
+  cw_chunked_write,
+  cw_chunked_close,
+  sizeof(struct chunked_writer)
+};
+
+/* max length of a HTTP chunk that we want to generate */
+#define CURL_CHUNKED_MINLEN   (1024)
+#define CURL_CHUNKED_MAXLEN   (64 * 1024)
+
+struct chunked_reader {
+  struct Curl_creader super;
+  struct bufq chunkbuf;
+  BIT(read_eos);  /* we read an EOS from the next reader */
+  BIT(eos);       /* we have returned an EOS */
+};
+
+static CURLcode cr_chunked_init(struct Curl_easy *data,
+                                struct Curl_creader *reader)
+{
+  struct chunked_reader *ctx = reader->ctx;
+  (void)data;
+  Curl_bufq_init2(&ctx->chunkbuf, CURL_CHUNKED_MAXLEN, 2, BUFQ_OPT_SOFT_LIMIT);
+  return CURLE_OK;
+}
+
+static void cr_chunked_close(struct Curl_easy *data,
+                             struct Curl_creader *reader)
+{
+  struct chunked_reader *ctx = reader->ctx;
+  (void)data;
+  Curl_bufq_free(&ctx->chunkbuf);
+}
+
+static CURLcode add_last_chunk(struct Curl_easy *data,
+                               struct Curl_creader *reader)
+{
+  struct chunked_reader *ctx = reader->ctx;
+  struct curl_slist *trailers = NULL, *tr;
+  CURLcode result;
+  size_t n;
+  int rc;
+
+  if(!data->set.trailer_callback) {
+    return Curl_bufq_cwrite(&ctx->chunkbuf, STRCONST("0\r\n\r\n"), &n);
+  }
+
+  result = Curl_bufq_cwrite(&ctx->chunkbuf, STRCONST("0\r\n"), &n);
+  if(result)
+    goto out;
+
+  Curl_set_in_callback(data, true);
+  rc = data->set.trailer_callback(&trailers, data->set.trailer_data);
+  Curl_set_in_callback(data, false);
+
+  if(rc != CURL_TRAILERFUNC_OK) {
+    failf(data, "operation aborted by trailing headers callback");
+    result = CURLE_ABORTED_BY_CALLBACK;
+    goto out;
+  }
+
+  for(tr = trailers; tr; tr = tr->next) {
+    /* only add correctly formatted trailers */
+    char *ptr = strchr(tr->data, ':');
+    if(!ptr || *(ptr + 1) != ' ') {
+      infof(data, "Malformatted trailing header, skipping trailer");
+      continue;
+    }
+
+    result = Curl_bufq_cwrite(&ctx->chunkbuf, tr->data,
+                              strlen(tr->data), &n);
+    if(!result)
+      result = Curl_bufq_cwrite(&ctx->chunkbuf, STRCONST("\r\n"), &n);
+    if(result)
+      goto out;
+  }
+
+  result = Curl_bufq_cwrite(&ctx->chunkbuf, STRCONST("\r\n"), &n);
+
+out:
+  curl_slist_free_all(trailers);
+  return result;
+}
+
+static CURLcode add_chunk(struct Curl_easy *data,
+                          struct Curl_creader *reader,
+                          char *buf, size_t blen)
+{
+  struct chunked_reader *ctx = reader->ctx;
+  CURLcode result;
+  char tmp[CURL_CHUNKED_MINLEN];
+  size_t nread;
+  bool eos;
+
+  DEBUGASSERT(!ctx->read_eos);
+  blen = CURLMIN(blen, CURL_CHUNKED_MAXLEN); /* respect our buffer pref */
+  if(blen < sizeof(tmp)) {
+    /* small read, make a chunk of decent size */
+    buf = tmp;
+    blen = sizeof(tmp);
+  }
+  else {
+    /* larger read, make a chunk that will fit when read back */
+    blen -= (8 + 2 + 2); /* deduct max overhead, 8 hex + 2*crlf */
+  }
+
+  result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);
+  if(result)
+    return result;
+  if(eos)
+    ctx->read_eos = TRUE;
+
+  if(nread) {
+    /* actually got bytes, wrap them into the chunkbuf */
+    char hd[11] = "";
+    int hdlen;
+    size_t n;
+
+    hdlen = msnprintf(hd, sizeof(hd), "%zx\r\n", nread);
+    if(hdlen <= 0)
+      return CURLE_READ_ERROR;
+    /* On a soft-limited bufq, we do not need to check that all was written */
+    result = Curl_bufq_cwrite(&ctx->chunkbuf, hd, hdlen, &n);
+    if(!result)
+      result = Curl_bufq_cwrite(&ctx->chunkbuf, buf, nread, &n);
+    if(!result)
+      result = Curl_bufq_cwrite(&ctx->chunkbuf, "\r\n", 2, &n);
+    if(result)
+      return result;
+  }
+
+  if(ctx->read_eos)
+    return add_last_chunk(data, reader);
+  return CURLE_OK;
+}
+
+static CURLcode cr_chunked_read(struct Curl_easy *data,
+                                struct Curl_creader *reader,
+                                char *buf, size_t blen,
+                                size_t *pnread, bool *peos)
+{
+  struct chunked_reader *ctx = reader->ctx;
+  CURLcode result = CURLE_READ_ERROR;
+
+  *pnread = 0;
+  *peos = ctx->eos;
+
+  if(!ctx->eos) {
+    if(!ctx->read_eos && Curl_bufq_is_empty(&ctx->chunkbuf)) {
+      /* Still getting data form the next reader, buffer is empty */
+      result = add_chunk(data, reader, buf, blen);
+      if(result)
+        return result;
+    }
+
+    if(!Curl_bufq_is_empty(&ctx->chunkbuf)) {
+      result = Curl_bufq_cread(&ctx->chunkbuf, buf, blen, pnread);
+      if(!result && ctx->read_eos && Curl_bufq_is_empty(&ctx->chunkbuf)) {
+        /* no more data, read all, done. */
+        ctx->eos = TRUE;
+        *peos = TRUE;
+      }
+      return result;
+    }
+  }
+  /* We may get here, because we are done or because callbacks paused */
+  DEBUGASSERT(ctx->eos || !ctx->read_eos);
+  return CURLE_OK;
+}
+
+static curl_off_t cr_chunked_total_length(struct Curl_easy *data,
+                                          struct Curl_creader *reader)
+{
+  /* this reader changes length depending on input */
+  (void)data;
+  (void)reader;
+  return -1;
+}
+
+/* HTTP chunked Transfer-Encoding encoder */
+const struct Curl_crtype Curl_httpchunk_encoder = {
+  "chunked",
+  cr_chunked_init,
+  cr_chunked_read,
+  cr_chunked_close,
+  Curl_creader_def_needs_rewind,
+  cr_chunked_total_length,
+  Curl_creader_def_resume_from,
+  Curl_creader_def_rewind,
+  Curl_creader_def_unpause,
+  Curl_creader_def_done,
+  sizeof(struct chunked_reader)
+};
+
+CURLcode Curl_httpchunk_add_reader(struct Curl_easy *data)
+{
+  struct Curl_creader *reader = NULL;
+  CURLcode result;
+
+  result = Curl_creader_create(&reader, data, &Curl_httpchunk_encoder,
+                               CURL_CR_TRANSFER_ENCODE);
+  if(!result)
+    result = Curl_creader_add(data, reader);
+
+  if(result && reader)
+    Curl_creader_free(data, reader);
+  return result;
+}
+
+#endif /* CURL_DISABLE_HTTP */
Index: trunk/src/libs/curl-8.7.1/lib/http_chunks.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http_chunks.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http_chunks.h	(revision 104083)
@@ -0,0 +1,145 @@
+#ifndef HEADER_CURL_HTTP_CHUNKS_H
+#define HEADER_CURL_HTTP_CHUNKS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_HTTP
+
+#include "dynbuf.h"
+
+struct connectdata;
+
+/*
+ * The longest possible hexadecimal number we support in a chunked transfer.
+ * Neither RFC2616 nor the later HTTP specs define a maximum chunk size.
+ * For 64 bit curl_off_t we support 16 digits. For 32 bit, 8 digits.
+ */
+#define CHUNK_MAXNUM_LEN (SIZEOF_CURL_OFF_T * 2)
+
+typedef enum {
+  /* await and buffer all hexadecimal digits until we get one that isn't a
+     hexadecimal digit. When done, we go CHUNK_LF */
+  CHUNK_HEX,
+
+  /* wait for LF, ignore all else */
+  CHUNK_LF,
+
+  /* We eat the amount of data specified. When done, we move on to the
+     POST_CR state. */
+  CHUNK_DATA,
+
+  /* POSTLF should get a CR and then a LF and nothing else, then move back to
+     HEX as the CRLF combination marks the end of a chunk. A missing CR is no
+     big deal. */
+  CHUNK_POSTLF,
+
+  /* Used to mark that we're out of the game.  NOTE: that there's a 'datasize'
+     field in the struct that will tell how many bytes that were not passed to
+     the client in the end of the last buffer! */
+  CHUNK_STOP,
+
+  /* At this point optional trailer headers can be found, unless the next line
+     is CRLF */
+  CHUNK_TRAILER,
+
+  /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR.
+     Next char must be a LF */
+  CHUNK_TRAILER_CR,
+
+  /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be
+     signalled If this is an empty trailer CHUNKE_STOP will be signalled.
+     Otherwise the trailer will be broadcasted via Curl_client_write() and the
+     next state will be CHUNK_TRAILER */
+  CHUNK_TRAILER_POSTCR,
+
+  /* Successfully de-chunked everything */
+  CHUNK_DONE,
+
+  /* Failed on seeing a bad or not correctly terminated chunk */
+  CHUNK_FAILED
+} ChunkyState;
+
+typedef enum {
+  CHUNKE_OK = 0,
+  CHUNKE_TOO_LONG_HEX = 1,
+  CHUNKE_ILLEGAL_HEX,
+  CHUNKE_BAD_CHUNK,
+  CHUNKE_BAD_ENCODING,
+  CHUNKE_OUT_OF_MEMORY,
+  CHUNKE_PASSTHRU_ERROR /* Curl_httpchunk_read() returns a CURLcode to use */
+} CHUNKcode;
+
+struct Curl_chunker {
+  curl_off_t datasize;
+  ChunkyState state;
+  CHUNKcode last_code;
+  struct dynbuf trailer; /* for chunked-encoded trailer */
+  unsigned char hexindex;
+  char hexbuffer[CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */
+  BIT(ignore_body); /* never write response body data */
+};
+
+/* The following functions are defined in http_chunks.c */
+void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch,
+                         bool ignore_body);
+void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch);
+void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch,
+                          bool ignore_body);
+
+/*
+ * Read BODY bytes in HTTP/1.1 chunked encoding from `buf` and return
+ * the amount of bytes consumed. The actual response bytes and trailer
+ * headers are written out to the client.
+ * On success, this will consume all bytes up to the end of the response,
+ * e.g. the last chunk, has been processed.
+ * @param data   the transfer involved
+ * @param ch     the chunker instance keeping state across calls
+ * @param buf    the response data
+ * @param blen   amount of bytes in `buf`
+ * @param pconsumed  on successful return, the number of bytes in `buf`
+ *                   consumed
+ *
+ * This function always uses ASCII hex values to accommodate non-ASCII hosts.
+ * For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
+ */
+CURLcode Curl_httpchunk_read(struct Curl_easy *data, struct Curl_chunker *ch,
+                             char *buf, size_t blen, size_t *pconsumed);
+
+/**
+ * @return TRUE iff chunked decoded has finished successfully.
+ */
+bool Curl_httpchunk_is_done(struct Curl_easy *data, struct Curl_chunker *ch);
+
+extern const struct Curl_cwtype Curl_httpchunk_unencoder;
+
+extern const struct Curl_crtype Curl_httpchunk_encoder;
+
+/**
+ * Add a transfer-encoding "chunked" reader to the transfers reader stack
+ */
+CURLcode Curl_httpchunk_add_reader(struct Curl_easy *data);
+
+#endif /* !CURL_DISABLE_HTTP */
+
+#endif /* HEADER_CURL_HTTP_CHUNKS_H */
Index: trunk/src/libs/curl-8.7.1/lib/http_digest.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http_digest.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http_digest.c	(revision 104083)
@@ -0,0 +1,185 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
+
+#include "urldata.h"
+#include "strcase.h"
+#include "vauth/vauth.h"
+#include "http_digest.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Test example headers:
+
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604598"
+Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598"
+
+*/
+
+CURLcode Curl_input_digest(struct Curl_easy *data,
+                           bool proxy,
+                           const char *header) /* rest of the *-authenticate:
+                                                  header */
+{
+  /* Point to the correct struct with this */
+  struct digestdata *digest;
+
+  if(proxy) {
+    digest = &data->state.proxydigest;
+  }
+  else {
+    digest = &data->state.digest;
+  }
+
+  if(!checkprefix("Digest", header) || !ISBLANK(header[6]))
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  header += strlen("Digest");
+  while(*header && ISBLANK(*header))
+    header++;
+
+  return Curl_auth_decode_digest_http_message(header, digest);
+}
+
+CURLcode Curl_output_digest(struct Curl_easy *data,
+                            bool proxy,
+                            const unsigned char *request,
+                            const unsigned char *uripath)
+{
+  CURLcode result;
+  unsigned char *path = NULL;
+  char *tmp = NULL;
+  char *response;
+  size_t len;
+  bool have_chlg;
+
+  /* Point to the address of the pointer that holds the string to send to the
+     server, which is for a plain host or for an HTTP proxy */
+  char **allocuserpwd;
+
+  /* Point to the name and password for this */
+  const char *userp;
+  const char *passwdp;
+
+  /* Point to the correct struct with this */
+  struct digestdata *digest;
+  struct auth *authp;
+
+  if(proxy) {
+#ifdef CURL_DISABLE_PROXY
+    return CURLE_NOT_BUILT_IN;
+#else
+    digest = &data->state.proxydigest;
+    allocuserpwd = &data->state.aptr.proxyuserpwd;
+    userp = data->state.aptr.proxyuser;
+    passwdp = data->state.aptr.proxypasswd;
+    authp = &data->state.authproxy;
+#endif
+  }
+  else {
+    digest = &data->state.digest;
+    allocuserpwd = &data->state.aptr.userpwd;
+    userp = data->state.aptr.user;
+    passwdp = data->state.aptr.passwd;
+    authp = &data->state.authhost;
+  }
+
+  Curl_safefree(*allocuserpwd);
+
+  /* not set means empty */
+  if(!userp)
+    userp = "";
+
+  if(!passwdp)
+    passwdp = "";
+
+#if defined(USE_WINDOWS_SSPI)
+  have_chlg = digest->input_token ? TRUE : FALSE;
+#else
+  have_chlg = digest->nonce ? TRUE : FALSE;
+#endif
+
+  if(!have_chlg) {
+    authp->done = FALSE;
+    return CURLE_OK;
+  }
+
+  /* So IE browsers < v7 cut off the URI part at the query part when they
+     evaluate the MD5 and some (IIS?) servers work with them so we may need to
+     do the Digest IE-style. Note that the different ways cause different MD5
+     sums to get sent.
+
+     Apache servers can be set to do the Digest IE-style automatically using
+     the BrowserMatch feature:
+     https://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie
+
+     Further details on Digest implementation differences:
+     http://www.fngtps.com/2006/09/http-authentication
+  */
+
+  if(authp->iestyle) {
+    tmp = strchr((char *)uripath, '?');
+    if(tmp) {
+      size_t urilen = tmp - (char *)uripath;
+      /* typecast is fine here since the value is always less than 32 bits */
+      path = (unsigned char *) aprintf("%.*s", (int)urilen, uripath);
+    }
+  }
+  if(!tmp)
+    path = (unsigned char *) strdup((char *) uripath);
+
+  if(!path)
+    return CURLE_OUT_OF_MEMORY;
+
+  result = Curl_auth_create_digest_http_message(data, userp, passwdp, request,
+                                                path, digest, &response, &len);
+  free(path);
+  if(result)
+    return result;
+
+  *allocuserpwd = aprintf("%sAuthorization: Digest %s\r\n",
+                          proxy ? "Proxy-" : "",
+                          response);
+  free(response);
+  if(!*allocuserpwd)
+    return CURLE_OUT_OF_MEMORY;
+
+  authp->done = TRUE;
+
+  return CURLE_OK;
+}
+
+void Curl_http_auth_cleanup_digest(struct Curl_easy *data)
+{
+  Curl_auth_digest_cleanup(&data->state.digest);
+  Curl_auth_digest_cleanup(&data->state.proxydigest);
+}
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/http_digest.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http_digest.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http_digest.h	(revision 104083)
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_HTTP_DIGEST_H
+#define HEADER_CURL_HTTP_DIGEST_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
+
+/* this is for digest header input */
+CURLcode Curl_input_digest(struct Curl_easy *data,
+                           bool proxy, const char *header);
+
+/* this is for creating digest header output */
+CURLcode Curl_output_digest(struct Curl_easy *data,
+                            bool proxy,
+                            const unsigned char *request,
+                            const unsigned char *uripath);
+
+void Curl_http_auth_cleanup_digest(struct Curl_easy *data);
+
+#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_DIGEST_AUTH */
+
+#endif /* HEADER_CURL_HTTP_DIGEST_H */
Index: trunk/src/libs/curl-8.7.1/lib/http_negotiate.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http_negotiate.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http_negotiate.c	(revision 104083)
@@ -0,0 +1,224 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
+
+#include "urldata.h"
+#include "sendf.h"
+#include "http_negotiate.h"
+#include "vauth/vauth.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
+                              bool proxy, const char *header)
+{
+  CURLcode result;
+  size_t len;
+
+  /* Point to the username, password, service and host */
+  const char *userp;
+  const char *passwdp;
+  const char *service;
+  const char *host;
+
+  /* Point to the correct struct with this */
+  struct negotiatedata *neg_ctx;
+  curlnegotiate state;
+
+  if(proxy) {
+#ifndef CURL_DISABLE_PROXY
+    userp = conn->http_proxy.user;
+    passwdp = conn->http_proxy.passwd;
+    service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
+              data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
+    host = conn->http_proxy.host.name;
+    neg_ctx = &conn->proxyneg;
+    state = conn->proxy_negotiate_state;
+#else
+    return CURLE_NOT_BUILT_IN;
+#endif
+  }
+  else {
+    userp = conn->user;
+    passwdp = conn->passwd;
+    service = data->set.str[STRING_SERVICE_NAME] ?
+              data->set.str[STRING_SERVICE_NAME] : "HTTP";
+    host = conn->host.name;
+    neg_ctx = &conn->negotiate;
+    state = conn->http_negotiate_state;
+  }
+
+  /* Not set means empty */
+  if(!userp)
+    userp = "";
+
+  if(!passwdp)
+    passwdp = "";
+
+  /* Obtain the input token, if any */
+  header += strlen("Negotiate");
+  while(*header && ISBLANK(*header))
+    header++;
+
+  len = strlen(header);
+  neg_ctx->havenegdata = len != 0;
+  if(!len) {
+    if(state == GSS_AUTHSUCC) {
+      infof(data, "Negotiate auth restarted");
+      Curl_http_auth_cleanup_negotiate(conn);
+    }
+    else if(state != GSS_AUTHNONE) {
+      /* The server rejected our authentication and hasn't supplied any more
+      negotiation mechanisms */
+      Curl_http_auth_cleanup_negotiate(conn);
+      return CURLE_LOGIN_DENIED;
+    }
+  }
+
+  /* Supports SSL channel binding for Windows ISS extended protection */
+#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
+  neg_ctx->sslContext = conn->sslContext;
+#endif
+
+  /* Initialize the security context and decode our challenge */
+  result = Curl_auth_decode_spnego_message(data, userp, passwdp, service,
+                                           host, header, neg_ctx);
+
+  if(result)
+    Curl_http_auth_cleanup_negotiate(conn);
+
+  return result;
+}
+
+CURLcode Curl_output_negotiate(struct Curl_easy *data,
+                               struct connectdata *conn, bool proxy)
+{
+  struct negotiatedata *neg_ctx = proxy ? &conn->proxyneg :
+    &conn->negotiate;
+  struct auth *authp = proxy ? &data->state.authproxy : &data->state.authhost;
+  curlnegotiate *state = proxy ? &conn->proxy_negotiate_state :
+    &conn->http_negotiate_state;
+  char *base64 = NULL;
+  size_t len = 0;
+  char *userp;
+  CURLcode result;
+
+  authp->done = FALSE;
+
+  if(*state == GSS_AUTHRECV) {
+    if(neg_ctx->havenegdata) {
+      neg_ctx->havemultiplerequests = TRUE;
+    }
+  }
+  else if(*state == GSS_AUTHSUCC) {
+    if(!neg_ctx->havenoauthpersist) {
+      neg_ctx->noauthpersist = !neg_ctx->havemultiplerequests;
+    }
+  }
+
+  if(neg_ctx->noauthpersist ||
+     (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) {
+
+    if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) {
+      infof(data, "Curl_output_negotiate, "
+            "no persistent authentication: cleanup existing context");
+      Curl_http_auth_cleanup_negotiate(conn);
+    }
+    if(!neg_ctx->context) {
+      result = Curl_input_negotiate(data, conn, proxy, "Negotiate");
+      if(result == CURLE_AUTH_ERROR) {
+        /* negotiate auth failed, let's continue unauthenticated to stay
+         * compatible with the behavior before curl-7_64_0-158-g6c6035532 */
+        authp->done = TRUE;
+        return CURLE_OK;
+      }
+      else if(result)
+        return result;
+    }
+
+    result = Curl_auth_create_spnego_message(neg_ctx, &base64, &len);
+    if(result)
+      return result;
+
+    userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "",
+                    base64);
+
+    if(proxy) {
+      Curl_safefree(data->state.aptr.proxyuserpwd);
+      data->state.aptr.proxyuserpwd = userp;
+    }
+    else {
+      Curl_safefree(data->state.aptr.userpwd);
+      data->state.aptr.userpwd = userp;
+    }
+
+    free(base64);
+
+    if(!userp) {
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    *state = GSS_AUTHSENT;
+  #ifdef HAVE_GSSAPI
+    if(neg_ctx->status == GSS_S_COMPLETE ||
+       neg_ctx->status == GSS_S_CONTINUE_NEEDED) {
+      *state = GSS_AUTHDONE;
+    }
+  #else
+  #ifdef USE_WINDOWS_SSPI
+    if(neg_ctx->status == SEC_E_OK ||
+       neg_ctx->status == SEC_I_CONTINUE_NEEDED) {
+      *state = GSS_AUTHDONE;
+    }
+  #endif
+  #endif
+  }
+
+  if(*state == GSS_AUTHDONE || *state == GSS_AUTHSUCC) {
+    /* connection is already authenticated,
+     * don't send a header in future requests */
+    authp->done = TRUE;
+  }
+
+  neg_ctx->havenegdata = FALSE;
+
+  return CURLE_OK;
+}
+
+void Curl_http_auth_cleanup_negotiate(struct connectdata *conn)
+{
+  conn->http_negotiate_state = GSS_AUTHNONE;
+  conn->proxy_negotiate_state = GSS_AUTHNONE;
+
+  Curl_auth_cleanup_spnego(&conn->negotiate);
+  Curl_auth_cleanup_spnego(&conn->proxyneg);
+}
+
+#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */
Index: trunk/src/libs/curl-8.7.1/lib/http_negotiate.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http_negotiate.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http_negotiate.h	(revision 104083)
@@ -0,0 +1,43 @@
+#ifndef HEADER_CURL_HTTP_NEGOTIATE_H
+#define HEADER_CURL_HTTP_NEGOTIATE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
+
+/* this is for Negotiate header input */
+CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
+                              bool proxy, const char *header);
+
+/* this is for creating Negotiate header output */
+CURLcode Curl_output_negotiate(struct Curl_easy *data,
+                               struct connectdata *conn, bool proxy);
+
+void Curl_http_auth_cleanup_negotiate(struct connectdata *conn);
+
+#else /* !CURL_DISABLE_HTTP && USE_SPNEGO */
+#define Curl_http_auth_cleanup_negotiate(x)
+#endif
+
+#endif /* HEADER_CURL_HTTP_NEGOTIATE_H */
Index: trunk/src/libs/curl-8.7.1/lib/http_ntlm.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http_ntlm.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http_ntlm.c	(revision 104083)
@@ -0,0 +1,275 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
+
+/*
+ * NTLM details:
+ *
+ * https://davenport.sourceforge.net/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
+ */
+
+#define DEBUG_ME 0
+
+#include "urldata.h"
+#include "sendf.h"
+#include "strcase.h"
+#include "http_ntlm.h"
+#include "curl_ntlm_core.h"
+#include "curl_ntlm_wb.h"
+#include "curl_base64.h"
+#include "vauth/vauth.h"
+#include "url.h"
+
+/* SSL backend-specific #if branches in this file must be kept in the order
+   documented in curl_ntlm_core. */
+#if defined(USE_WINDOWS_SSPI)
+#include "curl_sspi.h"
+#endif
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if DEBUG_ME
+# define DEBUG_OUT(x) x
+#else
+# define DEBUG_OUT(x) Curl_nop_stmt
+#endif
+
+CURLcode Curl_input_ntlm(struct Curl_easy *data,
+                         bool proxy,         /* if proxy or not */
+                         const char *header) /* rest of the www-authenticate:
+                                                header */
+{
+  /* point to the correct struct with this */
+  struct ntlmdata *ntlm;
+  curlntlm *state;
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+
+  ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
+  state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
+
+  if(checkprefix("NTLM", header)) {
+    header += strlen("NTLM");
+
+    while(*header && ISSPACE(*header))
+      header++;
+
+    if(*header) {
+      unsigned char *hdr;
+      size_t hdrlen;
+
+      result = Curl_base64_decode(header, &hdr, &hdrlen);
+      if(!result) {
+        struct bufref hdrbuf;
+
+        Curl_bufref_init(&hdrbuf);
+        Curl_bufref_set(&hdrbuf, hdr, hdrlen, curl_free);
+        result = Curl_auth_decode_ntlm_type2_message(data, &hdrbuf, ntlm);
+        Curl_bufref_free(&hdrbuf);
+      }
+      if(result)
+        return result;
+
+      *state = NTLMSTATE_TYPE2; /* We got a type-2 message */
+    }
+    else {
+      if(*state == NTLMSTATE_LAST) {
+        infof(data, "NTLM auth restarted");
+        Curl_http_auth_cleanup_ntlm(conn);
+      }
+      else if(*state == NTLMSTATE_TYPE3) {
+        infof(data, "NTLM handshake rejected");
+        Curl_http_auth_cleanup_ntlm(conn);
+        *state = NTLMSTATE_NONE;
+        return CURLE_REMOTE_ACCESS_DENIED;
+      }
+      else if(*state >= NTLMSTATE_TYPE1) {
+        infof(data, "NTLM handshake failure (internal error)");
+        return CURLE_REMOTE_ACCESS_DENIED;
+      }
+
+      *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
+    }
+  }
+
+  return result;
+}
+
+/*
+ * This is for creating ntlm header output
+ */
+CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
+{
+  char *base64 = NULL;
+  size_t len = 0;
+  CURLcode result = CURLE_OK;
+  struct bufref ntlmmsg;
+
+  /* point to the address of the pointer that holds the string to send to the
+     server, which is for a plain host or for an HTTP proxy */
+  char **allocuserpwd;
+
+  /* point to the username, password, service and host */
+  const char *userp;
+  const char *passwdp;
+  const char *service = NULL;
+  const char *hostname = NULL;
+
+  /* point to the correct struct with this */
+  struct ntlmdata *ntlm;
+  curlntlm *state;
+  struct auth *authp;
+  struct connectdata *conn = data->conn;
+
+  DEBUGASSERT(conn);
+  DEBUGASSERT(data);
+
+  if(proxy) {
+#ifndef CURL_DISABLE_PROXY
+    allocuserpwd = &data->state.aptr.proxyuserpwd;
+    userp = data->state.aptr.proxyuser;
+    passwdp = data->state.aptr.proxypasswd;
+    service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
+      data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
+    hostname = conn->http_proxy.host.name;
+    ntlm = &conn->proxyntlm;
+    state = &conn->proxy_ntlm_state;
+    authp = &data->state.authproxy;
+#else
+    return CURLE_NOT_BUILT_IN;
+#endif
+  }
+  else {
+    allocuserpwd = &data->state.aptr.userpwd;
+    userp = data->state.aptr.user;
+    passwdp = data->state.aptr.passwd;
+    service = data->set.str[STRING_SERVICE_NAME] ?
+      data->set.str[STRING_SERVICE_NAME] : "HTTP";
+    hostname = conn->host.name;
+    ntlm = &conn->ntlm;
+    state = &conn->http_ntlm_state;
+    authp = &data->state.authhost;
+  }
+  authp->done = FALSE;
+
+  /* not set means empty */
+  if(!userp)
+    userp = "";
+
+  if(!passwdp)
+    passwdp = "";
+
+#ifdef USE_WINDOWS_SSPI
+  if(!s_hSecDll) {
+    /* not thread safe and leaks - use curl_global_init() to avoid */
+    CURLcode err = Curl_sspi_global_init();
+    if(!s_hSecDll)
+      return err;
+  }
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+  ntlm->sslContext = conn->sslContext;
+#endif
+#endif
+
+  Curl_bufref_init(&ntlmmsg);
+
+  /* connection is already authenticated, don't send a header in future
+   * requests so go directly to NTLMSTATE_LAST */
+  if(*state == NTLMSTATE_TYPE3)
+    *state = NTLMSTATE_LAST;
+
+  switch(*state) {
+  case NTLMSTATE_TYPE1:
+  default: /* for the weird cases we (re)start here */
+    /* Create a type-1 message */
+    result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp,
+                                                 service, hostname,
+                                                 ntlm, &ntlmmsg);
+    if(!result) {
+      DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0);
+      result = Curl_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg),
+                                  Curl_bufref_len(&ntlmmsg), &base64, &len);
+      if(!result) {
+        free(*allocuserpwd);
+        *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+                                proxy ? "Proxy-" : "",
+                                base64);
+        free(base64);
+        if(!*allocuserpwd)
+          result = CURLE_OUT_OF_MEMORY;
+      }
+    }
+    break;
+
+  case NTLMSTATE_TYPE2:
+    /* We already received the type-2 message, create a type-3 message */
+    result = Curl_auth_create_ntlm_type3_message(data, userp, passwdp,
+                                                 ntlm, &ntlmmsg);
+    if(!result && Curl_bufref_len(&ntlmmsg)) {
+      result = Curl_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg),
+                                  Curl_bufref_len(&ntlmmsg), &base64, &len);
+      if(!result) {
+        free(*allocuserpwd);
+        *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+                                proxy ? "Proxy-" : "",
+                                base64);
+        free(base64);
+        if(!*allocuserpwd)
+          result = CURLE_OUT_OF_MEMORY;
+        else {
+          *state = NTLMSTATE_TYPE3; /* we send a type-3 */
+          authp->done = TRUE;
+        }
+      }
+    }
+    break;
+
+  case NTLMSTATE_LAST:
+    Curl_safefree(*allocuserpwd);
+    authp->done = TRUE;
+    break;
+  }
+  Curl_bufref_free(&ntlmmsg);
+
+  return result;
+}
+
+void Curl_http_auth_cleanup_ntlm(struct connectdata *conn)
+{
+  Curl_auth_cleanup_ntlm(&conn->ntlm);
+  Curl_auth_cleanup_ntlm(&conn->proxyntlm);
+
+#if defined(NTLM_WB_ENABLED)
+  Curl_http_auth_cleanup_ntlm_wb(conn);
+#endif
+}
+
+#endif /* !CURL_DISABLE_HTTP && USE_NTLM */
Index: trunk/src/libs/curl-8.7.1/lib/http_ntlm.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http_ntlm.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http_ntlm.h	(revision 104083)
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_HTTP_NTLM_H
+#define HEADER_CURL_HTTP_NTLM_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
+
+/* this is for ntlm header input */
+CURLcode Curl_input_ntlm(struct Curl_easy *data, bool proxy,
+                         const char *header);
+
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy);
+
+void Curl_http_auth_cleanup_ntlm(struct connectdata *conn);
+
+#else /* !CURL_DISABLE_HTTP && USE_NTLM */
+#define Curl_http_auth_cleanup_ntlm(x)
+#endif
+
+#endif /* HEADER_CURL_HTTP_NTLM_H */
Index: trunk/src/libs/curl-8.7.1/lib/http_proxy.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http_proxy.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http_proxy.c	(revision 104083)
@@ -0,0 +1,336 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "http_proxy.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
+
+#include <curl/curl.h>
+#ifdef USE_HYPER
+#include <hyper.h>
+#endif
+#include "sendf.h"
+#include "http.h"
+#include "url.h"
+#include "select.h"
+#include "progress.h"
+#include "cfilters.h"
+#include "cf-h1-proxy.h"
+#include "cf-h2-proxy.h"
+#include "connect.h"
+#include "curlx.h"
+#include "vtls/vtls.h"
+#include "transfer.h"
+#include "multiif.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+CURLcode Curl_http_proxy_get_destination(struct Curl_cfilter *cf,
+                                         const char **phostname,
+                                         int *pport, bool *pipv6_ip)
+{
+  DEBUGASSERT(cf);
+  DEBUGASSERT(cf->conn);
+
+  if(cf->conn->bits.conn_to_host)
+    *phostname = cf->conn->conn_to_host.name;
+  else if(cf->sockindex == SECONDARYSOCKET)
+    *phostname = cf->conn->secondaryhostname;
+  else
+    *phostname = cf->conn->host.name;
+
+  if(cf->sockindex == SECONDARYSOCKET)
+    *pport = cf->conn->secondary_port;
+  else if(cf->conn->bits.conn_to_port)
+    *pport = cf->conn->conn_to_port;
+  else
+    *pport = cf->conn->remote_port;
+
+  if(*phostname != cf->conn->host.name)
+    *pipv6_ip = (strchr(*phostname, ':') != NULL);
+  else
+    *pipv6_ip = cf->conn->bits.ipv6_ip;
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq,
+                                        struct Curl_cfilter *cf,
+                                        struct Curl_easy *data,
+                                        int http_version_major)
+{
+  const char *hostname = NULL;
+  char *authority = NULL;
+  int port;
+  bool ipv6_ip;
+  CURLcode result;
+  struct httpreq *req = NULL;
+
+  result = Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip);
+  if(result)
+    goto out;
+
+  authority = aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname,
+                      ipv6_ip?"]":"", port);
+  if(!authority) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+
+  result = Curl_http_req_make(&req, "CONNECT", sizeof("CONNECT")-1,
+                              NULL, 0, authority, strlen(authority),
+                              NULL, 0);
+  if(result)
+    goto out;
+
+  /* Setup the proxy-authorization header, if any */
+  result = Curl_http_output_auth(data, cf->conn, req->method, HTTPREQ_GET,
+                                 req->authority, TRUE);
+  if(result)
+    goto out;
+
+  /* If user is not overriding Host: header, we add for HTTP/1.x */
+  if(http_version_major == 1 &&
+     !Curl_checkProxyheaders(data, cf->conn, STRCONST("Host"))) {
+    result = Curl_dynhds_cadd(&req->headers, "Host", authority);
+    if(result)
+      goto out;
+  }
+
+  if(data->state.aptr.proxyuserpwd) {
+    result = Curl_dynhds_h1_cadd_line(&req->headers,
+                                      data->state.aptr.proxyuserpwd);
+    if(result)
+      goto out;
+  }
+
+  if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("User-Agent")) &&
+     data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) {
+    result = Curl_dynhds_cadd(&req->headers, "User-Agent",
+                              data->set.str[STRING_USERAGENT]);
+    if(result)
+      goto out;
+  }
+
+  if(http_version_major == 1 &&
+    !Curl_checkProxyheaders(data, cf->conn, STRCONST("Proxy-Connection"))) {
+    result = Curl_dynhds_cadd(&req->headers, "Proxy-Connection", "Keep-Alive");
+    if(result)
+      goto out;
+  }
+
+  result = Curl_dynhds_add_custom(data, TRUE, &req->headers);
+
+out:
+  if(result && req) {
+    Curl_http_req_free(req);
+    req = NULL;
+  }
+  free(authority);
+  *preq = req;
+  return result;
+}
+
+
+struct cf_proxy_ctx {
+  /* the protocol specific sub-filter we install during connect */
+  struct Curl_cfilter *cf_protocol;
+};
+
+static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data,
+                                      bool blocking, bool *done)
+{
+  struct cf_proxy_ctx *ctx = cf->ctx;
+  CURLcode result;
+
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  CURL_TRC_CF(data, cf, "connect");
+connect_sub:
+  result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+  if(result || !*done)
+    return result;
+
+  *done = FALSE;
+  if(!ctx->cf_protocol) {
+    struct Curl_cfilter *cf_protocol = NULL;
+    int alpn = Curl_conn_cf_is_ssl(cf->next)?
+      cf->conn->proxy_alpn : CURL_HTTP_VERSION_1_1;
+
+    /* First time call after the subchain connected */
+    switch(alpn) {
+    case CURL_HTTP_VERSION_NONE:
+    case CURL_HTTP_VERSION_1_0:
+    case CURL_HTTP_VERSION_1_1:
+      CURL_TRC_CF(data, cf, "installing subfilter for HTTP/1.1");
+      infof(data, "CONNECT tunnel: HTTP/1.%d negotiated",
+            (alpn == CURL_HTTP_VERSION_1_0)? 0 : 1);
+      result = Curl_cf_h1_proxy_insert_after(cf, data);
+      if(result)
+        goto out;
+      cf_protocol = cf->next;
+      break;
+#ifdef USE_NGHTTP2
+    case CURL_HTTP_VERSION_2:
+      CURL_TRC_CF(data, cf, "installing subfilter for HTTP/2");
+      infof(data, "CONNECT tunnel: HTTP/2 negotiated");
+      result = Curl_cf_h2_proxy_insert_after(cf, data);
+      if(result)
+        goto out;
+      cf_protocol = cf->next;
+      break;
+#endif
+    default:
+      infof(data, "CONNECT tunnel: unsupported ALPN(%d) negotiated", alpn);
+      result = CURLE_COULDNT_CONNECT;
+      goto out;
+    }
+
+    ctx->cf_protocol = cf_protocol;
+    /* after we installed the filter "below" us, we call connect
+     * on out sub-chain again.
+     */
+    goto connect_sub;
+  }
+  else {
+    /* subchain connected and we had already installed the protocol filter.
+     * This means the protocol tunnel is established, we are done.
+     */
+    DEBUGASSERT(ctx->cf_protocol);
+    result = CURLE_OK;
+  }
+
+out:
+  if(!result) {
+    cf->connected = TRUE;
+    *done = TRUE;
+  }
+  return result;
+}
+
+void Curl_cf_http_proxy_get_host(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 const char **phost,
+                                 const char **pdisplay_host,
+                                 int *pport)
+{
+  (void)data;
+  if(!cf->connected) {
+    *phost = cf->conn->http_proxy.host.name;
+    *pdisplay_host = cf->conn->http_proxy.host.dispname;
+    *pport = (int)cf->conn->http_proxy.port;
+  }
+  else {
+    cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
+  }
+}
+
+static void http_proxy_cf_destroy(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data)
+{
+  struct cf_proxy_ctx *ctx = cf->ctx;
+
+  (void)data;
+  CURL_TRC_CF(data, cf, "destroy");
+  free(ctx);
+}
+
+static void http_proxy_cf_close(struct Curl_cfilter *cf,
+                                struct Curl_easy *data)
+{
+  struct cf_proxy_ctx *ctx = cf->ctx;
+
+  CURL_TRC_CF(data, cf, "close");
+  cf->connected = FALSE;
+  if(ctx->cf_protocol) {
+    struct Curl_cfilter *f;
+    /* if someone already removed it, we assume he also
+     * took care of destroying it. */
+    for(f = cf->next; f; f = f->next) {
+      if(f == ctx->cf_protocol) {
+        /* still in our sub-chain */
+        Curl_conn_cf_discard_sub(cf, ctx->cf_protocol, data, FALSE);
+        break;
+      }
+    }
+    ctx->cf_protocol = NULL;
+  }
+  if(cf->next)
+    cf->next->cft->do_close(cf->next, data);
+}
+
+
+struct Curl_cftype Curl_cft_http_proxy = {
+  "HTTP-PROXY",
+  CF_TYPE_IP_CONNECT,
+  0,
+  http_proxy_cf_destroy,
+  http_proxy_cf_connect,
+  http_proxy_cf_close,
+  Curl_cf_http_proxy_get_host,
+  Curl_cf_def_adjust_pollset,
+  Curl_cf_def_data_pending,
+  Curl_cf_def_send,
+  Curl_cf_def_recv,
+  Curl_cf_def_cntrl,
+  Curl_cf_def_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  Curl_cf_def_query,
+};
+
+CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
+                                         struct Curl_easy *data)
+{
+  struct Curl_cfilter *cf;
+  struct cf_proxy_ctx *ctx = NULL;
+  CURLcode result;
+
+  (void)data;
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  result = Curl_cf_create(&cf, &Curl_cft_http_proxy, ctx);
+  if(result)
+    goto out;
+  ctx = NULL;
+  Curl_conn_cf_insert_after(cf_at, cf);
+
+out:
+  free(ctx);
+  return result;
+}
+
+#endif /* ! CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
Index: trunk/src/libs/curl-8.7.1/lib/http_proxy.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/http_proxy.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/http_proxy.h	(revision 104083)
@@ -0,0 +1,61 @@
+#ifndef HEADER_CURL_HTTP_PROXY_H
+#define HEADER_CURL_HTTP_PROXY_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
+
+#include "urldata.h"
+
+CURLcode Curl_http_proxy_get_destination(struct Curl_cfilter *cf,
+                                         const char **phostname,
+                                         int *pport, bool *pipv6_ip);
+
+CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq,
+                                        struct Curl_cfilter *cf,
+                                        struct Curl_easy *data,
+                                        int http_version_major);
+
+/* Default proxy timeout in milliseconds */
+#define PROXY_TIMEOUT (3600*1000)
+
+void Curl_cf_http_proxy_get_host(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 const char **phost,
+                                 const char **pdisplay_host,
+                                 int *pport);
+
+CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
+                                         struct Curl_easy *data);
+
+extern struct Curl_cftype Curl_cft_http_proxy;
+
+#endif /* !CURL_DISABLE_PROXY  && !CURL_DISABLE_HTTP */
+
+#define IS_HTTPS_PROXY(t) (((t) == CURLPROXY_HTTPS) ||  \
+                           ((t) == CURLPROXY_HTTPS2))
+
+#endif /* HEADER_CURL_HTTP_PROXY_H */
Index: trunk/src/libs/curl-8.7.1/lib/idn.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/idn.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/idn.c	(revision 104083)
@@ -0,0 +1,287 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+ /*
+  * IDN conversions
+  */
+
+#include "curl_setup.h"
+#include "urldata.h"
+#include "idn.h"
+#include "sendf.h"
+#include "curl_multibyte.h"
+#include "warnless.h"
+
+#ifdef USE_LIBIDN2
+#include <idn2.h>
+
+#if defined(_WIN32) && defined(UNICODE)
+#define IDN2_LOOKUP(name, host, flags)                                  \
+  idn2_lookup_u8((const uint8_t *)name, (uint8_t **)host, flags)
+#else
+#define IDN2_LOOKUP(name, host, flags)                          \
+  idn2_lookup_ul((const char *)name, (char **)host, flags)
+#endif
+#endif  /* USE_LIBIDN2 */
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef USE_WIN32_IDN
+/* using Windows kernel32 and normaliz libraries. */
+
+#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600
+WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags,
+                                 const WCHAR *lpUnicodeCharStr,
+                                 int cchUnicodeChar,
+                                 WCHAR *lpASCIICharStr,
+                                 int cchASCIIChar);
+WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,
+                                   const WCHAR *lpASCIICharStr,
+                                   int cchASCIIChar,
+                                   WCHAR *lpUnicodeCharStr,
+                                   int cchUnicodeChar);
+#endif
+
+#define IDN_MAX_LENGTH 255
+
+static CURLcode win32_idn_to_ascii(const char *in, char **out)
+{
+  wchar_t *in_w = curlx_convert_UTF8_to_wchar(in);
+  *out = NULL;
+  if(in_w) {
+    wchar_t punycode[IDN_MAX_LENGTH];
+    int chars = IdnToAscii(0, in_w, (int)(wcslen(in_w) + 1), punycode,
+                           IDN_MAX_LENGTH);
+    curlx_unicodefree(in_w);
+    if(chars) {
+      char *mstr = curlx_convert_wchar_to_UTF8(punycode);
+      if(mstr) {
+        *out = strdup(mstr);
+        curlx_unicodefree(mstr);
+        if(!*out)
+          return CURLE_OUT_OF_MEMORY;
+      }
+      else
+        return CURLE_OUT_OF_MEMORY;
+    }
+    else
+      return CURLE_URL_MALFORMAT;
+  }
+  else
+    return CURLE_URL_MALFORMAT;
+
+  return CURLE_OK;
+}
+
+static CURLcode win32_ascii_to_idn(const char *in, char **output)
+{
+  char *out = NULL;
+
+  wchar_t *in_w = curlx_convert_UTF8_to_wchar(in);
+  if(in_w) {
+    WCHAR idn[IDN_MAX_LENGTH]; /* stores a UTF-16 string */
+    int chars = IdnToUnicode(0, in_w, (int)(wcslen(in_w) + 1), idn,
+                             IDN_MAX_LENGTH);
+    if(chars) {
+      /* 'chars' is "the number of characters retrieved" */
+      char *mstr = curlx_convert_wchar_to_UTF8(idn);
+      if(mstr) {
+        out = strdup(mstr);
+        curlx_unicodefree(mstr);
+        if(!out)
+          return CURLE_OUT_OF_MEMORY;
+      }
+    }
+    else
+      return CURLE_URL_MALFORMAT;
+  }
+  else
+    return CURLE_URL_MALFORMAT;
+  *output = out;
+  return CURLE_OK;
+}
+
+#endif /* USE_WIN32_IDN */
+
+/*
+ * Helpers for IDNA conversions.
+ */
+bool Curl_is_ASCII_name(const char *hostname)
+{
+  /* get an UNSIGNED local version of the pointer */
+  const unsigned char *ch = (const unsigned char *)hostname;
+
+  if(!hostname) /* bad input, consider it ASCII! */
+    return TRUE;
+
+  while(*ch) {
+    if(*ch++ & 0x80)
+      return FALSE;
+  }
+  return TRUE;
+}
+
+#ifdef USE_IDN
+/*
+ * Curl_idn_decode() returns an allocated IDN decoded string if it was
+ * possible. NULL on error.
+ *
+ * CURLE_URL_MALFORMAT - the host name could not be converted
+ * CURLE_OUT_OF_MEMORY - memory problem
+ *
+ */
+static CURLcode idn_decode(const char *input, char **output)
+{
+  char *decoded = NULL;
+  CURLcode result = CURLE_OK;
+#ifdef USE_LIBIDN2
+  if(idn2_check_version(IDN2_VERSION)) {
+    int flags = IDN2_NFC_INPUT
+#if IDN2_VERSION_NUMBER >= 0x00140000
+      /* IDN2_NFC_INPUT: Normalize input string using normalization form C.
+         IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional
+         processing. */
+      | IDN2_NONTRANSITIONAL
+#endif
+      ;
+    int rc = IDN2_LOOKUP(input, &decoded, flags);
+    if(rc != IDN2_OK)
+      /* fallback to TR46 Transitional mode for better IDNA2003
+         compatibility */
+      rc = IDN2_LOOKUP(input, &decoded, IDN2_TRANSITIONAL);
+    if(rc != IDN2_OK)
+      result = CURLE_URL_MALFORMAT;
+  }
+  else
+    /* a too old libidn2 version */
+    result = CURLE_NOT_BUILT_IN;
+#elif defined(USE_WIN32_IDN)
+  result = win32_idn_to_ascii(input, &decoded);
+#endif
+  if(!result)
+    *output = decoded;
+  return result;
+}
+
+static CURLcode idn_encode(const char *puny, char **output)
+{
+  char *enc = NULL;
+#ifdef USE_LIBIDN2
+  int rc = idn2_to_unicode_8z8z(puny, &enc, 0);
+  if(rc != IDNA_SUCCESS)
+    return rc == IDNA_MALLOC_ERROR ? CURLE_OUT_OF_MEMORY : CURLE_URL_MALFORMAT;
+#elif defined(USE_WIN32_IDN)
+  CURLcode result = win32_ascii_to_idn(puny, &enc);
+  if(result)
+    return result;
+#endif
+  *output = enc;
+  return CURLE_OK;
+}
+
+CURLcode Curl_idn_decode(const char *input, char **output)
+{
+  char *d = NULL;
+  CURLcode result = idn_decode(input, &d);
+#ifdef USE_LIBIDN2
+  if(!result) {
+    char *c = strdup(d);
+    idn2_free(d);
+    if(c)
+      d = c;
+    else
+      result = CURLE_OUT_OF_MEMORY;
+  }
+#endif
+  if(!result)
+    *output = d;
+  return result;
+}
+
+CURLcode Curl_idn_encode(const char *puny, char **output)
+{
+  char *d = NULL;
+  CURLcode result = idn_encode(puny, &d);
+#ifdef USE_LIBIDN2
+  if(!result) {
+    char *c = strdup(d);
+    idn2_free(d);
+    if(c)
+      d = c;
+    else
+      result = CURLE_OUT_OF_MEMORY;
+  }
+#endif
+  if(!result)
+    *output = d;
+  return result;
+}
+
+/*
+ * Frees data allocated by idnconvert_hostname()
+ */
+void Curl_free_idnconverted_hostname(struct hostname *host)
+{
+  if(host->encalloc) {
+    /* must be freed with idn2_free() if allocated by libidn */
+    Curl_idn_free(host->encalloc);
+    host->encalloc = NULL;
+  }
+}
+
+#endif /* USE_IDN */
+
+/*
+ * Perform any necessary IDN conversion of hostname
+ */
+CURLcode Curl_idnconvert_hostname(struct hostname *host)
+{
+  /* set the name we use to display the host name */
+  host->dispname = host->name;
+
+#ifdef USE_IDN
+  /* Check name for non-ASCII and convert hostname if we can */
+  if(!Curl_is_ASCII_name(host->name)) {
+    char *decoded;
+    CURLcode result = idn_decode(host->name, &decoded);
+    if(!result) {
+      if(!*decoded) {
+        /* zero length is a bad host name */
+        Curl_idn_free(decoded);
+        return CURLE_URL_MALFORMAT;
+      }
+      /* successful */
+      host->encalloc = decoded;
+      /* change the name pointer to point to the encoded hostname */
+      host->name = host->encalloc;
+    }
+    else
+      return result;
+  }
+#endif
+  return CURLE_OK;
+}
Index: trunk/src/libs/curl-8.7.1/lib/idn.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/idn.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/idn.h	(revision 104083)
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_IDN_H
+#define HEADER_CURL_IDN_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+bool Curl_is_ASCII_name(const char *hostname);
+CURLcode Curl_idnconvert_hostname(struct hostname *host);
+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
+#define USE_IDN
+void Curl_free_idnconverted_hostname(struct hostname *host);
+CURLcode Curl_idn_decode(const char *input, char **output);
+CURLcode Curl_idn_encode(const char *input, char **output);
+#ifdef USE_LIBIDN2
+#define Curl_idn_free(x) idn2_free(x)
+#else
+#define Curl_idn_free(x) free(x)
+#endif
+
+#else
+#define Curl_free_idnconverted_hostname(x)
+#define Curl_idn_decode(x) NULL
+#endif
+#endif /* HEADER_CURL_IDN_H */
Index: trunk/src/libs/curl-8.7.1/lib/if2ip.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/if2ip.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/if2ip.c	(revision 104083)
@@ -0,0 +1,260 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#  include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#  include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#  include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#  include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NETDB_H
+#  include <netdb.h>
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+#  include <sys/sockio.h>
+#endif
+#ifdef HAVE_IFADDRS_H
+#  include <ifaddrs.h>
+#endif
+#ifdef HAVE_STROPTS_H
+#  include <stropts.h>
+#endif
+#ifdef __VMS
+#  include <inet.h>
+#endif
+
+#include "inet_ntop.h"
+#include "strcase.h"
+#include "if2ip.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* ------------------------------------------------------------------ */
+
+#ifdef ENABLE_IPV6
+/* Return the scope of the given address. */
+unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
+{
+  if(sa->sa_family == AF_INET6) {
+    const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa;
+    const unsigned char *b = sa6->sin6_addr.s6_addr;
+    unsigned short w = (unsigned short) ((b[0] << 8) | b[1]);
+
+    if((b[0] & 0xFE) == 0xFC) /* Handle ULAs */
+      return IPV6_SCOPE_UNIQUELOCAL;
+    switch(w & 0xFFC0) {
+    case 0xFE80:
+      return IPV6_SCOPE_LINKLOCAL;
+    case 0xFEC0:
+      return IPV6_SCOPE_SITELOCAL;
+    case 0x0000:
+      w = b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7] | b[8] | b[9] |
+          b[10] | b[11] | b[12] | b[13] | b[14];
+      if(w || b[15] != 0x01)
+        break;
+      return IPV6_SCOPE_NODELOCAL;
+    default:
+      break;
+    }
+  }
+  return IPV6_SCOPE_GLOBAL;
+}
+#endif
+
+#ifndef CURL_DISABLE_BINDLOCAL
+
+#if defined(HAVE_GETIFADDRS)
+
+if2ip_result_t Curl_if2ip(int af,
+#ifdef ENABLE_IPV6
+                          unsigned int remote_scope,
+                          unsigned int local_scope_id,
+#endif
+                          const char *interf,
+                          char *buf, int buf_size)
+{
+  struct ifaddrs *iface, *head;
+  if2ip_result_t res = IF2IP_NOT_FOUND;
+
+#if defined(ENABLE_IPV6) && \
+    !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
+  (void) local_scope_id;
+#endif
+
+  if(getifaddrs(&head) >= 0) {
+    for(iface = head; iface != NULL; iface = iface->ifa_next) {
+      if(iface->ifa_addr) {
+        if(iface->ifa_addr->sa_family == af) {
+          if(strcasecompare(iface->ifa_name, interf)) {
+            void *addr;
+            const char *ip;
+            char scope[12] = "";
+            char ipstr[64];
+#ifdef ENABLE_IPV6
+            if(af == AF_INET6) {
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+              unsigned int scopeid = 0;
+#endif
+              unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr);
+
+              if(ifscope != remote_scope) {
+                /* We are interested only in interface addresses whose scope
+                   matches the remote address we want to connect to: global
+                   for global, link-local for link-local, etc... */
+                if(res == IF2IP_NOT_FOUND)
+                  res = IF2IP_AF_NOT_SUPPORTED;
+                continue;
+              }
+
+              addr =
+                &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr;
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+              /* Include the scope of this interface as part of the address */
+              scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr)
+                            ->sin6_scope_id;
+
+              /* If given, scope id should match. */
+              if(local_scope_id && scopeid != local_scope_id) {
+                if(res == IF2IP_NOT_FOUND)
+                  res = IF2IP_AF_NOT_SUPPORTED;
+
+                continue;
+              }
+
+              if(scopeid)
+                msnprintf(scope, sizeof(scope), "%%%u", scopeid);
+#endif
+            }
+            else
+#endif
+              addr =
+                &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
+            res = IF2IP_FOUND;
+            ip = Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
+            msnprintf(buf, buf_size, "%s%s", ip, scope);
+            break;
+          }
+        }
+        else if((res == IF2IP_NOT_FOUND) &&
+                strcasecompare(iface->ifa_name, interf)) {
+          res = IF2IP_AF_NOT_SUPPORTED;
+        }
+      }
+    }
+
+    freeifaddrs(head);
+  }
+
+  return res;
+}
+
+#elif defined(HAVE_IOCTL_SIOCGIFADDR)
+
+if2ip_result_t Curl_if2ip(int af,
+#ifdef ENABLE_IPV6
+                          unsigned int remote_scope,
+                          unsigned int local_scope_id,
+#endif
+                          const char *interf,
+                          char *buf, int buf_size)
+{
+  struct ifreq req;
+  struct in_addr in;
+  struct sockaddr_in *s;
+  curl_socket_t dummy;
+  size_t len;
+  const char *r;
+
+#ifdef ENABLE_IPV6
+  (void)remote_scope;
+  (void)local_scope_id;
+#endif
+
+  if(!interf || (af != AF_INET))
+    return IF2IP_NOT_FOUND;
+
+  len = strlen(interf);
+  if(len >= sizeof(req.ifr_name))
+    return IF2IP_NOT_FOUND;
+
+  dummy = socket(AF_INET, SOCK_STREAM, 0);
+  if(CURL_SOCKET_BAD == dummy)
+    return IF2IP_NOT_FOUND;
+
+  memset(&req, 0, sizeof(req));
+  memcpy(req.ifr_name, interf, len + 1);
+  req.ifr_addr.sa_family = AF_INET;
+
+  if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
+    sclose(dummy);
+    /* With SIOCGIFADDR, we cannot tell the difference between an interface
+       that does not exist and an interface that has no address of the
+       correct family. Assume the interface does not exist */
+    return IF2IP_NOT_FOUND;
+  }
+
+  s = (struct sockaddr_in *)(void *)&req.ifr_addr;
+  memcpy(&in, &s->sin_addr, sizeof(in));
+  r = Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
+
+  sclose(dummy);
+  if(!r)
+    return IF2IP_NOT_FOUND;
+  return IF2IP_FOUND;
+}
+
+#else
+
+if2ip_result_t Curl_if2ip(int af,
+#ifdef ENABLE_IPV6
+                          unsigned int remote_scope,
+                          unsigned int local_scope_id,
+#endif
+                          const char *interf,
+                          char *buf, int buf_size)
+{
+    (void) af;
+#ifdef ENABLE_IPV6
+    (void) remote_scope;
+    (void) local_scope_id;
+#endif
+    (void) interf;
+    (void) buf;
+    (void) buf_size;
+    return IF2IP_NOT_FOUND;
+}
+
+#endif
+
+#endif /* CURL_DISABLE_BINDLOCAL */
Index: trunk/src/libs/curl-8.7.1/lib/if2ip.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/if2ip.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/if2ip.h	(revision 104083)
@@ -0,0 +1,92 @@
+#ifndef HEADER_CURL_IF2IP_H
+#define HEADER_CURL_IF2IP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+/* IPv6 address scopes. */
+#define IPV6_SCOPE_GLOBAL       0       /* Global scope. */
+#define IPV6_SCOPE_LINKLOCAL    1       /* Link-local scope. */
+#define IPV6_SCOPE_SITELOCAL    2       /* Site-local scope (deprecated). */
+#define IPV6_SCOPE_UNIQUELOCAL  3       /* Unique local */
+#define IPV6_SCOPE_NODELOCAL    4       /* Loopback. */
+
+#ifdef ENABLE_IPV6
+unsigned int Curl_ipv6_scope(const struct sockaddr *sa);
+#else
+#define Curl_ipv6_scope(x) 0
+#endif
+
+typedef enum {
+  IF2IP_NOT_FOUND = 0, /* Interface not found */
+  IF2IP_AF_NOT_SUPPORTED = 1, /* Int. exists but has no address for this af */
+  IF2IP_FOUND = 2 /* The address has been stored in "buf" */
+} if2ip_result_t;
+
+if2ip_result_t Curl_if2ip(int af,
+#ifdef ENABLE_IPV6
+                          unsigned int remote_scope,
+                          unsigned int local_scope_id,
+#endif
+                          const char *interf,
+                          char *buf, int buf_size);
+
+#ifdef __INTERIX
+
+/* Nedelcho Stanev's work-around for SFU 3.0 */
+struct ifreq {
+#define IFNAMSIZ 16
+#define IFHWADDRLEN 6
+  union {
+    char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+  } ifr_ifrn;
+
+ union {
+   struct sockaddr ifru_addr;
+   struct sockaddr ifru_broadaddr;
+   struct sockaddr ifru_netmask;
+   struct sockaddr ifru_hwaddr;
+   short ifru_flags;
+   int ifru_metric;
+   int ifru_mtu;
+ } ifr_ifru;
+};
+
+/* This define was added by Daniel to avoid an extra #ifdef INTERIX in the
+   C code. */
+
+#define ifr_name ifr_ifrn.ifrn_name /* interface name */
+#define ifr_addr ifr_ifru.ifru_addr /* address */
+#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
+#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
+#define ifr_flags ifr_ifru.ifru_flags /* flags */
+#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
+#define ifr_metric ifr_ifru.ifru_metric /* metric */
+#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
+
+#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */
+
+#endif /* __INTERIX */
+
+#endif /* HEADER_CURL_IF2IP_H */
Index: trunk/src/libs/curl-8.7.1/lib/imap.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/imap.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/imap.c	(revision 104083)
@@ -0,0 +1,2115 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC2195 CRAM-MD5 authentication
+ * RFC2595 Using TLS with IMAP, POP3 and ACAP
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC3501 IMAPv4 protocol
+ * RFC4422 Simple Authentication and Security Layer (SASL)
+ * RFC4616 PLAIN authentication
+ * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
+ * RFC4959 IMAP Extension for SASL Initial Client Response
+ * RFC5092 IMAP URL Scheme
+ * RFC6749 OAuth 2.0 Authorization Framework
+ * RFC8314 Use of TLS for Email Submission and Access
+ * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_IMAP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "imap.h"
+#include "mime.h"
+#include "strtoofft.h"
+#include "strcase.h"
+#include "vtls/vtls.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "select.h"
+#include "multiif.h"
+#include "url.h"
+#include "bufref.h"
+#include "curl_sasl.h"
+#include "warnless.h"
+#include "curl_ctype.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Local API functions */
+static CURLcode imap_regular_transfer(struct Curl_easy *data, bool *done);
+static CURLcode imap_do(struct Curl_easy *data, bool *done);
+static CURLcode imap_done(struct Curl_easy *data, CURLcode status,
+                          bool premature);
+static CURLcode imap_connect(struct Curl_easy *data, bool *done);
+static CURLcode imap_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
+static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done);
+static int imap_getsock(struct Curl_easy *data, struct connectdata *conn,
+                        curl_socket_t *socks);
+static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done);
+static CURLcode imap_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static char *imap_atom(const char *str, bool escape_only);
+static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
+  CURL_PRINTF(2, 3);
+static CURLcode imap_parse_url_options(struct connectdata *conn);
+static CURLcode imap_parse_url_path(struct Curl_easy *data);
+static CURLcode imap_parse_custom_request(struct Curl_easy *data);
+static CURLcode imap_perform_authenticate(struct Curl_easy *data,
+                                          const char *mech,
+                                          const struct bufref *initresp);
+static CURLcode imap_continue_authenticate(struct Curl_easy *data,
+                                           const char *mech,
+                                           const struct bufref *resp);
+static CURLcode imap_cancel_authenticate(struct Curl_easy *data,
+                                         const char *mech);
+static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out);
+
+/*
+ * IMAP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_imap = {
+  "IMAP",                           /* scheme */
+  imap_setup_connection,            /* setup_connection */
+  imap_do,                          /* do_it */
+  imap_done,                        /* done */
+  ZERO_NULL,                        /* do_more */
+  imap_connect,                     /* connect_it */
+  imap_multi_statemach,             /* connecting */
+  imap_doing,                       /* doing */
+  imap_getsock,                     /* proto_getsock */
+  imap_getsock,                     /* doing_getsock */
+  ZERO_NULL,                        /* domore_getsock */
+  ZERO_NULL,                        /* perform_getsock */
+  imap_disconnect,                  /* disconnect */
+  ZERO_NULL,                        /* write_resp */
+  ZERO_NULL,                        /* connection_check */
+  ZERO_NULL,                        /* attach connection */
+  PORT_IMAP,                        /* defport */
+  CURLPROTO_IMAP,                   /* protocol */
+  CURLPROTO_IMAP,                   /* family */
+  PROTOPT_CLOSEACTION|              /* flags */
+  PROTOPT_URLOPTIONS
+};
+
+#ifdef USE_SSL
+/*
+ * IMAPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_imaps = {
+  "IMAPS",                          /* scheme */
+  imap_setup_connection,            /* setup_connection */
+  imap_do,                          /* do_it */
+  imap_done,                        /* done */
+  ZERO_NULL,                        /* do_more */
+  imap_connect,                     /* connect_it */
+  imap_multi_statemach,             /* connecting */
+  imap_doing,                       /* doing */
+  imap_getsock,                     /* proto_getsock */
+  imap_getsock,                     /* doing_getsock */
+  ZERO_NULL,                        /* domore_getsock */
+  ZERO_NULL,                        /* perform_getsock */
+  imap_disconnect,                  /* disconnect */
+  ZERO_NULL,                        /* write_resp */
+  ZERO_NULL,                        /* connection_check */
+  ZERO_NULL,                        /* attach connection */
+  PORT_IMAPS,                       /* defport */
+  CURLPROTO_IMAPS,                  /* protocol */
+  CURLPROTO_IMAP,                   /* family */
+  PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
+  PROTOPT_URLOPTIONS
+};
+#endif
+
+#define IMAP_RESP_OK       1
+#define IMAP_RESP_NOT_OK   2
+#define IMAP_RESP_PREAUTH  3
+
+/* SASL parameters for the imap protocol */
+static const struct SASLproto saslimap = {
+  "imap",                     /* The service name */
+  imap_perform_authenticate,  /* Send authentication command */
+  imap_continue_authenticate, /* Send authentication continuation */
+  imap_cancel_authenticate,   /* Send authentication cancellation */
+  imap_get_message,           /* Get SASL response message */
+  0,                          /* No maximum initial response length */
+  '+',                        /* Code received when continuation is expected */
+  IMAP_RESP_OK,               /* Code to receive upon authentication success */
+  SASL_AUTH_DEFAULT,          /* Default mechanisms */
+  SASL_FLAG_BASE64            /* Configuration flags */
+};
+
+
+#ifdef USE_SSL
+static void imap_to_imaps(struct connectdata *conn)
+{
+  /* Change the connection handler */
+  conn->handler = &Curl_handler_imaps;
+
+  /* Set the connection's upgraded to TLS flag */
+  conn->bits.tls_upgraded = TRUE;
+}
+#else
+#define imap_to_imaps(x) Curl_nop_stmt
+#endif
+
+/***********************************************************************
+ *
+ * imap_matchresp()
+ *
+ * Determines whether the untagged response is related to the specified
+ * command by checking if it is in format "* <command-name> ..." or
+ * "* <number> <command-name> ...".
+ *
+ * The "* " marker is assumed to have already been checked by the caller.
+ */
+static bool imap_matchresp(const char *line, size_t len, const char *cmd)
+{
+  const char *end = line + len;
+  size_t cmd_len = strlen(cmd);
+
+  /* Skip the untagged response marker */
+  line += 2;
+
+  /* Do we have a number after the marker? */
+  if(line < end && ISDIGIT(*line)) {
+    /* Skip the number */
+    do
+      line++;
+    while(line < end && ISDIGIT(*line));
+
+    /* Do we have the space character? */
+    if(line == end || *line != ' ')
+      return FALSE;
+
+    line++;
+  }
+
+  /* Does the command name match and is it followed by a space character or at
+     the end of line? */
+  if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) &&
+     (line[cmd_len] == ' ' || line + cmd_len + 2 == end))
+    return TRUE;
+
+  return FALSE;
+}
+
+/***********************************************************************
+ *
+ * imap_endofresp()
+ *
+ * Checks whether the given string is a valid tagged, untagged or continuation
+ * response which can be processed by the response handler.
+ */
+static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
+                           char *line, size_t len, int *resp)
+{
+  struct IMAP *imap = data->req.p.imap;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  const char *id = imapc->resptag;
+  size_t id_len = strlen(id);
+
+  /* Do we have a tagged command response? */
+  if(len >= id_len + 1 && !memcmp(id, line, id_len) && line[id_len] == ' ') {
+    line += id_len + 1;
+    len -= id_len + 1;
+
+    if(len >= 2 && !memcmp(line, "OK", 2))
+      *resp = IMAP_RESP_OK;
+    else if(len >= 7 && !memcmp(line, "PREAUTH", 7))
+      *resp = IMAP_RESP_PREAUTH;
+    else
+      *resp = IMAP_RESP_NOT_OK;
+
+    return TRUE;
+  }
+
+  /* Do we have an untagged command response? */
+  if(len >= 2 && !memcmp("* ", line, 2)) {
+    switch(imapc->state) {
+      /* States which are interested in untagged responses */
+      case IMAP_CAPABILITY:
+        if(!imap_matchresp(line, len, "CAPABILITY"))
+          return FALSE;
+        break;
+
+      case IMAP_LIST:
+        if((!imap->custom && !imap_matchresp(line, len, "LIST")) ||
+          (imap->custom && !imap_matchresp(line, len, imap->custom) &&
+           (!strcasecompare(imap->custom, "STORE") ||
+            !imap_matchresp(line, len, "FETCH")) &&
+           !strcasecompare(imap->custom, "SELECT") &&
+           !strcasecompare(imap->custom, "EXAMINE") &&
+           !strcasecompare(imap->custom, "SEARCH") &&
+           !strcasecompare(imap->custom, "EXPUNGE") &&
+           !strcasecompare(imap->custom, "LSUB") &&
+           !strcasecompare(imap->custom, "UID") &&
+           !strcasecompare(imap->custom, "GETQUOTAROOT") &&
+           !strcasecompare(imap->custom, "NOOP")))
+          return FALSE;
+        break;
+
+      case IMAP_SELECT:
+        /* SELECT is special in that its untagged responses do not have a
+           common prefix so accept anything! */
+        break;
+
+      case IMAP_FETCH:
+        if(!imap_matchresp(line, len, "FETCH"))
+          return FALSE;
+        break;
+
+      case IMAP_SEARCH:
+        if(!imap_matchresp(line, len, "SEARCH"))
+          return FALSE;
+        break;
+
+      /* Ignore other untagged responses */
+      default:
+        return FALSE;
+    }
+
+    *resp = '*';
+    return TRUE;
+  }
+
+  /* Do we have a continuation response? This should be a + symbol followed by
+     a space and optionally some text as per RFC-3501 for the AUTHENTICATE and
+     APPEND commands and as outlined in Section 4. Examples of RFC-4959 but
+     some email servers ignore this and only send a single + instead. */
+  if(imap && !imap->custom && ((len == 3 && line[0] == '+') ||
+     (len >= 2 && !memcmp("+ ", line, 2)))) {
+    switch(imapc->state) {
+      /* States which are interested in continuation responses */
+      case IMAP_AUTHENTICATE:
+      case IMAP_APPEND:
+        *resp = '+';
+        break;
+
+      default:
+        failf(data, "Unexpected continuation response");
+        *resp = -1;
+        break;
+    }
+
+    return TRUE;
+  }
+
+  return FALSE; /* Nothing for us */
+}
+
+/***********************************************************************
+ *
+ * imap_get_message()
+ *
+ * Gets the authentication message from the response buffer.
+ */
+static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out)
+{
+  char *message = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
+  size_t len = data->conn->proto.imapc.pp.nfinal;
+
+  if(len > 2) {
+    /* Find the start of the message */
+    len -= 2;
+    for(message += 2; *message == ' ' || *message == '\t'; message++, len--)
+      ;
+
+    /* Find the end of the message */
+    while(len--)
+      if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
+         message[len] != '\t')
+        break;
+
+    /* Terminate the message */
+    message[++len] = '\0';
+    Curl_bufref_set(out, message, len, NULL);
+  }
+  else
+    /* junk input => zero length output */
+    Curl_bufref_set(out, "", 0, NULL);
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * imap_state()
+ *
+ * This is the ONLY way to change IMAP state!
+ */
+static void imap_state(struct Curl_easy *data, imapstate newstate)
+{
+  struct imap_conn *imapc = &data->conn->proto.imapc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[]={
+    "STOP",
+    "SERVERGREET",
+    "CAPABILITY",
+    "STARTTLS",
+    "UPGRADETLS",
+    "AUTHENTICATE",
+    "LOGIN",
+    "LIST",
+    "SELECT",
+    "FETCH",
+    "FETCH_FINAL",
+    "APPEND",
+    "APPEND_FINAL",
+    "SEARCH",
+    "LOGOUT",
+    /* LAST */
+  };
+
+  if(imapc->state != newstate)
+    infof(data, "IMAP %p state change from %s to %s",
+          (void *)imapc, names[imapc->state], names[newstate]);
+#endif
+
+  imapc->state = newstate;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_capability()
+ *
+ * Sends the CAPABILITY command in order to obtain a list of server side
+ * supported capabilities.
+ */
+static CURLcode imap_perform_capability(struct Curl_easy *data,
+                                        struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
+  imapc->sasl.authused = SASL_AUTH_NONE;  /* Clear the auth. mechanism used */
+  imapc->tls_supported = FALSE;           /* Clear the TLS capability */
+
+  /* Send the CAPABILITY command */
+  result = imap_sendf(data, "CAPABILITY");
+
+  if(!result)
+    imap_state(data, IMAP_CAPABILITY);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_starttls()
+ *
+ * Sends the STARTTLS command to start the upgrade to TLS.
+ */
+static CURLcode imap_perform_starttls(struct Curl_easy *data)
+{
+  /* Send the STARTTLS command */
+  CURLcode result = imap_sendf(data, "STARTTLS");
+
+  if(!result)
+    imap_state(data, IMAP_STARTTLS);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_upgrade_tls()
+ *
+ * Performs the upgrade to TLS.
+ */
+static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data,
+                                         struct connectdata *conn)
+{
+  /* Start the SSL connection */
+  struct imap_conn *imapc = &conn->proto.imapc;
+  CURLcode result;
+  bool ssldone = FALSE;
+
+  if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
+    result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
+    if(result)
+      goto out;
+  }
+
+  result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
+  if(!result) {
+    imapc->ssldone = ssldone;
+    if(imapc->state != IMAP_UPGRADETLS)
+      imap_state(data, IMAP_UPGRADETLS);
+
+    if(imapc->ssldone) {
+      imap_to_imaps(conn);
+      result = imap_perform_capability(data, conn);
+    }
+  }
+out:
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_login()
+ *
+ * Sends a clear text LOGIN command to authenticate with.
+ */
+static CURLcode imap_perform_login(struct Curl_easy *data,
+                                   struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  char *user;
+  char *passwd;
+
+  /* Check we have a username and password to authenticate with and end the
+     connect phase if we don't */
+  if(!data->state.aptr.user) {
+    imap_state(data, IMAP_STOP);
+
+    return result;
+  }
+
+  /* Make sure the username and password are in the correct atom format */
+  user = imap_atom(conn->user, false);
+  passwd = imap_atom(conn->passwd, false);
+
+  /* Send the LOGIN command */
+  result = imap_sendf(data, "LOGIN %s %s", user ? user : "",
+                      passwd ? passwd : "");
+
+  free(user);
+  free(passwd);
+
+  if(!result)
+    imap_state(data, IMAP_LOGIN);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_authenticate()
+ *
+ * Sends an AUTHENTICATE command allowing the client to login with the given
+ * SASL authentication mechanism.
+ */
+static CURLcode imap_perform_authenticate(struct Curl_easy *data,
+                                          const char *mech,
+                                          const struct bufref *initresp)
+{
+  CURLcode result = CURLE_OK;
+  const char *ir = (const char *) Curl_bufref_ptr(initresp);
+
+  if(ir) {
+    /* Send the AUTHENTICATE command with the initial response */
+    result = imap_sendf(data, "AUTHENTICATE %s %s", mech, ir);
+  }
+  else {
+    /* Send the AUTHENTICATE command */
+    result = imap_sendf(data, "AUTHENTICATE %s", mech);
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_continue_authenticate()
+ *
+ * Sends SASL continuation data.
+ */
+static CURLcode imap_continue_authenticate(struct Curl_easy *data,
+                                           const char *mech,
+                                           const struct bufref *resp)
+{
+  struct imap_conn *imapc = &data->conn->proto.imapc;
+
+  (void)mech;
+
+  return Curl_pp_sendf(data, &imapc->pp,
+                       "%s", (const char *) Curl_bufref_ptr(resp));
+}
+
+/***********************************************************************
+ *
+ * imap_cancel_authenticate()
+ *
+ * Sends SASL cancellation.
+ */
+static CURLcode imap_cancel_authenticate(struct Curl_easy *data,
+                                         const char *mech)
+{
+  struct imap_conn *imapc = &data->conn->proto.imapc;
+
+  (void)mech;
+
+  return Curl_pp_sendf(data, &imapc->pp, "*");
+}
+
+/***********************************************************************
+ *
+ * imap_perform_authentication()
+ *
+ * Initiates the authentication sequence, with the appropriate SASL
+ * authentication mechanism, falling back to clear text should a common
+ * mechanism not be available between the client and server.
+ */
+static CURLcode imap_perform_authentication(struct Curl_easy *data,
+                                            struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  saslprogress progress;
+
+  /* Check if already authenticated OR if there is enough data to authenticate
+     with and end the connect phase if we don't */
+  if(imapc->preauth ||
+     !Curl_sasl_can_authenticate(&imapc->sasl, data)) {
+    imap_state(data, IMAP_STOP);
+    return result;
+  }
+
+  /* Calculate the SASL login details */
+  result = Curl_sasl_start(&imapc->sasl, data, imapc->ir_supported, &progress);
+
+  if(!result) {
+    if(progress == SASL_INPROGRESS)
+      imap_state(data, IMAP_AUTHENTICATE);
+    else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
+      /* Perform clear text authentication */
+      result = imap_perform_login(data, conn);
+    else {
+      /* Other mechanisms not supported */
+      infof(data, "No known authentication mechanisms supported");
+      result = CURLE_LOGIN_DENIED;
+    }
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_list()
+ *
+ * Sends a LIST command or an alternative custom request.
+ */
+static CURLcode imap_perform_list(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct IMAP *imap = data->req.p.imap;
+
+  if(imap->custom)
+    /* Send the custom request */
+    result = imap_sendf(data, "%s%s", imap->custom,
+                        imap->custom_params ? imap->custom_params : "");
+  else {
+    /* Make sure the mailbox is in the correct atom format if necessary */
+    char *mailbox = imap->mailbox ? imap_atom(imap->mailbox, true)
+                                  : strdup("");
+    if(!mailbox)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* Send the LIST command */
+    result = imap_sendf(data, "LIST \"%s\" *", mailbox);
+
+    free(mailbox);
+  }
+
+  if(!result)
+    imap_state(data, IMAP_LIST);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_select()
+ *
+ * Sends a SELECT command to ask the server to change the selected mailbox.
+ */
+static CURLcode imap_perform_select(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct IMAP *imap = data->req.p.imap;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  char *mailbox;
+
+  /* Invalidate old information as we are switching mailboxes */
+  Curl_safefree(imapc->mailbox);
+  Curl_safefree(imapc->mailbox_uidvalidity);
+
+  /* Check we have a mailbox */
+  if(!imap->mailbox) {
+    failf(data, "Cannot SELECT without a mailbox.");
+    return CURLE_URL_MALFORMAT;
+  }
+
+  /* Make sure the mailbox is in the correct atom format */
+  mailbox = imap_atom(imap->mailbox, false);
+  if(!mailbox)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Send the SELECT command */
+  result = imap_sendf(data, "SELECT %s", mailbox);
+
+  free(mailbox);
+
+  if(!result)
+    imap_state(data, IMAP_SELECT);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_fetch()
+ *
+ * Sends a FETCH command to initiate the download of a message.
+ */
+static CURLcode imap_perform_fetch(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct IMAP *imap = data->req.p.imap;
+  /* Check we have a UID */
+  if(imap->uid) {
+
+    /* Send the FETCH command */
+    if(imap->partial)
+      result = imap_sendf(data, "UID FETCH %s BODY[%s]<%s>",
+                          imap->uid, imap->section ? imap->section : "",
+                          imap->partial);
+    else
+      result = imap_sendf(data, "UID FETCH %s BODY[%s]",
+                          imap->uid, imap->section ? imap->section : "");
+  }
+  else if(imap->mindex) {
+    /* Send the FETCH command */
+    if(imap->partial)
+      result = imap_sendf(data, "FETCH %s BODY[%s]<%s>",
+                          imap->mindex, imap->section ? imap->section : "",
+                          imap->partial);
+    else
+      result = imap_sendf(data, "FETCH %s BODY[%s]",
+                          imap->mindex, imap->section ? imap->section : "");
+  }
+  else {
+    failf(data, "Cannot FETCH without a UID.");
+    return CURLE_URL_MALFORMAT;
+  }
+  if(!result)
+    imap_state(data, IMAP_FETCH);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_append()
+ *
+ * Sends an APPEND command to initiate the upload of a message.
+ */
+static CURLcode imap_perform_append(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct IMAP *imap = data->req.p.imap;
+  char *mailbox;
+
+  /* Check we have a mailbox */
+  if(!imap->mailbox) {
+    failf(data, "Cannot APPEND without a mailbox.");
+    return CURLE_URL_MALFORMAT;
+  }
+
+#ifndef CURL_DISABLE_MIME
+  /* Prepare the mime data if some. */
+  if(data->set.mimepost.kind != MIMEKIND_NONE) {
+    /* Use the whole structure as data. */
+    data->set.mimepost.flags &= ~MIME_BODY_ONLY;
+
+    /* Add external headers and mime version. */
+    curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
+    result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL,
+                                       NULL, MIMESTRATEGY_MAIL);
+
+    if(!result)
+      if(!Curl_checkheaders(data, STRCONST("Mime-Version")))
+        result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
+                                      "Mime-Version: 1.0");
+
+    if(!result)
+      result = Curl_creader_set_mime(data, &data->set.mimepost);
+    if(result)
+      return result;
+    data->state.infilesize = Curl_creader_client_length(data);
+  }
+  else
+#endif
+  {
+    result = Curl_creader_set_fread(data, data->state.infilesize);
+    if(result)
+      return result;
+  }
+
+  /* Check we know the size of the upload */
+  if(data->state.infilesize < 0) {
+    failf(data, "Cannot APPEND with unknown input file size");
+    return CURLE_UPLOAD_FAILED;
+  }
+
+  /* Make sure the mailbox is in the correct atom format */
+  mailbox = imap_atom(imap->mailbox, false);
+  if(!mailbox)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Send the APPEND command */
+  result = imap_sendf(data,
+                      "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
+                      mailbox, data->state.infilesize);
+
+  free(mailbox);
+
+  if(!result)
+    imap_state(data, IMAP_APPEND);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_search()
+ *
+ * Sends a SEARCH command.
+ */
+static CURLcode imap_perform_search(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct IMAP *imap = data->req.p.imap;
+
+  /* Check we have a query string */
+  if(!imap->query) {
+    failf(data, "Cannot SEARCH without a query string.");
+    return CURLE_URL_MALFORMAT;
+  }
+
+  /* Send the SEARCH command */
+  result = imap_sendf(data, "SEARCH %s", imap->query);
+
+  if(!result)
+    imap_state(data, IMAP_SEARCH);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_logout()
+ *
+ * Performs the logout action prior to sclose() being called.
+ */
+static CURLcode imap_perform_logout(struct Curl_easy *data)
+{
+  /* Send the LOGOUT command */
+  CURLcode result = imap_sendf(data, "LOGOUT");
+
+  if(!result)
+    imap_state(data, IMAP_LOGOUT);
+
+  return result;
+}
+
+/* For the initial server greeting */
+static CURLcode imap_state_servergreet_resp(struct Curl_easy *data,
+                                            int imapcode,
+                                            imapstate instate)
+{
+  struct connectdata *conn = data->conn;
+  (void)instate; /* no use for this yet */
+
+  if(imapcode == IMAP_RESP_PREAUTH) {
+    /* PREAUTH */
+    struct imap_conn *imapc = &conn->proto.imapc;
+    imapc->preauth = TRUE;
+    infof(data, "PREAUTH connection, already authenticated");
+  }
+  else if(imapcode != IMAP_RESP_OK) {
+    failf(data, "Got unexpected imap-server response");
+    return CURLE_WEIRD_SERVER_REPLY;
+  }
+
+  return imap_perform_capability(data, conn);
+}
+
+/* For CAPABILITY responses */
+static CURLcode imap_state_capability_resp(struct Curl_easy *data,
+                                           int imapcode,
+                                           imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  const char *line = Curl_dyn_ptr(&imapc->pp.recvbuf);
+
+  (void)instate; /* no use for this yet */
+
+  /* Do we have a untagged response? */
+  if(imapcode == '*') {
+    line += 2;
+
+    /* Loop through the data line */
+    for(;;) {
+      size_t wordlen;
+      while(*line &&
+            (*line == ' ' || *line == '\t' ||
+              *line == '\r' || *line == '\n')) {
+
+        line++;
+      }
+
+      if(!*line)
+        break;
+
+      /* Extract the word */
+      for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' &&
+            line[wordlen] != '\t' && line[wordlen] != '\r' &&
+            line[wordlen] != '\n';)
+        wordlen++;
+
+      /* Does the server support the STARTTLS capability? */
+      if(wordlen == 8 && !memcmp(line, "STARTTLS", 8))
+        imapc->tls_supported = TRUE;
+
+      /* Has the server explicitly disabled clear text authentication? */
+      else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13))
+        imapc->login_disabled = TRUE;
+
+      /* Does the server support the SASL-IR capability? */
+      else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7))
+        imapc->ir_supported = TRUE;
+
+      /* Do we have a SASL based authentication mechanism? */
+      else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
+        size_t llen;
+        unsigned short mechbit;
+
+        line += 5;
+        wordlen -= 5;
+
+        /* Test the word for a matching authentication mechanism */
+        mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
+        if(mechbit && llen == wordlen)
+          imapc->sasl.authmechs |= mechbit;
+      }
+
+      line += wordlen;
+    }
+  }
+  else if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
+    /* PREAUTH is not compatible with STARTTLS. */
+    if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
+      /* Switch to TLS connection now */
+      result = imap_perform_starttls(data);
+    }
+    else if(data->set.use_ssl <= CURLUSESSL_TRY)
+      result = imap_perform_authentication(data, conn);
+    else {
+      failf(data, "STARTTLS not available.");
+      result = CURLE_USE_SSL_FAILED;
+    }
+  }
+  else
+    result = imap_perform_authentication(data, conn);
+
+  return result;
+}
+
+/* For STARTTLS responses */
+static CURLcode imap_state_starttls_resp(struct Curl_easy *data,
+                                         int imapcode,
+                                         imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+
+  (void)instate; /* no use for this yet */
+
+  /* Pipelining in response is forbidden. */
+  if(data->conn->proto.imapc.pp.overflow)
+    return CURLE_WEIRD_SERVER_REPLY;
+
+  if(imapcode != IMAP_RESP_OK) {
+    if(data->set.use_ssl != CURLUSESSL_TRY) {
+      failf(data, "STARTTLS denied");
+      result = CURLE_USE_SSL_FAILED;
+    }
+    else
+      result = imap_perform_authentication(data, conn);
+  }
+  else
+    result = imap_perform_upgrade_tls(data, conn);
+
+  return result;
+}
+
+/* For SASL authentication responses */
+static CURLcode imap_state_auth_resp(struct Curl_easy *data,
+                                     struct connectdata *conn,
+                                     int imapcode,
+                                     imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  saslprogress progress;
+
+  (void)instate; /* no use for this yet */
+
+  result = Curl_sasl_continue(&imapc->sasl, data, imapcode, &progress);
+  if(!result)
+    switch(progress) {
+    case SASL_DONE:
+      imap_state(data, IMAP_STOP);  /* Authenticated */
+      break;
+    case SASL_IDLE:            /* No mechanism left after cancellation */
+      if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
+        /* Perform clear text authentication */
+        result = imap_perform_login(data, conn);
+      else {
+        failf(data, "Authentication cancelled");
+        result = CURLE_LOGIN_DENIED;
+      }
+      break;
+    default:
+      break;
+    }
+
+  return result;
+}
+
+/* For LOGIN responses */
+static CURLcode imap_state_login_resp(struct Curl_easy *data,
+                                      int imapcode,
+                                      imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  (void)instate; /* no use for this yet */
+
+  if(imapcode != IMAP_RESP_OK) {
+    failf(data, "Access denied. %c", imapcode);
+    result = CURLE_LOGIN_DENIED;
+  }
+  else
+    /* End of connect phase */
+    imap_state(data, IMAP_STOP);
+
+  return result;
+}
+
+/* For LIST and SEARCH responses */
+static CURLcode imap_state_listsearch_resp(struct Curl_easy *data,
+                                           int imapcode,
+                                           imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
+  size_t len = data->conn->proto.imapc.pp.nfinal;
+
+  (void)instate; /* No use for this yet */
+
+  if(imapcode == '*')
+    result = Curl_client_write(data, CLIENTWRITE_BODY, line, len);
+  else if(imapcode != IMAP_RESP_OK)
+    result = CURLE_QUOTE_ERROR;
+  else
+    /* End of DO phase */
+    imap_state(data, IMAP_STOP);
+
+  return result;
+}
+
+/* For SELECT responses */
+static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
+                                       imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct IMAP *imap = data->req.p.imap;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  const char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
+
+  (void)instate; /* no use for this yet */
+
+  if(imapcode == '*') {
+    /* See if this is an UIDVALIDITY response */
+    if(checkprefix("OK [UIDVALIDITY ", line + 2)) {
+      size_t len = 0;
+      const char *p = &line[2] + strlen("OK [UIDVALIDITY ");
+      while((len < 20) && p[len] && ISDIGIT(p[len]))
+        len++;
+      if(len && (p[len] == ']')) {
+        struct dynbuf uid;
+        Curl_dyn_init(&uid, 20);
+        if(Curl_dyn_addn(&uid, p, len))
+          return CURLE_OUT_OF_MEMORY;
+        Curl_safefree(imapc->mailbox_uidvalidity);
+        imapc->mailbox_uidvalidity = Curl_dyn_ptr(&uid);
+      }
+    }
+  }
+  else if(imapcode == IMAP_RESP_OK) {
+    /* Check if the UIDVALIDITY has been specified and matches */
+    if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
+       !strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
+      failf(data, "Mailbox UIDVALIDITY has changed");
+      result = CURLE_REMOTE_FILE_NOT_FOUND;
+    }
+    else {
+      /* Note the currently opened mailbox on this connection */
+      DEBUGASSERT(!imapc->mailbox);
+      imapc->mailbox = strdup(imap->mailbox);
+      if(!imapc->mailbox)
+        return CURLE_OUT_OF_MEMORY;
+
+      if(imap->custom)
+        result = imap_perform_list(data);
+      else if(imap->query)
+        result = imap_perform_search(data);
+      else
+        result = imap_perform_fetch(data);
+    }
+  }
+  else {
+    failf(data, "Select failed");
+    result = CURLE_LOGIN_DENIED;
+  }
+
+  return result;
+}
+
+/* For the (first line of the) FETCH responses */
+static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
+                                      struct connectdata *conn, int imapcode,
+                                      imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  struct pingpong *pp = &imapc->pp;
+  const char *ptr = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
+  size_t len = data->conn->proto.imapc.pp.nfinal;
+  bool parsed = FALSE;
+  curl_off_t size = 0;
+
+  (void)instate; /* no use for this yet */
+
+  if(imapcode != '*') {
+    Curl_pgrsSetDownloadSize(data, -1);
+    imap_state(data, IMAP_STOP);
+    return CURLE_REMOTE_FILE_NOT_FOUND;
+  }
+
+  /* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse
+     the continuation data contained within the curly brackets */
+  ptr = memchr(ptr, '{', len);
+  if(ptr) {
+    char *endptr;
+    if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size) &&
+       (endptr - ptr > 1 && *endptr == '}'))
+      parsed = TRUE;
+  }
+
+  if(parsed) {
+    infof(data, "Found %" CURL_FORMAT_CURL_OFF_T " bytes to download",
+          size);
+    Curl_pgrsSetDownloadSize(data, size);
+
+    if(pp->overflow) {
+      /* At this point there is a data in the receive buffer that is body
+         content, send it as body and then skip it. Do note that there may
+         even be additional "headers" after the body. */
+      size_t chunk = pp->overflow;
+
+      /* keep only the overflow */
+      Curl_dyn_tail(&pp->recvbuf, chunk);
+      pp->nfinal = 0; /* done */
+
+      if(chunk > (size_t)size)
+        /* The conversion from curl_off_t to size_t is always fine here */
+        chunk = (size_t)size;
+
+      if(!chunk) {
+        /* no size, we're done with the data */
+        imap_state(data, IMAP_STOP);
+        return CURLE_OK;
+      }
+      result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                 Curl_dyn_ptr(&pp->recvbuf), chunk);
+      if(result)
+        return result;
+
+      infof(data, "Written %zu bytes, %" CURL_FORMAT_CURL_OFF_TU
+            " bytes are left for transfer", chunk, size - chunk);
+
+      /* Have we used the entire overflow or just part of it?*/
+      if(pp->overflow > chunk) {
+        /* remember the remaining trailing overflow data */
+        pp->overflow -= chunk;
+        Curl_dyn_tail(&pp->recvbuf, pp->overflow);
+      }
+      else {
+        pp->overflow = 0; /* handled */
+        /* Free the cache */
+        Curl_dyn_reset(&pp->recvbuf);
+      }
+    }
+
+    if(data->req.bytecount == size)
+      /* The entire data is already transferred! */
+      Curl_xfer_setup(data, -1, -1, FALSE, -1);
+    else {
+      /* IMAP download */
+      data->req.maxdownload = size;
+      /* force a recv/send check of this connection, as the data might've been
+       read off the socket already */
+      data->state.select_bits = CURL_CSELECT_IN;
+      Curl_xfer_setup(data, FIRSTSOCKET, size, FALSE, -1);
+    }
+  }
+  else {
+    /* We don't know how to parse this line */
+    failf(data, "Failed to parse FETCH response.");
+    result = CURLE_WEIRD_SERVER_REPLY;
+  }
+
+  /* End of DO phase */
+  imap_state(data, IMAP_STOP);
+
+  return result;
+}
+
+/* For final FETCH responses performed after the download */
+static CURLcode imap_state_fetch_final_resp(struct Curl_easy *data,
+                                            int imapcode,
+                                            imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+
+  (void)instate; /* No use for this yet */
+
+  if(imapcode != IMAP_RESP_OK)
+    result = CURLE_WEIRD_SERVER_REPLY;
+  else
+    /* End of DONE phase */
+    imap_state(data, IMAP_STOP);
+
+  return result;
+}
+
+/* For APPEND responses */
+static CURLcode imap_state_append_resp(struct Curl_easy *data, int imapcode,
+                                       imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  (void)instate; /* No use for this yet */
+
+  if(imapcode != '+') {
+    result = CURLE_UPLOAD_FAILED;
+  }
+  else {
+    /* Set the progress upload size */
+    Curl_pgrsSetUploadSize(data, data->state.infilesize);
+
+    /* IMAP upload */
+    Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
+
+    /* End of DO phase */
+    imap_state(data, IMAP_STOP);
+  }
+
+  return result;
+}
+
+/* For final APPEND responses performed after the upload */
+static CURLcode imap_state_append_final_resp(struct Curl_easy *data,
+                                             int imapcode,
+                                             imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+
+  (void)instate; /* No use for this yet */
+
+  if(imapcode != IMAP_RESP_OK)
+    result = CURLE_UPLOAD_FAILED;
+  else
+    /* End of DONE phase */
+    imap_state(data, IMAP_STOP);
+
+  return result;
+}
+
+static CURLcode imap_statemachine(struct Curl_easy *data,
+                                  struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  int imapcode;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  struct pingpong *pp = &imapc->pp;
+  size_t nread = 0;
+  (void)data;
+
+  /* Busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */
+  if(imapc->state == IMAP_UPGRADETLS)
+    return imap_perform_upgrade_tls(data, conn);
+
+  /* Flush any data that needs to be sent */
+  if(pp->sendleft)
+    return Curl_pp_flushsend(data, pp);
+
+  do {
+    /* Read the response from the server */
+    result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &imapcode, &nread);
+    if(result)
+      return result;
+
+    /* Was there an error parsing the response line? */
+    if(imapcode == -1)
+      return CURLE_WEIRD_SERVER_REPLY;
+
+    if(!imapcode)
+      break;
+
+    /* We have now received a full IMAP server response */
+    switch(imapc->state) {
+    case IMAP_SERVERGREET:
+      result = imap_state_servergreet_resp(data, imapcode, imapc->state);
+      break;
+
+    case IMAP_CAPABILITY:
+      result = imap_state_capability_resp(data, imapcode, imapc->state);
+      break;
+
+    case IMAP_STARTTLS:
+      result = imap_state_starttls_resp(data, imapcode, imapc->state);
+      break;
+
+    case IMAP_AUTHENTICATE:
+      result = imap_state_auth_resp(data, conn, imapcode, imapc->state);
+      break;
+
+    case IMAP_LOGIN:
+      result = imap_state_login_resp(data, imapcode, imapc->state);
+      break;
+
+    case IMAP_LIST:
+    case IMAP_SEARCH:
+      result = imap_state_listsearch_resp(data, imapcode, imapc->state);
+      break;
+
+    case IMAP_SELECT:
+      result = imap_state_select_resp(data, imapcode, imapc->state);
+      break;
+
+    case IMAP_FETCH:
+      result = imap_state_fetch_resp(data, conn, imapcode, imapc->state);
+      break;
+
+    case IMAP_FETCH_FINAL:
+      result = imap_state_fetch_final_resp(data, imapcode, imapc->state);
+      break;
+
+    case IMAP_APPEND:
+      result = imap_state_append_resp(data, imapcode, imapc->state);
+      break;
+
+    case IMAP_APPEND_FINAL:
+      result = imap_state_append_final_resp(data, imapcode, imapc->state);
+      break;
+
+    case IMAP_LOGOUT:
+    default:
+      /* internal error */
+      imap_state(data, IMAP_STOP);
+      break;
+    }
+  } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp));
+
+  return result;
+}
+
+/* Called repeatedly until done from multi.c */
+static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct imap_conn *imapc = &conn->proto.imapc;
+
+  if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) {
+    bool ssldone = FALSE;
+    result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
+    imapc->ssldone = ssldone;
+    if(result || !ssldone)
+      return result;
+  }
+
+  result = Curl_pp_statemach(data, &imapc->pp, FALSE, FALSE);
+  *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
+
+  return result;
+}
+
+static CURLcode imap_block_statemach(struct Curl_easy *data,
+                                     struct connectdata *conn,
+                                     bool disconnecting)
+{
+  CURLcode result = CURLE_OK;
+  struct imap_conn *imapc = &conn->proto.imapc;
+
+  while(imapc->state != IMAP_STOP && !result)
+    result = Curl_pp_statemach(data, &imapc->pp, TRUE, disconnecting);
+
+  return result;
+}
+
+/* Allocate and initialize the struct IMAP for the current Curl_easy if
+   required */
+static CURLcode imap_init(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct IMAP *imap;
+
+  imap = data->req.p.imap = calloc(1, sizeof(struct IMAP));
+  if(!imap)
+    result = CURLE_OUT_OF_MEMORY;
+
+  return result;
+}
+
+/* For the IMAP "protocol connect" and "doing" phases only */
+static int imap_getsock(struct Curl_easy *data,
+                        struct connectdata *conn,
+                        curl_socket_t *socks)
+{
+  return Curl_pp_getsock(data, &conn->proto.imapc.pp, socks);
+}
+
+/***********************************************************************
+ *
+ * imap_connect()
+ *
+ * This function should do everything that is to be considered a part of the
+ * connection phase.
+ *
+ * The variable 'done' points to will be TRUE if the protocol-layer connect
+ * phase is done when this function returns, or FALSE if not.
+ */
+static CURLcode imap_connect(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  struct pingpong *pp = &imapc->pp;
+
+  *done = FALSE; /* default to not done yet */
+
+  /* We always support persistent connections in IMAP */
+  connkeep(conn, "IMAP default");
+
+  PINGPONG_SETUP(pp, imap_statemachine, imap_endofresp);
+
+  /* Set the default preferred authentication type and mechanism */
+  imapc->preftype = IMAP_TYPE_ANY;
+  Curl_sasl_init(&imapc->sasl, data, &saslimap);
+
+  Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
+  Curl_pp_init(pp);
+
+  /* Parse the URL options */
+  result = imap_parse_url_options(conn);
+  if(result)
+    return result;
+
+  /* Start off waiting for the server greeting response */
+  imap_state(data, IMAP_SERVERGREET);
+
+  /* Start off with an response id of '*' */
+  strcpy(imapc->resptag, "*");
+
+  result = imap_multi_statemach(data, done);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode imap_done(struct Curl_easy *data, CURLcode status,
+                          bool premature)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct IMAP *imap = data->req.p.imap;
+
+  (void)premature;
+
+  if(!imap)
+    return CURLE_OK;
+
+  if(status) {
+    connclose(conn, "IMAP done with bad status"); /* marked for closure */
+    result = status;         /* use the already set error code */
+  }
+  else if(!data->set.connect_only && !imap->custom &&
+          (imap->uid || imap->mindex || data->state.upload ||
+          IS_MIME_POST(data))) {
+    /* Handle responses after FETCH or APPEND transfer has finished */
+
+    if(!data->state.upload && !IS_MIME_POST(data))
+      imap_state(data, IMAP_FETCH_FINAL);
+    else {
+      /* End the APPEND command first by sending an empty line */
+      result = Curl_pp_sendf(data, &conn->proto.imapc.pp, "%s", "");
+      if(!result)
+        imap_state(data, IMAP_APPEND_FINAL);
+    }
+
+    /* Run the state-machine */
+    if(!result)
+      result = imap_block_statemach(data, conn, FALSE);
+  }
+
+  /* Cleanup our per-request based variables */
+  Curl_safefree(imap->mailbox);
+  Curl_safefree(imap->uidvalidity);
+  Curl_safefree(imap->uid);
+  Curl_safefree(imap->mindex);
+  Curl_safefree(imap->section);
+  Curl_safefree(imap->partial);
+  Curl_safefree(imap->query);
+  Curl_safefree(imap->custom);
+  Curl_safefree(imap->custom_params);
+
+  /* Clear the transfer mode for the next request */
+  imap->transfer = PPTRANSFER_BODY;
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform()
+ *
+ * This is the actual DO function for IMAP. Fetch or append a message, or do
+ * other things according to the options previously setup.
+ */
+static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
+                             bool *dophase_done)
+{
+  /* This is IMAP and no proxy */
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct IMAP *imap = data->req.p.imap;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  bool selected = FALSE;
+
+  DEBUGF(infof(data, "DO phase starts"));
+
+  if(data->req.no_body) {
+    /* Requested no body means no transfer */
+    imap->transfer = PPTRANSFER_INFO;
+  }
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* Determine if the requested mailbox (with the same UIDVALIDITY if set)
+     has already been selected on this connection */
+  if(imap->mailbox && imapc->mailbox &&
+     strcasecompare(imap->mailbox, imapc->mailbox) &&
+     (!imap->uidvalidity || !imapc->mailbox_uidvalidity ||
+      strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)))
+    selected = TRUE;
+
+  /* Start the first command in the DO phase */
+  if(data->state.upload || IS_MIME_POST(data))
+    /* APPEND can be executed directly */
+    result = imap_perform_append(data);
+  else if(imap->custom && (selected || !imap->mailbox))
+    /* Custom command using the same mailbox or no mailbox */
+    result = imap_perform_list(data);
+  else if(!imap->custom && selected && (imap->uid || imap->mindex))
+    /* FETCH from the same mailbox */
+    result = imap_perform_fetch(data);
+  else if(!imap->custom && selected && imap->query)
+    /* SEARCH the current mailbox */
+    result = imap_perform_search(data);
+  else if(imap->mailbox && !selected &&
+         (imap->custom || imap->uid || imap->mindex || imap->query))
+    /* SELECT the mailbox */
+    result = imap_perform_select(data);
+  else
+    /* LIST */
+    result = imap_perform_list(data);
+
+  if(result)
+    return result;
+
+  /* Run the state-machine */
+  result = imap_multi_statemach(data, dophase_done);
+
+  *connected = Curl_conn_is_connected(conn, FIRSTSOCKET);
+
+  if(*dophase_done)
+    DEBUGF(infof(data, "DO phase is complete"));
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (imap_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode imap_do(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  *done = FALSE; /* default to false */
+
+  /* Parse the URL path */
+  result = imap_parse_url_path(data);
+  if(result)
+    return result;
+
+  /* Parse the custom request */
+  result = imap_parse_custom_request(data);
+  if(result)
+    return result;
+
+  result = imap_regular_transfer(data, done);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_disconnect()
+ *
+ * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode imap_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead_connection)
+{
+  struct imap_conn *imapc = &conn->proto.imapc;
+  (void)data;
+
+  /* We cannot send quit unconditionally. If this connection is stale or
+     bad in any way, sending quit and waiting around here will make the
+     disconnect wait in vain and cause more problems than we need to. */
+
+  /* The IMAP session may or may not have been allocated/setup at this
+     point! */
+  if(!dead_connection && conn->bits.protoconnstart) {
+    if(!imap_perform_logout(data))
+      (void)imap_block_statemach(data, conn, TRUE); /* ignore errors */
+  }
+
+  /* Disconnect from the server */
+  Curl_pp_disconnect(&imapc->pp);
+  Curl_dyn_free(&imapc->dyn);
+
+  /* Cleanup the SASL module */
+  Curl_sasl_cleanup(conn, imapc->sasl.authused);
+
+  /* Cleanup our connection based variables */
+  Curl_safefree(imapc->mailbox);
+  Curl_safefree(imapc->mailbox_uidvalidity);
+
+  return CURLE_OK;
+}
+
+/* Call this when the DO phase has completed */
+static CURLcode imap_dophase_done(struct Curl_easy *data, bool connected)
+{
+  struct IMAP *imap = data->req.p.imap;
+
+  (void)connected;
+
+  if(imap->transfer != PPTRANSFER_BODY)
+    /* no data to transfer */
+    Curl_xfer_setup(data, -1, -1, FALSE, -1);
+
+  return CURLE_OK;
+}
+
+/* Called from multi.c while DOing */
+static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done)
+{
+  CURLcode result = imap_multi_statemach(data, dophase_done);
+
+  if(result)
+    DEBUGF(infof(data, "DO phase failed"));
+  else if(*dophase_done) {
+    result = imap_dophase_done(data, FALSE /* not connected */);
+
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ */
+static CURLcode imap_regular_transfer(struct Curl_easy *data,
+                                      bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+  bool connected = FALSE;
+
+  /* Make sure size is unknown at this point */
+  data->req.size = -1;
+
+  /* Set the progress data */
+  Curl_pgrsSetUploadCounter(data, 0);
+  Curl_pgrsSetDownloadCounter(data, 0);
+  Curl_pgrsSetUploadSize(data, -1);
+  Curl_pgrsSetDownloadSize(data, -1);
+
+  /* Carry out the perform */
+  result = imap_perform(data, &connected, dophase_done);
+
+  /* Perform post DO phase operations if necessary */
+  if(!result && *dophase_done)
+    result = imap_dophase_done(data, connected);
+
+  return result;
+}
+
+static CURLcode imap_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  /* Initialise the IMAP layer */
+  CURLcode result = imap_init(data);
+  if(result)
+    return result;
+
+  /* Clear the TLS upgraded flag */
+  conn->bits.tls_upgraded = FALSE;
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * imap_sendf()
+ *
+ * Sends the formatted string as an IMAP command to the server.
+ *
+ * Designed to never block.
+ */
+static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
+{
+  CURLcode result = CURLE_OK;
+  struct imap_conn *imapc = &data->conn->proto.imapc;
+
+  DEBUGASSERT(fmt);
+
+  /* Calculate the tag based on the connection ID and command ID */
+  msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
+            'A' + curlx_sltosi((long)(data->conn->connection_id % 26)),
+            ++imapc->cmdid);
+
+  /* start with a blank buffer */
+  Curl_dyn_reset(&imapc->dyn);
+
+  /* append tag + space + fmt */
+  result = Curl_dyn_addf(&imapc->dyn, "%s %s", imapc->resptag, fmt);
+  if(!result) {
+    va_list ap;
+    va_start(ap, fmt);
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-nonliteral"
+#endif
+    result = Curl_pp_vsendf(data, &imapc->pp, Curl_dyn_ptr(&imapc->dyn), ap);
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+    va_end(ap);
+  }
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_atom()
+ *
+ * Checks the input string for characters that need escaping and returns an
+ * atom ready for sending to the server.
+ *
+ * The returned string needs to be freed.
+ *
+ */
+static char *imap_atom(const char *str, bool escape_only)
+{
+  struct dynbuf line;
+  size_t nclean;
+  size_t len;
+
+  if(!str)
+    return NULL;
+
+  len = strlen(str);
+  nclean = strcspn(str, "() {%*]\\\"");
+  if(len == nclean)
+    /* nothing to escape, return a strdup */
+    return strdup(str);
+
+  Curl_dyn_init(&line, 2000);
+
+  if(!escape_only && Curl_dyn_addn(&line, "\"", 1))
+    return NULL;
+
+  while(*str) {
+    if((*str == '\\' || *str == '"') &&
+       Curl_dyn_addn(&line, "\\", 1))
+      return NULL;
+    if(Curl_dyn_addn(&line, str, 1))
+      return NULL;
+    str++;
+  }
+
+  if(!escape_only && Curl_dyn_addn(&line, "\"", 1))
+    return NULL;
+
+  return Curl_dyn_ptr(&line);
+}
+
+/***********************************************************************
+ *
+ * imap_is_bchar()
+ *
+ * Portable test of whether the specified char is a "bchar" as defined in the
+ * grammar of RFC-5092.
+ */
+static bool imap_is_bchar(char ch)
+{
+  /* Performing the alnum check with this macro is faster because of ASCII
+     arithmetic */
+  if(ISALNUM(ch))
+    return true;
+
+  switch(ch) {
+    /* bchar */
+    case ':': case '@': case '/':
+    /* bchar -> achar */
+    case '&': case '=':
+    /* bchar -> achar -> uchar -> unreserved (without alphanumeric) */
+    case '-': case '.': case '_': case '~':
+    /* bchar -> achar -> uchar -> sub-delims-sh */
+    case '!': case '$': case '\'': case '(': case ')': case '*':
+    case '+': case ',':
+    /* bchar -> achar -> uchar -> pct-encoded */
+    case '%': /* HEXDIG chars are already included above */
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+/***********************************************************************
+ *
+ * imap_parse_url_options()
+ *
+ * Parse the URL login options.
+ */
+static CURLcode imap_parse_url_options(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  const char *ptr = conn->options;
+  bool prefer_login = false;
+
+  while(!result && ptr && *ptr) {
+    const char *key = ptr;
+    const char *value;
+
+    while(*ptr && *ptr != '=')
+      ptr++;
+
+    value = ptr + 1;
+
+    while(*ptr && *ptr != ';')
+      ptr++;
+
+    if(strncasecompare(key, "AUTH=+LOGIN", 11)) {
+      /* User prefers plaintext LOGIN over any SASL, including SASL LOGIN */
+      prefer_login = true;
+      imapc->sasl.prefmech = SASL_AUTH_NONE;
+    }
+    else if(strncasecompare(key, "AUTH=", 5)) {
+      prefer_login = false;
+      result = Curl_sasl_parse_url_auth_option(&imapc->sasl,
+                                               value, ptr - value);
+    }
+    else {
+      prefer_login = false;
+      result = CURLE_URL_MALFORMAT;
+    }
+
+    if(*ptr == ';')
+      ptr++;
+  }
+
+  if(prefer_login)
+    imapc->preftype = IMAP_TYPE_CLEARTEXT;
+  else {
+    switch(imapc->sasl.prefmech) {
+    case SASL_AUTH_NONE:
+      imapc->preftype = IMAP_TYPE_NONE;
+      break;
+    case SASL_AUTH_DEFAULT:
+      imapc->preftype = IMAP_TYPE_ANY;
+      break;
+    default:
+      imapc->preftype = IMAP_TYPE_SASL;
+      break;
+    }
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ *
+ */
+static CURLcode imap_parse_url_path(struct Curl_easy *data)
+{
+  /* The imap struct is already initialised in imap_connect() */
+  CURLcode result = CURLE_OK;
+  struct IMAP *imap = data->req.p.imap;
+  const char *begin = &data->state.up.path[1]; /* skip leading slash */
+  const char *ptr = begin;
+
+  /* See how much of the URL is a valid path and decode it */
+  while(imap_is_bchar(*ptr))
+    ptr++;
+
+  if(ptr != begin) {
+    /* Remove the trailing slash if present */
+    const char *end = ptr;
+    if(end > begin && end[-1] == '/')
+      end--;
+
+    result = Curl_urldecode(begin, end - begin, &imap->mailbox, NULL,
+                            REJECT_CTRL);
+    if(result)
+      return result;
+  }
+  else
+    imap->mailbox = NULL;
+
+  /* There can be any number of parameters in the form ";NAME=VALUE" */
+  while(*ptr == ';') {
+    char *name;
+    char *value;
+    size_t valuelen;
+
+    /* Find the length of the name parameter */
+    begin = ++ptr;
+    while(*ptr && *ptr != '=')
+      ptr++;
+
+    if(!*ptr)
+      return CURLE_URL_MALFORMAT;
+
+    /* Decode the name parameter */
+    result = Curl_urldecode(begin, ptr - begin, &name, NULL,
+                            REJECT_CTRL);
+    if(result)
+      return result;
+
+    /* Find the length of the value parameter */
+    begin = ++ptr;
+    while(imap_is_bchar(*ptr))
+      ptr++;
+
+    /* Decode the value parameter */
+    result = Curl_urldecode(begin, ptr - begin, &value, &valuelen,
+                            REJECT_CTRL);
+    if(result) {
+      free(name);
+      return result;
+    }
+
+    DEBUGF(infof(data, "IMAP URL parameter '%s' = '%s'", name, value));
+
+    /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and
+       PARTIAL) stripping of the trailing slash character if it is present.
+
+       Note: Unknown parameters trigger a URL_MALFORMAT error. */
+    if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) {
+      if(valuelen > 0 && value[valuelen - 1] == '/')
+        value[valuelen - 1] = '\0';
+
+      imap->uidvalidity = value;
+      value = NULL;
+    }
+    else if(strcasecompare(name, "UID") && !imap->uid) {
+      if(valuelen > 0 && value[valuelen - 1] == '/')
+        value[valuelen - 1] = '\0';
+
+      imap->uid = value;
+      value = NULL;
+    }
+    else if(strcasecompare(name, "MAILINDEX") && !imap->mindex) {
+      if(valuelen > 0 && value[valuelen - 1] == '/')
+        value[valuelen - 1] = '\0';
+
+      imap->mindex = value;
+      value = NULL;
+    }
+    else if(strcasecompare(name, "SECTION") && !imap->section) {
+      if(valuelen > 0 && value[valuelen - 1] == '/')
+        value[valuelen - 1] = '\0';
+
+      imap->section = value;
+      value = NULL;
+    }
+    else if(strcasecompare(name, "PARTIAL") && !imap->partial) {
+      if(valuelen > 0 && value[valuelen - 1] == '/')
+        value[valuelen - 1] = '\0';
+
+      imap->partial = value;
+      value = NULL;
+    }
+    else {
+      free(name);
+      free(value);
+
+      return CURLE_URL_MALFORMAT;
+    }
+
+    free(name);
+    free(value);
+  }
+
+  /* Does the URL contain a query parameter? Only valid when we have a mailbox
+     and no UID as per RFC-5092 */
+  if(imap->mailbox && !imap->uid && !imap->mindex) {
+    /* Get the query parameter, URL decoded */
+    (void)curl_url_get(data->state.uh, CURLUPART_QUERY, &imap->query,
+                       CURLU_URLDECODE);
+  }
+
+  /* Any extra stuff at the end of the URL is an error */
+  if(*ptr)
+    return CURLE_URL_MALFORMAT;
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * imap_parse_custom_request()
+ *
+ * Parse the custom request.
+ */
+static CURLcode imap_parse_custom_request(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct IMAP *imap = data->req.p.imap;
+  const char *custom = data->set.str[STRING_CUSTOMREQUEST];
+
+  if(custom) {
+    /* URL decode the custom request */
+    result = Curl_urldecode(custom, 0, &imap->custom, NULL, REJECT_CTRL);
+
+    /* Extract the parameters if specified */
+    if(!result) {
+      const char *params = imap->custom;
+
+      while(*params && *params != ' ')
+        params++;
+
+      if(*params) {
+        imap->custom_params = strdup(params);
+        imap->custom[params - imap->custom] = '\0';
+
+        if(!imap->custom_params)
+          result = CURLE_OUT_OF_MEMORY;
+      }
+    }
+  }
+
+  return result;
+}
+
+#endif /* CURL_DISABLE_IMAP */
Index: trunk/src/libs/curl-8.7.1/lib/imap.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/imap.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/imap.h	(revision 104083)
@@ -0,0 +1,101 @@
+#ifndef HEADER_CURL_IMAP_H
+#define HEADER_CURL_IMAP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "pingpong.h"
+#include "curl_sasl.h"
+
+/****************************************************************************
+ * IMAP unique setup
+ ***************************************************************************/
+typedef enum {
+  IMAP_STOP,         /* do nothing state, stops the state machine */
+  IMAP_SERVERGREET,  /* waiting for the initial greeting immediately after
+                        a connect */
+  IMAP_CAPABILITY,
+  IMAP_STARTTLS,
+  IMAP_UPGRADETLS,   /* asynchronously upgrade the connection to SSL/TLS
+                       (multi mode only) */
+  IMAP_AUTHENTICATE,
+  IMAP_LOGIN,
+  IMAP_LIST,
+  IMAP_SELECT,
+  IMAP_FETCH,
+  IMAP_FETCH_FINAL,
+  IMAP_APPEND,
+  IMAP_APPEND_FINAL,
+  IMAP_SEARCH,
+  IMAP_LOGOUT,
+  IMAP_LAST          /* never used */
+} imapstate;
+
+/* This IMAP struct is used in the Curl_easy. All IMAP data that is
+   connection-oriented must be in imap_conn to properly deal with the fact that
+   perhaps the Curl_easy is changed between the times the connection is
+   used. */
+struct IMAP {
+  curl_pp_transfer transfer;
+  char *mailbox;          /* Mailbox to select */
+  char *uidvalidity;      /* UIDVALIDITY to check in select */
+  char *uid;              /* Message UID to fetch */
+  char *mindex;           /* Index in mail box of mail to fetch */
+  char *section;          /* Message SECTION to fetch */
+  char *partial;          /* Message PARTIAL to fetch */
+  char *query;            /* Query to search for */
+  char *custom;           /* Custom request */
+  char *custom_params;    /* Parameters for the custom request */
+};
+
+/* imap_conn is used for struct connection-oriented data in the connectdata
+   struct */
+struct imap_conn {
+  struct pingpong pp;
+  struct SASL sasl;           /* SASL-related parameters */
+  struct dynbuf dyn;          /* for the IMAP commands */
+  char *mailbox;              /* The last selected mailbox */
+  char *mailbox_uidvalidity;  /* UIDVALIDITY parsed from select response */
+  imapstate state;            /* Always use imap.c:state() to change state! */
+  char resptag[5];            /* Response tag to wait for */
+  unsigned char preftype;     /* Preferred authentication type */
+  unsigned char cmdid;        /* Last used command ID */
+  BIT(ssldone);               /* Is connect() over SSL done? */
+  BIT(preauth);               /* Is this connection PREAUTH? */
+  BIT(tls_supported);         /* StartTLS capability supported by server */
+  BIT(login_disabled);        /* LOGIN command disabled by server */
+  BIT(ir_supported);          /* Initial response supported by server */
+};
+
+extern const struct Curl_handler Curl_handler_imap;
+extern const struct Curl_handler Curl_handler_imaps;
+
+/* Authentication type flags */
+#define IMAP_TYPE_CLEARTEXT (1 << 0)
+#define IMAP_TYPE_SASL      (1 << 1)
+
+/* Authentication type values */
+#define IMAP_TYPE_NONE      0
+#define IMAP_TYPE_ANY       (IMAP_TYPE_CLEARTEXT|IMAP_TYPE_SASL)
+
+#endif /* HEADER_CURL_IMAP_H */
Index: trunk/src/libs/curl-8.7.1/lib/inet_ntop.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/inet_ntop.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/inet_ntop.c	(revision 104083)
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 1996-2022  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * SPDX-License-Identifier: ISC
+ */
+/*
+ * Original code by Paul Vixie. "curlified" by Gisle Vanem.
+ */
+
+#include "curl_setup.h"
+
+#ifndef HAVE_INET_NTOP
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "inet_ntop.h"
+#include "curl_printf.h"
+
+#define IN6ADDRSZ       16
+#define INADDRSZ         4
+#define INT16SZ          2
+
+/*
+ * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * sure we have _some_ value for AF_INET6 without polluting our fake value
+ * everywhere.
+ */
+#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#define AF_INET6 (AF_INET + 1)
+#endif
+
+/*
+ * Format an IPv4 address, more or less like inet_ntop().
+ *
+ * Returns `dst' (as a const)
+ * Note:
+ *  - uses no statics
+ *  - takes a unsigned char* not an in_addr as input
+ */
+static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
+{
+  char tmp[sizeof("255.255.255.255")];
+  size_t len;
+
+  DEBUGASSERT(size >= 16);
+
+  tmp[0] = '\0';
+  (void)msnprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
+                  ((int)((unsigned char)src[0])) & 0xff,
+                  ((int)((unsigned char)src[1])) & 0xff,
+                  ((int)((unsigned char)src[2])) & 0xff,
+                  ((int)((unsigned char)src[3])) & 0xff);
+
+  len = strlen(tmp);
+  if(len == 0 || len >= size) {
+    errno = ENOSPC;
+    return (NULL);
+  }
+  strcpy(dst, tmp);
+  return dst;
+}
+
+/*
+ * Convert IPv6 binary address into presentation (printable) format.
+ */
+static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
+{
+  /*
+   * Note that int32_t and int16_t need only be "at least" large enough
+   * to contain a value of the specified size.  On some systems, like
+   * Crays, there is no such thing as an integer variable with 16 bits.
+   * Keep this in mind if you think this function should have been coded
+   * to use pointer overlays.  All the world's not a VAX.
+   */
+  char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+  char *tp;
+  struct {
+    int base;
+    int len;
+  } best, cur;
+  unsigned int words[IN6ADDRSZ / INT16SZ];
+  int i;
+
+  /* Preprocess:
+   *  Copy the input (bytewise) array into a wordwise array.
+   *  Find the longest run of 0x00's in src[] for :: shorthanding.
+   */
+  memset(words, '\0', sizeof(words));
+  for(i = 0; i < IN6ADDRSZ; i++)
+    words[i/2] |= ((unsigned int)src[i] << ((1 - (i % 2)) << 3));
+
+  best.base = -1;
+  cur.base  = -1;
+  best.len = 0;
+  cur.len = 0;
+
+  for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
+    if(words[i] == 0) {
+      if(cur.base == -1) {
+        cur.base = i; cur.len = 1;
+      }
+      else
+        cur.len++;
+    }
+    else if(cur.base != -1) {
+      if(best.base == -1 || cur.len > best.len)
+        best = cur;
+      cur.base = -1;
+    }
+  }
+  if((cur.base != -1) && (best.base == -1 || cur.len > best.len))
+    best = cur;
+  if(best.base != -1 && best.len < 2)
+    best.base = -1;
+  /* Format the result. */
+  tp = tmp;
+  for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
+    /* Are we inside the best run of 0x00's? */
+    if(best.base != -1 && i >= best.base && i < (best.base + best.len)) {
+      if(i == best.base)
+        *tp++ = ':';
+      continue;
+    }
+
+    /* Are we following an initial run of 0x00s or any real hex?
+     */
+    if(i)
+      *tp++ = ':';
+
+    /* Is this address an encapsulated IPv4?
+     */
+    if(i == 6 && best.base == 0 &&
+        (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+      if(!inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) {
+        errno = ENOSPC;
+        return (NULL);
+      }
+      tp += strlen(tp);
+      break;
+    }
+    tp += msnprintf(tp, 5, "%x", words[i]);
+  }
+
+  /* Was it a trailing run of 0x00's?
+   */
+  if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
+    *tp++ = ':';
+  *tp++ = '\0';
+
+  /* Check for overflow, copy, and we're done.
+   */
+  if((size_t)(tp - tmp) > size) {
+    errno = ENOSPC;
+    return (NULL);
+  }
+  strcpy(dst, tmp);
+  return dst;
+}
+
+/*
+ * Convert a network format address to presentation format.
+ *
+ * Returns pointer to presentation format address (`buf').
+ * Returns NULL on error and errno set with the specific
+ * error, EAFNOSUPPORT or ENOSPC.
+ *
+ * On Windows we store the error in the thread errno, not
+ * in the winsock error code. This is to avoid losing the
+ * actual last winsock error. So when this function returns
+ * NULL, check errno not SOCKERRNO.
+ */
+char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
+{
+  switch(af) {
+  case AF_INET:
+    return inet_ntop4((const unsigned char *)src, buf, size);
+  case AF_INET6:
+    return inet_ntop6((const unsigned char *)src, buf, size);
+  default:
+    errno = EAFNOSUPPORT;
+    return NULL;
+  }
+}
+#endif  /* HAVE_INET_NTOP */
Index: trunk/src/libs/curl-8.7.1/lib/inet_ntop.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/inet_ntop.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/inet_ntop.h	(revision 104083)
@@ -0,0 +1,39 @@
+#ifndef HEADER_CURL_INET_NTOP_H
+#define HEADER_CURL_INET_NTOP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
+
+#ifdef HAVE_INET_NTOP
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#define Curl_inet_ntop(af,addr,buf,size) \
+        inet_ntop(af, addr, buf, (curl_socklen_t)size)
+#endif
+
+#endif /* HEADER_CURL_INET_NTOP_H */
Index: trunk/src/libs/curl-8.7.1/lib/inet_pton.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/inet_pton.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/inet_pton.c	(revision 104083)
@@ -0,0 +1,243 @@
+/* This is from the BIND 4.9.4 release, modified to compile by itself */
+
+/* Copyright (c) Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * SPDX-License-Identifier: ISC
+ */
+
+#include "curl_setup.h"
+
+#ifndef HAVE_INET_PTON
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "inet_pton.h"
+
+#define IN6ADDRSZ       16
+#define INADDRSZ         4
+#define INT16SZ          2
+
+/*
+ * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * sure we have _some_ value for AF_INET6 without polluting our fake value
+ * everywhere.
+ */
+#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#define AF_INET6 (AF_INET + 1)
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int      inet_pton4(const char *src, unsigned char *dst);
+static int      inet_pton6(const char *src, unsigned char *dst);
+
+/* int
+ * inet_pton(af, src, dst)
+ *      convert from presentation format (which usually means ASCII printable)
+ *      to network format (which is usually some kind of binary format).
+ * return:
+ *      1 if the address was valid for the specified address family
+ *      0 if the address wasn't valid (`dst' is untouched in this case)
+ *      -1 if some other error occurred (`dst' is untouched in this case, too)
+ * notice:
+ *      On Windows we store the error in the thread errno, not
+ *      in the winsock error code. This is to avoid losing the
+ *      actual last winsock error. So when this function returns
+ *      -1, check errno not SOCKERRNO.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+int
+Curl_inet_pton(int af, const char *src, void *dst)
+{
+  switch(af) {
+  case AF_INET:
+    return (inet_pton4(src, (unsigned char *)dst));
+  case AF_INET6:
+    return (inet_pton6(src, (unsigned char *)dst));
+  default:
+    errno = EAFNOSUPPORT;
+    return (-1);
+  }
+  /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ *      like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *      1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *      does not touch `dst' unless it's returning 1.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+  static const char digits[] = "0123456789";
+  int saw_digit, octets, ch;
+  unsigned char tmp[INADDRSZ], *tp;
+
+  saw_digit = 0;
+  octets = 0;
+  tp = tmp;
+  *tp = 0;
+  while((ch = *src++) != '\0') {
+    const char *pch;
+
+    pch = strchr(digits, ch);
+    if(pch) {
+      unsigned int val = (unsigned int)(*tp * 10) +
+                         (unsigned int)(pch - digits);
+
+      if(saw_digit && *tp == 0)
+        return (0);
+      if(val > 255)
+        return (0);
+      *tp = (unsigned char)val;
+      if(!saw_digit) {
+        if(++octets > 4)
+          return (0);
+        saw_digit = 1;
+      }
+    }
+    else if(ch == '.' && saw_digit) {
+      if(octets == 4)
+        return (0);
+      *++tp = 0;
+      saw_digit = 0;
+    }
+    else
+      return (0);
+  }
+  if(octets < 4)
+    return (0);
+  memcpy(dst, tmp, INADDRSZ);
+  return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ *      convert presentation level address to network order binary form.
+ * return:
+ *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *      (1) does not touch `dst' unless it's returning 1.
+ *      (2) :: in a full address is silently ignored.
+ * credit:
+ *      inspired by Mark Andrews.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+  static const char xdigits_l[] = "0123456789abcdef",
+    xdigits_u[] = "0123456789ABCDEF";
+  unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+  const char *curtok;
+  int ch, saw_xdigit;
+  size_t val;
+
+  memset((tp = tmp), 0, IN6ADDRSZ);
+  endp = tp + IN6ADDRSZ;
+  colonp = NULL;
+  /* Leading :: requires some special handling. */
+  if(*src == ':')
+    if(*++src != ':')
+      return (0);
+  curtok = src;
+  saw_xdigit = 0;
+  val = 0;
+  while((ch = *src++) != '\0') {
+    const char *xdigits;
+    const char *pch;
+
+    pch = strchr((xdigits = xdigits_l), ch);
+    if(!pch)
+      pch = strchr((xdigits = xdigits_u), ch);
+    if(pch) {
+      val <<= 4;
+      val |= (pch - xdigits);
+      if(++saw_xdigit > 4)
+        return (0);
+      continue;
+    }
+    if(ch == ':') {
+      curtok = src;
+      if(!saw_xdigit) {
+        if(colonp)
+          return (0);
+        colonp = tp;
+        continue;
+      }
+      if(tp + INT16SZ > endp)
+        return (0);
+      *tp++ = (unsigned char) ((val >> 8) & 0xff);
+      *tp++ = (unsigned char) (val & 0xff);
+      saw_xdigit = 0;
+      val = 0;
+      continue;
+    }
+    if(ch == '.' && ((tp + INADDRSZ) <= endp) &&
+        inet_pton4(curtok, tp) > 0) {
+      tp += INADDRSZ;
+      saw_xdigit = 0;
+      break;    /* '\0' was seen by inet_pton4(). */
+    }
+    return (0);
+  }
+  if(saw_xdigit) {
+    if(tp + INT16SZ > endp)
+      return (0);
+    *tp++ = (unsigned char) ((val >> 8) & 0xff);
+    *tp++ = (unsigned char) (val & 0xff);
+  }
+  if(colonp) {
+    /*
+     * Since some memmove()'s erroneously fail to handle
+     * overlapping regions, we'll do the shift by hand.
+     */
+    const ssize_t n = tp - colonp;
+    ssize_t i;
+
+    if(tp == endp)
+      return (0);
+    for(i = 1; i <= n; i++) {
+      *(endp - i) = *(colonp + n - i);
+      *(colonp + n - i) = 0;
+    }
+    tp = endp;
+  }
+  if(tp != endp)
+    return (0);
+  memcpy(dst, tmp, IN6ADDRSZ);
+  return (1);
+}
+
+#endif /* HAVE_INET_PTON */
Index: trunk/src/libs/curl-8.7.1/lib/inet_pton.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/inet_pton.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/inet_pton.h	(revision 104083)
@@ -0,0 +1,38 @@
+#ifndef HEADER_CURL_INET_PTON_H
+#define HEADER_CURL_INET_PTON_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+int Curl_inet_pton(int, const char *, void *);
+
+#ifdef HAVE_INET_PTON
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
+#endif
+
+#endif /* HEADER_CURL_INET_PTON_H */
Index: trunk/src/libs/curl-8.7.1/lib/krb5.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/krb5.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/krb5.c	(revision 104083)
@@ -0,0 +1,916 @@
+/* GSSAPI/krb5 support for FTP - loosely based on old krb4.c
+ *
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * Copyright (C) Daniel Stenberg
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.  */
+
+#include "curl_setup.h"
+
+#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP)
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "urldata.h"
+#include "cfilters.h"
+#include "cf-socket.h"
+#include "curl_base64.h"
+#include "ftp.h"
+#include "curl_gssapi.h"
+#include "sendf.h"
+#include "transfer.h"
+#include "curl_krb5.h"
+#include "warnless.h"
+#include "strcase.h"
+#include "strdup.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
+                        const char *cmd)
+{
+  size_t bytes_written;
+#define SBUF_SIZE 1024
+  char s[SBUF_SIZE];
+  size_t write_len;
+  char *sptr = s;
+  CURLcode result = CURLE_OK;
+#ifdef HAVE_GSSAPI
+  unsigned char data_sec = conn->data_prot;
+#endif
+
+  DEBUGASSERT(cmd);
+
+  write_len = strlen(cmd);
+  if(!write_len || write_len > (sizeof(s) -3))
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  memcpy(&s, cmd, write_len);
+  strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
+  write_len += 2;
+  bytes_written = 0;
+
+  for(;;) {
+#ifdef HAVE_GSSAPI
+    conn->data_prot = PROT_CMD;
+#endif
+    result = Curl_xfer_send(data, sptr, write_len, &bytes_written);
+#ifdef HAVE_GSSAPI
+    DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
+    conn->data_prot = data_sec;
+#endif
+
+    if(result)
+      break;
+
+    Curl_debug(data, CURLINFO_HEADER_OUT, sptr, bytes_written);
+
+    if(bytes_written != write_len) {
+      write_len -= bytes_written;
+      sptr += bytes_written;
+    }
+    else
+      break;
+  }
+
+  return result;
+}
+
+static int
+krb5_init(void *app_data)
+{
+  gss_ctx_id_t *context = app_data;
+  /* Make sure our context is initialized for krb5_end. */
+  *context = GSS_C_NO_CONTEXT;
+  return 0;
+}
+
+static int
+krb5_check_prot(void *app_data, int level)
+{
+  (void)app_data; /* unused */
+  if(level == PROT_CONFIDENTIAL)
+    return -1;
+  return 0;
+}
+
+static int
+krb5_decode(void *app_data, void *buf, int len,
+            int level UNUSED_PARAM,
+            struct connectdata *conn UNUSED_PARAM)
+{
+  gss_ctx_id_t *context = app_data;
+  OM_uint32 maj, min;
+  gss_buffer_desc enc, dec;
+
+  (void)level;
+  (void)conn;
+
+  enc.value = buf;
+  enc.length = len;
+  maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL);
+  if(maj != GSS_S_COMPLETE)
+    return -1;
+
+  memcpy(buf, dec.value, dec.length);
+  len = curlx_uztosi(dec.length);
+  gss_release_buffer(&min, &dec);
+
+  return len;
+}
+
+static int
+krb5_encode(void *app_data, const void *from, int length, int level, void **to)
+{
+  gss_ctx_id_t *context = app_data;
+  gss_buffer_desc dec, enc;
+  OM_uint32 maj, min;
+  int state;
+  int len;
+
+  /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal
+   * libraries modify the input buffer in gss_wrap()
+   */
+  dec.value = (void *)from;
+  dec.length = length;
+  maj = gss_wrap(&min, *context,
+                 level == PROT_PRIVATE,
+                 GSS_C_QOP_DEFAULT,
+                 &dec, &state, &enc);
+
+  if(maj != GSS_S_COMPLETE)
+    return -1;
+
+  /* malloc a new buffer, in case gss_release_buffer doesn't work as
+     expected */
+  *to = malloc(enc.length);
+  if(!*to)
+    return -1;
+  memcpy(*to, enc.value, enc.length);
+  len = curlx_uztosi(enc.length);
+  gss_release_buffer(&min, &enc);
+  return len;
+}
+
+static int
+krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
+{
+  int ret = AUTH_OK;
+  char *p;
+  const char *host = conn->host.name;
+  ssize_t nread;
+  curl_socklen_t l = sizeof(conn->local_addr);
+  CURLcode result;
+  const char *service = data->set.str[STRING_SERVICE_NAME] ?
+                        data->set.str[STRING_SERVICE_NAME] :
+                        "ftp";
+  const char *srv_host = "host";
+  gss_buffer_desc input_buffer, output_buffer, _gssresp, *gssresp;
+  OM_uint32 maj, min;
+  gss_name_t gssname;
+  gss_ctx_id_t *context = app_data;
+  struct gss_channel_bindings_struct chan;
+  size_t base64_sz = 0;
+  struct sockaddr_in *remote_addr =
+    (struct sockaddr_in *)(void *)&conn->remote_addr->sa_addr;
+  char *stringp;
+
+  if(getsockname(conn->sock[FIRSTSOCKET],
+                 (struct sockaddr *)&conn->local_addr, &l) < 0)
+    perror("getsockname()");
+
+  chan.initiator_addrtype = GSS_C_AF_INET;
+  chan.initiator_address.length = l - 4;
+  chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr;
+  chan.acceptor_addrtype = GSS_C_AF_INET;
+  chan.acceptor_address.length = l - 4;
+  chan.acceptor_address.value = &remote_addr->sin_addr.s_addr;
+  chan.application_data.length = 0;
+  chan.application_data.value = NULL;
+
+  /* this loop will execute twice (once for service, once for host) */
+  for(;;) {
+    /* this really shouldn't be repeated here, but can't help it */
+    if(service == srv_host) {
+      result = ftpsend(data, conn, "AUTH GSSAPI");
+      if(result)
+        return -2;
+
+      if(Curl_GetFTPResponse(data, &nread, NULL))
+        return -1;
+      else {
+        struct pingpong *pp = &conn->proto.ftpc.pp;
+        char *line = Curl_dyn_ptr(&pp->recvbuf);
+        if(line[0] != '3')
+          return -1;
+      }
+    }
+
+    stringp = aprintf("%s@%s", service, host);
+    if(!stringp)
+      return -2;
+
+    input_buffer.value = stringp;
+    input_buffer.length = strlen(stringp);
+    maj = gss_import_name(&min, &input_buffer, GSS_C_NT_HOSTBASED_SERVICE,
+                          &gssname);
+    free(stringp);
+    if(maj != GSS_S_COMPLETE) {
+      gss_release_name(&min, &gssname);
+      if(service == srv_host) {
+        failf(data, "Error importing service name %s@%s", service, host);
+        return AUTH_ERROR;
+      }
+      service = srv_host;
+      continue;
+    }
+    /* We pass NULL as |output_name_type| to avoid a leak. */
+    gss_display_name(&min, gssname, &output_buffer, NULL);
+    infof(data, "Trying against %s", (char *)output_buffer.value);
+    gssresp = GSS_C_NO_BUFFER;
+    *context = GSS_C_NO_CONTEXT;
+
+    do {
+      /* Release the buffer at each iteration to avoid leaking: the first time
+         we are releasing the memory from gss_display_name. The last item is
+         taken care by a final gss_release_buffer. */
+      gss_release_buffer(&min, &output_buffer);
+      ret = AUTH_OK;
+      maj = Curl_gss_init_sec_context(data,
+                                      &min,
+                                      context,
+                                      gssname,
+                                      &Curl_krb5_mech_oid,
+                                      &chan,
+                                      gssresp,
+                                      &output_buffer,
+                                      TRUE,
+                                      NULL);
+
+      if(gssresp) {
+        free(_gssresp.value);
+        gssresp = NULL;
+      }
+
+      if(GSS_ERROR(maj)) {
+        infof(data, "Error creating security context");
+        ret = AUTH_ERROR;
+        break;
+      }
+
+      if(output_buffer.length) {
+        char *cmd;
+
+        result = Curl_base64_encode((char *)output_buffer.value,
+                                    output_buffer.length, &p, &base64_sz);
+        if(result) {
+          infof(data, "base64-encoding: %s", curl_easy_strerror(result));
+          ret = AUTH_ERROR;
+          break;
+        }
+
+        cmd = aprintf("ADAT %s", p);
+        if(cmd)
+          result = ftpsend(data, conn, cmd);
+        else
+          result = CURLE_OUT_OF_MEMORY;
+
+        free(p);
+        free(cmd);
+
+        if(result) {
+          ret = -2;
+          break;
+        }
+
+        if(Curl_GetFTPResponse(data, &nread, NULL)) {
+          ret = -1;
+          break;
+        }
+        else {
+          struct pingpong *pp = &conn->proto.ftpc.pp;
+          size_t len = Curl_dyn_len(&pp->recvbuf);
+          p = Curl_dyn_ptr(&pp->recvbuf);
+          if((len < 4) || (p[0] != '2' && p[0] != '3')) {
+            infof(data, "Server didn't accept auth data");
+            ret = AUTH_ERROR;
+            break;
+          }
+        }
+
+        _gssresp.value = NULL; /* make sure it is initialized */
+        p += 4; /* over '789 ' */
+        p = strstr(p, "ADAT=");
+        if(p) {
+          result = Curl_base64_decode(p + 5,
+                                      (unsigned char **)&_gssresp.value,
+                                      &_gssresp.length);
+          if(result) {
+            failf(data, "base64-decoding: %s", curl_easy_strerror(result));
+            ret = AUTH_CONTINUE;
+            break;
+          }
+        }
+
+        gssresp = &_gssresp;
+      }
+    } while(maj == GSS_S_CONTINUE_NEEDED);
+
+    gss_release_name(&min, &gssname);
+    gss_release_buffer(&min, &output_buffer);
+
+    if(gssresp)
+      free(_gssresp.value);
+
+    if(ret == AUTH_OK || service == srv_host)
+      return ret;
+
+    service = srv_host;
+  }
+  return ret;
+}
+
+static void krb5_end(void *app_data)
+{
+    OM_uint32 min;
+    gss_ctx_id_t *context = app_data;
+    if(*context != GSS_C_NO_CONTEXT) {
+      OM_uint32 maj = gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER);
+      (void)maj;
+      DEBUGASSERT(maj == GSS_S_COMPLETE);
+    }
+}
+
+static const struct Curl_sec_client_mech Curl_krb5_client_mech = {
+  "GSSAPI",
+  sizeof(gss_ctx_id_t),
+  krb5_init,
+  krb5_auth,
+  krb5_end,
+  krb5_check_prot,
+
+  krb5_encode,
+  krb5_decode
+};
+
+static const struct {
+  unsigned char level;
+  const char *name;
+} level_names[] = {
+  { PROT_CLEAR, "clear" },
+  { PROT_SAFE, "safe" },
+  { PROT_CONFIDENTIAL, "confidential" },
+  { PROT_PRIVATE, "private" }
+};
+
+static unsigned char name_to_level(const char *name)
+{
+  int i;
+  for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
+    if(curl_strequal(name, level_names[i].name))
+      return level_names[i].level;
+  return PROT_NONE;
+}
+
+/* Convert a protocol |level| to its char representation.
+   We take an int to catch programming mistakes. */
+static char level_to_char(int level)
+{
+  switch(level) {
+  case PROT_CLEAR:
+    return 'C';
+  case PROT_SAFE:
+    return 'S';
+  case PROT_CONFIDENTIAL:
+    return 'E';
+  case PROT_PRIVATE:
+    return 'P';
+  case PROT_CMD:
+  default:
+    /* Those 2 cases should not be reached! */
+    break;
+  }
+  DEBUGASSERT(0);
+  /* Default to the most secure alternative. */
+  return 'P';
+}
+
+/* Send an FTP command defined by |message| and the optional arguments. The
+   function returns the ftp_code. If an error occurs, -1 is returned. */
+static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
+  CURL_PRINTF(2, 3);
+
+static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
+{
+  int ftp_code;
+  ssize_t nread = 0;
+  va_list args;
+  char print_buffer[50];
+
+  va_start(args, message);
+  mvsnprintf(print_buffer, sizeof(print_buffer), message, args);
+  va_end(args);
+
+  if(ftpsend(data, data->conn, print_buffer)) {
+    ftp_code = -1;
+  }
+  else {
+    if(Curl_GetFTPResponse(data, &nread, &ftp_code))
+      ftp_code = -1;
+  }
+
+  (void)nread; /* Unused */
+  return ftp_code;
+}
+
+/* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode
+   saying whether an error occurred or CURLE_OK if |len| was read. */
+static CURLcode
+socket_read(struct Curl_easy *data, int sockindex, void *to, size_t len)
+{
+  char *to_p = to;
+  CURLcode result;
+  ssize_t nread = 0;
+
+  while(len > 0) {
+    result = Curl_conn_recv(data, sockindex, to_p, len, &nread);
+    if(nread > 0) {
+      len -= nread;
+      to_p += nread;
+    }
+    else {
+      if(result == CURLE_AGAIN)
+        continue;
+      return result;
+    }
+  }
+  return CURLE_OK;
+}
+
+
+/* Write |len| bytes from the buffer |to| to the socket |fd|. Return a
+   CURLcode saying whether an error occurred or CURLE_OK if |len| was
+   written. */
+static CURLcode
+socket_write(struct Curl_easy *data, int sockindex, const void *to,
+             size_t len)
+{
+  const char *to_p = to;
+  CURLcode result;
+  size_t written;
+
+  while(len > 0) {
+    result = Curl_conn_send(data, sockindex, to_p, len, &written);
+    if(!result && written > 0) {
+      len -= written;
+      to_p += written;
+    }
+    else {
+      if(result == CURLE_AGAIN)
+        continue;
+      return result;
+    }
+  }
+  return CURLE_OK;
+}
+
+static CURLcode read_data(struct Curl_easy *data, int sockindex,
+                          struct krb5buffer *buf)
+{
+  struct connectdata *conn = data->conn;
+  int len;
+  CURLcode result;
+  int nread;
+
+  result = socket_read(data, sockindex, &len, sizeof(len));
+  if(result)
+    return result;
+
+  if(len) {
+    /* only realloc if there was a length */
+    len = ntohl(len);
+    if(len > CURL_MAX_INPUT_LENGTH)
+      len = 0;
+    else
+      buf->data = Curl_saferealloc(buf->data, len);
+  }
+  if(!len || !buf->data)
+    return CURLE_OUT_OF_MEMORY;
+
+  result = socket_read(data, sockindex, buf->data, len);
+  if(result)
+    return result;
+  nread = conn->mech->decode(conn->app_data, buf->data, len,
+                             conn->data_prot, conn);
+  if(nread < 0)
+    return CURLE_RECV_ERROR;
+  buf->size = (size_t)nread;
+  buf->index = 0;
+  return CURLE_OK;
+}
+
+static size_t
+buffer_read(struct krb5buffer *buf, void *data, size_t len)
+{
+  if(buf->size - buf->index < len)
+    len = buf->size - buf->index;
+  memcpy(data, (char *)buf->data + buf->index, len);
+  buf->index += len;
+  return len;
+}
+
+/* Matches Curl_recv signature */
+static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
+                        char *buffer, size_t len, CURLcode *err)
+{
+  size_t bytes_read;
+  size_t total_read = 0;
+  struct connectdata *conn = data->conn;
+
+  *err = CURLE_OK;
+
+  /* Handle clear text response. */
+  if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) {
+    ssize_t nread;
+    *err = Curl_conn_recv(data, sockindex, buffer, len, &nread);
+    return nread;
+  }
+
+  if(conn->in_buffer.eof_flag) {
+    conn->in_buffer.eof_flag = 0;
+    return 0;
+  }
+
+  bytes_read = buffer_read(&conn->in_buffer, buffer, len);
+  len -= bytes_read;
+  total_read += bytes_read;
+  buffer += bytes_read;
+
+  while(len > 0) {
+    if(read_data(data, sockindex, &conn->in_buffer))
+      return -1;
+    if(conn->in_buffer.size == 0) {
+      if(bytes_read > 0)
+        conn->in_buffer.eof_flag = 1;
+      return bytes_read;
+    }
+    bytes_read = buffer_read(&conn->in_buffer, buffer, len);
+    len -= bytes_read;
+    total_read += bytes_read;
+    buffer += bytes_read;
+  }
+  return total_read;
+}
+
+/* Send |length| bytes from |from| to the |fd| socket taking care of encoding
+   and negotiating with the server. |from| can be NULL. */
+static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
+                        curl_socket_t fd, const char *from, int length)
+{
+  int bytes, htonl_bytes; /* 32-bit integers for htonl */
+  char *buffer = NULL;
+  char *cmd_buffer;
+  size_t cmd_size = 0;
+  CURLcode error;
+  enum protection_level prot_level = conn->data_prot;
+  bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE;
+
+  DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST);
+
+  if(iscmd) {
+    if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5))
+      prot_level = PROT_PRIVATE;
+    else
+      prot_level = conn->command_prot;
+  }
+  bytes = conn->mech->encode(conn->app_data, from, length, prot_level,
+                             (void **)&buffer);
+  if(!buffer || bytes <= 0)
+    return; /* error */
+
+  if(iscmd) {
+    error = Curl_base64_encode(buffer, curlx_sitouz(bytes),
+                               &cmd_buffer, &cmd_size);
+    if(error) {
+      free(buffer);
+      return; /* error */
+    }
+    if(cmd_size > 0) {
+      static const char *enc = "ENC ";
+      static const char *mic = "MIC ";
+      if(prot_level == PROT_PRIVATE)
+        socket_write(data, fd, enc, 4);
+      else
+        socket_write(data, fd, mic, 4);
+
+      socket_write(data, fd, cmd_buffer, cmd_size);
+      socket_write(data, fd, "\r\n", 2);
+      infof(data, "Send: %s%s", prot_level == PROT_PRIVATE?enc:mic,
+            cmd_buffer);
+      free(cmd_buffer);
+    }
+  }
+  else {
+    htonl_bytes = htonl(bytes);
+    socket_write(data, fd, &htonl_bytes, sizeof(htonl_bytes));
+    socket_write(data, fd, buffer, curlx_sitouz(bytes));
+  }
+  free(buffer);
+}
+
+static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn,
+                         curl_socket_t fd, const char *buffer, size_t length)
+{
+  ssize_t tx = 0, len = conn->buffer_size;
+
+  if(len <= 0)
+    len = length;
+  while(length) {
+    if(length < (size_t)len)
+      len = length;
+
+    do_sec_send(data, conn, fd, buffer, curlx_sztosi(len));
+    length -= len;
+    buffer += len;
+    tx += len;
+  }
+  return tx;
+}
+
+/* Matches Curl_send signature */
+static ssize_t sec_send(struct Curl_easy *data, int sockindex,
+                        const void *buffer, size_t len, CURLcode *err)
+{
+  struct connectdata *conn = data->conn;
+  curl_socket_t fd = conn->sock[sockindex];
+  *err = CURLE_OK;
+  return sec_write(data, conn, fd, buffer, len);
+}
+
+int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,
+                      char *buffer, enum protection_level level)
+{
+  /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an
+     int */
+  int decoded_len;
+  char *buf;
+  int ret_code = 0;
+  size_t decoded_sz = 0;
+  CURLcode error;
+
+  (void) data;
+
+  if(!conn->mech)
+    /* not initialized, return error */
+    return -1;
+
+  DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
+
+  error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz);
+  if(error || decoded_sz == 0)
+    return -1;
+
+  if(decoded_sz > (size_t)INT_MAX) {
+    free(buf);
+    return -1;
+  }
+  decoded_len = curlx_uztosi(decoded_sz);
+
+  decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
+                                   level, conn);
+  if(decoded_len <= 0) {
+    free(buf);
+    return -1;
+  }
+
+  {
+    buf[decoded_len] = '\n';
+    Curl_debug(data, CURLINFO_HEADER_IN, buf, decoded_len + 1);
+  }
+
+  buf[decoded_len] = '\0';
+  if(decoded_len <= 3)
+    /* suspiciously short */
+    return 0;
+
+  if(buf[3] != '-')
+    ret_code = atoi(buf);
+
+  if(buf[decoded_len - 1] == '\n')
+    buf[decoded_len - 1] = '\0';
+  strcpy(buffer, buf);
+  free(buf);
+  return ret_code;
+}
+
+static int sec_set_protection_level(struct Curl_easy *data)
+{
+  int code;
+  struct connectdata *conn = data->conn;
+  unsigned char level = conn->request_data_prot;
+
+  DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
+
+  if(!conn->sec_complete) {
+    infof(data, "Trying to change the protection level after the"
+                " completion of the data exchange.");
+    return -1;
+  }
+
+  /* Bail out if we try to set up the same level */
+  if(conn->data_prot == level)
+    return 0;
+
+  if(level) {
+    char *pbsz;
+    unsigned int buffer_size = 1 << 20; /* 1048576 */
+    struct pingpong *pp = &conn->proto.ftpc.pp;
+    char *line;
+
+    code = ftp_send_command(data, "PBSZ %u", buffer_size);
+    if(code < 0)
+      return -1;
+
+    if(code/100 != 2) {
+      failf(data, "Failed to set the protection's buffer size.");
+      return -1;
+    }
+    conn->buffer_size = buffer_size;
+
+    line = Curl_dyn_ptr(&pp->recvbuf);
+    pbsz = strstr(line, "PBSZ=");
+    if(pbsz) {
+      /* stick to default value if the check fails */
+      if(ISDIGIT(pbsz[5]))
+        buffer_size = atoi(&pbsz[5]);
+      if(buffer_size < conn->buffer_size)
+        conn->buffer_size = buffer_size;
+    }
+  }
+
+  /* Now try to negotiate the protection level. */
+  code = ftp_send_command(data, "PROT %c", level_to_char(level));
+
+  if(code < 0)
+    return -1;
+
+  if(code/100 != 2) {
+    failf(data, "Failed to set the protection level.");
+    return -1;
+  }
+
+  conn->data_prot = level;
+  if(level == PROT_PRIVATE)
+    conn->command_prot = level;
+
+  return 0;
+}
+
+int
+Curl_sec_request_prot(struct connectdata *conn, const char *level)
+{
+  unsigned char l = name_to_level(level);
+  if(l == PROT_NONE)
+    return -1;
+  DEBUGASSERT(l > PROT_NONE && l < PROT_LAST);
+  conn->request_data_prot = l;
+  return 0;
+}
+
+static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
+{
+  int ret;
+  void *tmp_allocation;
+  const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech;
+
+  tmp_allocation = realloc(conn->app_data, mech->size);
+  if(!tmp_allocation) {
+    failf(data, "Failed realloc of size %zu", mech->size);
+    mech = NULL;
+    return CURLE_OUT_OF_MEMORY;
+  }
+  conn->app_data = tmp_allocation;
+
+  if(mech->init) {
+    ret = mech->init(conn->app_data);
+    if(ret) {
+      infof(data, "Failed initialization for %s. Skipping it.",
+            mech->name);
+      return CURLE_FAILED_INIT;
+    }
+  }
+
+  infof(data, "Trying mechanism %s...", mech->name);
+  ret = ftp_send_command(data, "AUTH %s", mech->name);
+  if(ret < 0)
+    return CURLE_COULDNT_CONNECT;
+
+  if(ret/100 != 3) {
+    switch(ret) {
+    case 504:
+      infof(data, "Mechanism %s is not supported by the server (server "
+            "returned ftp code: 504).", mech->name);
+      break;
+    case 534:
+      infof(data, "Mechanism %s was rejected by the server (server returned "
+            "ftp code: 534).", mech->name);
+      break;
+    default:
+      if(ret/100 == 5) {
+        infof(data, "server does not support the security extensions");
+        return CURLE_USE_SSL_FAILED;
+      }
+      break;
+    }
+    return CURLE_LOGIN_DENIED;
+  }
+
+  /* Authenticate */
+  ret = mech->auth(conn->app_data, data, conn);
+
+  if(ret != AUTH_CONTINUE) {
+    if(ret != AUTH_OK) {
+      /* Mechanism has dumped the error to stderr, don't error here. */
+      return CURLE_USE_SSL_FAILED;
+    }
+    DEBUGASSERT(ret == AUTH_OK);
+
+    conn->mech = mech;
+    conn->sec_complete = 1;
+    conn->recv[FIRSTSOCKET] = sec_recv;
+    conn->send[FIRSTSOCKET] = sec_send;
+    conn->recv[SECONDARYSOCKET] = sec_recv;
+    conn->send[SECONDARYSOCKET] = sec_send;
+    conn->command_prot = PROT_SAFE;
+    /* Set the requested protection level */
+    /* BLOCKING */
+    (void)sec_set_protection_level(data);
+  }
+
+  return CURLE_OK;
+}
+
+CURLcode
+Curl_sec_login(struct Curl_easy *data, struct connectdata *conn)
+{
+  return choose_mech(data, conn);
+}
+
+
+void
+Curl_sec_end(struct connectdata *conn)
+{
+  if(conn->mech && conn->mech->end)
+    conn->mech->end(conn->app_data);
+  free(conn->app_data);
+  conn->app_data = NULL;
+  if(conn->in_buffer.data) {
+    free(conn->in_buffer.data);
+    conn->in_buffer.data = NULL;
+    conn->in_buffer.size = 0;
+    conn->in_buffer.index = 0;
+    conn->in_buffer.eof_flag = 0;
+  }
+  conn->sec_complete = 0;
+  conn->data_prot = PROT_CLEAR;
+  conn->mech = NULL;
+}
+
+#endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */
Index: trunk/src/libs/curl-8.7.1/lib/ldap.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/ldap.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/ldap.c	(revision 104083)
@@ -0,0 +1,1107 @@
+/***************************************************************************
+ *                      _   _ ____  _
+ *  Project         ___| | | |  _ \| |
+ *                 / __| | | | |_) | |
+ *                | (__| |_| |  _ <| |___
+ *                 \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_LDAP) && !defined(USE_OPENLDAP)
+
+/*
+ * Notice that USE_OPENLDAP is only a source code selection switch. When
+ * libcurl is built with USE_OPENLDAP defined the libcurl source code that
+ * gets compiled is the code from openldap.c, otherwise the code that gets
+ * compiled is the code from ldap.c.
+ *
+ * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
+ * might be required for compilation and runtime. In order to use ancient
+ * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
+ */
+
+/* Wincrypt must be included before anything that could include OpenSSL. */
+#if defined(USE_WIN32_CRYPTO)
+#include <wincrypt.h>
+/* Undefine wincrypt conflicting symbols for BoringSSL. */
+#undef X509_NAME
+#undef X509_EXTENSIONS
+#undef PKCS7_ISSUER_AND_SERIAL
+#undef PKCS7_SIGNER_INFO
+#undef OCSP_REQUEST
+#undef OCSP_RESPONSE
+#endif
+
+#ifdef USE_WIN32_LDAP           /* Use Windows LDAP implementation. */
+# ifdef _MSC_VER
+#  pragma warning(push)
+#  pragma warning(disable: 4201)
+# endif
+# include <subauth.h>  /* for [P]UNICODE_STRING */
+# ifdef _MSC_VER
+#  pragma warning(pop)
+# endif
+# include <winldap.h>
+# ifndef LDAP_VENDOR_NAME
+#  error Your Platform SDK is NOT sufficient for LDAP support! \
+         Update your Platform SDK, or disable LDAP support!
+# else
+#  include <winber.h>
+# endif
+#else
+# define LDAP_DEPRECATED 1      /* Be sure ldap_init() is defined. */
+# ifdef HAVE_LBER_H
+#  include <lber.h>
+# endif
+# include <ldap.h>
+# if (defined(HAVE_LDAP_SSL) && defined(HAVE_LDAP_SSL_H))
+#  include <ldap_ssl.h>
+# endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "sendf.h"
+#include "escape.h"
+#include "progress.h"
+#include "transfer.h"
+#include "strcase.h"
+#include "strtok.h"
+#include "curl_ldap.h"
+#include "curl_multibyte.h"
+#include "curl_base64.h"
+#include "connect.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef HAVE_LDAP_URL_PARSE
+
+/* Use our own implementation. */
+
+struct ldap_urldesc {
+  char   *lud_host;
+  int     lud_port;
+#if defined(USE_WIN32_LDAP)
+  TCHAR  *lud_dn;
+  TCHAR **lud_attrs;
+#else
+  char   *lud_dn;
+  char  **lud_attrs;
+#endif
+  int     lud_scope;
+#if defined(USE_WIN32_LDAP)
+  TCHAR  *lud_filter;
+#else
+  char   *lud_filter;
+#endif
+  char  **lud_exts;
+  size_t    lud_attrs_dups; /* how many were dup'ed, this field is not in the
+                               "real" struct so can only be used in code
+                               without HAVE_LDAP_URL_PARSE defined */
+};
+
+#undef LDAPURLDesc
+#define LDAPURLDesc struct ldap_urldesc
+
+static int  _ldap_url_parse(struct Curl_easy *data,
+                            const struct connectdata *conn,
+                            LDAPURLDesc **ludp);
+static void _ldap_free_urldesc(LDAPURLDesc *ludp);
+
+#undef ldap_free_urldesc
+#define ldap_free_urldesc       _ldap_free_urldesc
+#endif
+
+#ifdef DEBUG_LDAP
+  #define LDAP_TRACE(x)   do { \
+                            _ldap_trace("%u: ", __LINE__); \
+                            _ldap_trace x; \
+                          } while(0)
+
+  static void _ldap_trace(const char *fmt, ...) CURL_PRINTF(1, 2);
+#else
+  #define LDAP_TRACE(x)   Curl_nop_stmt
+#endif
+
+#if defined(USE_WIN32_LDAP) && defined(ldap_err2string)
+/* Use ansi error strings in UNICODE builds */
+#undef ldap_err2string
+#define ldap_err2string ldap_err2stringA
+#endif
+
+#if defined(USE_WIN32_LDAP) && defined(_MSC_VER) && (_MSC_VER <= 1600)
+/* Workaround for warning:
+   'type cast' : conversion from 'int' to 'void *' of greater size */
+#undef LDAP_OPT_ON
+#undef LDAP_OPT_OFF
+#define LDAP_OPT_ON   ((void *)(size_t)1)
+#define LDAP_OPT_OFF  ((void *)(size_t)0)
+#endif
+
+static CURLcode ldap_do(struct Curl_easy *data, bool *done);
+
+/*
+ * LDAP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldap = {
+  "LDAP",                               /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  ldap_do,                              /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_LDAP,                            /* defport */
+  CURLPROTO_LDAP,                       /* protocol */
+  CURLPROTO_LDAP,                       /* family */
+  PROTOPT_NONE                          /* flags */
+};
+
+#ifdef HAVE_LDAP_SSL
+/*
+ * LDAPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldaps = {
+  "LDAPS",                              /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  ldap_do,                              /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_LDAPS,                           /* defport */
+  CURLPROTO_LDAPS,                      /* protocol */
+  CURLPROTO_LDAP,                       /* family */
+  PROTOPT_SSL                           /* flags */
+};
+#endif
+
+#if defined(USE_WIN32_LDAP)
+
+#if defined(USE_WINDOWS_SSPI)
+static int ldap_win_bind_auth(LDAP *server, const char *user,
+                              const char *passwd, unsigned long authflags)
+{
+  ULONG method = 0;
+  SEC_WINNT_AUTH_IDENTITY cred;
+  int rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
+
+  memset(&cred, 0, sizeof(cred));
+
+#if defined(USE_SPNEGO)
+  if(authflags & CURLAUTH_NEGOTIATE) {
+    method = LDAP_AUTH_NEGOTIATE;
+  }
+  else
+#endif
+#if defined(USE_NTLM)
+  if(authflags & CURLAUTH_NTLM) {
+    method = LDAP_AUTH_NTLM;
+  }
+  else
+#endif
+#if !defined(CURL_DISABLE_DIGEST_AUTH)
+  if(authflags & CURLAUTH_DIGEST) {
+    method = LDAP_AUTH_DIGEST;
+  }
+  else
+#endif
+  {
+    /* required anyway if one of upper preprocessor definitions enabled */
+  }
+
+  if(method && user && passwd) {
+    rc = Curl_create_sspi_identity(user, passwd, &cred);
+    if(!rc) {
+      rc = ldap_bind_s(server, NULL, (TCHAR *)&cred, method);
+      Curl_sspi_free_identity(&cred);
+    }
+  }
+  else {
+    /* proceed with current user credentials */
+    method = LDAP_AUTH_NEGOTIATE;
+    rc = ldap_bind_s(server, NULL, NULL, method);
+  }
+  return rc;
+}
+#endif /* #if defined(USE_WINDOWS_SSPI) */
+
+static int ldap_win_bind(struct Curl_easy *data, LDAP *server,
+                         const char *user, const char *passwd)
+{
+  int rc = LDAP_INVALID_CREDENTIALS;
+
+  PTCHAR inuser = NULL;
+  PTCHAR inpass = NULL;
+
+  if(user && passwd && (data->set.httpauth & CURLAUTH_BASIC)) {
+    inuser = curlx_convert_UTF8_to_tchar((char *) user);
+    inpass = curlx_convert_UTF8_to_tchar((char *) passwd);
+
+    rc = ldap_simple_bind_s(server, inuser, inpass);
+
+    curlx_unicodefree(inuser);
+    curlx_unicodefree(inpass);
+  }
+#if defined(USE_WINDOWS_SSPI)
+  else {
+    rc = ldap_win_bind_auth(server, user, passwd, data->set.httpauth);
+  }
+#endif
+
+  return rc;
+}
+#endif /* #if defined(USE_WIN32_LDAP) */
+
+#if defined(USE_WIN32_LDAP)
+#define FREE_ON_WINLDAP(x) curlx_unicodefree(x)
+#else
+#define FREE_ON_WINLDAP(x)
+#endif
+
+
+static CURLcode ldap_do(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  int rc = 0;
+  LDAP *server = NULL;
+  LDAPURLDesc *ludp = NULL;
+  LDAPMessage *ldapmsg = NULL;
+  LDAPMessage *entryIterator;
+  int num = 0;
+  struct connectdata *conn = data->conn;
+  int ldap_proto = LDAP_VERSION3;
+  int ldap_ssl = 0;
+  char *val_b64 = NULL;
+  size_t val_b64_sz = 0;
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+  struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */
+#endif
+#if defined(USE_WIN32_LDAP)
+  TCHAR *host = NULL;
+#else
+  char *host = NULL;
+#endif
+  char *user = NULL;
+  char *passwd = NULL;
+
+  *done = TRUE; /* unconditionally */
+  infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d",
+        LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
+  infof(data, "LDAP local: %s", data->state.url);
+
+#ifdef HAVE_LDAP_URL_PARSE
+  rc = ldap_url_parse(data->state.url, &ludp);
+#else
+  rc = _ldap_url_parse(data, conn, &ludp);
+#endif
+  if(rc) {
+    failf(data, "Bad LDAP URL: %s", ldap_err2string(rc));
+    result = CURLE_URL_MALFORMAT;
+    goto quit;
+  }
+
+  /* Get the URL scheme (either ldap or ldaps) */
+  if(conn->given->flags & PROTOPT_SSL)
+    ldap_ssl = 1;
+  infof(data, "LDAP local: trying to establish %s connection",
+        ldap_ssl ? "encrypted" : "cleartext");
+
+#if defined(USE_WIN32_LDAP)
+  host = curlx_convert_UTF8_to_tchar(conn->host.name);
+  if(!host) {
+    result = CURLE_OUT_OF_MEMORY;
+
+    goto quit;
+  }
+#else
+  host = conn->host.name;
+#endif
+
+  if(data->state.aptr.user) {
+    user = conn->user;
+    passwd = conn->passwd;
+  }
+
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+  ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
+#endif
+  ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+
+  if(ldap_ssl) {
+#ifdef HAVE_LDAP_SSL
+#ifdef USE_WIN32_LDAP
+    /* Win32 LDAP SDK doesn't support insecure mode without CA! */
+    server = ldap_sslinit(host, conn->primary.remote_port, 1);
+    ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
+#else
+    int ldap_option;
+    char *ldap_ca = conn->ssl_config.CAfile;
+#if defined(CURL_HAS_NOVELL_LDAPSDK)
+    rc = ldapssl_client_init(NULL, NULL);
+    if(rc != LDAP_SUCCESS) {
+      failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc));
+      result = CURLE_SSL_CERTPROBLEM;
+      goto quit;
+    }
+    if(conn->ssl_config.verifypeer) {
+      /* Novell SDK supports DER or BASE64 files. */
+      int cert_type = LDAPSSL_CERT_FILETYPE_B64;
+      if((data->set.ssl.cert_type) &&
+         (strcasecompare(data->set.ssl.cert_type, "DER")))
+        cert_type = LDAPSSL_CERT_FILETYPE_DER;
+      if(!ldap_ca) {
+        failf(data, "LDAP local: ERROR %s CA cert not set",
+              (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"));
+        result = CURLE_SSL_CERTPROBLEM;
+        goto quit;
+      }
+      infof(data, "LDAP local: using %s CA cert '%s'",
+            (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
+            ldap_ca);
+      rc = ldapssl_add_trusted_cert(ldap_ca, cert_type);
+      if(rc != LDAP_SUCCESS) {
+        failf(data, "LDAP local: ERROR setting %s CA cert: %s",
+              (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
+              ldap_err2string(rc));
+        result = CURLE_SSL_CERTPROBLEM;
+        goto quit;
+      }
+      ldap_option = LDAPSSL_VERIFY_SERVER;
+    }
+    else
+      ldap_option = LDAPSSL_VERIFY_NONE;
+    rc = ldapssl_set_verify_mode(ldap_option);
+    if(rc != LDAP_SUCCESS) {
+      failf(data, "LDAP local: ERROR setting cert verify mode: %s",
+              ldap_err2string(rc));
+      result = CURLE_SSL_CERTPROBLEM;
+      goto quit;
+    }
+    server = ldapssl_init(host, conn->primary.remote_port, 1);
+    if(!server) {
+      failf(data, "LDAP local: Cannot connect to %s:%u",
+            conn->host.dispname, conn->primary.remote_port);
+      result = CURLE_COULDNT_CONNECT;
+      goto quit;
+    }
+#elif defined(LDAP_OPT_X_TLS)
+    if(conn->ssl_config.verifypeer) {
+      /* OpenLDAP SDK supports BASE64 files. */
+      if((data->set.ssl.cert_type) &&
+         (!strcasecompare(data->set.ssl.cert_type, "PEM"))) {
+        failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type");
+        result = CURLE_SSL_CERTPROBLEM;
+        goto quit;
+      }
+      if(!ldap_ca) {
+        failf(data, "LDAP local: ERROR PEM CA cert not set");
+        result = CURLE_SSL_CERTPROBLEM;
+        goto quit;
+      }
+      infof(data, "LDAP local: using PEM CA cert: %s", ldap_ca);
+      rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
+      if(rc != LDAP_SUCCESS) {
+        failf(data, "LDAP local: ERROR setting PEM CA cert: %s",
+                ldap_err2string(rc));
+        result = CURLE_SSL_CERTPROBLEM;
+        goto quit;
+      }
+      ldap_option = LDAP_OPT_X_TLS_DEMAND;
+    }
+    else
+      ldap_option = LDAP_OPT_X_TLS_NEVER;
+
+    rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option);
+    if(rc != LDAP_SUCCESS) {
+      failf(data, "LDAP local: ERROR setting cert verify mode: %s",
+              ldap_err2string(rc));
+      result = CURLE_SSL_CERTPROBLEM;
+      goto quit;
+    }
+    server = ldap_init(host, conn->primary.remote_port);
+    if(!server) {
+      failf(data, "LDAP local: Cannot connect to %s:%u",
+            conn->host.dispname, conn->primary.remote_port);
+      result = CURLE_COULDNT_CONNECT;
+      goto quit;
+    }
+    ldap_option = LDAP_OPT_X_TLS_HARD;
+    rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option);
+    if(rc != LDAP_SUCCESS) {
+      failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s",
+              ldap_err2string(rc));
+      result = CURLE_SSL_CERTPROBLEM;
+      goto quit;
+    }
+/*
+    rc = ldap_start_tls_s(server, NULL, NULL);
+    if(rc != LDAP_SUCCESS) {
+      failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s",
+              ldap_err2string(rc));
+      result = CURLE_SSL_CERTPROBLEM;
+      goto quit;
+    }
+*/
+#else
+    /* we should probably never come up to here since configure
+       should check in first place if we can support LDAP SSL/TLS */
+    failf(data, "LDAP local: SSL/TLS not supported with this version "
+            "of the OpenLDAP toolkit\n");
+    result = CURLE_SSL_CERTPROBLEM;
+    goto quit;
+#endif
+#endif
+#endif /* CURL_LDAP_USE_SSL */
+  }
+  else if(data->set.use_ssl > CURLUSESSL_TRY) {
+    failf(data, "LDAP local: explicit TLS not supported");
+    result = CURLE_NOT_BUILT_IN;
+    goto quit;
+  }
+  else {
+    server = ldap_init(host, conn->primary.remote_port);
+    if(!server) {
+      failf(data, "LDAP local: Cannot connect to %s:%u",
+            conn->host.dispname, conn->primary.remote_port);
+      result = CURLE_COULDNT_CONNECT;
+      goto quit;
+    }
+  }
+#ifdef USE_WIN32_LDAP
+  ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+  rc = ldap_win_bind(data, server, user, passwd);
+#else
+  rc = ldap_simple_bind_s(server, user, passwd);
+#endif
+  if(!ldap_ssl && rc) {
+    ldap_proto = LDAP_VERSION2;
+    ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+#ifdef USE_WIN32_LDAP
+    rc = ldap_win_bind(data, server, user, passwd);
+#else
+    rc = ldap_simple_bind_s(server, user, passwd);
+#endif
+  }
+  if(rc) {
+#ifdef USE_WIN32_LDAP
+    failf(data, "LDAP local: bind via ldap_win_bind %s",
+          ldap_err2string(rc));
+#else
+    failf(data, "LDAP local: bind via ldap_simple_bind_s %s",
+          ldap_err2string(rc));
+#endif
+    result = CURLE_LDAP_CANNOT_BIND;
+    goto quit;
+  }
+
+  Curl_pgrsSetDownloadCounter(data, 0);
+  rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
+                     ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);
+
+  if(rc && rc != LDAP_SIZELIMIT_EXCEEDED) {
+    failf(data, "LDAP remote: %s", ldap_err2string(rc));
+    result = CURLE_LDAP_SEARCH_FAILED;
+    goto quit;
+  }
+
+  for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg);
+      entryIterator;
+      entryIterator = ldap_next_entry(server, entryIterator), num++) {
+    BerElement *ber = NULL;
+#if defined(USE_WIN32_LDAP)
+    TCHAR *attribute;
+#else
+    char *attribute;
+#endif
+    int i;
+
+    /* Get the DN and write it to the client */
+    {
+      char *name;
+      size_t name_len;
+#if defined(USE_WIN32_LDAP)
+      TCHAR *dn = ldap_get_dn(server, entryIterator);
+      name = curlx_convert_tchar_to_UTF8(dn);
+      if(!name) {
+        ldap_memfree(dn);
+
+        result = CURLE_OUT_OF_MEMORY;
+
+        goto quit;
+      }
+#else
+      char *dn = name = ldap_get_dn(server, entryIterator);
+#endif
+      name_len = strlen(name);
+
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+      if(result) {
+        FREE_ON_WINLDAP(name);
+        ldap_memfree(dn);
+        goto quit;
+      }
+
+      result = Curl_client_write(data, CLIENTWRITE_BODY, name, name_len);
+      if(result) {
+        FREE_ON_WINLDAP(name);
+        ldap_memfree(dn);
+        goto quit;
+      }
+
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
+      if(result) {
+        FREE_ON_WINLDAP(name);
+        ldap_memfree(dn);
+
+        goto quit;
+      }
+
+      FREE_ON_WINLDAP(name);
+      ldap_memfree(dn);
+    }
+
+    /* Get the attributes and write them to the client */
+    for(attribute = ldap_first_attribute(server, entryIterator, &ber);
+        attribute;
+        attribute = ldap_next_attribute(server, entryIterator, ber)) {
+      BerValue **vals;
+      size_t attr_len;
+#if defined(USE_WIN32_LDAP)
+      char *attr = curlx_convert_tchar_to_UTF8(attribute);
+      if(!attr) {
+        if(ber)
+          ber_free(ber, 0);
+
+        result = CURLE_OUT_OF_MEMORY;
+
+        goto quit;
+      }
+#else
+      char *attr = attribute;
+#endif
+      attr_len = strlen(attr);
+
+      vals = ldap_get_values_len(server, entryIterator, attribute);
+      if(vals) {
+        for(i = 0; (vals[i] != NULL); i++) {
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
+          if(result) {
+            ldap_value_free_len(vals);
+            FREE_ON_WINLDAP(attr);
+            ldap_memfree(attribute);
+            if(ber)
+              ber_free(ber, 0);
+
+            goto quit;
+          }
+
+          result = Curl_client_write(data, CLIENTWRITE_BODY, attr, attr_len);
+          if(result) {
+            ldap_value_free_len(vals);
+            FREE_ON_WINLDAP(attr);
+            ldap_memfree(attribute);
+            if(ber)
+              ber_free(ber, 0);
+
+            goto quit;
+          }
+
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2);
+          if(result) {
+            ldap_value_free_len(vals);
+            FREE_ON_WINLDAP(attr);
+            ldap_memfree(attribute);
+            if(ber)
+              ber_free(ber, 0);
+
+            goto quit;
+          }
+
+          if((attr_len > 7) &&
+             (strcmp(";binary", attr + (attr_len - 7)) == 0)) {
+            /* Binary attribute, encode to base64. */
+            result = Curl_base64_encode(vals[i]->bv_val, vals[i]->bv_len,
+                                        &val_b64, &val_b64_sz);
+            if(result) {
+              ldap_value_free_len(vals);
+              FREE_ON_WINLDAP(attr);
+              ldap_memfree(attribute);
+              if(ber)
+                ber_free(ber, 0);
+
+              goto quit;
+            }
+
+            if(val_b64_sz > 0) {
+              result = Curl_client_write(data, CLIENTWRITE_BODY, val_b64,
+                                         val_b64_sz);
+              free(val_b64);
+              if(result) {
+                ldap_value_free_len(vals);
+                FREE_ON_WINLDAP(attr);
+                ldap_memfree(attribute);
+                if(ber)
+                  ber_free(ber, 0);
+
+                goto quit;
+              }
+            }
+          }
+          else {
+            result = Curl_client_write(data, CLIENTWRITE_BODY, vals[i]->bv_val,
+                                       vals[i]->bv_len);
+            if(result) {
+              ldap_value_free_len(vals);
+              FREE_ON_WINLDAP(attr);
+              ldap_memfree(attribute);
+              if(ber)
+                ber_free(ber, 0);
+
+              goto quit;
+            }
+          }
+
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
+          if(result) {
+            ldap_value_free_len(vals);
+            FREE_ON_WINLDAP(attr);
+            ldap_memfree(attribute);
+            if(ber)
+              ber_free(ber, 0);
+
+            goto quit;
+          }
+        }
+
+        /* Free memory used to store values */
+        ldap_value_free_len(vals);
+      }
+
+      /* Free the attribute as we are done with it */
+      FREE_ON_WINLDAP(attr);
+      ldap_memfree(attribute);
+
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
+      if(result)
+        goto quit;
+    }
+
+    if(ber)
+      ber_free(ber, 0);
+  }
+
+quit:
+  if(ldapmsg) {
+    ldap_msgfree(ldapmsg);
+    LDAP_TRACE(("Received %d entries\n", num));
+  }
+  if(rc == LDAP_SIZELIMIT_EXCEEDED)
+    infof(data, "There are more than %d entries", num);
+  if(ludp)
+    ldap_free_urldesc(ludp);
+  if(server)
+    ldap_unbind_s(server);
+#if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK)
+  if(ldap_ssl)
+    ldapssl_client_deinit();
+#endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */
+
+  FREE_ON_WINLDAP(host);
+
+  /* no data to transfer */
+  Curl_xfer_setup(data, -1, -1, FALSE, -1);
+  connclose(conn, "LDAP connection always disable reuse");
+
+  return result;
+}
+
+#ifdef DEBUG_LDAP
+static void _ldap_trace(const char *fmt, ...)
+{
+  static int do_trace = -1;
+  va_list args;
+
+  if(do_trace == -1) {
+    const char *env = getenv("CURL_TRACE");
+    do_trace = (env && strtol(env, NULL, 10) > 0);
+  }
+  if(!do_trace)
+    return;
+
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  va_end(args);
+}
+#endif
+
+#ifndef HAVE_LDAP_URL_PARSE
+
+/*
+ * Return scope-value for a scope-string.
+ */
+static int str2scope(const char *p)
+{
+  if(strcasecompare(p, "one"))
+    return LDAP_SCOPE_ONELEVEL;
+  if(strcasecompare(p, "onetree"))
+    return LDAP_SCOPE_ONELEVEL;
+  if(strcasecompare(p, "base"))
+    return LDAP_SCOPE_BASE;
+  if(strcasecompare(p, "sub"))
+    return LDAP_SCOPE_SUBTREE;
+  if(strcasecompare(p, "subtree"))
+    return LDAP_SCOPE_SUBTREE;
+  return (-1);
+}
+
+/*
+ * Split 'str' into strings separated by commas.
+ * Note: out[] points into 'str'.
+ */
+static bool split_str(char *str, char ***out, size_t *count)
+{
+  char **res;
+  char *lasts;
+  char *s;
+  size_t  i;
+  size_t items = 1;
+
+  s = strchr(str, ',');
+  while(s) {
+    items++;
+    s = strchr(++s, ',');
+  }
+
+  res = calloc(items, sizeof(char *));
+  if(!res)
+    return FALSE;
+
+  for(i = 0, s = strtok_r(str, ",", &lasts); s && i < items;
+      s = strtok_r(NULL, ",", &lasts), i++)
+    res[i] = s;
+
+  *out = res;
+  *count = items;
+
+  return TRUE;
+}
+
+/*
+ * Break apart the pieces of an LDAP URL.
+ * Syntax:
+ *   ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext>
+ *
+ * <hostname> already known from 'conn->host.name'.
+ * <port>     already known from 'conn->remote_port'.
+ * extract the rest from 'data->state.path+1'. All fields are optional.
+ * e.g.
+ *   ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
+ * yields ludp->lud_dn = "".
+ *
+ * Defined in RFC4516 section 2.
+ */
+static int _ldap_url_parse2(struct Curl_easy *data,
+                            const struct connectdata *conn, LDAPURLDesc *ludp)
+{
+  int rc = LDAP_SUCCESS;
+  char *p;
+  char *path;
+  char *q = NULL;
+  char *query = NULL;
+  size_t i;
+
+  if(!data ||
+     !data->state.up.path ||
+     data->state.up.path[0] != '/' ||
+     !strncasecompare("LDAP", data->state.up.scheme, 4))
+    return LDAP_INVALID_SYNTAX;
+
+  ludp->lud_scope = LDAP_SCOPE_BASE;
+  ludp->lud_port  = conn->remote_port;
+  ludp->lud_host  = conn->host.name;
+
+  /* Duplicate the path */
+  p = path = strdup(data->state.up.path + 1);
+  if(!path)
+    return LDAP_NO_MEMORY;
+
+  /* Duplicate the query if present */
+  if(data->state.up.query) {
+    q = query = strdup(data->state.up.query);
+    if(!query) {
+      free(path);
+      return LDAP_NO_MEMORY;
+    }
+  }
+
+  /* Parse the DN (Distinguished Name) */
+  if(*p) {
+    char *dn = p;
+    char *unescaped;
+    CURLcode result;
+
+    LDAP_TRACE(("DN '%s'\n", dn));
+
+    /* Unescape the DN */
+    result = Curl_urldecode(dn, 0, &unescaped, NULL, REJECT_ZERO);
+    if(result) {
+      rc = LDAP_NO_MEMORY;
+
+      goto quit;
+    }
+
+#if defined(USE_WIN32_LDAP)
+    /* Convert the unescaped string to a tchar */
+    ludp->lud_dn = curlx_convert_UTF8_to_tchar(unescaped);
+
+    /* Free the unescaped string as we are done with it */
+    free(unescaped);
+
+    if(!ludp->lud_dn) {
+      rc = LDAP_NO_MEMORY;
+
+      goto quit;
+    }
+#else
+    ludp->lud_dn = unescaped;
+#endif
+  }
+
+  p = q;
+  if(!p)
+    goto quit;
+
+  /* Parse the attributes. skip "??" */
+  q = strchr(p, '?');
+  if(q)
+    *q++ = '\0';
+
+  if(*p) {
+    char **attributes;
+    size_t count = 0;
+
+    /* Split the string into an array of attributes */
+    if(!split_str(p, &attributes, &count)) {
+      rc = LDAP_NO_MEMORY;
+
+      goto quit;
+    }
+
+    /* Allocate our array (+1 for the NULL entry) */
+#if defined(USE_WIN32_LDAP)
+    ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *));
+#else
+    ludp->lud_attrs = calloc(count + 1, sizeof(char *));
+#endif
+    if(!ludp->lud_attrs) {
+      free(attributes);
+
+      rc = LDAP_NO_MEMORY;
+
+      goto quit;
+    }
+
+    for(i = 0; i < count; i++) {
+      char *unescaped;
+      CURLcode result;
+
+      LDAP_TRACE(("attr[%zu] '%s'\n", i, attributes[i]));
+
+      /* Unescape the attribute */
+      result = Curl_urldecode(attributes[i], 0, &unescaped, NULL,
+                              REJECT_ZERO);
+      if(result) {
+        free(attributes);
+
+        rc = LDAP_NO_MEMORY;
+
+        goto quit;
+      }
+
+#if defined(USE_WIN32_LDAP)
+      /* Convert the unescaped string to a tchar */
+      ludp->lud_attrs[i] = curlx_convert_UTF8_to_tchar(unescaped);
+
+      /* Free the unescaped string as we are done with it */
+      free(unescaped);
+
+      if(!ludp->lud_attrs[i]) {
+        free(attributes);
+
+        rc = LDAP_NO_MEMORY;
+
+        goto quit;
+      }
+#else
+      ludp->lud_attrs[i] = unescaped;
+#endif
+
+      ludp->lud_attrs_dups++;
+    }
+
+    free(attributes);
+  }
+
+  p = q;
+  if(!p)
+    goto quit;
+
+  /* Parse the scope. skip "??" */
+  q = strchr(p, '?');
+  if(q)
+    *q++ = '\0';
+
+  if(*p) {
+    ludp->lud_scope = str2scope(p);
+    if(ludp->lud_scope == -1) {
+      rc = LDAP_INVALID_SYNTAX;
+
+      goto quit;
+    }
+    LDAP_TRACE(("scope %d\n", ludp->lud_scope));
+  }
+
+  p = q;
+  if(!p)
+    goto quit;
+
+  /* Parse the filter */
+  q = strchr(p, '?');
+  if(q)
+    *q++ = '\0';
+
+  if(*p) {
+    char *filter = p;
+    char *unescaped;
+    CURLcode result;
+
+    LDAP_TRACE(("filter '%s'\n", filter));
+
+    /* Unescape the filter */
+    result = Curl_urldecode(filter, 0, &unescaped, NULL, REJECT_ZERO);
+    if(result) {
+      rc = LDAP_NO_MEMORY;
+
+      goto quit;
+    }
+
+#if defined(USE_WIN32_LDAP)
+    /* Convert the unescaped string to a tchar */
+    ludp->lud_filter = curlx_convert_UTF8_to_tchar(unescaped);
+
+    /* Free the unescaped string as we are done with it */
+    free(unescaped);
+
+    if(!ludp->lud_filter) {
+      rc = LDAP_NO_MEMORY;
+
+      goto quit;
+    }
+#else
+    ludp->lud_filter = unescaped;
+#endif
+  }
+
+  p = q;
+  if(p && !*p) {
+    rc = LDAP_INVALID_SYNTAX;
+
+    goto quit;
+  }
+
+quit:
+  free(path);
+  free(query);
+
+  return rc;
+}
+
+static int _ldap_url_parse(struct Curl_easy *data,
+                           const struct connectdata *conn,
+                           LDAPURLDesc **ludpp)
+{
+  LDAPURLDesc *ludp = calloc(1, sizeof(*ludp));
+  int rc;
+
+  *ludpp = NULL;
+  if(!ludp)
+    return LDAP_NO_MEMORY;
+
+  rc = _ldap_url_parse2(data, conn, ludp);
+  if(rc != LDAP_SUCCESS) {
+    _ldap_free_urldesc(ludp);
+    ludp = NULL;
+  }
+  *ludpp = ludp;
+  return (rc);
+}
+
+static void _ldap_free_urldesc(LDAPURLDesc *ludp)
+{
+  if(!ludp)
+    return;
+
+#if defined(USE_WIN32_LDAP)
+  curlx_unicodefree(ludp->lud_dn);
+  curlx_unicodefree(ludp->lud_filter);
+#else
+  free(ludp->lud_dn);
+  free(ludp->lud_filter);
+#endif
+
+  if(ludp->lud_attrs) {
+    size_t i;
+    for(i = 0; i < ludp->lud_attrs_dups; i++) {
+#if defined(USE_WIN32_LDAP)
+      curlx_unicodefree(ludp->lud_attrs[i]);
+#else
+      free(ludp->lud_attrs[i]);
+#endif
+    }
+    free(ludp->lud_attrs);
+  }
+
+  free(ludp);
+}
+#endif  /* !HAVE_LDAP_URL_PARSE */
+#endif  /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */
Index: trunk/src/libs/curl-8.7.1/lib/libcurl.plist
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/libcurl.plist	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/libcurl.plist	(revision 104083)
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+
+	<key>CFBundleExecutable</key>
+	<string>curl</string>
+
+	<key>CFBundleIdentifier</key>
+	<string>se.curl.libcurl</string>
+
+	<key>CFBundleVersion</key>
+	<string>8.7.1</string>
+
+	<key>CFBundleName</key>
+	<string>libcurl</string>
+
+	<key>CFBundlePackageType</key>
+	<string>FMWK</string>
+
+	<key>CFBundleSignature</key>
+	<string>????</string>
+
+	<key>CFBundleShortVersionString</key>
+	<string>libcurl 8.7.1</string>
+
+	<key>CFBundleGetInfoString</key>
+	<string>libcurl.plist 8.7.1</string>
+</dict>
+</plist>
Index: trunk/src/libs/curl-8.7.1/lib/libcurl.plist.in
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/libcurl.plist.in	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/libcurl.plist.in	(revision 104083)
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+
+	<key>CFBundleExecutable</key>
+	<string>curl</string>
+
+	<key>CFBundleIdentifier</key>
+	<string>se.curl.libcurl</string>
+
+	<key>CFBundleVersion</key>
+	<string>@CURL_PLIST_VERSION@</string>
+
+	<key>CFBundleName</key>
+	<string>libcurl</string>
+
+	<key>CFBundlePackageType</key>
+	<string>FMWK</string>
+
+	<key>CFBundleSignature</key>
+	<string>????</string>
+
+	<key>CFBundleShortVersionString</key>
+	<string>libcurl @CURL_PLIST_VERSION@</string>
+
+	<key>CFBundleGetInfoString</key>
+	<string>libcurl.plist @CURL_PLIST_VERSION@</string>
+</dict>
+</plist>
Index: trunk/src/libs/curl-8.7.1/lib/libcurl.rc
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/libcurl.rc	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/libcurl.rc	(revision 104083)
@@ -0,0 +1,65 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include <winver.h>
+#include "../include/curl/curlver.h"
+
+LANGUAGE  0, 0
+
+#define RC_VERSION  LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH, 0
+
+VS_VERSION_INFO VERSIONINFO
+  FILEVERSION     RC_VERSION
+  PRODUCTVERSION  RC_VERSION
+  FILEFLAGSMASK   VS_FFI_FILEFLAGSMASK
+#if defined(DEBUGBUILD) || defined(_DEBUG)
+  FILEFLAGS VS_FF_DEBUG
+#else
+  FILEFLAGS 0L
+#endif
+  FILEOS      VOS__WINDOWS32
+  FILETYPE    VFT_DLL
+  FILESUBTYPE 0L
+
+BEGIN
+  BLOCK "StringFileInfo"
+  BEGIN
+    BLOCK "040904b0"
+    BEGIN
+      VALUE "CompanyName",      "The curl library, https://curl.se/\0"
+      VALUE "FileDescription",  "libcurl Shared Library\0"
+      VALUE "FileVersion",      LIBCURL_VERSION "\0"
+      VALUE "InternalName",     "libcurl\0"
+      VALUE "OriginalFilename", "libcurl.dll\0"
+      VALUE "ProductName",      "The curl library\0"
+      VALUE "ProductVersion",   LIBCURL_VERSION "\0"
+      VALUE "LegalCopyright",   "Copyright (C) " LIBCURL_COPYRIGHT "\0"
+      VALUE "License",          "https://curl.se/docs/copyright.html\0"
+    END
+  END
+
+  BLOCK "VarFileInfo"
+  BEGIN
+    VALUE "Translation", 0x409, 1200
+  END
+END
Index: trunk/src/libs/curl-8.7.1/lib/libcurl.vers.in
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/libcurl.vers.in	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/libcurl.vers.in	(revision 104083)
@@ -0,0 +1,13 @@
+HIDDEN
+{
+  local:
+    __*;
+    _rest*;
+    _save*;
+};
+
+CURL_@CURL_LT_SHLIB_VERSIONED_FLAVOUR@4
+{
+  global: curl_*;
+  local: *;
+};
Index: trunk/src/libs/curl-8.7.1/lib/llist.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/llist.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/llist.c	(revision 104083)
@@ -0,0 +1,146 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "llist.h"
+#include "curl_memory.h"
+
+/* this must be the last include file */
+#include "memdebug.h"
+
+/*
+ * @unittest: 1300
+ */
+void
+Curl_llist_init(struct Curl_llist *l, Curl_llist_dtor dtor)
+{
+  l->size = 0;
+  l->dtor = dtor;
+  l->head = NULL;
+  l->tail = NULL;
+}
+
+/*
+ * Curl_llist_insert_next()
+ *
+ * Inserts a new list element after the given one 'e'. If the given existing
+ * entry is NULL and the list already has elements, the new one will be
+ * inserted first in the list.
+ *
+ * The 'ne' argument should be a pointer into the object to store.
+ *
+ * @unittest: 1300
+ */
+void
+Curl_llist_insert_next(struct Curl_llist *list, struct Curl_llist_element *e,
+                       const void *p,
+                       struct Curl_llist_element *ne)
+{
+  ne->ptr = (void *) p;
+  if(list->size == 0) {
+    list->head = ne;
+    list->head->prev = NULL;
+    list->head->next = NULL;
+    list->tail = ne;
+  }
+  else {
+    /* if 'e' is NULL here, we insert the new element first in the list */
+    ne->next = e?e->next:list->head;
+    ne->prev = e;
+    if(!e) {
+      list->head->prev = ne;
+      list->head = ne;
+    }
+    else if(e->next) {
+      e->next->prev = ne;
+    }
+    else {
+      list->tail = ne;
+    }
+    if(e)
+      e->next = ne;
+  }
+
+  ++list->size;
+}
+
+/*
+ * @unittest: 1300
+ */
+void
+Curl_llist_remove(struct Curl_llist *list, struct Curl_llist_element *e,
+                  void *user)
+{
+  void *ptr;
+  if(!e || list->size == 0)
+    return;
+
+  if(e == list->head) {
+    list->head = e->next;
+
+    if(!list->head)
+      list->tail = NULL;
+    else
+      e->next->prev = NULL;
+  }
+  else {
+    if(e->prev)
+      e->prev->next = e->next;
+
+    if(!e->next)
+      list->tail = e->prev;
+    else
+      e->next->prev = e->prev;
+  }
+
+  ptr = e->ptr;
+
+  e->ptr  = NULL;
+  e->prev = NULL;
+  e->next = NULL;
+
+  --list->size;
+
+  /* call the dtor() last for when it actually frees the 'e' memory itself */
+  if(list->dtor)
+    list->dtor(user, ptr);
+}
+
+void
+Curl_llist_destroy(struct Curl_llist *list, void *user)
+{
+  if(list) {
+    while(list->size > 0)
+      Curl_llist_remove(list, list->tail, user);
+  }
+}
+
+size_t
+Curl_llist_count(struct Curl_llist *list)
+{
+  return list->size;
+}
Index: trunk/src/libs/curl-8.7.1/lib/llist.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/llist.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/llist.h	(revision 104083)
@@ -0,0 +1,52 @@
+#ifndef HEADER_CURL_LLIST_H
+#define HEADER_CURL_LLIST_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include <stddef.h>
+
+typedef void (*Curl_llist_dtor)(void *, void *);
+
+struct Curl_llist_element {
+  void *ptr;
+  struct Curl_llist_element *prev;
+  struct Curl_llist_element *next;
+};
+
+struct Curl_llist {
+  struct Curl_llist_element *head;
+  struct Curl_llist_element *tail;
+  Curl_llist_dtor dtor;
+  size_t size;
+};
+
+void Curl_llist_init(struct Curl_llist *, Curl_llist_dtor);
+void Curl_llist_insert_next(struct Curl_llist *, struct Curl_llist_element *,
+                            const void *, struct Curl_llist_element *node);
+void Curl_llist_remove(struct Curl_llist *, struct Curl_llist_element *,
+                       void *);
+size_t Curl_llist_count(struct Curl_llist *);
+void Curl_llist_destroy(struct Curl_llist *, void *);
+#endif /* HEADER_CURL_LLIST_H */
Index: trunk/src/libs/curl-8.7.1/lib/macos.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/macos.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/macos.c	(revision 104083)
@@ -0,0 +1,55 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef CURL_MACOS_CALL_COPYPROXIES
+
+#include <curl/curl.h>
+
+#include "macos.h"
+
+#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
+
+CURLcode Curl_macos_init(void)
+{
+  {
+    /*
+     * The automagic conversion from IPv4 literals to IPv6 literals only
+     * works if the SCDynamicStoreCopyProxies system function gets called
+     * first. As Curl currently doesn't support system-wide HTTP proxies, we
+     * therefore don't use any value this function might return.
+     *
+     * This function is only available on macOS and is not needed for
+     * IPv4-only builds, hence the conditions for defining
+     * CURL_MACOS_CALL_COPYPROXIES in curl_setup.h.
+     */
+    CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
+    if(dict)
+      CFRelease(dict);
+  }
+  return CURLE_OK;
+}
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/macos.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/macos.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/macos.h	(revision 104083)
@@ -0,0 +1,39 @@
+#ifndef HEADER_CURL_MACOS_H
+#define HEADER_CURL_MACOS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef CURL_MACOS_CALL_COPYPROXIES
+
+CURLcode Curl_macos_init(void);
+
+#else
+
+#define Curl_macos_init() CURLE_OK
+
+#endif
+
+#endif /* HEADER_CURL_MACOS_H */
Index: trunk/src/libs/curl-8.7.1/lib/md4.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/md4.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/md4.c	(revision 104083)
@@ -0,0 +1,525 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_CURL_NTLM_CORE)
+
+#include <string.h>
+
+#include "strdup.h"
+#include "curl_md4.h"
+#include "warnless.h"
+
+#ifdef USE_OPENSSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) && !defined(USE_AMISSL)
+/* OpenSSL 3.0.0 marks the MD4 functions as deprecated */
+#define OPENSSL_NO_MD4
+#endif
+#endif /* USE_OPENSSL */
+
+#ifdef USE_WOLFSSL
+#include <wolfssl/options.h>
+#define VOID_MD4_INIT
+#ifdef NO_MD4
+#define WOLFSSL_NO_MD4
+#endif
+#endif
+
+#ifdef USE_MBEDTLS
+#include <mbedtls/version.h>
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+#include <mbedtls/mbedtls_config.h>
+#else
+#include <mbedtls/config.h>
+#endif
+#if(MBEDTLS_VERSION_NUMBER >= 0x02070000)
+  #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
+#endif
+#endif /* USE_MBEDTLS */
+
+#if defined(USE_GNUTLS)
+#include <nettle/md4.h>
+/* When OpenSSL or wolfSSL is available, we use their MD4 functions. */
+#elif defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4)
+#include <wolfssl/openssl/md4.h>
+#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4)
+#include <openssl/md4.h>
+#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
+              (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040) && \
+       defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \
+              (__MAC_OS_X_VERSION_MIN_REQUIRED < 101500)) || \
+      (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
+              (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000) && \
+       defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && \
+              (__IPHONE_OS_VERSION_MIN_REQUIRED < 130000))
+#define AN_APPLE_OS
+#include <CommonCrypto/CommonDigest.h>
+#elif defined(USE_WIN32_CRYPTO)
+#include <wincrypt.h>
+#elif(defined(USE_MBEDTLS) && defined(MBEDTLS_MD4_C))
+#include <mbedtls/md4.h>
+#endif
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+#if defined(USE_GNUTLS)
+
+typedef struct md4_ctx MD4_CTX;
+
+static int MD4_Init(MD4_CTX *ctx)
+{
+  md4_init(ctx);
+  return 1;
+}
+
+static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
+{
+  md4_update(ctx, size, data);
+}
+
+static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
+{
+  md4_digest(ctx, MD4_DIGEST_SIZE, result);
+}
+
+#elif defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4)
+
+#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4)
+
+#elif defined(AN_APPLE_OS)
+typedef CC_MD4_CTX MD4_CTX;
+
+static int MD4_Init(MD4_CTX *ctx)
+{
+  return CC_MD4_Init(ctx);
+}
+
+static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
+{
+  (void)CC_MD4_Update(ctx, data, (CC_LONG)size);
+}
+
+static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
+{
+  (void)CC_MD4_Final(result, ctx);
+}
+
+#elif defined(USE_WIN32_CRYPTO)
+
+struct md4_ctx {
+  HCRYPTPROV hCryptProv;
+  HCRYPTHASH hHash;
+};
+typedef struct md4_ctx MD4_CTX;
+
+static int MD4_Init(MD4_CTX *ctx)
+{
+  ctx->hCryptProv = 0;
+  ctx->hHash = 0;
+
+  if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
+                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+    return 0;
+
+  if(!CryptCreateHash(ctx->hCryptProv, CALG_MD4, 0, 0, &ctx->hHash)) {
+    CryptReleaseContext(ctx->hCryptProv, 0);
+    ctx->hCryptProv = 0;
+    return 0;
+  }
+
+  return 1;
+}
+
+static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
+{
+  CryptHashData(ctx->hHash, (BYTE *)data, (unsigned int) size, 0);
+}
+
+static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
+{
+  unsigned long length = 0;
+
+  CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
+  if(length == MD4_DIGEST_LENGTH)
+    CryptGetHashParam(ctx->hHash, HP_HASHVAL, result, &length, 0);
+
+  if(ctx->hHash)
+    CryptDestroyHash(ctx->hHash);
+
+  if(ctx->hCryptProv)
+    CryptReleaseContext(ctx->hCryptProv, 0);
+}
+
+#elif(defined(USE_MBEDTLS) && defined(MBEDTLS_MD4_C))
+
+struct md4_ctx {
+  void *data;
+  unsigned long size;
+};
+typedef struct md4_ctx MD4_CTX;
+
+static int MD4_Init(MD4_CTX *ctx)
+{
+  ctx->data = NULL;
+  ctx->size = 0;
+  return 1;
+}
+
+static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
+{
+  if(!ctx->data) {
+    ctx->data = Curl_memdup(data, size);
+    if(ctx->data)
+      ctx->size = size;
+  }
+}
+
+static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
+{
+  if(ctx->data) {
+#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
+    mbedtls_md4(ctx->data, ctx->size, result);
+#else
+    (void) mbedtls_md4_ret(ctx->data, ctx->size, result);
+#endif
+
+    Curl_safefree(ctx->data);
+    ctx->size = 0;
+  }
+}
+
+#else
+/* When no other crypto library is available, or the crypto library doesn't
+ * support MD4, we use this code segment this implementation of it
+ *
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD4 Message-Digest Algorithm (RFC 1320).
+ *
+ * Homepage:
+ https://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001.  No copyright is
+ * claimed, and the software is hereby placed in the public domain.  In case
+ * this attempt to disclaim copyright and place the software in the public
+ * domain is deemed null and void, then the software is Copyright (c) 2001
+ * Alexander Peslyak and it is hereby released to the general public under the
+ * following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+ *
+ * This differs from Colin Plumb's older public domain implementation in that
+ * no exactly 32-bit integer data type is required (any 32-bit or wider
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's.  No code from
+ * Colin Plumb's implementation has been reused; this comment merely compares
+ * the properties of the two independent implementations.
+ *
+ * The primary goals of this implementation are portability and ease of use.
+ * It is meant to be fast, but not as fast as possible.  Some known
+ * optimizations are not included to reduce source code size and avoid
+ * compile-time configuration.
+ */
+
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef unsigned int MD4_u32plus;
+
+struct md4_ctx {
+  MD4_u32plus lo, hi;
+  MD4_u32plus a, b, c, d;
+  unsigned char buffer[64];
+  MD4_u32plus block[16];
+};
+typedef struct md4_ctx MD4_CTX;
+
+static int MD4_Init(MD4_CTX *ctx);
+static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size);
+static void MD4_Final(unsigned char *result, MD4_CTX *ctx);
+
+/*
+ * The basic MD4 functions.
+ *
+ * F and G are optimized compared to their RFC 1320 definitions, with the
+ * optimization for F borrowed from Colin Plumb's MD5 implementation.
+ */
+#define F(x, y, z)                      ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z)                      (((x) & ((y) | (z))) | ((y) & (z)))
+#define H(x, y, z)                      ((x) ^ (y) ^ (z))
+
+/*
+ * The MD4 transformation for all three rounds.
+ */
+#define STEP(f, a, b, c, d, x, s) \
+        (a) += f((b), (c), (d)) + (x); \
+        (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s))));
+
+/*
+ * SET reads 4 input bytes in little-endian byte order and stores them
+ * in a properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures that tolerate unaligned
+ * memory accesses is just an optimization.  Nothing will break if it
+ * doesn't work.
+ */
+#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
+#define SET(n) \
+        (*(MD4_u32plus *)(void *)&ptr[(n) * 4])
+#define GET(n) \
+        SET(n)
+#else
+#define SET(n) \
+        (ctx->block[(n)] = \
+        (MD4_u32plus)ptr[(n) * 4] | \
+        ((MD4_u32plus)ptr[(n) * 4 + 1] << 8) | \
+        ((MD4_u32plus)ptr[(n) * 4 + 2] << 16) | \
+        ((MD4_u32plus)ptr[(n) * 4 + 3] << 24))
+#define GET(n) \
+        (ctx->block[(n)])
+#endif
+
+/*
+ * This processes one or more 64-byte data blocks, but does NOT update
+ * the bit counters.  There are no alignment requirements.
+ */
+static const void *body(MD4_CTX *ctx, const void *data, unsigned long size)
+{
+  const unsigned char *ptr;
+  MD4_u32plus a, b, c, d;
+
+  ptr = (const unsigned char *)data;
+
+  a = ctx->a;
+  b = ctx->b;
+  c = ctx->c;
+  d = ctx->d;
+
+  do {
+    MD4_u32plus saved_a, saved_b, saved_c, saved_d;
+
+    saved_a = a;
+    saved_b = b;
+    saved_c = c;
+    saved_d = d;
+
+/* Round 1 */
+    STEP(F, a, b, c, d, SET(0), 3)
+    STEP(F, d, a, b, c, SET(1), 7)
+    STEP(F, c, d, a, b, SET(2), 11)
+    STEP(F, b, c, d, a, SET(3), 19)
+    STEP(F, a, b, c, d, SET(4), 3)
+    STEP(F, d, a, b, c, SET(5), 7)
+    STEP(F, c, d, a, b, SET(6), 11)
+    STEP(F, b, c, d, a, SET(7), 19)
+    STEP(F, a, b, c, d, SET(8), 3)
+    STEP(F, d, a, b, c, SET(9), 7)
+    STEP(F, c, d, a, b, SET(10), 11)
+    STEP(F, b, c, d, a, SET(11), 19)
+    STEP(F, a, b, c, d, SET(12), 3)
+    STEP(F, d, a, b, c, SET(13), 7)
+    STEP(F, c, d, a, b, SET(14), 11)
+    STEP(F, b, c, d, a, SET(15), 19)
+
+/* Round 2 */
+    STEP(G, a, b, c, d, GET(0) + 0x5a827999, 3)
+    STEP(G, d, a, b, c, GET(4) + 0x5a827999, 5)
+    STEP(G, c, d, a, b, GET(8) + 0x5a827999, 9)
+    STEP(G, b, c, d, a, GET(12) + 0x5a827999, 13)
+    STEP(G, a, b, c, d, GET(1) + 0x5a827999, 3)
+    STEP(G, d, a, b, c, GET(5) + 0x5a827999, 5)
+    STEP(G, c, d, a, b, GET(9) + 0x5a827999, 9)
+    STEP(G, b, c, d, a, GET(13) + 0x5a827999, 13)
+    STEP(G, a, b, c, d, GET(2) + 0x5a827999, 3)
+    STEP(G, d, a, b, c, GET(6) + 0x5a827999, 5)
+    STEP(G, c, d, a, b, GET(10) + 0x5a827999, 9)
+    STEP(G, b, c, d, a, GET(14) + 0x5a827999, 13)
+    STEP(G, a, b, c, d, GET(3) + 0x5a827999, 3)
+    STEP(G, d, a, b, c, GET(7) + 0x5a827999, 5)
+    STEP(G, c, d, a, b, GET(11) + 0x5a827999, 9)
+    STEP(G, b, c, d, a, GET(15) + 0x5a827999, 13)
+
+/* Round 3 */
+    STEP(H, a, b, c, d, GET(0) + 0x6ed9eba1, 3)
+    STEP(H, d, a, b, c, GET(8) + 0x6ed9eba1, 9)
+    STEP(H, c, d, a, b, GET(4) + 0x6ed9eba1, 11)
+    STEP(H, b, c, d, a, GET(12) + 0x6ed9eba1, 15)
+    STEP(H, a, b, c, d, GET(2) + 0x6ed9eba1, 3)
+    STEP(H, d, a, b, c, GET(10) + 0x6ed9eba1, 9)
+    STEP(H, c, d, a, b, GET(6) + 0x6ed9eba1, 11)
+    STEP(H, b, c, d, a, GET(14) + 0x6ed9eba1, 15)
+    STEP(H, a, b, c, d, GET(1) + 0x6ed9eba1, 3)
+    STEP(H, d, a, b, c, GET(9) + 0x6ed9eba1, 9)
+    STEP(H, c, d, a, b, GET(5) + 0x6ed9eba1, 11)
+    STEP(H, b, c, d, a, GET(13) + 0x6ed9eba1, 15)
+    STEP(H, a, b, c, d, GET(3) + 0x6ed9eba1, 3)
+    STEP(H, d, a, b, c, GET(11) + 0x6ed9eba1, 9)
+    STEP(H, c, d, a, b, GET(7) + 0x6ed9eba1, 11)
+    STEP(H, b, c, d, a, GET(15) + 0x6ed9eba1, 15)
+
+    a += saved_a;
+    b += saved_b;
+    c += saved_c;
+    d += saved_d;
+
+    ptr += 64;
+  } while(size -= 64);
+
+  ctx->a = a;
+  ctx->b = b;
+  ctx->c = c;
+  ctx->d = d;
+
+  return ptr;
+}
+
+static int MD4_Init(MD4_CTX *ctx)
+{
+  ctx->a = 0x67452301;
+  ctx->b = 0xefcdab89;
+  ctx->c = 0x98badcfe;
+  ctx->d = 0x10325476;
+
+  ctx->lo = 0;
+  ctx->hi = 0;
+  return 1;
+}
+
+static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
+{
+  MD4_u32plus saved_lo;
+  unsigned long used;
+
+  saved_lo = ctx->lo;
+  ctx->lo = (saved_lo + size) & 0x1fffffff;
+  if(ctx->lo < saved_lo)
+    ctx->hi++;
+  ctx->hi += (MD4_u32plus)size >> 29;
+
+  used = saved_lo & 0x3f;
+
+  if(used) {
+    unsigned long available = 64 - used;
+
+    if(size < available) {
+      memcpy(&ctx->buffer[used], data, size);
+      return;
+    }
+
+    memcpy(&ctx->buffer[used], data, available);
+    data = (const unsigned char *)data + available;
+    size -= available;
+    body(ctx, ctx->buffer, 64);
+  }
+
+  if(size >= 64) {
+    data = body(ctx, data, size & ~(unsigned long)0x3f);
+    size &= 0x3f;
+  }
+
+  memcpy(ctx->buffer, data, size);
+}
+
+static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
+{
+  unsigned long used, available;
+
+  used = ctx->lo & 0x3f;
+
+  ctx->buffer[used++] = 0x80;
+
+  available = 64 - used;
+
+  if(available < 8) {
+    memset(&ctx->buffer[used], 0, available);
+    body(ctx, ctx->buffer, 64);
+    used = 0;
+    available = 64;
+  }
+
+  memset(&ctx->buffer[used], 0, available - 8);
+
+  ctx->lo <<= 3;
+  ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
+  ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
+  ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
+  ctx->buffer[59] = curlx_ultouc((ctx->lo >> 24)&0xff);
+  ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
+  ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
+  ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
+  ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);
+
+  body(ctx, ctx->buffer, 64);
+
+  result[0] = curlx_ultouc((ctx->a)&0xff);
+  result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
+  result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
+  result[3] = curlx_ultouc(ctx->a >> 24);
+  result[4] = curlx_ultouc((ctx->b)&0xff);
+  result[5] = curlx_ultouc((ctx->b >> 8)&0xff);
+  result[6] = curlx_ultouc((ctx->b >> 16)&0xff);
+  result[7] = curlx_ultouc(ctx->b >> 24);
+  result[8] = curlx_ultouc((ctx->c)&0xff);
+  result[9] = curlx_ultouc((ctx->c >> 8)&0xff);
+  result[10] = curlx_ultouc((ctx->c >> 16)&0xff);
+  result[11] = curlx_ultouc(ctx->c >> 24);
+  result[12] = curlx_ultouc((ctx->d)&0xff);
+  result[13] = curlx_ultouc((ctx->d >> 8)&0xff);
+  result[14] = curlx_ultouc((ctx->d >> 16)&0xff);
+  result[15] = curlx_ultouc(ctx->d >> 24);
+
+  memset(ctx, 0, sizeof(*ctx));
+}
+
+#endif /* CRYPTO LIBS */
+
+CURLcode Curl_md4it(unsigned char *output, const unsigned char *input,
+                    const size_t len)
+{
+  MD4_CTX ctx;
+
+#ifdef VOID_MD4_INIT
+  MD4_Init(&ctx);
+#else
+  if(!MD4_Init(&ctx))
+    return CURLE_FAILED_INIT;
+#endif
+
+  MD4_Update(&ctx, input, curlx_uztoui(len));
+  MD4_Final(output, &ctx);
+  return CURLE_OK;
+}
+
+#endif /* USE_CURL_NTLM_CORE */
Index: trunk/src/libs/curl-8.7.1/lib/md5.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/md5.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/md5.c	(revision 104083)
@@ -0,0 +1,656 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \
+    || !defined(CURL_DISABLE_DIGEST_AUTH)
+
+#include <string.h>
+#include <curl/curl.h>
+
+#include "curl_md5.h"
+#include "curl_hmac.h"
+#include "warnless.h"
+
+#ifdef USE_MBEDTLS
+#include <mbedtls/version.h>
+
+#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \
+   (MBEDTLS_VERSION_NUMBER < 0x03000000)
+  #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
+#endif
+#endif /* USE_MBEDTLS */
+
+#ifdef USE_OPENSSL
+  #include <openssl/opensslconf.h>
+  #if !defined(OPENSSL_NO_MD5) && !defined(OPENSSL_NO_DEPRECATED_3_0)
+    #define USE_OPENSSL_MD5
+  #endif
+#endif
+
+#ifdef USE_WOLFSSL
+  #include <wolfssl/options.h>
+  #ifndef NO_MD5
+    #define USE_WOLFSSL_MD5
+  #endif
+#endif
+
+#if defined(USE_GNUTLS)
+#include <nettle/md5.h>
+#elif defined(USE_OPENSSL_MD5)
+#include <openssl/md5.h>
+#elif defined(USE_WOLFSSL_MD5)
+#include <wolfssl/openssl/md5.h>
+#elif defined(USE_MBEDTLS)
+#include <mbedtls/md5.h>
+#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
+              (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040) && \
+       defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \
+              (__MAC_OS_X_VERSION_MIN_REQUIRED < 101500)) || \
+      (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
+              (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000) && \
+       defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && \
+              (__IPHONE_OS_VERSION_MIN_REQUIRED < 130000))
+#define AN_APPLE_OS
+#include <CommonCrypto/CommonDigest.h>
+#elif defined(USE_WIN32_CRYPTO)
+#include <wincrypt.h>
+#endif
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if defined(USE_GNUTLS)
+
+typedef struct md5_ctx my_md5_ctx;
+
+static CURLcode my_md5_init(my_md5_ctx *ctx)
+{
+  md5_init(ctx);
+  return CURLE_OK;
+}
+
+static void my_md5_update(my_md5_ctx *ctx,
+                          const unsigned char *input,
+                          unsigned int inputLen)
+{
+  md5_update(ctx, inputLen, input);
+}
+
+static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
+{
+  md5_digest(ctx, 16, digest);
+}
+
+#elif defined(USE_OPENSSL_MD5) || defined(USE_WOLFSSL_MD5)
+
+typedef MD5_CTX my_md5_ctx;
+
+static CURLcode my_md5_init(my_md5_ctx *ctx)
+{
+  if(!MD5_Init(ctx))
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+static void my_md5_update(my_md5_ctx *ctx,
+                          const unsigned char *input,
+                          unsigned int len)
+{
+  (void)MD5_Update(ctx, input, len);
+}
+
+static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
+{
+  (void)MD5_Final(digest, ctx);
+}
+
+#elif defined(USE_MBEDTLS)
+
+typedef mbedtls_md5_context my_md5_ctx;
+
+static CURLcode my_md5_init(my_md5_ctx *ctx)
+{
+#if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
+  if(mbedtls_md5_starts(ctx))
+    return CURLE_OUT_OF_MEMORY;
+#elif defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
+  if(mbedtls_md5_starts_ret(ctx))
+    return CURLE_OUT_OF_MEMORY;
+#else
+  (void)mbedtls_md5_starts(ctx);
+#endif
+  return CURLE_OK;
+}
+
+static void my_md5_update(my_md5_ctx *ctx,
+                          const unsigned char *data,
+                          unsigned int length)
+{
+#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
+  (void) mbedtls_md5_update(ctx, data, length);
+#else
+  (void) mbedtls_md5_update_ret(ctx, data, length);
+#endif
+}
+
+static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
+{
+#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
+  (void) mbedtls_md5_finish(ctx, digest);
+#else
+  (void) mbedtls_md5_finish_ret(ctx, digest);
+#endif
+}
+
+#elif defined(AN_APPLE_OS)
+
+/* For Apple operating systems: CommonCrypto has the functions we need.
+   These functions are available on Tiger and later, as well as iOS 2.0
+   and later. If you're building for an older cat, well, sorry.
+
+   Declaring the functions as static like this seems to be a bit more
+   reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */
+#  define my_md5_ctx CC_MD5_CTX
+
+static CURLcode my_md5_init(my_md5_ctx *ctx)
+{
+  if(!CC_MD5_Init(ctx))
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+static void my_md5_update(my_md5_ctx *ctx,
+                          const unsigned char *input,
+                          unsigned int inputLen)
+{
+  CC_MD5_Update(ctx, input, inputLen);
+}
+
+static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
+{
+  CC_MD5_Final(digest, ctx);
+}
+
+#elif defined(USE_WIN32_CRYPTO)
+
+struct md5_ctx {
+  HCRYPTPROV hCryptProv;
+  HCRYPTHASH hHash;
+};
+typedef struct md5_ctx my_md5_ctx;
+
+static CURLcode my_md5_init(my_md5_ctx *ctx)
+{
+  if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
+                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+    return CURLE_OUT_OF_MEMORY;
+
+  if(!CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash)) {
+    CryptReleaseContext(ctx->hCryptProv, 0);
+    ctx->hCryptProv = 0;
+    return CURLE_FAILED_INIT;
+  }
+
+  return CURLE_OK;
+}
+
+static void my_md5_update(my_md5_ctx *ctx,
+                          const unsigned char *input,
+                          unsigned int inputLen)
+{
+  CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
+}
+
+static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
+{
+  unsigned long length = 0;
+  CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
+  if(length == 16)
+    CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
+  if(ctx->hHash)
+    CryptDestroyHash(ctx->hHash);
+  if(ctx->hCryptProv)
+    CryptReleaseContext(ctx->hCryptProv, 0);
+}
+
+#else
+
+/* When no other crypto library is available we use this code segment */
+
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001.  No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+ *
+ * This differs from Colin Plumb's older public domain implementation in that
+ * no exactly 32-bit integer data type is required (any 32-bit or wider
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's.  No code from
+ * Colin Plumb's implementation has been reused; this comment merely compares
+ * the properties of the two independent implementations.
+ *
+ * The primary goals of this implementation are portability and ease of use.
+ * It is meant to be fast, but not as fast as possible.  Some known
+ * optimizations are not included to reduce source code size and avoid
+ * compile-time configuration.
+ */
+
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef unsigned int MD5_u32plus;
+
+struct md5_ctx {
+  MD5_u32plus lo, hi;
+  MD5_u32plus a, b, c, d;
+  unsigned char buffer[64];
+  MD5_u32plus block[16];
+};
+typedef struct md5_ctx my_md5_ctx;
+
+static CURLcode my_md5_init(my_md5_ctx *ctx);
+static void my_md5_update(my_md5_ctx *ctx, const void *data,
+                          unsigned long size);
+static void my_md5_final(unsigned char *result, my_md5_ctx *ctx);
+
+/*
+ * The basic MD5 functions.
+ *
+ * F and G are optimized compared to their RFC 1321 definitions for
+ * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
+ * implementation.
+ */
+#define F(x, y, z)                      ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z)                      ((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z)                      (((x) ^ (y)) ^ (z))
+#define H2(x, y, z)                     ((x) ^ ((y) ^ (z)))
+#define I(x, y, z)                      ((y) ^ ((x) | ~(z)))
+
+/*
+ * The MD5 transformation for all four rounds.
+ */
+#define STEP(f, a, b, c, d, x, t, s) \
+        (a) += f((b), (c), (d)) + (x) + (t); \
+        (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+        (a) += (b);
+
+/*
+ * SET reads 4 input bytes in little-endian byte order and stores them
+ * in a properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures that tolerate unaligned
+ * memory accesses is just an optimization.  Nothing will break if it
+ * doesn't work.
+ */
+#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
+#define SET(n) \
+        (*(MD5_u32plus *)(void *)&ptr[(n) * 4])
+#define GET(n) \
+        SET(n)
+#else
+#define SET(n) \
+        (ctx->block[(n)] = \
+        (MD5_u32plus)ptr[(n) * 4] | \
+        ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
+        ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
+        ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
+#define GET(n) \
+        (ctx->block[(n)])
+#endif
+
+/*
+ * This processes one or more 64-byte data blocks, but does NOT update
+ * the bit counters.  There are no alignment requirements.
+ */
+static const void *body(my_md5_ctx *ctx, const void *data, unsigned long size)
+{
+  const unsigned char *ptr;
+  MD5_u32plus a, b, c, d;
+
+  ptr = (const unsigned char *)data;
+
+  a = ctx->a;
+  b = ctx->b;
+  c = ctx->c;
+  d = ctx->d;
+
+  do {
+    MD5_u32plus saved_a, saved_b, saved_c, saved_d;
+
+    saved_a = a;
+    saved_b = b;
+    saved_c = c;
+    saved_d = d;
+
+/* Round 1 */
+    STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
+    STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+    STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+    STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+    STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+    STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+    STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+    STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+    STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+    STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+    STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+    STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+    STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+    STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+    STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+    STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+
+/* Round 2 */
+    STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+    STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+    STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+    STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+    STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+    STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+    STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+    STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+    STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+    STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+    STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+    STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+    STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+    STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+    STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+    STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+
+/* Round 3 */
+    STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+    STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
+    STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+    STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
+    STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+    STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+    STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+    STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
+    STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+    STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
+    STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+    STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
+    STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+    STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
+    STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+    STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
+
+/* Round 4 */
+    STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+    STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+    STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+    STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+    STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+    STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+    STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+    STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+    STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+    STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+    STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+    STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+    STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+    STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+    STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+    STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
+
+    a += saved_a;
+    b += saved_b;
+    c += saved_c;
+    d += saved_d;
+
+    ptr += 64;
+  } while(size -= 64);
+
+  ctx->a = a;
+  ctx->b = b;
+  ctx->c = c;
+  ctx->d = d;
+
+  return ptr;
+}
+
+static CURLcode my_md5_init(my_md5_ctx *ctx)
+{
+  ctx->a = 0x67452301;
+  ctx->b = 0xefcdab89;
+  ctx->c = 0x98badcfe;
+  ctx->d = 0x10325476;
+
+  ctx->lo = 0;
+  ctx->hi = 0;
+
+  return CURLE_OK;
+}
+
+static void my_md5_update(my_md5_ctx *ctx, const void *data,
+                          unsigned long size)
+{
+  MD5_u32plus saved_lo;
+  unsigned long used;
+
+  saved_lo = ctx->lo;
+  ctx->lo = (saved_lo + size) & 0x1fffffff;
+  if(ctx->lo < saved_lo)
+    ctx->hi++;
+  ctx->hi += (MD5_u32plus)size >> 29;
+
+  used = saved_lo & 0x3f;
+
+  if(used) {
+    unsigned long available = 64 - used;
+
+    if(size < available) {
+      memcpy(&ctx->buffer[used], data, size);
+      return;
+    }
+
+    memcpy(&ctx->buffer[used], data, available);
+    data = (const unsigned char *)data + available;
+    size -= available;
+    body(ctx, ctx->buffer, 64);
+  }
+
+  if(size >= 64) {
+    data = body(ctx, data, size & ~(unsigned long)0x3f);
+    size &= 0x3f;
+  }
+
+  memcpy(ctx->buffer, data, size);
+}
+
+static void my_md5_final(unsigned char *result, my_md5_ctx *ctx)
+{
+  unsigned long used, available;
+
+  used = ctx->lo & 0x3f;
+
+  ctx->buffer[used++] = 0x80;
+
+  available = 64 - used;
+
+  if(available < 8) {
+    memset(&ctx->buffer[used], 0, available);
+    body(ctx, ctx->buffer, 64);
+    used = 0;
+    available = 64;
+  }
+
+  memset(&ctx->buffer[used], 0, available - 8);
+
+  ctx->lo <<= 3;
+  ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
+  ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
+  ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
+  ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24);
+  ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
+  ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
+  ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
+  ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);
+
+  body(ctx, ctx->buffer, 64);
+
+  result[0] = curlx_ultouc((ctx->a)&0xff);
+  result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
+  result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
+  result[3] = curlx_ultouc(ctx->a >> 24);
+  result[4] = curlx_ultouc((ctx->b)&0xff);
+  result[5] = curlx_ultouc((ctx->b >> 8)&0xff);
+  result[6] = curlx_ultouc((ctx->b >> 16)&0xff);
+  result[7] = curlx_ultouc(ctx->b >> 24);
+  result[8] = curlx_ultouc((ctx->c)&0xff);
+  result[9] = curlx_ultouc((ctx->c >> 8)&0xff);
+  result[10] = curlx_ultouc((ctx->c >> 16)&0xff);
+  result[11] = curlx_ultouc(ctx->c >> 24);
+  result[12] = curlx_ultouc((ctx->d)&0xff);
+  result[13] = curlx_ultouc((ctx->d >> 8)&0xff);
+  result[14] = curlx_ultouc((ctx->d >> 16)&0xff);
+  result[15] = curlx_ultouc(ctx->d >> 24);
+
+  memset(ctx, 0, sizeof(*ctx));
+}
+
+#endif /* CRYPTO LIBS */
+
+const struct HMAC_params Curl_HMAC_MD5[] = {
+  {
+    /* Hash initialization function. */
+    CURLX_FUNCTION_CAST(HMAC_hinit_func, my_md5_init),
+    /* Hash update function. */
+    CURLX_FUNCTION_CAST(HMAC_hupdate_func, my_md5_update),
+    /* Hash computation end function. */
+    CURLX_FUNCTION_CAST(HMAC_hfinal_func, my_md5_final),
+    /* Size of hash context structure. */
+    sizeof(my_md5_ctx),
+    /* Maximum key length. */
+    64,
+    /* Result size. */
+    16
+  }
+};
+
+const struct MD5_params Curl_DIGEST_MD5[] = {
+  {
+    /* Digest initialization function */
+    CURLX_FUNCTION_CAST(Curl_MD5_init_func, my_md5_init),
+    /* Digest update function */
+    CURLX_FUNCTION_CAST(Curl_MD5_update_func, my_md5_update),
+    /* Digest computation end function */
+    CURLX_FUNCTION_CAST(Curl_MD5_final_func, my_md5_final),
+    /* Size of digest context struct */
+    sizeof(my_md5_ctx),
+    /* Result size */
+    16
+  }
+};
+
+/*
+ * @unittest: 1601
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_md5it(unsigned char *outbuffer, const unsigned char *input,
+                    const size_t len)
+{
+  CURLcode result;
+  my_md5_ctx ctx;
+
+  result = my_md5_init(&ctx);
+  if(!result) {
+    my_md5_update(&ctx, input, curlx_uztoui(len));
+    my_md5_final(outbuffer, &ctx);
+  }
+  return result;
+}
+
+struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params)
+{
+  struct MD5_context *ctxt;
+
+  /* Create MD5 context */
+  ctxt = malloc(sizeof(*ctxt));
+
+  if(!ctxt)
+    return ctxt;
+
+  ctxt->md5_hashctx = malloc(md5params->md5_ctxtsize);
+
+  if(!ctxt->md5_hashctx) {
+    free(ctxt);
+    return NULL;
+  }
+
+  ctxt->md5_hash = md5params;
+
+  if((*md5params->md5_init_func)(ctxt->md5_hashctx)) {
+    free(ctxt->md5_hashctx);
+    free(ctxt);
+    return NULL;
+  }
+
+  return ctxt;
+}
+
+CURLcode Curl_MD5_update(struct MD5_context *context,
+                         const unsigned char *data,
+                         unsigned int len)
+{
+  (*context->md5_hash->md5_update_func)(context->md5_hashctx, data, len);
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_MD5_final(struct MD5_context *context, unsigned char *result)
+{
+  (*context->md5_hash->md5_final_func)(result, context->md5_hashctx);
+
+  free(context->md5_hashctx);
+  free(context);
+
+  return CURLE_OK;
+}
+
+#endif /* Using NTLM (without SSPI) || Digest */
Index: trunk/src/libs/curl-8.7.1/lib/memdebug.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/memdebug.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/memdebug.c	(revision 104083)
@@ -0,0 +1,463 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef CURLDEBUG
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+
+#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+struct memdebug {
+  size_t size;
+  union {
+    curl_off_t o;
+    double d;
+    void *p;
+  } mem[1];
+  /* I'm hoping this is the thing with the strictest alignment
+   * requirements.  That also means we waste some space :-( */
+};
+
+/*
+ * Note that these debug functions are very simple and they are meant to
+ * remain so. For advanced analysis, record a log file and write perl scripts
+ * to analyze them!
+ *
+ * Don't use these with multithreaded test programs!
+ */
+
+FILE *curl_dbg_logfile = NULL;
+static bool registered_cleanup = FALSE; /* atexit registered cleanup */
+static bool memlimit = FALSE; /* enable memory limit */
+static long memsize = 0;  /* set number of mallocs allowed */
+
+/* LeakSantizier (LSAN) calls _exit() instead of exit() when a leak is detected
+   on exit so the logfile must be closed explicitly or data could be lost.
+   Though _exit() does not call atexit handlers such as this, LSAN's call to
+   _exit() comes after the atexit handlers are called. curl/curl#6620 */
+static void curl_dbg_cleanup(void)
+{
+  if(curl_dbg_logfile &&
+     curl_dbg_logfile != stderr &&
+     curl_dbg_logfile != stdout) {
+    fclose(curl_dbg_logfile);
+  }
+  curl_dbg_logfile = NULL;
+}
+
+/* this sets the log file name */
+void curl_dbg_memdebug(const char *logname)
+{
+  if(!curl_dbg_logfile) {
+    if(logname && *logname)
+      curl_dbg_logfile = fopen(logname, FOPEN_WRITETEXT);
+    else
+      curl_dbg_logfile = stderr;
+#ifdef MEMDEBUG_LOG_SYNC
+    /* Flush the log file after every line so the log isn't lost in a crash */
+    if(curl_dbg_logfile)
+      setbuf(curl_dbg_logfile, (char *)NULL);
+#endif
+  }
+  if(!registered_cleanup)
+    registered_cleanup = !atexit(curl_dbg_cleanup);
+}
+
+/* This function sets the number of malloc() calls that should return
+   successfully! */
+void curl_dbg_memlimit(long limit)
+{
+  if(!memlimit) {
+    memlimit = TRUE;
+    memsize = limit;
+  }
+}
+
+/* returns TRUE if this isn't allowed! */
+static bool countcheck(const char *func, int line, const char *source)
+{
+  /* if source is NULL, then the call is made internally and this check
+     should not be made */
+  if(memlimit && source) {
+    if(!memsize) {
+      /* log to file */
+      curl_dbg_log("LIMIT %s:%d %s reached memlimit\n",
+                   source, line, func);
+      /* log to stderr also */
+      fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
+              source, line, func);
+      fflush(curl_dbg_logfile); /* because it might crash now */
+      errno = ENOMEM;
+      return TRUE; /* RETURN ERROR! */
+    }
+    else
+      memsize--; /* countdown */
+
+
+  }
+
+  return FALSE; /* allow this */
+}
+
+ALLOC_FUNC void *curl_dbg_malloc(size_t wantedsize,
+                                 int line, const char *source)
+{
+  struct memdebug *mem;
+  size_t size;
+
+  DEBUGASSERT(wantedsize != 0);
+
+  if(countcheck("malloc", line, source))
+    return NULL;
+
+  /* alloc at least 64 bytes */
+  size = sizeof(struct memdebug) + wantedsize;
+
+  mem = (Curl_cmalloc)(size);
+  if(mem) {
+    mem->size = wantedsize;
+  }
+
+  if(source)
+    curl_dbg_log("MEM %s:%d malloc(%zu) = %p\n",
+                 source, line, wantedsize,
+                 mem ? (void *)mem->mem : (void *)0);
+
+  return (mem ? mem->mem : NULL);
+}
+
+ALLOC_FUNC void *curl_dbg_calloc(size_t wanted_elements, size_t wanted_size,
+                                 int line, const char *source)
+{
+  struct memdebug *mem;
+  size_t size, user_size;
+
+  DEBUGASSERT(wanted_elements != 0);
+  DEBUGASSERT(wanted_size != 0);
+
+  if(countcheck("calloc", line, source))
+    return NULL;
+
+  /* alloc at least 64 bytes */
+  user_size = wanted_size * wanted_elements;
+  size = sizeof(struct memdebug) + user_size;
+
+  mem = (Curl_ccalloc)(1, size);
+  if(mem)
+    mem->size = user_size;
+
+  if(source)
+    curl_dbg_log("MEM %s:%d calloc(%zu,%zu) = %p\n",
+                 source, line, wanted_elements, wanted_size,
+                 mem ? (void *)mem->mem : (void *)0);
+
+  return (mem ? mem->mem : NULL);
+}
+
+ALLOC_FUNC char *curl_dbg_strdup(const char *str,
+                                 int line, const char *source)
+{
+  char *mem;
+  size_t len;
+
+  DEBUGASSERT(str != NULL);
+
+  if(countcheck("strdup", line, source))
+    return NULL;
+
+  len = strlen(str) + 1;
+
+  mem = curl_dbg_malloc(len, 0, NULL); /* NULL prevents logging */
+  if(mem)
+    memcpy(mem, str, len);
+
+  if(source)
+    curl_dbg_log("MEM %s:%d strdup(%p) (%zu) = %p\n",
+                 source, line, (const void *)str, len, (const void *)mem);
+
+  return mem;
+}
+
+#if defined(_WIN32) && defined(UNICODE)
+ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str,
+                                    int line, const char *source)
+{
+  wchar_t *mem;
+  size_t wsiz, bsiz;
+
+  DEBUGASSERT(str != NULL);
+
+  if(countcheck("wcsdup", line, source))
+    return NULL;
+
+  wsiz = wcslen(str) + 1;
+  bsiz = wsiz * sizeof(wchar_t);
+
+  mem = curl_dbg_malloc(bsiz, 0, NULL); /* NULL prevents logging */
+  if(mem)
+    memcpy(mem, str, bsiz);
+
+  if(source)
+    curl_dbg_log("MEM %s:%d wcsdup(%p) (%zu) = %p\n",
+                source, line, (void *)str, bsiz, (void *)mem);
+
+  return mem;
+}
+#endif
+
+/* We provide a realloc() that accepts a NULL as pointer, which then
+   performs a malloc(). In order to work with ares. */
+void *curl_dbg_realloc(void *ptr, size_t wantedsize,
+                      int line, const char *source)
+{
+  struct memdebug *mem = NULL;
+
+  size_t size = sizeof(struct memdebug) + wantedsize;
+
+  DEBUGASSERT(wantedsize != 0);
+
+  if(countcheck("realloc", line, source))
+    return NULL;
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:1684)
+   /* 1684: conversion from pointer to same-sized integral type */
+#endif
+
+  if(ptr)
+    mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+
+  mem = (Curl_crealloc)(mem, size);
+  if(source)
+    curl_dbg_log("MEM %s:%d realloc(%p, %zu) = %p\n",
+                source, line, (void *)ptr, wantedsize,
+                mem ? (void *)mem->mem : (void *)0);
+
+  if(mem) {
+    mem->size = wantedsize;
+    return mem->mem;
+  }
+
+  return NULL;
+}
+
+void curl_dbg_free(void *ptr, int line, const char *source)
+{
+  if(ptr) {
+    struct memdebug *mem;
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:1684)
+   /* 1684: conversion from pointer to same-sized integral type */
+#endif
+
+    mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+
+    /* free for real */
+    (Curl_cfree)(mem);
+  }
+
+  if(source && ptr)
+    curl_dbg_log("MEM %s:%d free(%p)\n", source, line, (void *)ptr);
+}
+
+curl_socket_t curl_dbg_socket(int domain, int type, int protocol,
+                             int line, const char *source)
+{
+  curl_socket_t sockfd;
+
+  if(countcheck("socket", line, source))
+    return CURL_SOCKET_BAD;
+
+  sockfd = socket(domain, type, protocol);
+
+  if(source && (sockfd != CURL_SOCKET_BAD))
+    curl_dbg_log("FD %s:%d socket() = %" CURL_FORMAT_SOCKET_T "\n",
+                 source, line, sockfd);
+
+  return sockfd;
+}
+
+SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd,
+                            SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf,
+                            SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, int line,
+                            const char *source)
+{
+  SEND_TYPE_RETV rc;
+  if(countcheck("send", line, source))
+    return -1;
+  rc = send(sockfd, buf, len, flags);
+  if(source)
+    curl_dbg_log("SEND %s:%d send(%lu) = %ld\n",
+                source, line, (unsigned long)len, (long)rc);
+  return rc;
+}
+
+RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf,
+                            RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, int line,
+                            const char *source)
+{
+  RECV_TYPE_RETV rc;
+  if(countcheck("recv", line, source))
+    return -1;
+  rc = recv(sockfd, buf, len, flags);
+  if(source)
+    curl_dbg_log("RECV %s:%d recv(%lu) = %ld\n",
+                source, line, (unsigned long)len, (long)rc);
+  return rc;
+}
+
+#ifdef HAVE_SOCKETPAIR
+int curl_dbg_socketpair(int domain, int type, int protocol,
+                       curl_socket_t socket_vector[2],
+                       int line, const char *source)
+{
+  int res = socketpair(domain, type, protocol, socket_vector);
+
+  if(source && (0 == res))
+    curl_dbg_log("FD %s:%d socketpair() = "
+      "%" CURL_FORMAT_SOCKET_T " %" CURL_FORMAT_SOCKET_T "\n",
+      source, line, socket_vector[0], socket_vector[1]);
+
+  return res;
+}
+#endif
+
+curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen,
+                             int line, const char *source)
+{
+  struct sockaddr *addr = (struct sockaddr *)saddr;
+  curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
+
+  curl_socket_t sockfd = accept(s, addr, addrlen);
+
+  if(source && (sockfd != CURL_SOCKET_BAD))
+    curl_dbg_log("FD %s:%d accept() = %" CURL_FORMAT_SOCKET_T "\n",
+                 source, line, sockfd);
+
+  return sockfd;
+}
+
+/* separate function to allow libcurl to mark a "faked" close */
+void curl_dbg_mark_sclose(curl_socket_t sockfd, int line, const char *source)
+{
+  if(source)
+    curl_dbg_log("FD %s:%d sclose(%" CURL_FORMAT_SOCKET_T ")\n",
+                 source, line, sockfd);
+}
+
+/* this is our own defined way to close sockets on *ALL* platforms */
+int curl_dbg_sclose(curl_socket_t sockfd, int line, const char *source)
+{
+  int res = sclose(sockfd);
+  curl_dbg_mark_sclose(sockfd, line, source);
+  return res;
+}
+
+ALLOC_FUNC FILE *curl_dbg_fopen(const char *file, const char *mode,
+                                int line, const char *source)
+{
+  FILE *res = fopen(file, mode);
+
+  if(source)
+    curl_dbg_log("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
+                source, line, file, mode, (void *)res);
+
+  return res;
+}
+
+ALLOC_FUNC FILE *curl_dbg_fdopen(int filedes, const char *mode,
+                                 int line, const char *source)
+{
+  FILE *res = fdopen(filedes, mode);
+  if(source)
+    curl_dbg_log("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
+                 source, line, filedes, mode, (void *)res);
+  return res;
+}
+
+int curl_dbg_fclose(FILE *file, int line, const char *source)
+{
+  int res;
+
+  DEBUGASSERT(file != NULL);
+
+  if(source)
+    curl_dbg_log("FILE %s:%d fclose(%p)\n",
+                 source, line, (void *)file);
+
+  res = fclose(file);
+
+  return res;
+}
+
+#define LOGLINE_BUFSIZE  1024
+
+/* this does the writing to the memory tracking log file */
+void curl_dbg_log(const char *format, ...)
+{
+  char *buf;
+  int nchars;
+  va_list ap;
+
+  if(!curl_dbg_logfile)
+    return;
+
+  buf = (Curl_cmalloc)(LOGLINE_BUFSIZE);
+  if(!buf)
+    return;
+
+  va_start(ap, format);
+  nchars = mvsnprintf(buf, LOGLINE_BUFSIZE, format, ap);
+  va_end(ap);
+
+  if(nchars > LOGLINE_BUFSIZE - 1)
+    nchars = LOGLINE_BUFSIZE - 1;
+
+  if(nchars > 0)
+    fwrite(buf, 1, (size_t)nchars, curl_dbg_logfile);
+
+  (Curl_cfree)(buf);
+}
+
+#endif /* CURLDEBUG */
Index: trunk/src/libs/curl-8.7.1/lib/memdebug.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/memdebug.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/memdebug.h	(revision 104083)
@@ -0,0 +1,202 @@
+#ifndef HEADER_CURL_MEMDEBUG_H
+#define HEADER_CURL_MEMDEBUG_H
+#ifdef CURLDEBUG
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * CAUTION: this header is designed to work when included by the app-side
+ * as well as the library. Do not mix with library internals!
+ */
+
+#include <curl/curl.h>
+#include "functypes.h"
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#  define ALLOC_FUNC __attribute__((malloc))
+#  define ALLOC_SIZE(s) __attribute__((alloc_size(s)))
+#  define ALLOC_SIZE2(n, s) __attribute__((alloc_size(n, s)))
+#elif defined(_MSC_VER)
+#  define ALLOC_FUNC __declspec(restrict)
+#  define ALLOC_SIZE(s)
+#  define ALLOC_SIZE2(n, s)
+#else
+#  define ALLOC_FUNC
+#  define ALLOC_SIZE(s)
+#  define ALLOC_SIZE2(n, s)
+#endif
+
+#define CURL_MT_LOGFNAME_BUFSIZE 512
+
+extern FILE *curl_dbg_logfile;
+
+/* memory functions */
+CURL_EXTERN ALLOC_FUNC ALLOC_SIZE(1) void *curl_dbg_malloc(size_t size,
+                                                           int line,
+                                                           const char *source);
+CURL_EXTERN ALLOC_FUNC ALLOC_SIZE2(1, 2) void *curl_dbg_calloc(size_t elements,
+                                   size_t size, int line, const char *source);
+CURL_EXTERN ALLOC_SIZE(2) void *curl_dbg_realloc(void *ptr,
+                                                 size_t size,
+                                                 int line,
+                                                 const char *source);
+CURL_EXTERN void curl_dbg_free(void *ptr, int line, const char *source);
+CURL_EXTERN ALLOC_FUNC char *curl_dbg_strdup(const char *str, int line,
+                                             const char *src);
+#if defined(_WIN32) && defined(UNICODE)
+CURL_EXTERN ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str,
+                                                int line,
+                                                const char *source);
+#endif
+
+CURL_EXTERN void curl_dbg_memdebug(const char *logname);
+CURL_EXTERN void curl_dbg_memlimit(long limit);
+CURL_EXTERN void curl_dbg_log(const char *format, ...) CURL_PRINTF(1, 2);
+
+/* file descriptor manipulators */
+CURL_EXTERN curl_socket_t curl_dbg_socket(int domain, int type, int protocol,
+                                          int line, const char *source);
+CURL_EXTERN void curl_dbg_mark_sclose(curl_socket_t sockfd,
+                                      int line, const char *source);
+CURL_EXTERN int curl_dbg_sclose(curl_socket_t sockfd,
+                                int line, const char *source);
+CURL_EXTERN curl_socket_t curl_dbg_accept(curl_socket_t s, void *a, void *alen,
+                                          int line, const char *source);
+#ifdef HAVE_SOCKETPAIR
+CURL_EXTERN int curl_dbg_socketpair(int domain, int type, int protocol,
+                                    curl_socket_t socket_vector[2],
+                                    int line, const char *source);
+#endif
+
+/* send/receive sockets */
+CURL_EXTERN SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd,
+                                         SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf,
+                                         SEND_TYPE_ARG3 len,
+                                         SEND_TYPE_ARG4 flags, int line,
+                                         const char *source);
+CURL_EXTERN RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd,
+                                         RECV_TYPE_ARG2 buf,
+                                         RECV_TYPE_ARG3 len,
+                                         RECV_TYPE_ARG4 flags, int line,
+                                         const char *source);
+
+/* FILE functions */
+CURL_EXTERN ALLOC_FUNC FILE *curl_dbg_fopen(const char *file, const char *mode,
+                                  int line, const char *source);
+CURL_EXTERN ALLOC_FUNC FILE *curl_dbg_fdopen(int filedes, const char *mode,
+                                             int line, const char *source);
+
+CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source);
+
+#ifndef MEMDEBUG_NODEFINES
+
+/* Set this symbol on the command-line, recompile all lib-sources */
+#undef strdup
+#define strdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__)
+#define malloc(size) curl_dbg_malloc(size, __LINE__, __FILE__)
+#define calloc(nbelem,size) curl_dbg_calloc(nbelem, size, __LINE__, __FILE__)
+#define realloc(ptr,size) curl_dbg_realloc(ptr, size, __LINE__, __FILE__)
+#define free(ptr) curl_dbg_free(ptr, __LINE__, __FILE__)
+#define send(a,b,c,d) curl_dbg_send(a,b,c,d, __LINE__, __FILE__)
+#define recv(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__)
+
+#ifdef _WIN32
+#  ifdef UNICODE
+#    undef wcsdup
+#    define wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__)
+#    undef _wcsdup
+#    define _wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__)
+#    undef _tcsdup
+#    define _tcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__)
+#  else
+#    undef _tcsdup
+#    define _tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__)
+#  endif
+#endif
+
+#undef socket
+#define socket(domain,type,protocol)\
+ curl_dbg_socket(domain, type, protocol, __LINE__, __FILE__)
+#undef accept /* for those with accept as a macro */
+#define accept(sock,addr,len)\
+ curl_dbg_accept(sock, addr, len, __LINE__, __FILE__)
+#ifdef HAVE_SOCKETPAIR
+#define socketpair(domain,type,protocol,socket_vector)\
+ curl_dbg_socketpair(domain, type, protocol, socket_vector, __LINE__, __FILE__)
+#endif
+
+#ifdef HAVE_GETADDRINFO
+#if defined(getaddrinfo) && defined(__osf__)
+/* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define
+   our macro as for other platforms. Instead, we redefine the new name they
+   define getaddrinfo to become! */
+#define ogetaddrinfo(host,serv,hint,res) \
+  curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__)
+#else
+#undef getaddrinfo
+#define getaddrinfo(host,serv,hint,res) \
+  curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__)
+#endif
+#endif /* HAVE_GETADDRINFO */
+
+#ifdef HAVE_FREEADDRINFO
+#undef freeaddrinfo
+#define freeaddrinfo(data) \
+  curl_dbg_freeaddrinfo(data, __LINE__, __FILE__)
+#endif /* HAVE_FREEADDRINFO */
+
+/* sclose is probably already defined, redefine it! */
+#undef sclose
+#define sclose(sockfd) curl_dbg_sclose(sockfd,__LINE__,__FILE__)
+
+#define fake_sclose(sockfd) curl_dbg_mark_sclose(sockfd,__LINE__,__FILE__)
+
+#undef fopen
+#define fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__)
+#undef fdopen
+#define fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__)
+#define fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__)
+
+#endif /* MEMDEBUG_NODEFINES */
+
+#endif /* CURLDEBUG */
+
+/*
+** Following section applies even when CURLDEBUG is not defined.
+*/
+
+#ifndef fake_sclose
+#define fake_sclose(x)  Curl_nop_stmt
+#endif
+
+/*
+ * Curl_safefree defined as a macro to allow MemoryTracking feature
+ * to log free() calls at same location where Curl_safefree is used.
+ * This macro also assigns NULL to given pointer when free'd.
+ */
+
+#define Curl_safefree(ptr) \
+  do { free((ptr)); (ptr) = NULL;} while(0)
+
+#endif /* HEADER_CURL_MEMDEBUG_H */
Index: trunk/src/libs/curl-8.7.1/lib/mime.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/mime.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/mime.c	(revision 104083)
@@ -0,0 +1,2239 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "mime.h"
+#include "warnless.h"
+#include "urldata.h"
+#include "sendf.h"
+#include "strdup.h"
+
+#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) ||      \
+                                    !defined(CURL_DISABLE_SMTP) ||      \
+                                    !defined(CURL_DISABLE_IMAP))
+
+#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
+#include <libgen.h>
+#endif
+
+#include "rand.h"
+#include "slist.h"
+#include "strcase.h"
+#include "dynbuf.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef _WIN32
+# ifndef R_OK
+#  define R_OK 4
+# endif
+#endif
+
+
+#define READ_ERROR                      ((size_t) -1)
+#define STOP_FILLING                    ((size_t) -2)
+
+static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
+                                 void *instream, bool *hasread);
+
+/* Encoders. */
+static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
+                                curl_mimepart *part);
+static curl_off_t encoder_nop_size(curl_mimepart *part);
+static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
+                                curl_mimepart *part);
+static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
+                                curl_mimepart *part);
+static curl_off_t encoder_base64_size(curl_mimepart *part);
+static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
+                              curl_mimepart *part);
+static curl_off_t encoder_qp_size(curl_mimepart *part);
+static curl_off_t mime_size(curl_mimepart *part);
+
+static const struct mime_encoder encoders[] = {
+  {"binary", encoder_nop_read, encoder_nop_size},
+  {"8bit", encoder_nop_read, encoder_nop_size},
+  {"7bit", encoder_7bit_read, encoder_nop_size},
+  {"base64", encoder_base64_read, encoder_base64_size},
+  {"quoted-printable", encoder_qp_read, encoder_qp_size},
+  {ZERO_NULL, ZERO_NULL, ZERO_NULL}
+};
+
+/* Base64 encoding table */
+static const char base64enc[] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/* Quoted-printable character class table.
+ *
+ * We cannot rely on ctype functions since quoted-printable input data
+ * is assumed to be ascii-compatible, even on non-ascii platforms. */
+#define QP_OK           1       /* Can be represented by itself. */
+#define QP_SP           2       /* Space or tab. */
+#define QP_CR           3       /* Carriage return. */
+#define QP_LF           4       /* Line-feed. */
+static const unsigned char qp_class[] = {
+ 0,     0,     0,     0,     0,     0,     0,     0,            /* 00 - 07 */
+ 0,     QP_SP, QP_LF, 0,     0,     QP_CR, 0,     0,            /* 08 - 0F */
+ 0,     0,     0,     0,     0,     0,     0,     0,            /* 10 - 17 */
+ 0,     0,     0,     0,     0,     0,     0,     0,            /* 18 - 1F */
+ QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 20 - 27 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 28 - 2F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 30 - 37 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0    , QP_OK, QP_OK,        /* 38 - 3F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 40 - 47 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 48 - 4F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 50 - 57 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 58 - 5F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 60 - 67 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 68 - 6F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 70 - 77 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0,            /* 78 - 7F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* 80 - 8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* 90 - 9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* A0 - AF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* B0 - BF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* C0 - CF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* D0 - DF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* E0 - EF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0                 /* F0 - FF */
+};
+
+
+/* Binary --> hexadecimal ASCII table. */
+static const char aschex[] =
+  "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46";
+
+
+
+#ifndef __VMS
+#define filesize(name, stat_data) (stat_data.st_size)
+#define fopen_read fopen
+
+#else
+
+#include <fabdef.h>
+/*
+ * get_vms_file_size does what it takes to get the real size of the file
+ *
+ * For fixed files, find out the size of the EOF block and adjust.
+ *
+ * For all others, have to read the entire file in, discarding the contents.
+ * Most posted text files will be small, and binary files like zlib archives
+ * and CD/DVD images should be either a STREAM_LF format or a fixed format.
+ *
+ */
+curl_off_t VmsRealFileSize(const char *name,
+                           const struct_stat *stat_buf)
+{
+  char buffer[8192];
+  curl_off_t count;
+  int ret_stat;
+  FILE * file;
+
+  file = fopen(name, FOPEN_READTEXT); /* VMS */
+  if(!file)
+    return 0;
+
+  count = 0;
+  ret_stat = 1;
+  while(ret_stat > 0) {
+    ret_stat = fread(buffer, 1, sizeof(buffer), file);
+    if(ret_stat)
+      count += ret_stat;
+  }
+  fclose(file);
+
+  return count;
+}
+
+/*
+ *
+ *  VmsSpecialSize checks to see if the stat st_size can be trusted and
+ *  if not to call a routine to get the correct size.
+ *
+ */
+static curl_off_t VmsSpecialSize(const char *name,
+                                 const struct_stat *stat_buf)
+{
+  switch(stat_buf->st_fab_rfm) {
+  case FAB$C_VAR:
+  case FAB$C_VFC:
+    return VmsRealFileSize(name, stat_buf);
+    break;
+  default:
+    return stat_buf->st_size;
+  }
+}
+
+#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
+
+/*
+ * vmsfopenread
+ *
+ * For upload to work as expected on VMS, different optional
+ * parameters must be added to the fopen command based on
+ * record format of the file.
+ *
+ */
+static FILE * vmsfopenread(const char *file, const char *mode)
+{
+  struct_stat statbuf;
+  int result;
+
+  result = stat(file, &statbuf);
+
+  switch(statbuf.st_fab_rfm) {
+  case FAB$C_VAR:
+  case FAB$C_VFC:
+  case FAB$C_STMCR:
+    return fopen(file, FOPEN_READTEXT); /* VMS */
+    break;
+  default:
+    return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
+  }
+}
+
+#define fopen_read vmsfopenread
+#endif
+
+
+#ifndef HAVE_BASENAME
+/*
+  (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
+  Edition)
+
+  The basename() function shall take the pathname pointed to by path and
+  return a pointer to the final component of the pathname, deleting any
+  trailing '/' characters.
+
+  If the string pointed to by path consists entirely of the '/' character,
+  basename() shall return a pointer to the string "/". If the string pointed
+  to by path is exactly "//", it is implementation-defined whether '/' or "//"
+  is returned.
+
+  If path is a null pointer or points to an empty string, basename() shall
+  return a pointer to the string ".".
+
+  The basename() function may modify the string pointed to by path, and may
+  return a pointer to static storage that may then be overwritten by a
+  subsequent call to basename().
+
+  The basename() function need not be reentrant. A function that is not
+  required to be reentrant is not required to be thread-safe.
+
+*/
+static char *Curl_basename(char *path)
+{
+  /* Ignore all the details above for now and make a quick and simple
+     implementation here */
+  char *s1;
+  char *s2;
+
+  s1 = strrchr(path, '/');
+  s2 = strrchr(path, '\\');
+
+  if(s1 && s2) {
+    path = (s1 > s2? s1 : s2) + 1;
+  }
+  else if(s1)
+    path = s1 + 1;
+  else if(s2)
+    path = s2 + 1;
+
+  return path;
+}
+
+#define basename(x)  Curl_basename((x))
+#endif
+
+
+/* Set readback state. */
+static void mimesetstate(struct mime_state *state,
+                         enum mimestate tok, void *ptr)
+{
+  state->state = tok;
+  state->ptr = ptr;
+  state->offset = 0;
+}
+
+
+/* Escape header string into allocated memory. */
+static char *escape_string(struct Curl_easy *data,
+                           const char *src, enum mimestrategy strategy)
+{
+  CURLcode result;
+  struct dynbuf db;
+  const char * const *table;
+  const char * const *p;
+  /* replace first character by rest of string. */
+  static const char * const mimetable[] = {
+    "\\\\\\",
+    "\"\\\"",
+    NULL
+  };
+  /* WHATWG HTML living standard 4.10.21.8 2 specifies:
+     For field names and filenames for file fields, the result of the
+     encoding in the previous bullet point must be escaped by replacing
+     any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D`
+     and 0x22 (") with `%22`.
+     The user agent must not perform any other escapes. */
+  static const char * const formtable[] = {
+    "\"%22",
+    "\r%0D",
+    "\n%0A",
+    NULL
+  };
+
+  table = formtable;
+  /* data can be NULL when this function is called indirectly from
+     curl_formget(). */
+  if(strategy == MIMESTRATEGY_MAIL || (data && (data->set.mime_formescape)))
+    table = mimetable;
+
+  Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
+
+  for(result = Curl_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
+    for(p = table; *p && **p != *src; p++)
+      ;
+
+    if(*p)
+      result = Curl_dyn_add(&db, *p + 1);
+    else
+      result = Curl_dyn_addn(&db, src, 1);
+  }
+
+  return Curl_dyn_ptr(&db);
+}
+
+/* Check if header matches. */
+static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
+{
+  char *value = NULL;
+
+  if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':')
+    for(value = hdr->data + len + 1; *value == ' '; value++)
+      ;
+  return value;
+}
+
+/* Get a header from an slist. */
+static char *search_header(struct curl_slist *hdrlist,
+                           const char *hdr, size_t len)
+{
+  char *value = NULL;
+
+  for(; !value && hdrlist; hdrlist = hdrlist->next)
+    value = match_header(hdrlist, hdr, len);
+
+  return value;
+}
+
+static char *strippath(const char *fullfile)
+{
+  char *filename;
+  char *base;
+  filename = strdup(fullfile); /* duplicate since basename() may ruin the
+                                  buffer it works on */
+  if(!filename)
+    return NULL;
+  base = strdup(basename(filename));
+
+  free(filename); /* free temporary buffer */
+
+  return base; /* returns an allocated string or NULL ! */
+}
+
+/* Initialize data encoder state. */
+static void cleanup_encoder_state(struct mime_encoder_state *p)
+{
+  p->pos = 0;
+  p->bufbeg = 0;
+  p->bufend = 0;
+}
+
+
+/* Dummy encoder. This is used for 8bit and binary content encodings. */
+static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
+                               struct curl_mimepart *part)
+{
+  struct mime_encoder_state *st = &part->encstate;
+  size_t insize = st->bufend - st->bufbeg;
+
+  (void) ateof;
+
+  if(!size)
+    return STOP_FILLING;
+
+  if(size > insize)
+    size = insize;
+
+  if(size)
+    memcpy(buffer, st->buf + st->bufbeg, size);
+
+  st->bufbeg += size;
+  return size;
+}
+
+static curl_off_t encoder_nop_size(curl_mimepart *part)
+{
+  return part->datasize;
+}
+
+
+/* 7bit encoder: the encoder is just a data validity check. */
+static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
+                                curl_mimepart *part)
+{
+  struct mime_encoder_state *st = &part->encstate;
+  size_t cursize = st->bufend - st->bufbeg;
+
+  (void) ateof;
+
+  if(!size)
+    return STOP_FILLING;
+
+  if(size > cursize)
+    size = cursize;
+
+  for(cursize = 0; cursize < size; cursize++) {
+    *buffer = st->buf[st->bufbeg];
+    if(*buffer++ & 0x80)
+      return cursize? cursize: READ_ERROR;
+    st->bufbeg++;
+  }
+
+  return cursize;
+}
+
+
+/* Base64 content encoder. */
+static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
+                                curl_mimepart *part)
+{
+  struct mime_encoder_state *st = &part->encstate;
+  size_t cursize = 0;
+  int i;
+  char *ptr = buffer;
+
+  while(st->bufbeg < st->bufend) {
+    /* Line full ? */
+    if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) {
+      /* Yes, we need 2 characters for CRLF. */
+      if(size < 2) {
+        if(!cursize)
+          return STOP_FILLING;
+        break;
+      }
+      *ptr++ = '\r';
+      *ptr++ = '\n';
+      st->pos = 0;
+      cursize += 2;
+      size -= 2;
+    }
+
+    /* Be sure there is enough space and input data for a base64 group. */
+    if(size < 4) {
+      if(!cursize)
+        return STOP_FILLING;
+      break;
+    }
+    if(st->bufend - st->bufbeg < 3)
+      break;
+
+    /* Encode three bytes as four characters. */
+    i = st->buf[st->bufbeg++] & 0xFF;
+    i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
+    i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
+    *ptr++ = base64enc[(i >> 18) & 0x3F];
+    *ptr++ = base64enc[(i >> 12) & 0x3F];
+    *ptr++ = base64enc[(i >> 6) & 0x3F];
+    *ptr++ = base64enc[i & 0x3F];
+    cursize += 4;
+    st->pos += 4;
+    size -= 4;
+  }
+
+  /* If at eof, we have to flush the buffered data. */
+  if(ateof) {
+    if(size < 4) {
+      if(!cursize)
+        return STOP_FILLING;
+    }
+    else {
+      /* Buffered data size can only be 0, 1 or 2. */
+      ptr[2] = ptr[3] = '=';
+      i = 0;
+
+      /* If there is buffered data */
+      if(st->bufend != st->bufbeg) {
+
+        if(st->bufend - st->bufbeg == 2)
+          i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
+
+        i |= (st->buf[st->bufbeg] & 0xFF) << 16;
+        ptr[0] = base64enc[(i >> 18) & 0x3F];
+        ptr[1] = base64enc[(i >> 12) & 0x3F];
+        if(++st->bufbeg != st->bufend) {
+          ptr[2] = base64enc[(i >> 6) & 0x3F];
+          st->bufbeg++;
+        }
+        cursize += 4;
+        st->pos += 4;
+      }
+    }
+  }
+
+  return cursize;
+}
+
+static curl_off_t encoder_base64_size(curl_mimepart *part)
+{
+  curl_off_t size = part->datasize;
+
+  if(size <= 0)
+    return size;    /* Unknown size or no data. */
+
+  /* Compute base64 character count. */
+  size = 4 * (1 + (size - 1) / 3);
+
+  /* Effective character count must include CRLFs. */
+  return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH);
+}
+
+
+/* Quoted-printable lookahead.
+ *
+ * Check if a CRLF or end of data is in input buffer at current position + n.
+ * Return -1 if more data needed, 1 if CRLF or end of data, else 0.
+ */
+static int qp_lookahead_eol(struct mime_encoder_state *st, int ateof, size_t n)
+{
+  n += st->bufbeg;
+  if(n >= st->bufend && ateof)
+    return 1;
+  if(n + 2 > st->bufend)
+    return ateof? 0: -1;
+  if(qp_class[st->buf[n] & 0xFF] == QP_CR &&
+     qp_class[st->buf[n + 1] & 0xFF] == QP_LF)
+    return 1;
+  return 0;
+}
+
+/* Quoted-printable encoder. */
+static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
+                              curl_mimepart *part)
+{
+  struct mime_encoder_state *st = &part->encstate;
+  char *ptr = buffer;
+  size_t cursize = 0;
+  int softlinebreak;
+  char buf[4];
+
+  /* On all platforms, input is supposed to be ASCII compatible: for this
+     reason, we use hexadecimal ASCII codes in this function rather than
+     character constants that can be interpreted as non-ascii on some
+     platforms. Preserve ASCII encoding on output too. */
+  while(st->bufbeg < st->bufend) {
+    size_t len = 1;
+    size_t consumed = 1;
+    int i = st->buf[st->bufbeg];
+    buf[0] = (char) i;
+    buf[1] = aschex[(i >> 4) & 0xF];
+    buf[2] = aschex[i & 0xF];
+
+    switch(qp_class[st->buf[st->bufbeg] & 0xFF]) {
+    case QP_OK:          /* Not a special character. */
+      break;
+    case QP_SP:          /* Space or tab. */
+      /* Spacing must be escaped if followed by CRLF. */
+      switch(qp_lookahead_eol(st, ateof, 1)) {
+      case -1:          /* More input data needed. */
+        return cursize;
+      case 0:           /* No encoding needed. */
+        break;
+      default:          /* CRLF after space or tab. */
+        buf[0] = '\x3D';    /* '=' */
+        len = 3;
+        break;
+      }
+      break;
+    case QP_CR:         /* Carriage return. */
+      /* If followed by a line-feed, output the CRLF pair.
+         Else escape it. */
+      switch(qp_lookahead_eol(st, ateof, 0)) {
+      case -1:          /* Need more data. */
+        return cursize;
+      case 1:           /* CRLF found. */
+        buf[len++] = '\x0A';    /* Append '\n'. */
+        consumed = 2;
+        break;
+      default:          /* Not followed by LF: escape. */
+        buf[0] = '\x3D';    /* '=' */
+        len = 3;
+        break;
+      }
+      break;
+    default:            /* Character must be escaped. */
+      buf[0] = '\x3D';    /* '=' */
+      len = 3;
+      break;
+    }
+
+    /* Be sure the encoded character fits within maximum line length. */
+    if(buf[len - 1] != '\x0A') {    /* '\n' */
+      softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH;
+      if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) {
+        /* We may use the current line only if end of data or followed by
+           a CRLF. */
+        switch(qp_lookahead_eol(st, ateof, consumed)) {
+        case -1:        /* Need more data. */
+          return cursize;
+        case 0:         /* Not followed by a CRLF. */
+          softlinebreak = 1;
+          break;
+        }
+      }
+      if(softlinebreak) {
+        strcpy(buf, "\x3D\x0D\x0A");    /* "=\r\n" */
+        len = 3;
+        consumed = 0;
+      }
+    }
+
+    /* If the output buffer would overflow, do not store. */
+    if(len > size) {
+      if(!cursize)
+        return STOP_FILLING;
+      break;
+    }
+
+    /* Append to output buffer. */
+    memcpy(ptr, buf, len);
+    cursize += len;
+    ptr += len;
+    size -= len;
+    st->pos += len;
+    if(buf[len - 1] == '\x0A')    /* '\n' */
+      st->pos = 0;
+    st->bufbeg += consumed;
+  }
+
+  return cursize;
+}
+
+static curl_off_t encoder_qp_size(curl_mimepart *part)
+{
+  /* Determining the size can only be done by reading the data: unless the
+     data size is 0, we return it as unknown (-1). */
+  return part->datasize? -1: 0;
+}
+
+
+/* In-memory data callbacks. */
+/* Argument is a pointer to the mime part. */
+static size_t mime_mem_read(char *buffer, size_t size, size_t nitems,
+                            void *instream)
+{
+  curl_mimepart *part = (curl_mimepart *) instream;
+  size_t sz = curlx_sotouz(part->datasize - part->state.offset);
+  (void) size;   /* Always 1.*/
+
+  if(!nitems)
+    return STOP_FILLING;
+
+  if(sz > nitems)
+    sz = nitems;
+
+  if(sz)
+    memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz);
+
+  return sz;
+}
+
+static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
+{
+  curl_mimepart *part = (curl_mimepart *) instream;
+
+  switch(whence) {
+  case SEEK_CUR:
+    offset += part->state.offset;
+    break;
+  case SEEK_END:
+    offset += part->datasize;
+    break;
+  }
+
+  if(offset < 0 || offset > part->datasize)
+    return CURL_SEEKFUNC_FAIL;
+
+  part->state.offset = offset;
+  return CURL_SEEKFUNC_OK;
+}
+
+static void mime_mem_free(void *ptr)
+{
+  Curl_safefree(((curl_mimepart *) ptr)->data);
+}
+
+
+/* Named file callbacks. */
+/* Argument is a pointer to the mime part. */
+static int mime_open_file(curl_mimepart *part)
+{
+  /* Open a MIMEKIND_FILE part. */
+
+  if(part->fp)
+    return 0;
+  part->fp = fopen_read(part->data, "rb");
+  return part->fp? 0: -1;
+}
+
+static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
+                             void *instream)
+{
+  curl_mimepart *part = (curl_mimepart *) instream;
+
+  if(!nitems)
+    return STOP_FILLING;
+
+  if(mime_open_file(part))
+    return READ_ERROR;
+
+  return fread(buffer, size, nitems, part->fp);
+}
+
+static int mime_file_seek(void *instream, curl_off_t offset, int whence)
+{
+  curl_mimepart *part = (curl_mimepart *) instream;
+
+  if(whence == SEEK_SET && !offset && !part->fp)
+    return CURL_SEEKFUNC_OK;   /* Not open: implicitly already at BOF. */
+
+  if(mime_open_file(part))
+    return CURL_SEEKFUNC_FAIL;
+
+  return fseek(part->fp, (long) offset, whence)?
+               CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK;
+}
+
+static void mime_file_free(void *ptr)
+{
+  curl_mimepart *part = (curl_mimepart *) ptr;
+
+  if(part->fp) {
+    fclose(part->fp);
+    part->fp = NULL;
+  }
+  Curl_safefree(part->data);
+}
+
+
+/* Subparts callbacks. */
+/* Argument is a pointer to the mime structure. */
+
+/* Readback a byte string segment. */
+static size_t readback_bytes(struct mime_state *state,
+                             char *buffer, size_t bufsize,
+                             const char *bytes, size_t numbytes,
+                             const char *trail, size_t traillen)
+{
+  size_t sz;
+  size_t offset = curlx_sotouz(state->offset);
+
+  if(numbytes > offset) {
+    sz = numbytes - offset;
+    bytes += offset;
+  }
+  else {
+    sz = offset - numbytes;
+    if(sz >= traillen)
+      return 0;
+    bytes = trail + sz;
+    sz = traillen - sz;
+  }
+
+  if(sz > bufsize)
+    sz = bufsize;
+
+  memcpy(buffer, bytes, sz);
+  state->offset += sz;
+  return sz;
+}
+
+/* Read a non-encoded part content. */
+static size_t read_part_content(curl_mimepart *part,
+                                char *buffer, size_t bufsize, bool *hasread)
+{
+  size_t sz = 0;
+
+  switch(part->lastreadstatus) {
+  case 0:
+  case CURL_READFUNC_ABORT:
+  case CURL_READFUNC_PAUSE:
+  case READ_ERROR:
+    return part->lastreadstatus;
+  default:
+    break;
+  }
+
+  /* If we can determine we are at end of part data, spare a read. */
+  if(part->datasize != (curl_off_t) -1 &&
+     part->state.offset >= part->datasize) {
+    /* sz is already zero. */
+  }
+  else {
+    switch(part->kind) {
+    case MIMEKIND_MULTIPART:
+      /*
+       * Cannot be processed as other kinds since read function requires
+       * an additional parameter and is highly recursive.
+       */
+       sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread);
+       break;
+    case MIMEKIND_FILE:
+      if(part->fp && feof(part->fp))
+        break;  /* At EOF. */
+      FALLTHROUGH();
+    default:
+      if(part->readfunc) {
+        if(!(part->flags & MIME_FAST_READ)) {
+          if(*hasread)
+            return STOP_FILLING;
+          *hasread = TRUE;
+        }
+        sz = part->readfunc(buffer, 1, bufsize, part->arg);
+      }
+      break;
+    }
+  }
+
+  switch(sz) {
+  case STOP_FILLING:
+    break;
+  case 0:
+  case CURL_READFUNC_ABORT:
+  case CURL_READFUNC_PAUSE:
+  case READ_ERROR:
+    part->lastreadstatus = sz;
+    break;
+  default:
+    part->state.offset += sz;
+    part->lastreadstatus = sz;
+    break;
+  }
+
+  return sz;
+}
+
+/* Read and encode part content. */
+static size_t read_encoded_part_content(curl_mimepart *part, char *buffer,
+                                        size_t bufsize, bool *hasread)
+{
+  struct mime_encoder_state *st = &part->encstate;
+  size_t cursize = 0;
+  size_t sz;
+  bool ateof = FALSE;
+
+  for(;;) {
+    if(st->bufbeg < st->bufend || ateof) {
+      /* Encode buffered data. */
+      sz = part->encoder->encodefunc(buffer, bufsize, ateof, part);
+      switch(sz) {
+      case 0:
+        if(ateof)
+          return cursize;
+        break;
+      case READ_ERROR:
+      case STOP_FILLING:
+        return cursize? cursize: sz;
+      default:
+        cursize += sz;
+        buffer += sz;
+        bufsize -= sz;
+        continue;
+      }
+    }
+
+    /* We need more data in input buffer. */
+    if(st->bufbeg) {
+      size_t len = st->bufend - st->bufbeg;
+
+      if(len)
+        memmove(st->buf, st->buf + st->bufbeg, len);
+      st->bufbeg = 0;
+      st->bufend = len;
+    }
+    if(st->bufend >= sizeof(st->buf))
+      return cursize? cursize: READ_ERROR;    /* Buffer full. */
+    sz = read_part_content(part, st->buf + st->bufend,
+                           sizeof(st->buf) - st->bufend, hasread);
+    switch(sz) {
+    case 0:
+      ateof = TRUE;
+      break;
+    case CURL_READFUNC_ABORT:
+    case CURL_READFUNC_PAUSE:
+    case READ_ERROR:
+    case STOP_FILLING:
+      return cursize? cursize: sz;
+    default:
+      st->bufend += sz;
+      break;
+    }
+  }
+
+  /* NOTREACHED */
+}
+
+/* Readback a mime part. */
+static size_t readback_part(curl_mimepart *part,
+                            char *buffer, size_t bufsize, bool *hasread)
+{
+  size_t cursize = 0;
+
+  /* Readback from part. */
+
+  while(bufsize) {
+    size_t sz = 0;
+    struct curl_slist *hdr = (struct curl_slist *) part->state.ptr;
+    switch(part->state.state) {
+    case MIMESTATE_BEGIN:
+      mimesetstate(&part->state,
+                   (part->flags & MIME_BODY_ONLY)?
+                     MIMESTATE_BODY: MIMESTATE_CURLHEADERS,
+                   part->curlheaders);
+      break;
+    case MIMESTATE_USERHEADERS:
+      if(!hdr) {
+        mimesetstate(&part->state, MIMESTATE_EOH, NULL);
+        break;
+      }
+      if(match_header(hdr, "Content-Type", 12)) {
+        mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
+        break;
+      }
+      FALLTHROUGH();
+    case MIMESTATE_CURLHEADERS:
+      if(!hdr)
+        mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
+      else {
+        sz = readback_bytes(&part->state, buffer, bufsize,
+                            hdr->data, strlen(hdr->data), STRCONST("\r\n"));
+        if(!sz)
+          mimesetstate(&part->state, part->state.state, hdr->next);
+      }
+      break;
+    case MIMESTATE_EOH:
+      sz = readback_bytes(&part->state, buffer, bufsize, STRCONST("\r\n"),
+                          STRCONST(""));
+      if(!sz)
+        mimesetstate(&part->state, MIMESTATE_BODY, NULL);
+      break;
+    case MIMESTATE_BODY:
+      cleanup_encoder_state(&part->encstate);
+      mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
+      break;
+    case MIMESTATE_CONTENT:
+      if(part->encoder)
+        sz = read_encoded_part_content(part, buffer, bufsize, hasread);
+      else
+        sz = read_part_content(part, buffer, bufsize, hasread);
+      switch(sz) {
+      case 0:
+        mimesetstate(&part->state, MIMESTATE_END, NULL);
+        /* Try sparing open file descriptors. */
+        if(part->kind == MIMEKIND_FILE && part->fp) {
+          fclose(part->fp);
+          part->fp = NULL;
+        }
+        FALLTHROUGH();
+      case CURL_READFUNC_ABORT:
+      case CURL_READFUNC_PAUSE:
+      case READ_ERROR:
+      case STOP_FILLING:
+        return cursize? cursize: sz;
+      }
+      break;
+    case MIMESTATE_END:
+      return cursize;
+    default:
+      break;    /* Other values not in part state. */
+    }
+
+    /* Bump buffer and counters according to read size. */
+    cursize += sz;
+    buffer += sz;
+    bufsize -= sz;
+  }
+
+  return cursize;
+}
+
+/* Readback from mime. Warning: not a read callback function. */
+static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
+                                 void *instream, bool *hasread)
+{
+  curl_mime *mime = (curl_mime *) instream;
+  size_t cursize = 0;
+  (void) size;   /* Always 1. */
+
+  while(nitems) {
+    size_t sz = 0;
+    curl_mimepart *part = mime->state.ptr;
+    switch(mime->state.state) {
+    case MIMESTATE_BEGIN:
+    case MIMESTATE_BODY:
+      mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart);
+      /* The first boundary always follows the header termination empty line,
+         so is always preceded by a CRLF. We can then spare 2 characters
+         by skipping the leading CRLF in boundary. */
+      mime->state.offset += 2;
+      break;
+    case MIMESTATE_BOUNDARY1:
+      sz = readback_bytes(&mime->state, buffer, nitems, STRCONST("\r\n--"),
+                          STRCONST(""));
+      if(!sz)
+        mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
+      break;
+    case MIMESTATE_BOUNDARY2:
+      if(part)
+        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
+                            MIME_BOUNDARY_LEN, STRCONST("\r\n"));
+      else
+        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
+                            MIME_BOUNDARY_LEN, STRCONST("--\r\n"));
+      if(!sz) {
+        mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
+      }
+      break;
+    case MIMESTATE_CONTENT:
+      if(!part) {
+        mimesetstate(&mime->state, MIMESTATE_END, NULL);
+        break;
+      }
+      sz = readback_part(part, buffer, nitems, hasread);
+      switch(sz) {
+      case CURL_READFUNC_ABORT:
+      case CURL_READFUNC_PAUSE:
+      case READ_ERROR:
+      case STOP_FILLING:
+        return cursize? cursize: sz;
+      case 0:
+        mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
+        break;
+      }
+      break;
+    case MIMESTATE_END:
+      return cursize;
+    default:
+      break;    /* other values not used in mime state. */
+    }
+
+    /* Bump buffer and counters according to read size. */
+    cursize += sz;
+    buffer += sz;
+    nitems -= sz;
+  }
+
+  return cursize;
+}
+
+static int mime_part_rewind(curl_mimepart *part)
+{
+  int res = CURL_SEEKFUNC_OK;
+  enum mimestate targetstate = MIMESTATE_BEGIN;
+
+  if(part->flags & MIME_BODY_ONLY)
+    targetstate = MIMESTATE_BODY;
+  cleanup_encoder_state(&part->encstate);
+  if(part->state.state > targetstate) {
+    res = CURL_SEEKFUNC_CANTSEEK;
+    if(part->seekfunc) {
+      res = part->seekfunc(part->arg, (curl_off_t) 0, SEEK_SET);
+      switch(res) {
+      case CURL_SEEKFUNC_OK:
+      case CURL_SEEKFUNC_FAIL:
+      case CURL_SEEKFUNC_CANTSEEK:
+        break;
+      case -1:    /* For fseek() error. */
+        res = CURL_SEEKFUNC_CANTSEEK;
+        break;
+      default:
+        res = CURL_SEEKFUNC_FAIL;
+        break;
+      }
+    }
+  }
+
+  if(res == CURL_SEEKFUNC_OK)
+    mimesetstate(&part->state, targetstate, NULL);
+
+  part->lastreadstatus = 1; /* Successful read status. */
+  return res;
+}
+
+static int mime_subparts_seek(void *instream, curl_off_t offset, int whence)
+{
+  curl_mime *mime = (curl_mime *) instream;
+  curl_mimepart *part;
+  int result = CURL_SEEKFUNC_OK;
+
+  if(whence != SEEK_SET || offset)
+    return CURL_SEEKFUNC_CANTSEEK;    /* Only support full rewind. */
+
+  if(mime->state.state == MIMESTATE_BEGIN)
+    return CURL_SEEKFUNC_OK;           /* Already rewound. */
+
+  for(part = mime->firstpart; part; part = part->nextpart) {
+    int res = mime_part_rewind(part);
+    if(res != CURL_SEEKFUNC_OK)
+      result = res;
+  }
+
+  if(result == CURL_SEEKFUNC_OK)
+    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
+
+  return result;
+}
+
+/* Release part content. */
+static void cleanup_part_content(curl_mimepart *part)
+{
+  if(part->freefunc)
+    part->freefunc(part->arg);
+
+  part->readfunc = NULL;
+  part->seekfunc = NULL;
+  part->freefunc = NULL;
+  part->arg = (void *) part;          /* Defaults to part itself. */
+  part->data = NULL;
+  part->fp = NULL;
+  part->datasize = (curl_off_t) 0;    /* No size yet. */
+  cleanup_encoder_state(&part->encstate);
+  part->kind = MIMEKIND_NONE;
+  part->flags &= ~MIME_FAST_READ;
+  part->lastreadstatus = 1; /* Successful read status. */
+  part->state.state = MIMESTATE_BEGIN;
+}
+
+static void mime_subparts_free(void *ptr)
+{
+  curl_mime *mime = (curl_mime *) ptr;
+
+  if(mime && mime->parent) {
+    mime->parent->freefunc = NULL;  /* Be sure we won't be called again. */
+    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
+  }
+  curl_mime_free(mime);
+}
+
+/* Do not free subparts: unbind them. This is used for the top level only. */
+static void mime_subparts_unbind(void *ptr)
+{
+  curl_mime *mime = (curl_mime *) ptr;
+
+  if(mime && mime->parent) {
+    mime->parent->freefunc = NULL;  /* Be sure we won't be called again. */
+    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
+    mime->parent = NULL;
+  }
+}
+
+
+void Curl_mime_cleanpart(curl_mimepart *part)
+{
+  if(part) {
+    cleanup_part_content(part);
+    curl_slist_free_all(part->curlheaders);
+    if(part->flags & MIME_USERHEADERS_OWNER)
+      curl_slist_free_all(part->userheaders);
+    Curl_safefree(part->mimetype);
+    Curl_safefree(part->name);
+    Curl_safefree(part->filename);
+    Curl_mime_initpart(part);
+  }
+}
+
+/* Recursively delete a mime handle and its parts. */
+void curl_mime_free(curl_mime *mime)
+{
+  curl_mimepart *part;
+
+  if(mime) {
+    mime_subparts_unbind(mime);  /* Be sure it's not referenced anymore. */
+    while(mime->firstpart) {
+      part = mime->firstpart;
+      mime->firstpart = part->nextpart;
+      Curl_mime_cleanpart(part);
+      free(part);
+    }
+    free(mime);
+  }
+}
+
+CURLcode Curl_mime_duppart(struct Curl_easy *data,
+                           curl_mimepart *dst, const curl_mimepart *src)
+{
+  curl_mime *mime;
+  curl_mimepart *d;
+  const curl_mimepart *s;
+  CURLcode res = CURLE_OK;
+
+  DEBUGASSERT(dst);
+
+  /* Duplicate content. */
+  switch(src->kind) {
+  case MIMEKIND_NONE:
+    break;
+  case MIMEKIND_DATA:
+    res = curl_mime_data(dst, src->data, (size_t) src->datasize);
+    break;
+  case MIMEKIND_FILE:
+    res = curl_mime_filedata(dst, src->data);
+    /* Do not abort duplication if file is not readable. */
+    if(res == CURLE_READ_ERROR)
+      res = CURLE_OK;
+    break;
+  case MIMEKIND_CALLBACK:
+    res = curl_mime_data_cb(dst, src->datasize, src->readfunc,
+                            src->seekfunc, src->freefunc, src->arg);
+    break;
+  case MIMEKIND_MULTIPART:
+    /* No one knows about the cloned subparts, thus always attach ownership
+       to the part. */
+    mime = curl_mime_init(data);
+    res = mime? curl_mime_subparts(dst, mime): CURLE_OUT_OF_MEMORY;
+
+    /* Duplicate subparts. */
+    for(s = ((curl_mime *) src->arg)->firstpart; !res && s; s = s->nextpart) {
+      d = curl_mime_addpart(mime);
+      res = d? Curl_mime_duppart(data, d, s): CURLE_OUT_OF_MEMORY;
+    }
+    break;
+  default:  /* Invalid kind: should not occur. */
+    DEBUGF(infof(data, "invalid MIMEKIND* attempt"));
+    res = CURLE_BAD_FUNCTION_ARGUMENT;  /* Internal error? */
+    break;
+  }
+
+  /* Duplicate headers. */
+  if(!res && src->userheaders) {
+    struct curl_slist *hdrs = Curl_slist_duplicate(src->userheaders);
+
+    if(!hdrs)
+      res = CURLE_OUT_OF_MEMORY;
+    else {
+      /* No one but this procedure knows about the new header list,
+         so always take ownership. */
+      res = curl_mime_headers(dst, hdrs, TRUE);
+      if(res)
+        curl_slist_free_all(hdrs);
+    }
+  }
+
+  if(!res) {
+    /* Duplicate other fields. */
+    dst->encoder = src->encoder;
+    res = curl_mime_type(dst, src->mimetype);
+  }
+  if(!res)
+    res = curl_mime_name(dst, src->name);
+  if(!res)
+    res = curl_mime_filename(dst, src->filename);
+
+  /* If an error occurred, rollback. */
+  if(res)
+    Curl_mime_cleanpart(dst);
+
+  return res;
+}
+
+/*
+ * Mime build functions.
+ */
+
+/* Create a mime handle. */
+curl_mime *curl_mime_init(struct Curl_easy *easy)
+{
+  curl_mime *mime;
+
+  mime = (curl_mime *) malloc(sizeof(*mime));
+
+  if(mime) {
+    mime->parent = NULL;
+    mime->firstpart = NULL;
+    mime->lastpart = NULL;
+
+    memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
+    if(Curl_rand_alnum(easy,
+                       (unsigned char *) &mime->boundary[MIME_BOUNDARY_DASHES],
+                       MIME_RAND_BOUNDARY_CHARS + 1)) {
+      /* failed to get random separator, bail out */
+      free(mime);
+      return NULL;
+    }
+    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
+  }
+
+  return mime;
+}
+
+/* Initialize a mime part. */
+void Curl_mime_initpart(curl_mimepart *part)
+{
+  memset((char *) part, 0, sizeof(*part));
+  part->lastreadstatus = 1; /* Successful read status. */
+  mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
+}
+
+/* Create a mime part and append it to a mime handle's part list. */
+curl_mimepart *curl_mime_addpart(curl_mime *mime)
+{
+  curl_mimepart *part;
+
+  if(!mime)
+    return NULL;
+
+  part = (curl_mimepart *) malloc(sizeof(*part));
+
+  if(part) {
+    Curl_mime_initpart(part);
+    part->parent = mime;
+
+    if(mime->lastpart)
+      mime->lastpart->nextpart = part;
+    else
+      mime->firstpart = part;
+
+    mime->lastpart = part;
+  }
+
+  return part;
+}
+
+/* Set mime part name. */
+CURLcode curl_mime_name(curl_mimepart *part, const char *name)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  Curl_safefree(part->name);
+
+  if(name) {
+    part->name = strdup(name);
+    if(!part->name)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  return CURLE_OK;
+}
+
+/* Set mime part remote file name. */
+CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  Curl_safefree(part->filename);
+
+  if(filename) {
+    part->filename = strdup(filename);
+    if(!part->filename)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  return CURLE_OK;
+}
+
+/* Set mime part content from memory data. */
+CURLcode curl_mime_data(curl_mimepart *part,
+                        const char *ptr, size_t datasize)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  cleanup_part_content(part);
+
+  if(ptr) {
+    if(datasize == CURL_ZERO_TERMINATED)
+      datasize = strlen(ptr);
+
+    part->data = Curl_memdup0(ptr, datasize);
+    if(!part->data)
+      return CURLE_OUT_OF_MEMORY;
+
+    part->datasize = datasize;
+    part->readfunc = mime_mem_read;
+    part->seekfunc = mime_mem_seek;
+    part->freefunc = mime_mem_free;
+    part->flags |= MIME_FAST_READ;
+    part->kind = MIMEKIND_DATA;
+  }
+
+  return CURLE_OK;
+}
+
+/* Set mime part content from named local file. */
+CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
+{
+  CURLcode result = CURLE_OK;
+
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  cleanup_part_content(part);
+
+  if(filename) {
+    char *base;
+    struct_stat sbuf;
+
+    if(stat(filename, &sbuf) || access(filename, R_OK))
+      result = CURLE_READ_ERROR;
+
+    part->data = strdup(filename);
+    if(!part->data)
+      result = CURLE_OUT_OF_MEMORY;
+
+    part->datasize = -1;
+    if(!result && S_ISREG(sbuf.st_mode)) {
+      part->datasize = filesize(filename, sbuf);
+      part->seekfunc = mime_file_seek;
+    }
+
+    part->readfunc = mime_file_read;
+    part->freefunc = mime_file_free;
+    part->kind = MIMEKIND_FILE;
+
+    /* As a side effect, set the filename to the current file's base name.
+       It is possible to withdraw this by explicitly calling
+       curl_mime_filename() with a NULL filename argument after the current
+       call. */
+    base = strippath(filename);
+    if(!base)
+      result = CURLE_OUT_OF_MEMORY;
+    else {
+      CURLcode res = curl_mime_filename(part, base);
+
+      if(res)
+        result = res;
+      free(base);
+    }
+  }
+  return result;
+}
+
+/* Set mime part type. */
+CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  Curl_safefree(part->mimetype);
+
+  if(mimetype) {
+    part->mimetype = strdup(mimetype);
+    if(!part->mimetype)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  return CURLE_OK;
+}
+
+/* Set mime data transfer encoder. */
+CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
+{
+  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
+  const struct mime_encoder *mep;
+
+  if(!part)
+    return result;
+
+  part->encoder = NULL;
+
+  if(!encoding)
+    return CURLE_OK;    /* Removing current encoder. */
+
+  for(mep = encoders; mep->name; mep++)
+    if(strcasecompare(encoding, mep->name)) {
+      part->encoder = mep;
+      result = CURLE_OK;
+    }
+
+  return result;
+}
+
+/* Set mime part headers. */
+CURLcode curl_mime_headers(curl_mimepart *part,
+                           struct curl_slist *headers, int take_ownership)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  if(part->flags & MIME_USERHEADERS_OWNER) {
+    if(part->userheaders != headers)  /* Allow setting twice the same list. */
+      curl_slist_free_all(part->userheaders);
+    part->flags &= ~MIME_USERHEADERS_OWNER;
+  }
+  part->userheaders = headers;
+  if(headers && take_ownership)
+    part->flags |= MIME_USERHEADERS_OWNER;
+  return CURLE_OK;
+}
+
+/* Set mime part content from callback. */
+CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
+                           curl_read_callback readfunc,
+                           curl_seek_callback seekfunc,
+                           curl_free_callback freefunc, void *arg)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  cleanup_part_content(part);
+
+  if(readfunc) {
+    part->readfunc = readfunc;
+    part->seekfunc = seekfunc;
+    part->freefunc = freefunc;
+    part->arg = arg;
+    part->datasize = datasize;
+    part->kind = MIMEKIND_CALLBACK;
+  }
+
+  return CURLE_OK;
+}
+
+/* Set mime part content from subparts. */
+CURLcode Curl_mime_set_subparts(curl_mimepart *part,
+                                curl_mime *subparts, int take_ownership)
+{
+  curl_mime *root;
+
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  /* Accept setting twice the same subparts. */
+  if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
+    return CURLE_OK;
+
+  cleanup_part_content(part);
+
+  if(subparts) {
+    /* Should not have been attached already. */
+    if(subparts->parent)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+
+    /* Should not be the part's root. */
+    root = part->parent;
+    if(root) {
+      while(root->parent && root->parent->parent)
+        root = root->parent->parent;
+      if(subparts == root) {
+        /* Can't add as a subpart of itself. */
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+      }
+    }
+
+    subparts->parent = part;
+    /* Subparts are processed internally: no read callback. */
+    part->seekfunc = mime_subparts_seek;
+    part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind;
+    part->arg = subparts;
+    part->datasize = -1;
+    part->kind = MIMEKIND_MULTIPART;
+  }
+
+  return CURLE_OK;
+}
+
+CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
+{
+  return Curl_mime_set_subparts(part, subparts, TRUE);
+}
+
+
+/* Readback from top mime. */
+/* Argument is the dummy top part. */
+size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
+{
+  curl_mimepart *part = (curl_mimepart *) instream;
+  size_t ret;
+  bool hasread;
+
+  (void) size;   /* Always 1. */
+
+  do {
+    hasread = FALSE;
+    ret = readback_part(part, buffer, nitems, &hasread);
+    /*
+     * If this is not possible to get some data without calling more than
+     * one read callback (probably because a content encoder is not able to
+     * deliver a new bunch for the few data accumulated so far), force another
+     * read until we get enough data or a special exit code.
+     */
+  } while(ret == STOP_FILLING);
+
+  return ret;
+}
+
+/* Rewind mime stream. */
+static CURLcode mime_rewind(curl_mimepart *part)
+{
+  return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
+         CURLE_OK: CURLE_SEND_FAIL_REWIND;
+}
+
+/* Compute header list size. */
+static size_t slist_size(struct curl_slist *s,
+                         size_t overhead, const char *skip, size_t skiplen)
+{
+  size_t size = 0;
+
+  for(; s; s = s->next)
+    if(!skip || !match_header(s, skip, skiplen))
+      size += strlen(s->data) + overhead;
+  return size;
+}
+
+/* Get/compute multipart size. */
+static curl_off_t multipart_size(curl_mime *mime)
+{
+  curl_off_t size;
+  curl_off_t boundarysize;
+  curl_mimepart *part;
+
+  if(!mime)
+    return 0;           /* Not present -> empty. */
+
+  boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
+  size = boundarysize;  /* Final boundary - CRLF after headers. */
+
+  for(part = mime->firstpart; part; part = part->nextpart) {
+    curl_off_t sz = mime_size(part);
+
+    if(sz < 0)
+      size = sz;
+
+    if(size >= 0)
+      size += boundarysize + sz;
+  }
+
+  return size;
+}
+
+/* Get/compute mime size. */
+static curl_off_t mime_size(curl_mimepart *part)
+{
+  curl_off_t size;
+
+  if(part->kind == MIMEKIND_MULTIPART)
+    part->datasize = multipart_size(part->arg);
+
+  size = part->datasize;
+
+  if(part->encoder)
+    size = part->encoder->sizefunc(part);
+
+  if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
+    /* Compute total part size. */
+    size += slist_size(part->curlheaders, 2, NULL, 0);
+    size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
+    size += 2;    /* CRLF after headers. */
+  }
+  return size;
+}
+
+/* Add a header. */
+/* VARARGS2 */
+CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
+{
+  struct curl_slist *hdr = NULL;
+  char *s = NULL;
+  va_list ap;
+
+  va_start(ap, fmt);
+  s = curl_mvaprintf(fmt, ap);
+  va_end(ap);
+
+  if(s) {
+    hdr = Curl_slist_append_nodup(*slp, s);
+    if(hdr)
+      *slp = hdr;
+    else
+      free(s);
+  }
+
+  return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY;
+}
+
+/* Add a content type header. */
+static CURLcode add_content_type(struct curl_slist **slp,
+                                 const char *type, const char *boundary)
+{
+  return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
+                              boundary? "; boundary=": "",
+                              boundary? boundary: "");
+}
+
+const char *Curl_mime_contenttype(const char *filename)
+{
+  /*
+   * If no content type was specified, we scan through a few well-known
+   * extensions and pick the first we match!
+   */
+  struct ContentType {
+    const char *extension;
+    const char *type;
+  };
+  static const struct ContentType ctts[] = {
+    {".gif",  "image/gif"},
+    {".jpg",  "image/jpeg"},
+    {".jpeg", "image/jpeg"},
+    {".png",  "image/png"},
+    {".svg",  "image/svg+xml"},
+    {".txt",  "text/plain"},
+    {".htm",  "text/html"},
+    {".html", "text/html"},
+    {".pdf",  "application/pdf"},
+    {".xml",  "application/xml"}
+  };
+
+  if(filename) {
+    size_t len1 = strlen(filename);
+    const char *nameend = filename + len1;
+    unsigned int i;
+
+    for(i = 0; i < sizeof(ctts) / sizeof(ctts[0]); i++) {
+      size_t len2 = strlen(ctts[i].extension);
+
+      if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
+        return ctts[i].type;
+    }
+  }
+  return NULL;
+}
+
+static bool content_type_match(const char *contenttype,
+                               const char *target, size_t len)
+{
+  if(contenttype && strncasecompare(contenttype, target, len))
+    switch(contenttype[len]) {
+    case '\0':
+    case '\t':
+    case '\r':
+    case '\n':
+    case ' ':
+    case ';':
+      return TRUE;
+    }
+  return FALSE;
+}
+
+CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
+                                   curl_mimepart *part,
+                                   const char *contenttype,
+                                   const char *disposition,
+                                   enum mimestrategy strategy)
+{
+  curl_mime *mime = NULL;
+  const char *boundary = NULL;
+  char *customct;
+  const char *cte = NULL;
+  CURLcode ret = CURLE_OK;
+
+  /* Get rid of previously prepared headers. */
+  curl_slist_free_all(part->curlheaders);
+  part->curlheaders = NULL;
+
+  /* Be sure we won't access old headers later. */
+  if(part->state.state == MIMESTATE_CURLHEADERS)
+    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
+
+  /* Check if content type is specified. */
+  customct = part->mimetype;
+  if(!customct)
+    customct = search_header(part->userheaders, STRCONST("Content-Type"));
+  if(customct)
+    contenttype = customct;
+
+  /* If content type is not specified, try to determine it. */
+  if(!contenttype) {
+    switch(part->kind) {
+    case MIMEKIND_MULTIPART:
+      contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
+      break;
+    case MIMEKIND_FILE:
+      contenttype = Curl_mime_contenttype(part->filename);
+      if(!contenttype)
+        contenttype = Curl_mime_contenttype(part->data);
+      if(!contenttype && part->filename)
+        contenttype = FILE_CONTENTTYPE_DEFAULT;
+      break;
+    default:
+      contenttype = Curl_mime_contenttype(part->filename);
+      break;
+    }
+  }
+
+  if(part->kind == MIMEKIND_MULTIPART) {
+    mime = (curl_mime *) part->arg;
+    if(mime)
+      boundary = mime->boundary;
+  }
+  else if(contenttype && !customct &&
+          content_type_match(contenttype, STRCONST("text/plain")))
+    if(strategy == MIMESTRATEGY_MAIL || !part->filename)
+      contenttype = NULL;
+
+  /* Issue content-disposition header only if not already set by caller. */
+  if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
+    if(!disposition)
+      if(part->filename || part->name ||
+        (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
+          disposition = DISPOSITION_DEFAULT;
+    if(disposition && curl_strequal(disposition, "attachment") &&
+     !part->name && !part->filename)
+      disposition = NULL;
+    if(disposition) {
+      char *name = NULL;
+      char *filename = NULL;
+
+      if(part->name) {
+        name = escape_string(data, part->name, strategy);
+        if(!name)
+          ret = CURLE_OUT_OF_MEMORY;
+      }
+      if(!ret && part->filename) {
+        filename = escape_string(data, part->filename, strategy);
+        if(!filename)
+          ret = CURLE_OUT_OF_MEMORY;
+      }
+      if(!ret)
+        ret = Curl_mime_add_header(&part->curlheaders,
+                                   "Content-Disposition: %s%s%s%s%s%s%s",
+                                   disposition,
+                                   name? "; name=\"": "",
+                                   name? name: "",
+                                   name? "\"": "",
+                                   filename? "; filename=\"": "",
+                                   filename? filename: "",
+                                   filename? "\"": "");
+      Curl_safefree(name);
+      Curl_safefree(filename);
+      if(ret)
+        return ret;
+      }
+    }
+
+  /* Issue Content-Type header. */
+  if(contenttype) {
+    ret = add_content_type(&part->curlheaders, contenttype, boundary);
+    if(ret)
+      return ret;
+  }
+
+  /* Content-Transfer-Encoding header. */
+  if(!search_header(part->userheaders,
+                    STRCONST("Content-Transfer-Encoding"))) {
+    if(part->encoder)
+      cte = part->encoder->name;
+    else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
+     part->kind != MIMEKIND_MULTIPART)
+      cte = "8bit";
+    if(cte) {
+      ret = Curl_mime_add_header(&part->curlheaders,
+                                 "Content-Transfer-Encoding: %s", cte);
+      if(ret)
+        return ret;
+    }
+  }
+
+  /* If we were reading curl-generated headers, restart with new ones (this
+     should not occur). */
+  if(part->state.state == MIMESTATE_CURLHEADERS)
+    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
+
+  /* Process subparts. */
+  if(part->kind == MIMEKIND_MULTIPART && mime) {
+    curl_mimepart *subpart;
+
+    disposition = NULL;
+    if(content_type_match(contenttype, STRCONST("multipart/form-data")))
+      disposition = "form-data";
+    for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
+      ret = Curl_mime_prepare_headers(data, subpart, NULL,
+                                      disposition, strategy);
+      if(ret)
+        return ret;
+    }
+  }
+  return ret;
+}
+
+/* Recursively reset paused status in the given part. */
+static void mime_unpause(curl_mimepart *part)
+{
+  if(part) {
+    if(part->lastreadstatus == CURL_READFUNC_PAUSE)
+      part->lastreadstatus = 1; /* Successful read status. */
+    if(part->kind == MIMEKIND_MULTIPART) {
+      curl_mime *mime = (curl_mime *) part->arg;
+
+      if(mime) {
+        curl_mimepart *subpart;
+
+        for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
+          mime_unpause(subpart);
+      }
+    }
+  }
+}
+
+struct cr_mime_ctx {
+  struct Curl_creader super;
+  curl_mimepart *part;
+  curl_off_t total_len;
+  curl_off_t read_len;
+  CURLcode error_result;
+  BIT(seen_eos);
+  BIT(errored);
+};
+
+static CURLcode cr_mime_init(struct Curl_easy *data,
+                             struct Curl_creader *reader)
+{
+  struct cr_mime_ctx *ctx = reader->ctx;
+  (void)data;
+  ctx->total_len = -1;
+  ctx->read_len = 0;
+  return CURLE_OK;
+}
+
+/* Real client reader to installed client callbacks. */
+static CURLcode cr_mime_read(struct Curl_easy *data,
+                             struct Curl_creader *reader,
+                             char *buf, size_t blen,
+                             size_t *pnread, bool *peos)
+{
+  struct cr_mime_ctx *ctx = reader->ctx;
+  size_t nread;
+
+  /* Once we have errored, we will return the same error forever */
+  if(ctx->errored) {
+    *pnread = 0;
+    *peos = FALSE;
+    return ctx->error_result;
+  }
+  if(ctx->seen_eos) {
+    *pnread = 0;
+    *peos = TRUE;
+    return CURLE_OK;
+  }
+  /* respect length limitations */
+  if(ctx->total_len >= 0) {
+    curl_off_t remain = ctx->total_len - ctx->read_len;
+    if(remain <= 0)
+      blen = 0;
+    else if(remain < (curl_off_t)blen)
+      blen = (size_t)remain;
+  }
+  nread = 0;
+  if(blen) {
+    nread = Curl_mime_read(buf, 1, blen, ctx->part);
+  }
+
+  switch(nread) {
+  case 0:
+    if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
+      failf(data, "client mime read EOF fail, only "
+            "only %"CURL_FORMAT_CURL_OFF_T"/%"CURL_FORMAT_CURL_OFF_T
+            " of needed bytes read", ctx->read_len, ctx->total_len);
+      return CURLE_READ_ERROR;
+    }
+    *pnread = 0;
+    *peos = TRUE;
+    ctx->seen_eos = TRUE;
+    break;
+
+  case CURL_READFUNC_ABORT:
+    failf(data, "operation aborted by callback");
+    *pnread = 0;
+    *peos = FALSE;
+    ctx->errored = TRUE;
+    ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
+    return CURLE_ABORTED_BY_CALLBACK;
+
+  case CURL_READFUNC_PAUSE:
+    /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
+    data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
+    *pnread = 0;
+    *peos = FALSE;
+    break; /* nothing was read */
+
+  default:
+    if(nread > blen) {
+      /* the read function returned a too large value */
+      failf(data, "read function returned funny value");
+      *pnread = 0;
+      *peos = FALSE;
+      ctx->errored = TRUE;
+      ctx->error_result = CURLE_READ_ERROR;
+      return CURLE_READ_ERROR;
+    }
+    ctx->read_len += nread;
+    if(ctx->total_len >= 0)
+      ctx->seen_eos = (ctx->read_len >= ctx->total_len);
+    *pnread = nread;
+    *peos = ctx->seen_eos;
+    break;
+  }
+  DEBUGF(infof(data, "cr_mime_read(len=%zu, total=%"CURL_FORMAT_CURL_OFF_T
+         ", read=%"CURL_FORMAT_CURL_OFF_T") -> %d, %zu, %d",
+         blen, ctx->total_len, ctx->read_len, CURLE_OK, *pnread, *peos));
+  return CURLE_OK;
+}
+
+static bool cr_mime_needs_rewind(struct Curl_easy *data,
+                                 struct Curl_creader *reader)
+{
+  struct cr_mime_ctx *ctx = reader->ctx;
+  (void)data;
+  return ctx->read_len > 0;
+}
+
+static curl_off_t cr_mime_total_length(struct Curl_easy *data,
+                                       struct Curl_creader *reader)
+{
+  struct cr_mime_ctx *ctx = reader->ctx;
+  (void)data;
+  return ctx->total_len;
+}
+
+static CURLcode cr_mime_resume_from(struct Curl_easy *data,
+                                    struct Curl_creader *reader,
+                                    curl_off_t offset)
+{
+  struct cr_mime_ctx *ctx = reader->ctx;
+
+  if(offset > 0) {
+    curl_off_t passed = 0;
+
+    do {
+      char scratch[4*1024];
+      size_t readthisamountnow =
+        (offset - passed > (curl_off_t)sizeof(scratch)) ?
+        sizeof(scratch) :
+        curlx_sotouz(offset - passed);
+      size_t nread;
+
+      nread = Curl_mime_read(scratch, 1, readthisamountnow, ctx->part);
+      passed += (curl_off_t)nread;
+      if((nread == 0) || (nread > readthisamountnow)) {
+        /* this checks for greater-than only to make sure that the
+           CURL_READFUNC_ABORT return code still aborts */
+        failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T
+              " bytes from the mime post", passed);
+        return CURLE_READ_ERROR;
+      }
+    } while(passed < offset);
+
+    /* now, decrease the size of the read */
+    if(ctx->total_len > 0) {
+      ctx->total_len -= offset;
+
+      if(ctx->total_len <= 0) {
+        failf(data, "Mime post already completely uploaded");
+        return CURLE_PARTIAL_FILE;
+      }
+    }
+    /* we've passed, proceed as normal */
+  }
+  return CURLE_OK;
+}
+
+static CURLcode cr_mime_rewind(struct Curl_easy *data,
+                               struct Curl_creader *reader)
+{
+  struct cr_mime_ctx *ctx = reader->ctx;
+  CURLcode result = mime_rewind(ctx->part);
+  if(result)
+    failf(data, "Cannot rewind mime/post data");
+  return result;
+}
+
+static CURLcode cr_mime_unpause(struct Curl_easy *data,
+                                struct Curl_creader *reader)
+{
+  struct cr_mime_ctx *ctx = reader->ctx;
+  (void)data;
+  mime_unpause(ctx->part);
+  return CURLE_OK;
+}
+
+static const struct Curl_crtype cr_mime = {
+  "cr-mime",
+  cr_mime_init,
+  cr_mime_read,
+  Curl_creader_def_close,
+  cr_mime_needs_rewind,
+  cr_mime_total_length,
+  cr_mime_resume_from,
+  cr_mime_rewind,
+  cr_mime_unpause,
+  Curl_creader_def_done,
+  sizeof(struct cr_mime_ctx)
+};
+
+CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part)
+{
+  struct Curl_creader *r;
+  struct cr_mime_ctx *ctx;
+  CURLcode result;
+
+  result = Curl_creader_create(&r, data, &cr_mime, CURL_CR_CLIENT);
+  if(result)
+    return result;
+  ctx = r->ctx;
+  ctx->part = part;
+  /* Make sure we will read the entire mime structure. */
+  result = mime_rewind(ctx->part);
+  if(result) {
+    Curl_creader_free(data, r);
+    return result;
+  }
+  ctx->total_len = mime_size(ctx->part);
+
+  return Curl_creader_set(data, r);
+}
+
+#else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP ||
+                                !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */
+
+/* Mime not compiled in: define stubs for externally-referenced functions. */
+curl_mime *curl_mime_init(CURL *easy)
+{
+  (void) easy;
+  return NULL;
+}
+
+void curl_mime_free(curl_mime *mime)
+{
+  (void) mime;
+}
+
+curl_mimepart *curl_mime_addpart(curl_mime *mime)
+{
+  (void) mime;
+  return NULL;
+}
+
+CURLcode curl_mime_name(curl_mimepart *part, const char *name)
+{
+  (void) part;
+  (void) name;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
+{
+  (void) part;
+  (void) filename;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
+{
+  (void) part;
+  (void) mimetype;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
+{
+  (void) part;
+  (void) encoding;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_data(curl_mimepart *part,
+                        const char *data, size_t datasize)
+{
+  (void) part;
+  (void) data;
+  (void) datasize;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
+{
+  (void) part;
+  (void) filename;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_data_cb(curl_mimepart *part,
+                           curl_off_t datasize,
+                           curl_read_callback readfunc,
+                           curl_seek_callback seekfunc,
+                           curl_free_callback freefunc,
+                           void *arg)
+{
+  (void) part;
+  (void) datasize;
+  (void) readfunc;
+  (void) seekfunc;
+  (void) freefunc;
+  (void) arg;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
+{
+  (void) part;
+  (void) subparts;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_headers(curl_mimepart *part,
+                           struct curl_slist *headers, int take_ownership)
+{
+  (void) part;
+  (void) headers;
+  (void) take_ownership;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
+{
+  (void)slp;
+  (void)fmt;
+  return CURLE_NOT_BUILT_IN;
+}
+
+#endif /* if disabled */
Index: trunk/src/libs/curl-8.7.1/lib/mime.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/mime.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/mime.h	(revision 104083)
@@ -0,0 +1,176 @@
+#ifndef HEADER_CURL_MIME_H
+#define HEADER_CURL_MIME_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#define MIME_BOUNDARY_DASHES            24  /* leading boundary dashes */
+#define MIME_RAND_BOUNDARY_CHARS        22  /* Nb. of random boundary chars. */
+#define MAX_ENCODED_LINE_LENGTH         76  /* Maximum encoded line length. */
+#define ENCODING_BUFFER_SIZE            256 /* Encoding temp buffers size. */
+
+/* Part flags. */
+#define MIME_USERHEADERS_OWNER  (1 << 0)
+#define MIME_BODY_ONLY          (1 << 1)
+#define MIME_FAST_READ          (1 << 2)
+
+#define FILE_CONTENTTYPE_DEFAULT        "application/octet-stream"
+#define MULTIPART_CONTENTTYPE_DEFAULT   "multipart/mixed"
+#define DISPOSITION_DEFAULT             "attachment"
+
+/* Part source kinds. */
+enum mimekind {
+  MIMEKIND_NONE = 0,            /* Part not set. */
+  MIMEKIND_DATA,                /* Allocated mime data. */
+  MIMEKIND_FILE,                /* Data from file. */
+  MIMEKIND_CALLBACK,            /* Data from `read' callback. */
+  MIMEKIND_MULTIPART,           /* Data is a mime subpart. */
+  MIMEKIND_LAST
+};
+
+/* Readback state tokens. */
+enum mimestate {
+  MIMESTATE_BEGIN,              /* Readback has not yet started. */
+  MIMESTATE_CURLHEADERS,        /* In curl-generated headers. */
+  MIMESTATE_USERHEADERS,        /* In caller's supplied headers. */
+  MIMESTATE_EOH,                /* End of headers. */
+  MIMESTATE_BODY,               /* Placeholder. */
+  MIMESTATE_BOUNDARY1,          /* In boundary prefix. */
+  MIMESTATE_BOUNDARY2,          /* In boundary. */
+  MIMESTATE_CONTENT,            /* In content. */
+  MIMESTATE_END,                /* End of part reached. */
+  MIMESTATE_LAST
+};
+
+/* Mime headers strategies. */
+enum mimestrategy {
+  MIMESTRATEGY_MAIL,            /* Mime mail. */
+  MIMESTRATEGY_FORM,            /* HTTP post form. */
+  MIMESTRATEGY_LAST
+};
+
+/* Content transfer encoder. */
+struct mime_encoder {
+  const char *   name;          /* Encoding name. */
+  size_t         (*encodefunc)(char *buffer, size_t size, bool ateof,
+                               curl_mimepart *part);  /* Encoded read. */
+  curl_off_t     (*sizefunc)(curl_mimepart *part);  /* Encoded size. */
+};
+
+/* Content transfer encoder state. */
+struct mime_encoder_state {
+  size_t         pos;           /* Position on output line. */
+  size_t         bufbeg;        /* Next data index in input buffer. */
+  size_t         bufend;        /* First unused byte index in input buffer. */
+  char           buf[ENCODING_BUFFER_SIZE]; /* Input buffer. */
+};
+
+/* Mime readback state. */
+struct mime_state {
+  enum mimestate state;       /* Current state token. */
+  void *ptr;                  /* State-dependent pointer. */
+  curl_off_t offset;          /* State-dependent offset. */
+};
+
+/* Boundary string length. */
+#define MIME_BOUNDARY_LEN (MIME_BOUNDARY_DASHES + MIME_RAND_BOUNDARY_CHARS)
+
+/* A mime multipart. */
+struct curl_mime {
+  curl_mimepart *parent;           /* Parent part. */
+  curl_mimepart *firstpart;        /* First part. */
+  curl_mimepart *lastpart;         /* Last part. */
+  char boundary[MIME_BOUNDARY_LEN + 1]; /* The part boundary. */
+  struct mime_state state;         /* Current readback state. */
+};
+
+/* A mime part. */
+struct curl_mimepart {
+  curl_mime *parent;               /* Parent mime structure. */
+  curl_mimepart *nextpart;         /* Forward linked list. */
+  enum mimekind kind;              /* The part kind. */
+  unsigned int flags;              /* Flags. */
+  char *data;                      /* Memory data or file name. */
+  curl_read_callback readfunc;     /* Read function. */
+  curl_seek_callback seekfunc;     /* Seek function. */
+  curl_free_callback freefunc;     /* Argument free function. */
+  void *arg;                       /* Argument to callback functions. */
+  FILE *fp;                        /* File pointer. */
+  struct curl_slist *curlheaders;  /* Part headers. */
+  struct curl_slist *userheaders;  /* Part headers. */
+  char *mimetype;                  /* Part mime type. */
+  char *filename;                  /* Remote file name. */
+  char *name;                      /* Data name. */
+  curl_off_t datasize;             /* Expected data size. */
+  struct mime_state state;         /* Current readback state. */
+  const struct mime_encoder *encoder; /* Content data encoder. */
+  struct mime_encoder_state encstate; /* Data encoder state. */
+  size_t lastreadstatus;           /* Last read callback returned status. */
+};
+
+CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
+  CURL_PRINTF(2, 3);
+
+#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) ||      \
+                                    !defined(CURL_DISABLE_SMTP) ||      \
+                                    !defined(CURL_DISABLE_IMAP))
+
+/* Prototypes. */
+void Curl_mime_initpart(struct curl_mimepart *part);
+void Curl_mime_cleanpart(struct curl_mimepart *part);
+CURLcode Curl_mime_duppart(struct Curl_easy *data,
+                           struct curl_mimepart *dst,
+                           const curl_mimepart *src);
+CURLcode Curl_mime_set_subparts(struct curl_mimepart *part,
+                                struct curl_mime *subparts,
+                                int take_ownership);
+CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
+                                   struct curl_mimepart *part,
+                                   const char *contenttype,
+                                   const char *disposition,
+                                   enum mimestrategy strategy);
+size_t Curl_mime_read(char *buffer, size_t size, size_t nitems,
+                      void *instream);
+const char *Curl_mime_contenttype(const char *filename);
+
+/**
+ * Install a client reader as upload source that reads the given
+ * mime part.
+ */
+CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part);
+
+#else
+/* if disabled */
+#define Curl_mime_initpart(x)
+#define Curl_mime_cleanpart(x)
+#define Curl_mime_duppart(x,y,z) CURLE_OK /* Nothing to duplicate. Succeed */
+#define Curl_mime_set_subparts(a,b,c) CURLE_NOT_BUILT_IN
+#define Curl_mime_prepare_headers(a,b,c,d,e) CURLE_NOT_BUILT_IN
+#define Curl_mime_read NULL
+#define Curl_creader_set_mime(x,y) ((void)x, CURLE_NOT_BUILT_IN)
+#endif
+
+
+#endif /* HEADER_CURL_MIME_H */
Index: trunk/src/libs/curl-8.7.1/lib/mprintf.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/mprintf.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/mprintf.c	(revision 104083)
@@ -0,0 +1,1204 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ */
+
+#include "curl_setup.h"
+#include "dynbuf.h"
+#include "curl_printf.h"
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * If SIZEOF_SIZE_T has not been defined, default to the size of long.
+ */
+
+#ifdef HAVE_LONGLONG
+#  define LONG_LONG_TYPE long long
+#  define HAVE_LONG_LONG_TYPE
+#else
+#  if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+#    define LONG_LONG_TYPE __int64
+#    define HAVE_LONG_LONG_TYPE
+#  else
+#    undef LONG_LONG_TYPE
+#    undef HAVE_LONG_LONG_TYPE
+#  endif
+#endif
+
+/*
+ * Max integer data types that mprintf.c is capable
+ */
+
+#ifdef HAVE_LONG_LONG_TYPE
+#  define mp_intmax_t LONG_LONG_TYPE
+#  define mp_uintmax_t unsigned LONG_LONG_TYPE
+#else
+#  define mp_intmax_t long
+#  define mp_uintmax_t unsigned long
+#endif
+
+#define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should
+                        fit negative DBL_MAX (317 letters) */
+#define MAX_PARAMETERS 128 /* number of input arguments */
+#define MAX_SEGMENTS   128 /* number of output segments */
+
+#ifdef __AMIGA__
+# undef FORMAT_INT
+#endif
+
+/* Lower-case digits.  */
+static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+/* Upper-case digits.  */
+static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+#define OUTCHAR(x)                                      \
+  do {                                                  \
+    if(!stream(x, userp))                               \
+      done++;                                           \
+    else                                                \
+      return done; /* return on failure */              \
+  } while(0)
+
+/* Data type to read from the arglist */
+typedef enum {
+  FORMAT_STRING,
+  FORMAT_PTR,
+  FORMAT_INTPTR,
+  FORMAT_INT,
+  FORMAT_LONG,
+  FORMAT_LONGLONG,
+  FORMAT_INTU,
+  FORMAT_LONGU,
+  FORMAT_LONGLONGU,
+  FORMAT_DOUBLE,
+  FORMAT_LONGDOUBLE,
+  FORMAT_WIDTH,
+  FORMAT_PRECISION
+} FormatType;
+
+/* conversion and display flags */
+enum {
+  FLAGS_SPACE      = 1<<0,
+  FLAGS_SHOWSIGN   = 1<<1,
+  FLAGS_LEFT       = 1<<2,
+  FLAGS_ALT        = 1<<3,
+  FLAGS_SHORT      = 1<<4,
+  FLAGS_LONG       = 1<<5,
+  FLAGS_LONGLONG   = 1<<6,
+  FLAGS_LONGDOUBLE = 1<<7,
+  FLAGS_PAD_NIL    = 1<<8,
+  FLAGS_UNSIGNED   = 1<<9,
+  FLAGS_OCTAL      = 1<<10,
+  FLAGS_HEX        = 1<<11,
+  FLAGS_UPPER      = 1<<12,
+  FLAGS_WIDTH      = 1<<13, /* '*' or '*<num>$' used */
+  FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */
+  FLAGS_PREC       = 1<<15, /* precision was specified */
+  FLAGS_PRECPARAM  = 1<<16, /* precision PARAMETER was specified */
+  FLAGS_CHAR       = 1<<17, /* %c story */
+  FLAGS_FLOATE     = 1<<18, /* %e or %E */
+  FLAGS_FLOATG     = 1<<19, /* %g or %G */
+  FLAGS_SUBSTR     = 1<<20  /* no input, only substring */
+};
+
+enum {
+  DOLLAR_UNKNOWN,
+  DOLLAR_NOPE,
+  DOLLAR_USE
+};
+
+/*
+ * Describes an input va_arg type and hold its value.
+ */
+struct va_input {
+  FormatType type; /* FormatType */
+  union {
+    char *str;
+    void *ptr;
+    mp_intmax_t nums; /* signed */
+    mp_uintmax_t numu; /* unsigned */
+    double dnum;
+  } val;
+};
+
+/*
+ * Describes an output segment.
+ */
+struct outsegment {
+  int width;     /* width OR width parameter number */
+  int precision; /* precision OR precision parameter number */
+  unsigned int flags;
+  unsigned int input; /* input argument array index */
+  char *start;      /* format string start to output */
+  size_t outlen;     /* number of bytes from the format string to output */
+};
+
+struct nsprintf {
+  char *buffer;
+  size_t length;
+  size_t max;
+};
+
+struct asprintf {
+  struct dynbuf *b;
+  char merr;
+};
+
+/* the provided input number is 1-based but this returns the number 0-based.
+
+   returns -1 if no valid number was provided.
+*/
+static int dollarstring(char *input, char **end)
+{
+  if(ISDIGIT(*input)) {
+    int number = 0;
+    do {
+      if(number < MAX_PARAMETERS) {
+        number *= 10;
+        number += *input - '0';
+      }
+      input++;
+    } while(ISDIGIT(*input));
+
+    if(number && (number <= MAX_PARAMETERS) && ('$' == *input)) {
+      *end = ++input;
+      return number - 1;
+    }
+  }
+  return -1;
+}
+
+/*
+ * Parse the format string.
+ *
+ * Create two arrays. One describes the inputs, one describes the outputs.
+ *
+ * Returns zero on success.
+ */
+
+#define PFMT_OK          0
+#define PFMT_DOLLAR      1 /* bad dollar for main param */
+#define PFMT_DOLLARWIDTH 2 /* bad dollar use for width */
+#define PFMT_DOLLARPREC  3 /* bad dollar use for precision */
+#define PFMT_MANYARGS    4 /* too many input arguments used */
+#define PFMT_PREC        5 /* precision overflow */
+#define PFMT_PRECMIX     6 /* bad mix of precision specifiers */
+#define PFMT_WIDTH       7 /* width overflow */
+#define PFMT_INPUTGAP    8 /* gap in arguments */
+#define PFMT_WIDTHARG    9 /* attempted to use same arg twice, for width */
+#define PFMT_PRECARG    10 /* attempted to use same arg twice, for prec */
+#define PFMT_MANYSEGS   11 /* maxed out output segments */
+
+static int parsefmt(const char *format,
+                    struct outsegment *out,
+                    struct va_input *in,
+                    int *opieces,
+                    int *ipieces, va_list arglist)
+{
+  char *fmt = (char *)format;
+  int param_num = 0;
+  int param;
+  int width;
+  int precision;
+  unsigned int flags;
+  FormatType type;
+  int max_param = -1;
+  int i;
+  int ocount = 0;
+  unsigned char usedinput[MAX_PARAMETERS/8];
+  size_t outlen = 0;
+  struct outsegment *optr;
+  int use_dollar = DOLLAR_UNKNOWN;
+  char *start = fmt;
+
+  /* clear, set a bit for each used input */
+  memset(usedinput, 0, sizeof(usedinput));
+
+  while(*fmt) {
+    if(*fmt == '%') {
+      struct va_input *iptr;
+      bool loopit = TRUE;
+      fmt++;
+      outlen = fmt - start - 1;
+      if(*fmt == '%') {
+        /* this means a %% that should be output only as %. Create an output
+           segment. */
+        if(outlen) {
+          optr = &out[ocount++];
+          if(ocount > MAX_SEGMENTS)
+            return PFMT_MANYSEGS;
+          optr->input = 0;
+          optr->flags = FLAGS_SUBSTR;
+          optr->start = start;
+          optr->outlen = outlen;
+        }
+        start = fmt;
+        fmt++;
+        continue; /* while */
+      }
+
+      flags = width = precision = 0;
+
+      if(use_dollar != DOLLAR_NOPE) {
+        param = dollarstring(fmt, &fmt);
+        if(param < 0) {
+          if(use_dollar == DOLLAR_USE)
+            /* illegal combo */
+            return PFMT_DOLLAR;
+
+          /* we got no positional, just get the next arg */
+          param = -1;
+          use_dollar = DOLLAR_NOPE;
+        }
+        else
+          use_dollar = DOLLAR_USE;
+      }
+      else
+        param = -1;
+
+      /* Handle the flags */
+      while(loopit) {
+        switch(*fmt++) {
+        case ' ':
+          flags |= FLAGS_SPACE;
+          break;
+        case '+':
+          flags |= FLAGS_SHOWSIGN;
+          break;
+        case '-':
+          flags |= FLAGS_LEFT;
+          flags &= ~FLAGS_PAD_NIL;
+          break;
+        case '#':
+          flags |= FLAGS_ALT;
+          break;
+        case '.':
+          if('*' == *fmt) {
+            /* The precision is picked from a specified parameter */
+            flags |= FLAGS_PRECPARAM;
+            fmt++;
+
+            if(use_dollar == DOLLAR_USE) {
+              precision = dollarstring(fmt, &fmt);
+              if(precision < 0)
+                /* illegal combo */
+                return PFMT_DOLLARPREC;
+            }
+            else
+              /* get it from the next argument */
+              precision = -1;
+          }
+          else {
+            bool is_neg = FALSE;
+            flags |= FLAGS_PREC;
+            precision = 0;
+            if('-' == *fmt) {
+              is_neg = TRUE;
+              fmt++;
+            }
+            while(ISDIGIT(*fmt)) {
+              if(precision > INT_MAX/10)
+                return PFMT_PREC;
+              precision *= 10;
+              precision += *fmt - '0';
+              fmt++;
+            }
+            if(is_neg)
+              precision = -precision;
+          }
+          if((flags & (FLAGS_PREC | FLAGS_PRECPARAM)) ==
+             (FLAGS_PREC | FLAGS_PRECPARAM))
+            /* it is not permitted to use both kinds of precision for the same
+               argument */
+            return PFMT_PRECMIX;
+          break;
+        case 'h':
+          flags |= FLAGS_SHORT;
+          break;
+#if defined(_WIN32) || defined(_WIN32_WCE)
+        case 'I':
+          /* Non-ANSI integer extensions I32 I64 */
+          if((fmt[0] == '3') && (fmt[1] == '2')) {
+            flags |= FLAGS_LONG;
+            fmt += 2;
+          }
+          else if((fmt[0] == '6') && (fmt[1] == '4')) {
+            flags |= FLAGS_LONGLONG;
+            fmt += 2;
+          }
+          else {
+#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
+            flags |= FLAGS_LONGLONG;
+#else
+            flags |= FLAGS_LONG;
+#endif
+          }
+          break;
+#endif /* _WIN32 || _WIN32_WCE */
+        case 'l':
+          if(flags & FLAGS_LONG)
+            flags |= FLAGS_LONGLONG;
+          else
+            flags |= FLAGS_LONG;
+          break;
+        case 'L':
+          flags |= FLAGS_LONGDOUBLE;
+          break;
+        case 'q':
+          flags |= FLAGS_LONGLONG;
+          break;
+        case 'z':
+          /* the code below generates a warning if -Wunreachable-code is
+             used */
+#if (SIZEOF_SIZE_T > SIZEOF_LONG)
+          flags |= FLAGS_LONGLONG;
+#else
+          flags |= FLAGS_LONG;
+#endif
+          break;
+        case 'O':
+#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
+          flags |= FLAGS_LONGLONG;
+#else
+          flags |= FLAGS_LONG;
+#endif
+          break;
+        case '0':
+          if(!(flags & FLAGS_LEFT))
+            flags |= FLAGS_PAD_NIL;
+          FALLTHROUGH();
+        case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+          flags |= FLAGS_WIDTH;
+          width = 0;
+          fmt--;
+          do {
+            if(width > INT_MAX/10)
+              return PFMT_WIDTH;
+            width *= 10;
+            width += *fmt - '0';
+            fmt++;
+          } while(ISDIGIT(*fmt));
+          break;
+        case '*':  /* read width from argument list */
+          flags |= FLAGS_WIDTHPARAM;
+          if(use_dollar == DOLLAR_USE) {
+            width = dollarstring(fmt, &fmt);
+            if(width < 0)
+              /* illegal combo */
+              return PFMT_DOLLARWIDTH;
+          }
+          else
+            /* pick from the next argument */
+            width = -1;
+          break;
+        default:
+          loopit = FALSE;
+          fmt--;
+          break;
+        } /* switch */
+      } /* while */
+
+      switch(*fmt) {
+      case 'S':
+        flags |= FLAGS_ALT;
+        FALLTHROUGH();
+      case 's':
+        type = FORMAT_STRING;
+        break;
+      case 'n':
+        type = FORMAT_INTPTR;
+        break;
+      case 'p':
+        type = FORMAT_PTR;
+        break;
+      case 'd':
+      case 'i':
+        if(flags & FLAGS_LONGLONG)
+          type = FORMAT_LONGLONG;
+        else if(flags & FLAGS_LONG)
+          type = FORMAT_LONG;
+        else
+          type = FORMAT_INT;
+        break;
+      case 'u':
+        if(flags & FLAGS_LONGLONG)
+          type = FORMAT_LONGLONGU;
+        else if(flags & FLAGS_LONG)
+          type = FORMAT_LONGU;
+        else
+          type = FORMAT_INTU;
+        flags |= FLAGS_UNSIGNED;
+        break;
+      case 'o':
+        type = FORMAT_INT;
+        flags |= FLAGS_OCTAL;
+        break;
+      case 'x':
+        type = FORMAT_INTU;
+        flags |= FLAGS_HEX|FLAGS_UNSIGNED;
+        break;
+      case 'X':
+        type = FORMAT_INTU;
+        flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
+        break;
+      case 'c':
+        type = FORMAT_INT;
+        flags |= FLAGS_CHAR;
+        break;
+      case 'f':
+        type = FORMAT_DOUBLE;
+        break;
+      case 'e':
+        type = FORMAT_DOUBLE;
+        flags |= FLAGS_FLOATE;
+        break;
+      case 'E':
+        type = FORMAT_DOUBLE;
+        flags |= FLAGS_FLOATE|FLAGS_UPPER;
+        break;
+      case 'g':
+        type = FORMAT_DOUBLE;
+        flags |= FLAGS_FLOATG;
+        break;
+      case 'G':
+        type = FORMAT_DOUBLE;
+        flags |= FLAGS_FLOATG|FLAGS_UPPER;
+        break;
+      default:
+        /* invalid instruction, disregard and continue */
+        continue;
+      } /* switch */
+
+      if(flags & FLAGS_WIDTHPARAM) {
+        if(width < 0)
+          width = param_num++;
+        else {
+          /* if this identifies a parameter already used, this
+             is illegal */
+          if(usedinput[width/8] & (1 << (width&7)))
+            return PFMT_WIDTHARG;
+        }
+        if(width >= MAX_PARAMETERS)
+          return PFMT_MANYARGS;
+        if(width >= max_param)
+          max_param = width;
+
+        in[width].type = FORMAT_WIDTH;
+        /* mark as used */
+        usedinput[width/8] |= (unsigned char)(1 << (width&7));
+      }
+
+      if(flags & FLAGS_PRECPARAM) {
+        if(precision < 0)
+          precision = param_num++;
+        else {
+          /* if this identifies a parameter already used, this
+             is illegal */
+          if(usedinput[precision/8] & (1 << (precision&7)))
+            return PFMT_PRECARG;
+        }
+        if(precision >= MAX_PARAMETERS)
+          return PFMT_MANYARGS;
+        if(precision >= max_param)
+          max_param = precision;
+
+        in[precision].type = FORMAT_PRECISION;
+        usedinput[precision/8] |= (unsigned char)(1 << (precision&7));
+      }
+
+      /* Handle the specifier */
+      if(param < 0)
+        param = param_num++;
+      if(param >= MAX_PARAMETERS)
+        return PFMT_MANYARGS;
+      if(param >= max_param)
+        max_param = param;
+
+      iptr = &in[param];
+      iptr->type = type;
+
+      /* mark this input as used */
+      usedinput[param/8] |= (unsigned char)(1 << (param&7));
+
+      fmt++;
+      optr = &out[ocount++];
+      if(ocount > MAX_SEGMENTS)
+        return PFMT_MANYSEGS;
+      optr->input = param;
+      optr->flags = flags;
+      optr->width = width;
+      optr->precision = precision;
+      optr->start = start;
+      optr->outlen = outlen;
+      start = fmt;
+    }
+    else
+      fmt++;
+  }
+
+  /* is there a trailing piece */
+  outlen = fmt - start;
+  if(outlen) {
+    optr = &out[ocount++];
+    if(ocount > MAX_SEGMENTS)
+      return PFMT_MANYSEGS;
+    optr->input = 0;
+    optr->flags = FLAGS_SUBSTR;
+    optr->start = start;
+    optr->outlen = outlen;
+  }
+
+  /* Read the arg list parameters into our data list */
+  for(i = 0; i < max_param + 1; i++) {
+    struct va_input *iptr = &in[i];
+    if(!(usedinput[i/8] & (1 << (i&7))))
+      /* bad input */
+      return PFMT_INPUTGAP;
+
+    /* based on the type, read the correct argument */
+    switch(iptr->type) {
+    case FORMAT_STRING:
+      iptr->val.str = va_arg(arglist, char *);
+      break;
+
+    case FORMAT_INTPTR:
+    case FORMAT_PTR:
+      iptr->val.ptr = va_arg(arglist, void *);
+      break;
+
+    case FORMAT_LONGLONGU:
+      iptr->val.numu = (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
+      break;
+
+    case FORMAT_LONGLONG:
+      iptr->val.nums = (mp_intmax_t)va_arg(arglist, mp_intmax_t);
+      break;
+
+    case FORMAT_LONGU:
+      iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned long);
+      break;
+
+    case FORMAT_LONG:
+      iptr->val.nums = (mp_intmax_t)va_arg(arglist, long);
+      break;
+
+    case FORMAT_INTU:
+      iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned int);
+      break;
+
+    case FORMAT_INT:
+    case FORMAT_WIDTH:
+    case FORMAT_PRECISION:
+      iptr->val.nums = (mp_intmax_t)va_arg(arglist, int);
+      break;
+
+    case FORMAT_DOUBLE:
+      iptr->val.dnum = va_arg(arglist, double);
+      break;
+
+    default:
+      DEBUGASSERT(NULL); /* unexpected */
+      break;
+    }
+  }
+  *ipieces = max_param + 1;
+  *opieces = ocount;
+
+  return PFMT_OK;
+}
+
+/*
+ * formatf() - the general printf function.
+ *
+ * It calls parsefmt() to parse the format string. It populates two arrays;
+ * one that describes the input arguments and one that describes a number of
+ * output segments.
+ *
+ * On success, the input array describes the type of all arguments and their
+ * values.
+ *
+ * The function then iterates over the output segments and outputs them one
+ * by one until done. Using the appropriate input arguments (if any).
+ *
+ * All output is sent to the 'stream()' callback, one byte at a time.
+ */
+
+static int formatf(
+  void *userp, /* untouched by format(), just sent to the stream() function in
+                  the second argument */
+  /* function pointer called for each output character */
+  int (*stream)(unsigned char, void *),
+  const char *format,    /* %-formatted string */
+  va_list ap_save) /* list of parameters */
+{
+  static const char nilstr[] = "(nil)";
+  const char *digits = lower_digits;   /* Base-36 digits for numbers.  */
+  int done = 0;   /* number of characters written  */
+  int i;
+  int ocount = 0; /* number of output segments */
+  int icount = 0; /* number of input arguments */
+
+  struct outsegment output[MAX_SEGMENTS];
+  struct va_input input[MAX_PARAMETERS];
+  char work[BUFFSIZE];
+
+  /* 'workend' points to the final buffer byte position, but with an extra
+     byte as margin to avoid the (false?) warning Coverity gives us
+     otherwise */
+  char *workend = &work[sizeof(work) - 2];
+
+  /* Parse the format string */
+  if(parsefmt(format, output, input, &ocount, &icount, ap_save))
+    return 0;
+
+  for(i = 0; i < ocount; i++) {
+    struct outsegment *optr = &output[i];
+    struct va_input *iptr;
+    bool is_alt;            /* Format spec modifiers.  */
+    int width;              /* Width of a field.  */
+    int prec;               /* Precision of a field.  */
+    bool is_neg;            /* Decimal integer is negative.  */
+    unsigned long base;     /* Base of a number to be written.  */
+    mp_uintmax_t num;       /* Integral values to be written.  */
+    mp_intmax_t signed_num; /* Used to convert negative in positive.  */
+    char *w;
+    size_t outlen = optr->outlen;
+    int flags = optr->flags;
+
+    if(outlen) {
+      char *str = optr->start;
+      for(; outlen && *str; outlen--)
+        OUTCHAR(*str++);
+      if(optr->flags & FLAGS_SUBSTR)
+        /* this is just a substring */
+        continue;
+    }
+
+    /* pick up the specified width */
+    if(flags & FLAGS_WIDTHPARAM) {
+      width = (int)input[optr->width].val.nums;
+      if(width < 0) {
+        /* "A negative field width is taken as a '-' flag followed by a
+           positive field width." */
+        if(width == INT_MIN)
+          width = INT_MAX;
+        else
+          width = -width;
+        flags |= FLAGS_LEFT;
+        flags &= ~FLAGS_PAD_NIL;
+      }
+    }
+    else
+      width = optr->width;
+
+    /* pick up the specified precision */
+    if(flags & FLAGS_PRECPARAM) {
+      prec = (int)input[optr->precision].val.nums;
+      if(prec < 0)
+        /* "A negative precision is taken as if the precision were
+           omitted." */
+        prec = -1;
+    }
+    else if(flags & FLAGS_PREC)
+      prec = optr->precision;
+    else
+      prec = -1;
+
+    is_alt = (flags & FLAGS_ALT) ? 1 : 0;
+    iptr = &input[optr->input];
+
+    switch(iptr->type) {
+    case FORMAT_INTU:
+    case FORMAT_LONGU:
+    case FORMAT_LONGLONGU:
+      flags |= FLAGS_UNSIGNED;
+      FALLTHROUGH();
+    case FORMAT_INT:
+    case FORMAT_LONG:
+    case FORMAT_LONGLONG:
+      num = iptr->val.numu;
+      if(flags & FLAGS_CHAR) {
+        /* Character.  */
+        if(!(flags & FLAGS_LEFT))
+          while(--width > 0)
+            OUTCHAR(' ');
+        OUTCHAR((char) num);
+        if(flags & FLAGS_LEFT)
+          while(--width > 0)
+            OUTCHAR(' ');
+        break;
+      }
+      if(flags & FLAGS_OCTAL) {
+        /* Octal unsigned integer */
+        base = 8;
+        is_neg = FALSE;
+      }
+      else if(flags & FLAGS_HEX) {
+        /* Hexadecimal unsigned integer */
+        digits = (flags & FLAGS_UPPER)? upper_digits : lower_digits;
+        base = 16;
+        is_neg = FALSE;
+      }
+      else if(flags & FLAGS_UNSIGNED) {
+        /* Decimal unsigned integer */
+        base = 10;
+        is_neg = FALSE;
+      }
+      else {
+        /* Decimal integer.  */
+        base = 10;
+
+        is_neg = (iptr->val.nums < (mp_intmax_t)0);
+        if(is_neg) {
+          /* signed_num might fail to hold absolute negative minimum by 1 */
+          signed_num = iptr->val.nums + (mp_intmax_t)1;
+          signed_num = -signed_num;
+          num = (mp_uintmax_t)signed_num;
+          num += (mp_uintmax_t)1;
+        }
+      }
+number:
+      /* Supply a default precision if none was given.  */
+      if(prec == -1)
+        prec = 1;
+
+      /* Put the number in WORK.  */
+      w = workend;
+      switch(base) {
+      case 10:
+        while(num > 0) {
+          *w-- = (char)('0' + (num % 10));
+          num /= 10;
+        }
+        break;
+      default:
+        while(num > 0) {
+          *w-- = digits[num % base];
+          num /= base;
+        }
+        break;
+      }
+      width -= (int)(workend - w);
+      prec -= (int)(workend - w);
+
+      if(is_alt && base == 8 && prec <= 0) {
+        *w-- = '0';
+        --width;
+      }
+
+      if(prec > 0) {
+        width -= prec;
+        while(prec-- > 0 && w >= work)
+          *w-- = '0';
+      }
+
+      if(is_alt && base == 16)
+        width -= 2;
+
+      if(is_neg || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
+        --width;
+
+      if(!(flags & FLAGS_LEFT) && !(flags & FLAGS_PAD_NIL))
+        while(width-- > 0)
+          OUTCHAR(' ');
+
+      if(is_neg)
+        OUTCHAR('-');
+      else if(flags & FLAGS_SHOWSIGN)
+        OUTCHAR('+');
+      else if(flags & FLAGS_SPACE)
+        OUTCHAR(' ');
+
+      if(is_alt && base == 16) {
+        OUTCHAR('0');
+        if(flags & FLAGS_UPPER)
+          OUTCHAR('X');
+        else
+          OUTCHAR('x');
+      }
+
+      if(!(flags & FLAGS_LEFT) && (flags & FLAGS_PAD_NIL))
+        while(width-- > 0)
+          OUTCHAR('0');
+
+      /* Write the number.  */
+      while(++w <= workend) {
+        OUTCHAR(*w);
+      }
+
+      if(flags & FLAGS_LEFT)
+        while(width-- > 0)
+          OUTCHAR(' ');
+      break;
+
+    case FORMAT_STRING: {
+      const char *str;
+      size_t len;
+
+      str = (char *)iptr->val.str;
+      if(!str) {
+        /* Write null string if there's space.  */
+        if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) {
+          str = nilstr;
+          len = sizeof(nilstr) - 1;
+          /* Disable quotes around (nil) */
+          flags &= (~FLAGS_ALT);
+        }
+        else {
+          str = "";
+          len = 0;
+        }
+      }
+      else if(prec != -1)
+        len = (size_t)prec;
+      else if(*str == '\0')
+        len = 0;
+      else
+        len = strlen(str);
+
+      width -= (len > INT_MAX) ? INT_MAX : (int)len;
+
+      if(flags & FLAGS_ALT)
+        OUTCHAR('"');
+
+      if(!(flags&FLAGS_LEFT))
+        while(width-- > 0)
+          OUTCHAR(' ');
+
+      for(; len && *str; len--)
+        OUTCHAR(*str++);
+      if(flags&FLAGS_LEFT)
+        while(width-- > 0)
+          OUTCHAR(' ');
+
+      if(flags & FLAGS_ALT)
+        OUTCHAR('"');
+      break;
+    }
+
+    case FORMAT_PTR:
+      /* Generic pointer.  */
+      if(iptr->val.ptr) {
+        /* If the pointer is not NULL, write it as a %#x spec.  */
+        base = 16;
+        digits = (flags & FLAGS_UPPER)? upper_digits : lower_digits;
+        is_alt = TRUE;
+        num = (size_t) iptr->val.ptr;
+        is_neg = FALSE;
+        goto number;
+      }
+      else {
+        /* Write "(nil)" for a nil pointer.  */
+        const char *point;
+
+        width -= (int)(sizeof(nilstr) - 1);
+        if(flags & FLAGS_LEFT)
+          while(width-- > 0)
+            OUTCHAR(' ');
+        for(point = nilstr; *point != '\0'; ++point)
+          OUTCHAR(*point);
+        if(!(flags & FLAGS_LEFT))
+          while(width-- > 0)
+            OUTCHAR(' ');
+      }
+      break;
+
+    case FORMAT_DOUBLE: {
+      char formatbuf[32]="%";
+      char *fptr = &formatbuf[1];
+      size_t left = sizeof(formatbuf)-strlen(formatbuf);
+      int len;
+
+      if(flags & FLAGS_WIDTH)
+        width = optr->width;
+
+      if(flags & FLAGS_PREC)
+        prec = optr->precision;
+
+      if(flags & FLAGS_LEFT)
+        *fptr++ = '-';
+      if(flags & FLAGS_SHOWSIGN)
+        *fptr++ = '+';
+      if(flags & FLAGS_SPACE)
+        *fptr++ = ' ';
+      if(flags & FLAGS_ALT)
+        *fptr++ = '#';
+
+      *fptr = 0;
+
+      if(width >= 0) {
+        if(width >= (int)sizeof(work))
+          width = sizeof(work)-1;
+        /* RECURSIVE USAGE */
+        len = curl_msnprintf(fptr, left, "%d", width);
+        fptr += len;
+        left -= len;
+      }
+      if(prec >= 0) {
+        /* for each digit in the integer part, we can have one less
+           precision */
+        size_t maxprec = sizeof(work) - 2;
+        double val = iptr->val.dnum;
+        if(width > 0 && prec <= width)
+          maxprec -= width;
+        while(val >= 10.0) {
+          val /= 10;
+          maxprec--;
+        }
+
+        if(prec > (int)maxprec)
+          prec = (int)maxprec-1;
+        if(prec < 0)
+          prec = 0;
+        /* RECURSIVE USAGE */
+        len = curl_msnprintf(fptr, left, ".%d", prec);
+        fptr += len;
+      }
+      if(flags & FLAGS_LONG)
+        *fptr++ = 'l';
+
+      if(flags & FLAGS_FLOATE)
+        *fptr++ = (char)((flags & FLAGS_UPPER) ? 'E':'e');
+      else if(flags & FLAGS_FLOATG)
+        *fptr++ = (char)((flags & FLAGS_UPPER) ? 'G' : 'g');
+      else
+        *fptr++ = 'f';
+
+      *fptr = 0; /* and a final null-termination */
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-nonliteral"
+#endif
+      /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
+         output characters */
+#ifdef HAVE_SNPRINTF
+      (snprintf)(work, sizeof(work), formatbuf, iptr->val.dnum);
+#else
+      (sprintf)(work, formatbuf, iptr->val.dnum);
+#endif
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+      DEBUGASSERT(strlen(work) <= sizeof(work));
+      for(fptr = work; *fptr; fptr++)
+        OUTCHAR(*fptr);
+      break;
+    }
+
+    case FORMAT_INTPTR:
+      /* Answer the count of characters written.  */
+#ifdef HAVE_LONG_LONG_TYPE
+      if(flags & FLAGS_LONGLONG)
+        *(LONG_LONG_TYPE *) iptr->val.ptr = (LONG_LONG_TYPE)done;
+      else
+#endif
+        if(flags & FLAGS_LONG)
+          *(long *) iptr->val.ptr = (long)done;
+      else if(!(flags & FLAGS_SHORT))
+        *(int *) iptr->val.ptr = (int)done;
+      else
+        *(short *) iptr->val.ptr = (short)done;
+      break;
+
+    default:
+      break;
+    }
+  }
+  return done;
+}
+
+/* fputc() look-alike */
+static int addbyter(unsigned char outc, void *f)
+{
+  struct nsprintf *infop = f;
+  if(infop->length < infop->max) {
+    /* only do this if we haven't reached max length yet */
+    *infop->buffer++ = outc; /* store */
+    infop->length++; /* we are now one byte larger */
+    return 0;     /* fputc() returns like this on success */
+  }
+  return 1;
+}
+
+int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
+                    va_list ap_save)
+{
+  int retcode;
+  struct nsprintf info;
+
+  info.buffer = buffer;
+  info.length = 0;
+  info.max = maxlength;
+
+  retcode = formatf(&info, addbyter, format, ap_save);
+  if(info.max) {
+    /* we terminate this with a zero byte */
+    if(info.max == info.length) {
+      /* we're at maximum, scrap the last letter */
+      info.buffer[-1] = 0;
+      DEBUGASSERT(retcode);
+      retcode--; /* don't count the nul byte */
+    }
+    else
+      info.buffer[0] = 0;
+  }
+  return retcode;
+}
+
+int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
+{
+  int retcode;
+  va_list ap_save; /* argument pointer */
+  va_start(ap_save, format);
+  retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
+  va_end(ap_save);
+  return retcode;
+}
+
+/* fputc() look-alike */
+static int alloc_addbyter(unsigned char outc, void *f)
+{
+  struct asprintf *infop = f;
+  CURLcode result = Curl_dyn_addn(infop->b, &outc, 1);
+  if(result) {
+    infop->merr = result == CURLE_TOO_LARGE ? MERR_TOO_LARGE : MERR_MEM;
+    return 1 ; /* fail */
+  }
+  return 0;
+}
+
+/* appends the formatted string, returns MERR error code */
+int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save)
+{
+  struct asprintf info;
+  info.b = dyn;
+  info.merr = MERR_OK;
+
+  (void)formatf(&info, alloc_addbyter, format, ap_save);
+  if(info.merr) {
+    Curl_dyn_free(info.b);
+    return info.merr;
+  }
+  return 0;
+}
+
+char *curl_mvaprintf(const char *format, va_list ap_save)
+{
+  struct asprintf info;
+  struct dynbuf dyn;
+  info.b = &dyn;
+  Curl_dyn_init(info.b, DYN_APRINTF);
+  info.merr = MERR_OK;
+
+  (void)formatf(&info, alloc_addbyter, format, ap_save);
+  if(info.merr) {
+    Curl_dyn_free(info.b);
+    return NULL;
+  }
+  if(Curl_dyn_len(info.b))
+    return Curl_dyn_ptr(info.b);
+  return strdup("");
+}
+
+char *curl_maprintf(const char *format, ...)
+{
+  va_list ap_save;
+  char *s;
+  va_start(ap_save, format);
+  s = curl_mvaprintf(format, ap_save);
+  va_end(ap_save);
+  return s;
+}
+
+static int storebuffer(unsigned char outc, void *f)
+{
+  char **buffer = f;
+  **buffer = outc;
+  (*buffer)++;
+  return 0;
+}
+
+int curl_msprintf(char *buffer, const char *format, ...)
+{
+  va_list ap_save; /* argument pointer */
+  int retcode;
+  va_start(ap_save, format);
+  retcode = formatf(&buffer, storebuffer, format, ap_save);
+  va_end(ap_save);
+  *buffer = 0; /* we terminate this with a zero byte */
+  return retcode;
+}
+
+static int fputc_wrapper(unsigned char outc, void *f)
+{
+  int out = outc;
+  FILE *s = f;
+  int rc = fputc(out, s);
+  if(rc == out)
+    return 0;
+  return 1;
+}
+
+int curl_mprintf(const char *format, ...)
+{
+  int retcode;
+  va_list ap_save; /* argument pointer */
+  va_start(ap_save, format);
+
+  retcode = formatf(stdout, fputc_wrapper, format, ap_save);
+  va_end(ap_save);
+  return retcode;
+}
+
+int curl_mfprintf(FILE *whereto, const char *format, ...)
+{
+  int retcode;
+  va_list ap_save; /* argument pointer */
+  va_start(ap_save, format);
+  retcode = formatf(whereto, fputc_wrapper, format, ap_save);
+  va_end(ap_save);
+  return retcode;
+}
+
+int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
+{
+  int retcode = formatf(&buffer, storebuffer, format, ap_save);
+  *buffer = 0; /* we terminate this with a zero byte */
+  return retcode;
+}
+
+int curl_mvprintf(const char *format, va_list ap_save)
+{
+  return formatf(stdout, fputc_wrapper, format, ap_save);
+}
+
+int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
+{
+  return formatf(whereto, fputc_wrapper, format, ap_save);
+}
Index: trunk/src/libs/curl-8.7.1/lib/mqtt.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/mqtt.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/mqtt.c	(revision 104083)
@@ -0,0 +1,841 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Björn Stenberg, <bjorn@haxx.se>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_MQTT
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "progress.h"
+#include "mqtt.h"
+#include "select.h"
+#include "strdup.h"
+#include "url.h"
+#include "escape.h"
+#include "warnless.h"
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "multiif.h"
+#include "rand.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define MQTT_MSG_CONNECT   0x10
+#define MQTT_MSG_CONNACK   0x20
+#define MQTT_MSG_PUBLISH   0x30
+#define MQTT_MSG_SUBSCRIBE 0x82
+#define MQTT_MSG_SUBACK    0x90
+#define MQTT_MSG_DISCONNECT 0xe0
+
+#define MQTT_CONNACK_LEN 2
+#define MQTT_SUBACK_LEN 3
+#define MQTT_CLIENTID_LEN 12 /* "curl0123abcd" */
+
+/*
+ * Forward declarations.
+ */
+
+static CURLcode mqtt_do(struct Curl_easy *data, bool *done);
+static CURLcode mqtt_done(struct Curl_easy *data,
+                          CURLcode status, bool premature);
+static CURLcode mqtt_doing(struct Curl_easy *data, bool *done);
+static int mqtt_getsock(struct Curl_easy *data, struct connectdata *conn,
+                        curl_socket_t *sock);
+static CURLcode mqtt_setup_conn(struct Curl_easy *data,
+                                struct connectdata *conn);
+
+/*
+ * MQTT protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_mqtt = {
+  "MQTT",                             /* scheme */
+  mqtt_setup_conn,                    /* setup_connection */
+  mqtt_do,                            /* do_it */
+  mqtt_done,                          /* done */
+  ZERO_NULL,                          /* do_more */
+  ZERO_NULL,                          /* connect_it */
+  ZERO_NULL,                          /* connecting */
+  mqtt_doing,                         /* doing */
+  ZERO_NULL,                          /* proto_getsock */
+  mqtt_getsock,                       /* doing_getsock */
+  ZERO_NULL,                          /* domore_getsock */
+  ZERO_NULL,                          /* perform_getsock */
+  ZERO_NULL,                          /* disconnect */
+  ZERO_NULL,                          /* write_resp */
+  ZERO_NULL,                          /* connection_check */
+  ZERO_NULL,                          /* attach connection */
+  PORT_MQTT,                          /* defport */
+  CURLPROTO_MQTT,                     /* protocol */
+  CURLPROTO_MQTT,                     /* family */
+  PROTOPT_NONE                        /* flags */
+};
+
+static CURLcode mqtt_setup_conn(struct Curl_easy *data,
+                                struct connectdata *conn)
+{
+  /* allocate the HTTP-specific struct for the Curl_easy, only to survive
+     during this request */
+  struct MQTT *mq;
+  (void)conn;
+  DEBUGASSERT(data->req.p.mqtt == NULL);
+
+  mq = calloc(1, sizeof(struct MQTT));
+  if(!mq)
+    return CURLE_OUT_OF_MEMORY;
+  Curl_dyn_init(&mq->recvbuf, DYN_MQTT_RECV);
+  data->req.p.mqtt = mq;
+  return CURLE_OK;
+}
+
+static CURLcode mqtt_send(struct Curl_easy *data,
+                          char *buf, size_t len)
+{
+  CURLcode result = CURLE_OK;
+  struct MQTT *mq = data->req.p.mqtt;
+  size_t n;
+  result = Curl_xfer_send(data, buf, len, &n);
+  if(result)
+    return result;
+  Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
+  if(len != n) {
+    size_t nsend = len - n;
+    char *sendleftovers = Curl_memdup(&buf[n], nsend);
+    if(!sendleftovers)
+      return CURLE_OUT_OF_MEMORY;
+    mq->sendleftovers = sendleftovers;
+    mq->nsend = nsend;
+  }
+  else {
+    mq->sendleftovers = NULL;
+    mq->nsend = 0;
+  }
+  return result;
+}
+
+/* Generic function called by the multi interface to figure out what socket(s)
+   to wait for and for what actions during the DOING and PROTOCONNECT
+   states */
+static int mqtt_getsock(struct Curl_easy *data,
+                        struct connectdata *conn,
+                        curl_socket_t *sock)
+{
+  (void)data;
+  sock[0] = conn->sock[FIRSTSOCKET];
+  return GETSOCK_READSOCK(FIRSTSOCKET);
+}
+
+static int mqtt_encode_len(char *buf, size_t len)
+{
+  unsigned char encoded;
+  int i;
+
+  for(i = 0; (len > 0) && (i<4); i++) {
+    encoded = len % 0x80;
+    len /= 0x80;
+    if(len)
+      encoded |= 0x80;
+    buf[i] = encoded;
+  }
+
+  return i;
+}
+
+/* add the passwd to the CONNECT packet */
+static int add_passwd(const char *passwd, const size_t plen,
+                       char *pkt, const size_t start, int remain_pos)
+{
+  /* magic number that need to be set properly */
+  const size_t conn_flags_pos = remain_pos + 8;
+  if(plen > 0xffff)
+    return 1;
+
+  /* set password flag */
+  pkt[conn_flags_pos] |= 0x40;
+
+  /* length of password provided */
+  pkt[start] = (char)((plen >> 8) & 0xFF);
+  pkt[start + 1] = (char)(plen & 0xFF);
+  memcpy(&pkt[start + 2], passwd, plen);
+  return 0;
+}
+
+/* add user to the CONNECT packet */
+static int add_user(const char *username, const size_t ulen,
+                    unsigned char *pkt, const size_t start, int remain_pos)
+{
+  /* magic number that need to be set properly */
+  const size_t conn_flags_pos = remain_pos + 8;
+  if(ulen > 0xffff)
+    return 1;
+
+  /* set username flag */
+  pkt[conn_flags_pos] |= 0x80;
+  /* length of username provided */
+  pkt[start] = (unsigned char)((ulen >> 8) & 0xFF);
+  pkt[start + 1] = (unsigned char)(ulen & 0xFF);
+  memcpy(&pkt[start + 2], username, ulen);
+  return 0;
+}
+
+/* add client ID to the CONNECT packet */
+static int add_client_id(const char *client_id, const size_t client_id_len,
+                         char *pkt, const size_t start)
+{
+  if(client_id_len != MQTT_CLIENTID_LEN)
+    return 1;
+  pkt[start] = 0x00;
+  pkt[start + 1] = MQTT_CLIENTID_LEN;
+  memcpy(&pkt[start + 2], client_id, MQTT_CLIENTID_LEN);
+  return 0;
+}
+
+/* Set initial values of CONNECT packet */
+static int init_connpack(char *packet, char *remain, int remain_pos)
+{
+  /* Fixed header starts */
+  /* packet type */
+  packet[0] = MQTT_MSG_CONNECT;
+  /* remaining length field */
+  memcpy(&packet[1], remain, remain_pos);
+  /* Fixed header ends */
+
+  /* Variable header starts */
+  /* protocol length */
+  packet[remain_pos + 1] = 0x00;
+  packet[remain_pos + 2] = 0x04;
+  /* protocol name */
+  packet[remain_pos + 3] = 'M';
+  packet[remain_pos + 4] = 'Q';
+  packet[remain_pos + 5] = 'T';
+  packet[remain_pos + 6] = 'T';
+  /* protocol level */
+  packet[remain_pos + 7] = 0x04;
+  /* CONNECT flag: CleanSession */
+  packet[remain_pos + 8] = 0x02;
+  /* keep-alive 0 = disabled */
+  packet[remain_pos + 9] = 0x00;
+  packet[remain_pos + 10] = 0x3c;
+  /* end of variable header */
+  return remain_pos + 10;
+}
+
+static CURLcode mqtt_connect(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  int pos = 0;
+  int rc = 0;
+  /* remain length */
+  int remain_pos = 0;
+  char remain[4] = {0};
+  size_t packetlen = 0;
+  size_t payloadlen = 0;
+  size_t start_user = 0;
+  size_t start_pwd = 0;
+  char client_id[MQTT_CLIENTID_LEN + 1] = "curl";
+  const size_t clen = strlen("curl");
+  char *packet = NULL;
+
+  /* extracting username from request */
+  const char *username = data->state.aptr.user ?
+    data->state.aptr.user : "";
+  const size_t ulen = strlen(username);
+  /* extracting password from request */
+  const char *passwd = data->state.aptr.passwd ?
+    data->state.aptr.passwd : "";
+  const size_t plen = strlen(passwd);
+
+  payloadlen = ulen + plen + MQTT_CLIENTID_LEN + 2;
+  /* The plus 2 are for the MSB and LSB describing the length of the string to
+   * be added on the payload. Refer to spec 1.5.2 and 1.5.4 */
+  if(ulen)
+    payloadlen += 2;
+  if(plen)
+    payloadlen += 2;
+
+  /* getting how much occupy the remain length */
+  remain_pos = mqtt_encode_len(remain, payloadlen + 10);
+
+  /* 10 length of variable header and 1 the first byte of the fixed header */
+  packetlen = payloadlen + 10 + remain_pos + 1;
+
+  /* allocating packet */
+  if(packetlen > 268435455)
+    return CURLE_WEIRD_SERVER_REPLY;
+  packet = malloc(packetlen);
+  if(!packet)
+    return CURLE_OUT_OF_MEMORY;
+  memset(packet, 0, packetlen);
+
+  /* set initial values for the CONNECT packet */
+  pos = init_connpack(packet, remain, remain_pos);
+
+  result = Curl_rand_alnum(data, (unsigned char *)&client_id[clen],
+                           MQTT_CLIENTID_LEN - clen + 1);
+  /* add client id */
+  rc = add_client_id(client_id, strlen(client_id), packet, pos + 1);
+  if(rc) {
+    failf(data, "Client ID length mismatched: [%zu]", strlen(client_id));
+    result = CURLE_WEIRD_SERVER_REPLY;
+    goto end;
+  }
+  infof(data, "Using client id '%s'", client_id);
+
+  /* position where starts the user payload */
+  start_user = pos + 3 + MQTT_CLIENTID_LEN;
+  /* position where starts the password payload */
+  start_pwd = start_user + ulen;
+  /* if user name was provided, add it to the packet */
+  if(ulen) {
+    start_pwd += 2;
+
+    rc = add_user(username, ulen,
+                  (unsigned char *)packet, start_user, remain_pos);
+    if(rc) {
+      failf(data, "Username is too large: [%zu]", ulen);
+      result = CURLE_WEIRD_SERVER_REPLY;
+      goto end;
+    }
+  }
+
+  /* if passwd was provided, add it to the packet */
+  if(plen) {
+    rc = add_passwd(passwd, plen, packet, start_pwd, remain_pos);
+    if(rc) {
+      failf(data, "Password is too large: [%zu]", plen);
+      result = CURLE_WEIRD_SERVER_REPLY;
+      goto end;
+    }
+  }
+
+  if(!result)
+    result = mqtt_send(data, packet, packetlen);
+
+end:
+  if(packet)
+    free(packet);
+  Curl_safefree(data->state.aptr.user);
+  Curl_safefree(data->state.aptr.passwd);
+  return result;
+}
+
+static CURLcode mqtt_disconnect(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct MQTT *mq = data->req.p.mqtt;
+  result = mqtt_send(data, (char *)"\xe0\x00", 2);
+  Curl_safefree(mq->sendleftovers);
+  Curl_dyn_free(&mq->recvbuf);
+  return result;
+}
+
+static CURLcode mqtt_recv_atleast(struct Curl_easy *data, size_t nbytes)
+{
+  struct MQTT *mq = data->req.p.mqtt;
+  size_t rlen = Curl_dyn_len(&mq->recvbuf);
+  CURLcode result;
+
+  if(rlen < nbytes) {
+    unsigned char readbuf[1024];
+    ssize_t nread;
+
+    DEBUGASSERT(nbytes - rlen < sizeof(readbuf));
+    result = Curl_xfer_recv(data, (char *)readbuf, nbytes - rlen, &nread);
+    if(result)
+      return result;
+    DEBUGASSERT(nread >= 0);
+    if(Curl_dyn_addn(&mq->recvbuf, readbuf, (size_t)nread))
+      return CURLE_OUT_OF_MEMORY;
+    rlen = Curl_dyn_len(&mq->recvbuf);
+  }
+  return (rlen >= nbytes)? CURLE_OK : CURLE_AGAIN;
+}
+
+static void mqtt_recv_consume(struct Curl_easy *data, size_t nbytes)
+{
+  struct MQTT *mq = data->req.p.mqtt;
+  size_t rlen = Curl_dyn_len(&mq->recvbuf);
+  if(rlen <= nbytes)
+    Curl_dyn_reset(&mq->recvbuf);
+  else
+    Curl_dyn_tail(&mq->recvbuf, rlen - nbytes);
+}
+
+static CURLcode mqtt_verify_connack(struct Curl_easy *data)
+{
+  struct MQTT *mq = data->req.p.mqtt;
+  CURLcode result;
+  char *ptr;
+
+  result = mqtt_recv_atleast(data, MQTT_CONNACK_LEN);
+  if(result)
+    goto fail;
+
+  /* verify CONNACK */
+  DEBUGASSERT(Curl_dyn_len(&mq->recvbuf) >= MQTT_CONNACK_LEN);
+  ptr = Curl_dyn_ptr(&mq->recvbuf);
+  Curl_debug(data, CURLINFO_HEADER_IN, ptr, MQTT_CONNACK_LEN);
+
+  if(ptr[0] != 0x00 || ptr[1] != 0x00) {
+    failf(data, "Expected %02x%02x but got %02x%02x",
+          0x00, 0x00, ptr[0], ptr[1]);
+    Curl_dyn_reset(&mq->recvbuf);
+    result = CURLE_WEIRD_SERVER_REPLY;
+    goto fail;
+  }
+  mqtt_recv_consume(data, MQTT_CONNACK_LEN);
+fail:
+  return result;
+}
+
+static CURLcode mqtt_get_topic(struct Curl_easy *data,
+                               char **topic, size_t *topiclen)
+{
+  char *path = data->state.up.path;
+  CURLcode result = CURLE_URL_MALFORMAT;
+  if(strlen(path) > 1) {
+    result = Curl_urldecode(path + 1, 0, topic, topiclen, REJECT_NADA);
+    if(!result && (*topiclen > 0xffff)) {
+      failf(data, "Too long MQTT topic");
+      result = CURLE_URL_MALFORMAT;
+    }
+  }
+  else
+    failf(data, "No MQTT topic found. Forgot to URL encode it?");
+
+  return result;
+}
+
+static CURLcode mqtt_subscribe(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  char *topic = NULL;
+  size_t topiclen;
+  unsigned char *packet = NULL;
+  size_t packetlen;
+  char encodedsize[4];
+  size_t n;
+  struct connectdata *conn = data->conn;
+
+  result = mqtt_get_topic(data, &topic, &topiclen);
+  if(result)
+    goto fail;
+
+  conn->proto.mqtt.packetid++;
+
+  packetlen = topiclen + 5; /* packetid + topic (has a two byte length field)
+                               + 2 bytes topic length + QoS byte */
+  n = mqtt_encode_len((char *)encodedsize, packetlen);
+  packetlen += n + 1; /* add one for the control packet type byte */
+
+  packet = malloc(packetlen);
+  if(!packet) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto fail;
+  }
+
+  packet[0] = MQTT_MSG_SUBSCRIBE;
+  memcpy(&packet[1], encodedsize, n);
+  packet[1 + n] = (conn->proto.mqtt.packetid >> 8) & 0xff;
+  packet[2 + n] = conn->proto.mqtt.packetid & 0xff;
+  packet[3 + n] = (topiclen >> 8) & 0xff;
+  packet[4 + n ] = topiclen & 0xff;
+  memcpy(&packet[5 + n], topic, topiclen);
+  packet[5 + n + topiclen] = 0; /* QoS zero */
+
+  result = mqtt_send(data, (char *)packet, packetlen);
+
+fail:
+  free(topic);
+  free(packet);
+  return result;
+}
+
+/*
+ * Called when the first byte was already read.
+ */
+static CURLcode mqtt_verify_suback(struct Curl_easy *data)
+{
+  struct MQTT *mq = data->req.p.mqtt;
+  struct connectdata *conn = data->conn;
+  struct mqtt_conn *mqtt = &conn->proto.mqtt;
+  CURLcode result;
+  char *ptr;
+
+  result = mqtt_recv_atleast(data, MQTT_SUBACK_LEN);
+  if(result)
+    goto fail;
+
+  /* verify SUBACK */
+  DEBUGASSERT(Curl_dyn_len(&mq->recvbuf) >= MQTT_SUBACK_LEN);
+  ptr = Curl_dyn_ptr(&mq->recvbuf);
+  Curl_debug(data, CURLINFO_HEADER_IN, ptr, MQTT_SUBACK_LEN);
+
+  if(((unsigned char)ptr[0]) != ((mqtt->packetid >> 8) & 0xff) ||
+     ((unsigned char)ptr[1]) != (mqtt->packetid & 0xff) ||
+     ptr[2] != 0x00) {
+    Curl_dyn_reset(&mq->recvbuf);
+    result = CURLE_WEIRD_SERVER_REPLY;
+    goto fail;
+  }
+  mqtt_recv_consume(data, MQTT_SUBACK_LEN);
+fail:
+  return result;
+}
+
+static CURLcode mqtt_publish(struct Curl_easy *data)
+{
+  CURLcode result;
+  char *payload = data->set.postfields;
+  size_t payloadlen;
+  char *topic = NULL;
+  size_t topiclen;
+  unsigned char *pkt = NULL;
+  size_t i = 0;
+  size_t remaininglength;
+  size_t encodelen;
+  char encodedbytes[4];
+  curl_off_t postfieldsize = data->set.postfieldsize;
+
+  if(!payload) {
+    DEBUGF(infof(data, "mqtt_publish without payload, return bad arg"));
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+  if(postfieldsize < 0)
+    payloadlen = strlen(payload);
+  else
+    payloadlen = (size_t)postfieldsize;
+
+  result = mqtt_get_topic(data, &topic, &topiclen);
+  if(result)
+    goto fail;
+
+  remaininglength = payloadlen + 2 + topiclen;
+  encodelen = mqtt_encode_len(encodedbytes, remaininglength);
+
+  /* add the control byte and the encoded remaining length */
+  pkt = malloc(remaininglength + 1 + encodelen);
+  if(!pkt) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto fail;
+  }
+
+  /* assemble packet */
+  pkt[i++] = MQTT_MSG_PUBLISH;
+  memcpy(&pkt[i], encodedbytes, encodelen);
+  i += encodelen;
+  pkt[i++] = (topiclen >> 8) & 0xff;
+  pkt[i++] = (topiclen & 0xff);
+  memcpy(&pkt[i], topic, topiclen);
+  i += topiclen;
+  memcpy(&pkt[i], payload, payloadlen);
+  i += payloadlen;
+  result = mqtt_send(data, (char *)pkt, i);
+
+fail:
+  free(pkt);
+  free(topic);
+  return result;
+}
+
+static size_t mqtt_decode_len(unsigned char *buf,
+                              size_t buflen, size_t *lenbytes)
+{
+  size_t len = 0;
+  size_t mult = 1;
+  size_t i;
+  unsigned char encoded = 128;
+
+  for(i = 0; (i < buflen) && (encoded & 128); i++) {
+    encoded = buf[i];
+    len += (encoded & 127) * mult;
+    mult *= 128;
+  }
+
+  if(lenbytes)
+    *lenbytes = i;
+
+  return len;
+}
+
+#ifdef CURLDEBUG
+static const char *statenames[]={
+  "MQTT_FIRST",
+  "MQTT_REMAINING_LENGTH",
+  "MQTT_CONNACK",
+  "MQTT_SUBACK",
+  "MQTT_SUBACK_COMING",
+  "MQTT_PUBWAIT",
+  "MQTT_PUB_REMAIN",
+
+  "NOT A STATE"
+};
+#endif
+
+/* The only way to change state */
+static void mqstate(struct Curl_easy *data,
+                    enum mqttstate state,
+                    enum mqttstate nextstate) /* used if state == FIRST */
+{
+  struct connectdata *conn = data->conn;
+  struct mqtt_conn *mqtt = &conn->proto.mqtt;
+#ifdef CURLDEBUG
+  infof(data, "%s (from %s) (next is %s)",
+        statenames[state],
+        statenames[mqtt->state],
+        (state == MQTT_FIRST)? statenames[nextstate] : "");
+#endif
+  mqtt->state = state;
+  if(state == MQTT_FIRST)
+    mqtt->nextstate = nextstate;
+}
+
+
+static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  ssize_t nread;
+  size_t remlen;
+  struct mqtt_conn *mqtt = &conn->proto.mqtt;
+  struct MQTT *mq = data->req.p.mqtt;
+  unsigned char packet;
+
+  switch(mqtt->state) {
+MQTT_SUBACK_COMING:
+  case MQTT_SUBACK_COMING:
+    result = mqtt_verify_suback(data);
+    if(result)
+      break;
+
+    mqstate(data, MQTT_FIRST, MQTT_PUBWAIT);
+    break;
+
+  case MQTT_SUBACK:
+  case MQTT_PUBWAIT:
+    /* we are expecting PUBLISH or SUBACK */
+    packet = mq->firstbyte & 0xf0;
+    if(packet == MQTT_MSG_PUBLISH)
+      mqstate(data, MQTT_PUB_REMAIN, MQTT_NOSTATE);
+    else if(packet == MQTT_MSG_SUBACK) {
+      mqstate(data, MQTT_SUBACK_COMING, MQTT_NOSTATE);
+      goto MQTT_SUBACK_COMING;
+    }
+    else if(packet == MQTT_MSG_DISCONNECT) {
+      infof(data, "Got DISCONNECT");
+      *done = TRUE;
+      goto end;
+    }
+    else {
+      result = CURLE_WEIRD_SERVER_REPLY;
+      goto end;
+    }
+
+    /* -- switched state -- */
+    remlen = mq->remaining_length;
+    infof(data, "Remaining length: %zu bytes", remlen);
+    if(data->set.max_filesize &&
+       (curl_off_t)remlen > data->set.max_filesize) {
+      failf(data, "Maximum file size exceeded");
+      result = CURLE_FILESIZE_EXCEEDED;
+      goto end;
+    }
+    Curl_pgrsSetDownloadSize(data, remlen);
+    data->req.bytecount = 0;
+    data->req.size = remlen;
+    mq->npacket = remlen; /* get this many bytes */
+    FALLTHROUGH();
+  case MQTT_PUB_REMAIN: {
+    /* read rest of packet, but no more. Cap to buffer size */
+    char buffer[4*1024];
+    size_t rest = mq->npacket;
+    if(rest > sizeof(buffer))
+      rest = sizeof(buffer);
+    result = Curl_xfer_recv(data, buffer, rest, &nread);
+    if(result) {
+      if(CURLE_AGAIN == result) {
+        infof(data, "EEEE AAAAGAIN");
+      }
+      goto end;
+    }
+    if(!nread) {
+      infof(data, "server disconnected");
+      result = CURLE_PARTIAL_FILE;
+      goto end;
+    }
+
+    /* if QoS is set, message contains packet id */
+    result = Curl_client_write(data, CLIENTWRITE_BODY, buffer, nread);
+    if(result)
+      goto end;
+
+    mq->npacket -= nread;
+    if(!mq->npacket)
+      /* no more PUBLISH payload, back to subscribe wait state */
+      mqstate(data, MQTT_FIRST, MQTT_PUBWAIT);
+    break;
+  }
+  default:
+    DEBUGASSERT(NULL); /* illegal state */
+    result = CURLE_WEIRD_SERVER_REPLY;
+    goto end;
+  }
+end:
+  return result;
+}
+
+static CURLcode mqtt_do(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  *done = FALSE; /* unconditionally */
+
+  result = mqtt_connect(data);
+  if(result) {
+    failf(data, "Error %d sending MQTT CONNECT request", result);
+    return result;
+  }
+  mqstate(data, MQTT_FIRST, MQTT_CONNACK);
+  return CURLE_OK;
+}
+
+static CURLcode mqtt_done(struct Curl_easy *data,
+                          CURLcode status, bool premature)
+{
+  struct MQTT *mq = data->req.p.mqtt;
+  (void)status;
+  (void)premature;
+  Curl_safefree(mq->sendleftovers);
+  Curl_dyn_free(&mq->recvbuf);
+  return CURLE_OK;
+}
+
+static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct mqtt_conn *mqtt = &conn->proto.mqtt;
+  struct MQTT *mq = data->req.p.mqtt;
+  ssize_t nread;
+  unsigned char byte;
+
+  *done = FALSE;
+
+  if(mq->nsend) {
+    /* send the remainder of an outgoing packet */
+    char *ptr = mq->sendleftovers;
+    result = mqtt_send(data, mq->sendleftovers, mq->nsend);
+    free(ptr);
+    if(result)
+      return result;
+  }
+
+  infof(data, "mqtt_doing: state [%d]", (int) mqtt->state);
+  switch(mqtt->state) {
+  case MQTT_FIRST:
+    /* Read the initial byte only */
+    result = Curl_xfer_recv(data, (char *)&mq->firstbyte, 1, &nread);
+    if(result)
+      break;
+    else if(!nread) {
+      failf(data, "Connection disconnected");
+      *done = TRUE;
+      result = CURLE_RECV_ERROR;
+      break;
+    }
+    Curl_debug(data, CURLINFO_HEADER_IN, (char *)&mq->firstbyte, 1);
+    /* remember the first byte */
+    mq->npacket = 0;
+    mqstate(data, MQTT_REMAINING_LENGTH, MQTT_NOSTATE);
+    FALLTHROUGH();
+  case MQTT_REMAINING_LENGTH:
+    do {
+      result = Curl_xfer_recv(data, (char *)&byte, 1, &nread);
+      if(!nread)
+        break;
+      Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
+      mq->pkt_hd[mq->npacket++] = byte;
+    } while((byte & 0x80) && (mq->npacket < 4));
+    if(nread && (byte & 0x80))
+      /* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 +
+         127 * 128^3 bytes. server tried to send more */
+      result = CURLE_WEIRD_SERVER_REPLY;
+    if(result)
+      break;
+    mq->remaining_length = mqtt_decode_len(mq->pkt_hd, mq->npacket, NULL);
+    mq->npacket = 0;
+    if(mq->remaining_length) {
+      mqstate(data, mqtt->nextstate, MQTT_NOSTATE);
+      break;
+    }
+    mqstate(data, MQTT_FIRST, MQTT_FIRST);
+
+    if(mq->firstbyte == MQTT_MSG_DISCONNECT) {
+      infof(data, "Got DISCONNECT");
+      *done = TRUE;
+    }
+    break;
+  case MQTT_CONNACK:
+    result = mqtt_verify_connack(data);
+    if(result)
+      break;
+
+    if(data->state.httpreq == HTTPREQ_POST) {
+      result = mqtt_publish(data);
+      if(!result) {
+        result = mqtt_disconnect(data);
+        *done = TRUE;
+      }
+      mqtt->nextstate = MQTT_FIRST;
+    }
+    else {
+      result = mqtt_subscribe(data);
+      if(!result) {
+        mqstate(data, MQTT_FIRST, MQTT_SUBACK);
+      }
+    }
+    break;
+
+  case MQTT_SUBACK:
+  case MQTT_PUBWAIT:
+  case MQTT_PUB_REMAIN:
+    result = mqtt_read_publish(data, done);
+    break;
+
+  default:
+    failf(data, "State not handled yet");
+    *done = TRUE;
+    break;
+  }
+
+  if(result == CURLE_AGAIN)
+    result = CURLE_OK;
+  return result;
+}
+
+#endif /* CURL_DISABLE_MQTT */
Index: trunk/src/libs/curl-8.7.1/lib/mqtt.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/mqtt.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/mqtt.h	(revision 104083)
@@ -0,0 +1,63 @@
+#ifndef HEADER_CURL_MQTT_H
+#define HEADER_CURL_MQTT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Björn Stenberg, <bjorn@haxx.se>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_MQTT
+extern const struct Curl_handler Curl_handler_mqtt;
+#endif
+
+enum mqttstate {
+  MQTT_FIRST,             /* 0 */
+  MQTT_REMAINING_LENGTH,  /* 1 */
+  MQTT_CONNACK,           /* 2 */
+  MQTT_SUBACK,            /* 3 */
+  MQTT_SUBACK_COMING,     /* 4 - the SUBACK remainder */
+  MQTT_PUBWAIT,    /* 5 - wait for publish */
+  MQTT_PUB_REMAIN,  /* 6 - wait for the remainder of the publish */
+
+  MQTT_NOSTATE /* 7 - never used an actual state */
+};
+
+struct mqtt_conn {
+  enum mqttstate state;
+  enum mqttstate nextstate; /* switch to this after remaining length is
+                               done */
+  unsigned int packetid;
+};
+
+/* protocol-specific transfer-related data */
+struct MQTT {
+  char *sendleftovers;
+  size_t nsend; /* size of sendleftovers */
+
+  /* when receiving */
+  size_t npacket; /* byte counter */
+  unsigned char firstbyte;
+  size_t remaining_length;
+  struct dynbuf recvbuf;
+  unsigned char pkt_hd[4]; /* for decoding the arriving packet length */
+};
+
+#endif /* HEADER_CURL_MQTT_H */
Index: trunk/src/libs/curl-8.7.1/lib/multi.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/multi.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/multi.c	(revision 104083)
@@ -0,0 +1,3863 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "transfer.h"
+#include "url.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "progress.h"
+#include "easyif.h"
+#include "share.h"
+#include "psl.h"
+#include "multiif.h"
+#include "sendf.h"
+#include "timeval.h"
+#include "http.h"
+#include "select.h"
+#include "warnless.h"
+#include "speedcheck.h"
+#include "conncache.h"
+#include "multihandle.h"
+#include "sigpipe.h"
+#include "vtls/vtls.h"
+#include "http_proxy.h"
+#include "http2.h"
+#include "socketpair.h"
+#include "socks.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+  CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
+  to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes.  Still, every
+  CURL handle takes 45-50 K memory, therefore this 3K are not significant.
+*/
+#ifndef CURL_SOCKET_HASH_TABLE_SIZE
+#define CURL_SOCKET_HASH_TABLE_SIZE 911
+#endif
+
+#ifndef CURL_CONNECTION_HASH_SIZE
+#define CURL_CONNECTION_HASH_SIZE 97
+#endif
+
+#ifndef CURL_DNS_HASH_SIZE
+#define CURL_DNS_HASH_SIZE 71
+#endif
+
+#define CURL_MULTI_HANDLE 0x000bab1e
+
+#ifdef DEBUGBUILD
+/* On a debug build, we want to fail hard on multi handles that
+ * are not NULL, but no longer have the MAGIC touch. This gives
+ * us early warning on things only discovered by valgrind otherwise. */
+#define GOOD_MULTI_HANDLE(x) \
+  (((x) && (x)->magic == CURL_MULTI_HANDLE)? TRUE: \
+  (DEBUGASSERT(!(x)), FALSE))
+#else
+#define GOOD_MULTI_HANDLE(x) \
+  ((x) && (x)->magic == CURL_MULTI_HANDLE)
+#endif
+
+static CURLMcode singlesocket(struct Curl_multi *multi,
+                              struct Curl_easy *data);
+static CURLMcode add_next_timeout(struct curltime now,
+                                  struct Curl_multi *multi,
+                                  struct Curl_easy *d);
+static CURLMcode multi_timeout(struct Curl_multi *multi,
+                               long *timeout_ms);
+static void process_pending_handles(struct Curl_multi *multi);
+static void multi_xfer_bufs_free(struct Curl_multi *multi);
+
+#ifdef DEBUGBUILD
+static const char * const multi_statename[]={
+  "INIT",
+  "PENDING",
+  "CONNECT",
+  "RESOLVING",
+  "CONNECTING",
+  "TUNNELING",
+  "PROTOCONNECT",
+  "PROTOCONNECTING",
+  "DO",
+  "DOING",
+  "DOING_MORE",
+  "DID",
+  "PERFORMING",
+  "RATELIMITING",
+  "DONE",
+  "COMPLETED",
+  "MSGSENT",
+};
+#endif
+
+/* function pointer called once when switching TO a state */
+typedef void (*init_multistate_func)(struct Curl_easy *data);
+
+/* called in DID state, before PERFORMING state */
+static void before_perform(struct Curl_easy *data)
+{
+  data->req.chunk = FALSE;
+  Curl_pgrsTime(data, TIMER_PRETRANSFER);
+}
+
+static void init_completed(struct Curl_easy *data)
+{
+  /* this is a completed transfer */
+
+  /* Important: reset the conn pointer so that we don't point to memory
+     that could be freed anytime */
+  Curl_detach_connection(data);
+  Curl_expire_clear(data); /* stop all timers */
+}
+
+/* always use this function to change state, to make debugging easier */
+static void mstate(struct Curl_easy *data, CURLMstate state
+#ifdef DEBUGBUILD
+                   , int lineno
+#endif
+)
+{
+  CURLMstate oldstate = data->mstate;
+  static const init_multistate_func finit[MSTATE_LAST] = {
+    NULL,              /* INIT */
+    NULL,              /* PENDING */
+    Curl_init_CONNECT, /* CONNECT */
+    NULL,              /* RESOLVING */
+    NULL,              /* CONNECTING */
+    NULL,              /* TUNNELING */
+    NULL,              /* PROTOCONNECT */
+    NULL,              /* PROTOCONNECTING */
+    NULL,              /* DO */
+    NULL,              /* DOING */
+    NULL,              /* DOING_MORE */
+    before_perform,    /* DID */
+    NULL,              /* PERFORMING */
+    NULL,              /* RATELIMITING */
+    NULL,              /* DONE */
+    init_completed,    /* COMPLETED */
+    NULL               /* MSGSENT */
+  };
+
+#if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) lineno;
+#endif
+
+  if(oldstate == state)
+    /* don't bother when the new state is the same as the old state */
+    return;
+
+  data->mstate = state;
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  if(data->mstate >= MSTATE_PENDING &&
+     data->mstate < MSTATE_COMPLETED) {
+    infof(data,
+          "STATE: %s => %s handle %p; line %d",
+          multi_statename[oldstate], multi_statename[data->mstate],
+          (void *)data, lineno);
+  }
+#endif
+
+  if(state == MSTATE_COMPLETED) {
+    /* changing to COMPLETED means there's one less easy handle 'alive' */
+    DEBUGASSERT(data->multi->num_alive > 0);
+    data->multi->num_alive--;
+    if(!data->multi->num_alive) {
+      /* free the transfer buffer when we have no more active transfers */
+      multi_xfer_bufs_free(data->multi);
+    }
+  }
+
+  /* if this state has an init-function, run it */
+  if(finit[state])
+    finit[state](data);
+}
+
+#ifndef DEBUGBUILD
+#define multistate(x,y) mstate(x,y)
+#else
+#define multistate(x,y) mstate(x,y, __LINE__)
+#endif
+
+/*
+ * We add one of these structs to the sockhash for each socket
+ */
+
+struct Curl_sh_entry {
+  struct Curl_hash transfers; /* hash of transfers using this socket */
+  unsigned int action;  /* what combined action READ/WRITE this socket waits
+                           for */
+  unsigned int users; /* number of transfers using this */
+  void *socketp; /* settable by users with curl_multi_assign() */
+  unsigned int readers; /* this many transfers want to read */
+  unsigned int writers; /* this many transfers want to write */
+};
+
+/* look up a given socket in the socket hash, skip invalid sockets */
+static struct Curl_sh_entry *sh_getentry(struct Curl_hash *sh,
+                                         curl_socket_t s)
+{
+  if(s != CURL_SOCKET_BAD) {
+    /* only look for proper sockets */
+    return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
+  }
+  return NULL;
+}
+
+#define TRHASH_SIZE 13
+static size_t trhash(void *key, size_t key_length, size_t slots_num)
+{
+  size_t keyval = (size_t)*(struct Curl_easy **)key;
+  (void) key_length;
+
+  return (keyval % slots_num);
+}
+
+static size_t trhash_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
+{
+  (void)k1_len;
+  (void)k2_len;
+
+  return *(struct Curl_easy **)k1 == *(struct Curl_easy **)k2;
+}
+
+static void trhash_dtor(void *nada)
+{
+  (void)nada;
+}
+
+/*
+ * The sockhash has its own separate subhash in each entry that need to be
+ * safely destroyed first.
+ */
+static void sockhash_destroy(struct Curl_hash *h)
+{
+  struct Curl_hash_iterator iter;
+  struct Curl_hash_element *he;
+
+  DEBUGASSERT(h);
+  Curl_hash_start_iterate(h, &iter);
+  he = Curl_hash_next_element(&iter);
+  while(he) {
+    struct Curl_sh_entry *sh = (struct Curl_sh_entry *)he->ptr;
+    Curl_hash_destroy(&sh->transfers);
+    he = Curl_hash_next_element(&iter);
+  }
+  Curl_hash_destroy(h);
+}
+
+
+/* make sure this socket is present in the hash for this handle */
+static struct Curl_sh_entry *sh_addentry(struct Curl_hash *sh,
+                                         curl_socket_t s)
+{
+  struct Curl_sh_entry *there = sh_getentry(sh, s);
+  struct Curl_sh_entry *check;
+
+  if(there) {
+    /* it is present, return fine */
+    return there;
+  }
+
+  /* not present, add it */
+  check = calloc(1, sizeof(struct Curl_sh_entry));
+  if(!check)
+    return NULL; /* major failure */
+
+  Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash, trhash_compare,
+                 trhash_dtor);
+
+  /* make/add new hash entry */
+  if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
+    Curl_hash_destroy(&check->transfers);
+    free(check);
+    return NULL; /* major failure */
+  }
+
+  return check; /* things are good in sockhash land */
+}
+
+
+/* delete the given socket + handle from the hash */
+static void sh_delentry(struct Curl_sh_entry *entry,
+                        struct Curl_hash *sh, curl_socket_t s)
+{
+  Curl_hash_destroy(&entry->transfers);
+
+  /* We remove the hash entry. This will end up in a call to
+     sh_freeentry(). */
+  Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
+}
+
+/*
+ * free a sockhash entry
+ */
+static void sh_freeentry(void *freethis)
+{
+  struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
+
+  free(p);
+}
+
+static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
+{
+  (void) k1_len; (void) k2_len;
+
+  return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2));
+}
+
+static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
+{
+  curl_socket_t fd = *((curl_socket_t *) key);
+  (void) key_length;
+
+  return (fd % slots_num);
+}
+
+/*
+ * sh_init() creates a new socket hash and returns the handle for it.
+ *
+ * Quote from README.multi_socket:
+ *
+ * "Some tests at 7000 and 9000 connections showed that the socket hash lookup
+ * is somewhat of a bottle neck. Its current implementation may be a bit too
+ * limiting. It simply has a fixed-size array, and on each entry in the array
+ * it has a linked list with entries. So the hash only checks which list to
+ * scan through. The code I had used so for used a list with merely 7 slots
+ * (as that is what the DNS hash uses) but with 7000 connections that would
+ * make an average of 1000 nodes in each list to run through. I upped that to
+ * 97 slots (I believe a prime is suitable) and noticed a significant speed
+ * increase.  I need to reconsider the hash implementation or use a rather
+ * large default value like this. At 9000 connections I was still below 10us
+ * per call."
+ *
+ */
+static void sh_init(struct Curl_hash *hash, int hashsize)
+{
+  Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
+                 sh_freeentry);
+}
+
+/*
+ * multi_addmsg()
+ *
+ * Called when a transfer is completed. Adds the given msg pointer to
+ * the list kept in the multi handle.
+ */
+static void multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg)
+{
+  Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg,
+                         &msg->list);
+}
+
+struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
+                                     int chashsize, /* connection hash */
+                                     int dnssize) /* dns hash */
+{
+  struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
+
+  if(!multi)
+    return NULL;
+
+  multi->magic = CURL_MULTI_HANDLE;
+
+  Curl_init_dnscache(&multi->hostcache, dnssize);
+
+  sh_init(&multi->sockhash, hashsize);
+
+  if(Curl_conncache_init(&multi->conn_cache, chashsize))
+    goto error;
+
+  Curl_llist_init(&multi->msglist, NULL);
+  Curl_llist_init(&multi->pending, NULL);
+  Curl_llist_init(&multi->msgsent, NULL);
+
+  multi->multiplexing = TRUE;
+  multi->max_concurrent_streams = 100;
+
+#ifdef USE_WINSOCK
+  multi->wsa_event = WSACreateEvent();
+  if(multi->wsa_event == WSA_INVALID_EVENT)
+    goto error;
+#else
+#ifdef ENABLE_WAKEUP
+  if(wakeup_create(multi->wakeup_pair) < 0) {
+    multi->wakeup_pair[0] = CURL_SOCKET_BAD;
+    multi->wakeup_pair[1] = CURL_SOCKET_BAD;
+  }
+  else if(curlx_nonblock(multi->wakeup_pair[0], TRUE) < 0 ||
+          curlx_nonblock(multi->wakeup_pair[1], TRUE) < 0) {
+    wakeup_close(multi->wakeup_pair[0]);
+    wakeup_close(multi->wakeup_pair[1]);
+    multi->wakeup_pair[0] = CURL_SOCKET_BAD;
+    multi->wakeup_pair[1] = CURL_SOCKET_BAD;
+  }
+#endif
+#endif
+
+  return multi;
+
+error:
+
+  sockhash_destroy(&multi->sockhash);
+  Curl_hash_destroy(&multi->hostcache);
+  Curl_conncache_destroy(&multi->conn_cache);
+  free(multi);
+  return NULL;
+}
+
+struct Curl_multi *curl_multi_init(void)
+{
+  return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE,
+                           CURL_CONNECTION_HASH_SIZE,
+                           CURL_DNS_HASH_SIZE);
+}
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+static void multi_warn_debug(struct Curl_multi *multi, struct Curl_easy *data)
+{
+  if(!multi->warned) {
+    infof(data, "!!! WARNING !!!");
+    infof(data, "This is a debug build of libcurl, "
+          "do not use in production.");
+    multi->warned = true;
+  }
+}
+#else
+#define multi_warn_debug(x,y) Curl_nop_stmt
+#endif
+
+/* returns TRUE if the easy handle is supposed to be present in the main link
+   list */
+static bool in_main_list(struct Curl_easy *data)
+{
+  return ((data->mstate != MSTATE_PENDING) &&
+          (data->mstate != MSTATE_MSGSENT));
+}
+
+static void link_easy(struct Curl_multi *multi,
+                      struct Curl_easy *data)
+{
+  /* We add the new easy entry last in the list. */
+  data->next = NULL; /* end of the line */
+  if(multi->easyp) {
+    struct Curl_easy *last = multi->easylp;
+    last->next = data;
+    data->prev = last;
+    multi->easylp = data; /* the new last node */
+  }
+  else {
+    /* first node, make prev NULL! */
+    data->prev = NULL;
+    multi->easylp = multi->easyp = data; /* both first and last */
+  }
+}
+
+/* unlink the given easy handle from the linked list of easy handles */
+static void unlink_easy(struct Curl_multi *multi,
+                        struct Curl_easy *data)
+{
+  /* make the previous node point to our next */
+  if(data->prev)
+    data->prev->next = data->next;
+  else
+    multi->easyp = data->next; /* point to first node */
+
+  /* make our next point to our previous node */
+  if(data->next)
+    data->next->prev = data->prev;
+  else
+    multi->easylp = data->prev; /* point to last node */
+
+  data->prev = data->next = NULL;
+}
+
+
+CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
+                                struct Curl_easy *data)
+{
+  CURLMcode rc;
+  /* First, make some basic checks that the CURLM handle is a good handle */
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  /* Verify that we got a somewhat good easy handle too */
+  if(!GOOD_EASY_HANDLE(data))
+    return CURLM_BAD_EASY_HANDLE;
+
+  /* Prevent users from adding same easy handle more than once and prevent
+     adding to more than one multi stack */
+  if(data->multi)
+    return CURLM_ADDED_ALREADY;
+
+  if(multi->in_callback)
+    return CURLM_RECURSIVE_API_CALL;
+
+  if(multi->dead) {
+    /* a "dead" handle cannot get added transfers while any existing easy
+       handles are still alive - but if there are none alive anymore, it is
+       fine to start over and unmark the "deadness" of this handle */
+    if(multi->num_alive)
+      return CURLM_ABORTED_BY_CALLBACK;
+    multi->dead = FALSE;
+  }
+
+  if(data->multi_easy) {
+    /* if this easy handle was previously used for curl_easy_perform(), there
+       is a private multi handle here that we can kill */
+    curl_multi_cleanup(data->multi_easy);
+    data->multi_easy = NULL;
+  }
+
+  /* Initialize timeout list for this handle */
+  Curl_llist_init(&data->state.timeoutlist, NULL);
+
+  /*
+   * No failure allowed in this function beyond this point. And no
+   * modification of easy nor multi handle allowed before this except for
+   * potential multi's connection cache growing which won't be undone in this
+   * function no matter what.
+   */
+  if(data->set.errorbuffer)
+    data->set.errorbuffer[0] = 0;
+
+  /* make the Curl_easy refer back to this multi handle - before Curl_expire()
+     is called. */
+  data->multi = multi;
+
+  /* Set the timeout for this handle to expire really soon so that it will
+     be taken care of even when this handle is added in the midst of operation
+     when only the curl_multi_socket() API is used. During that flow, only
+     sockets that time-out or have actions will be dealt with. Since this
+     handle has no action yet, we make sure it times out to get things to
+     happen. */
+  Curl_expire(data, 0, EXPIRE_RUN_NOW);
+
+  /* A somewhat crude work-around for a little glitch in Curl_update_timer()
+     that happens if the lastcall time is set to the same time when the handle
+     is removed as when the next handle is added, as then the check in
+     Curl_update_timer() that prevents calling the application multiple times
+     with the same timer info will not trigger and then the new handle's
+     timeout will not be notified to the app.
+
+     The work-around is thus simply to clear the 'lastcall' variable to force
+     Curl_update_timer() to always trigger a callback to the app when a new
+     easy handle is added */
+  memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
+
+  rc = Curl_update_timer(multi);
+  if(rc)
+    return rc;
+
+  /* set the easy handle */
+  multistate(data, MSTATE_INIT);
+
+  /* for multi interface connections, we share DNS cache automatically if the
+     easy handle's one is currently not set. */
+  if(!data->dns.hostcache ||
+     (data->dns.hostcachetype == HCACHE_NONE)) {
+    data->dns.hostcache = &multi->hostcache;
+    data->dns.hostcachetype = HCACHE_MULTI;
+  }
+
+  /* Point to the shared or multi handle connection cache */
+  if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT)))
+    data->state.conn_cache = &data->share->conn_cache;
+  else
+    data->state.conn_cache = &multi->conn_cache;
+  data->state.lastconnect_id = -1;
+
+#ifdef USE_LIBPSL
+  /* Do the same for PSL. */
+  if(data->share && (data->share->specifier & (1 << CURL_LOCK_DATA_PSL)))
+    data->psl = &data->share->psl;
+  else
+    data->psl = &multi->psl;
+#endif
+
+  link_easy(multi, data);
+
+  /* increase the node-counter */
+  multi->num_easy++;
+
+  /* increase the alive-counter */
+  multi->num_alive++;
+
+  CONNCACHE_LOCK(data);
+  /* The closure handle only ever has default timeouts set. To improve the
+     state somewhat we clone the timeouts from each added handle so that the
+     closure handle always has the same timeouts as the most recently added
+     easy handle. */
+  data->state.conn_cache->closure_handle->set.timeout = data->set.timeout;
+  data->state.conn_cache->closure_handle->set.server_response_timeout =
+    data->set.server_response_timeout;
+  data->state.conn_cache->closure_handle->set.no_signal =
+    data->set.no_signal;
+  data->id = data->state.conn_cache->next_easy_id++;
+  if(data->state.conn_cache->next_easy_id <= 0)
+    data->state.conn_cache->next_easy_id = 0;
+  CONNCACHE_UNLOCK(data);
+
+  multi_warn_debug(multi, data);
+
+  return CURLM_OK;
+}
+
+#if 0
+/* Debug-function, used like this:
+ *
+ * Curl_hash_print(&multi->sockhash, debug_print_sock_hash);
+ *
+ * Enable the hash print function first by editing hash.c
+ */
+static void debug_print_sock_hash(void *p)
+{
+  struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
+
+  fprintf(stderr, " [readers %u][writers %u]",
+          sh->readers, sh->writers);
+}
+#endif
+
+static CURLcode multi_done(struct Curl_easy *data,
+                           CURLcode status,  /* an error if this is called
+                                                after an error was detected */
+                           bool premature)
+{
+  CURLcode result, r2;
+  struct connectdata *conn = data->conn;
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  DEBUGF(infof(data, "multi_done[%s]: status: %d prem: %d done: %d",
+               multi_statename[data->mstate],
+               (int)status, (int)premature, data->state.done));
+#else
+  DEBUGF(infof(data, "multi_done: status: %d prem: %d done: %d",
+               (int)status, (int)premature, data->state.done));
+#endif
+
+  if(data->state.done)
+    /* Stop if multi_done() has already been called */
+    return CURLE_OK;
+
+  /* Stop the resolver and free its own resources (but not dns_entry yet). */
+  Curl_resolver_kill(data);
+
+  /* Cleanup possible redirect junk */
+  Curl_safefree(data->req.newurl);
+  Curl_safefree(data->req.location);
+
+  switch(status) {
+  case CURLE_ABORTED_BY_CALLBACK:
+  case CURLE_READ_ERROR:
+  case CURLE_WRITE_ERROR:
+    /* When we're aborted due to a callback return code it basically have to
+       be counted as premature as there is trouble ahead if we don't. We have
+       many callbacks and protocols work differently, we could potentially do
+       this more fine-grained in the future. */
+    premature = TRUE;
+    FALLTHROUGH();
+  default:
+    break;
+  }
+
+  /* this calls the protocol-specific function pointer previously set */
+  if(conn->handler->done)
+    result = conn->handler->done(data, status, premature);
+  else
+    result = status;
+
+  if(CURLE_ABORTED_BY_CALLBACK != result) {
+    /* avoid this if we already aborted by callback to avoid this calling
+       another callback */
+    int rc = Curl_pgrsDone(data);
+    if(!result && rc)
+      result = CURLE_ABORTED_BY_CALLBACK;
+  }
+
+  /* Make sure that transfer client writes are really done now. */
+  r2 = Curl_xfer_write_done(data, premature);
+  if(r2 && !result)
+    result = r2;
+
+  /* Inform connection filters that this transfer is done */
+  Curl_conn_ev_data_done(data, premature);
+
+  process_pending_handles(data->multi); /* connection / multiplex */
+
+  if(!result)
+    result = Curl_req_done(&data->req, data, premature);
+
+  CONNCACHE_LOCK(data);
+  Curl_detach_connection(data);
+  if(CONN_INUSE(conn)) {
+    /* Stop if still used. */
+    CONNCACHE_UNLOCK(data);
+    DEBUGF(infof(data, "Connection still in use %zu, "
+                 "no more multi_done now!",
+                 conn->easyq.size));
+    return CURLE_OK;
+  }
+
+  data->state.done = TRUE; /* called just now! */
+
+  if(conn->dns_entry) {
+    Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
+    conn->dns_entry = NULL;
+  }
+  Curl_hostcache_prune(data);
+
+  /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
+     forced us to close this connection. This is ignored for requests taking
+     place in a NTLM/NEGOTIATE authentication handshake
+
+     if conn->bits.close is TRUE, it means that the connection should be
+     closed in spite of all our efforts to be nice, due to protocol
+     restrictions in our or the server's end
+
+     if premature is TRUE, it means this connection was said to be DONE before
+     the entire request operation is complete and thus we can't know in what
+     state it is for reusing, so we're forced to close it. In a perfect world
+     we can add code that keep track of if we really must close it here or not,
+     but currently we have no such detail knowledge.
+  */
+
+  data->state.recent_conn_id = conn->connection_id;
+  if((data->set.reuse_forbid
+#if defined(USE_NTLM)
+      && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 ||
+           conn->proxy_ntlm_state == NTLMSTATE_TYPE2)
+#endif
+#if defined(USE_SPNEGO)
+      && !(conn->http_negotiate_state == GSS_AUTHRECV ||
+           conn->proxy_negotiate_state == GSS_AUTHRECV)
+#endif
+     ) || conn->bits.close
+       || (premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) {
+    DEBUGF(infof(data, "multi_done, not reusing connection=%"
+                       CURL_FORMAT_CURL_OFF_T ", forbid=%d"
+                       ", close=%d, premature=%d, conn_multiplex=%d",
+                 conn->connection_id,
+                 data->set.reuse_forbid, conn->bits.close, premature,
+                 Curl_conn_is_multiplex(conn, FIRSTSOCKET)));
+    connclose(conn, "disconnecting");
+    Curl_conncache_remove_conn(data, conn, FALSE);
+    CONNCACHE_UNLOCK(data);
+    Curl_disconnect(data, conn, premature);
+  }
+  else {
+    char buffer[256];
+    const char *host =
+#ifndef CURL_DISABLE_PROXY
+      conn->bits.socksproxy ?
+      conn->socks_proxy.host.dispname :
+      conn->bits.httpproxy ? conn->http_proxy.host.dispname :
+#endif
+      conn->bits.conn_to_host ? conn->conn_to_host.dispname :
+      conn->host.dispname;
+    /* create string before returning the connection */
+    curl_off_t connection_id = conn->connection_id;
+    msnprintf(buffer, sizeof(buffer),
+              "Connection #%" CURL_FORMAT_CURL_OFF_T " to host %s left intact",
+              connection_id, host);
+    /* the connection is no longer in use by this transfer */
+    CONNCACHE_UNLOCK(data);
+    if(Curl_conncache_return_conn(data, conn)) {
+      /* remember the most recently used connection */
+      data->state.lastconnect_id = connection_id;
+      data->state.recent_conn_id = connection_id;
+      infof(data, "%s", buffer);
+    }
+    else
+      data->state.lastconnect_id = -1;
+  }
+
+  return result;
+}
+
+static int close_connect_only(struct Curl_easy *data,
+                              struct connectdata *conn, void *param)
+{
+  (void)param;
+  if(data->state.lastconnect_id != conn->connection_id)
+    return 0;
+
+  if(!conn->connect_only)
+    return 1;
+
+  connclose(conn, "Removing connect-only easy handle");
+
+  return 1;
+}
+
+CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
+                                   struct Curl_easy *data)
+{
+  struct Curl_easy *easy = data;
+  bool premature;
+  struct Curl_llist_element *e;
+  CURLMcode rc;
+
+  /* First, make some basic checks that the CURLM handle is a good handle */
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  /* Verify that we got a somewhat good easy handle too */
+  if(!GOOD_EASY_HANDLE(data))
+    return CURLM_BAD_EASY_HANDLE;
+
+  /* Prevent users from trying to remove same easy handle more than once */
+  if(!data->multi)
+    return CURLM_OK; /* it is already removed so let's say it is fine! */
+
+  /* Prevent users from trying to remove an easy handle from the wrong multi */
+  if(data->multi != multi)
+    return CURLM_BAD_EASY_HANDLE;
+
+  if(multi->in_callback)
+    return CURLM_RECURSIVE_API_CALL;
+
+  premature = (data->mstate < MSTATE_COMPLETED) ? TRUE : FALSE;
+
+  /* If the 'state' is not INIT or COMPLETED, we might need to do something
+     nice to put the easy_handle in a good known state when this returns. */
+  if(premature) {
+    /* this handle is "alive" so we need to count down the total number of
+       alive connections when this is removed */
+    multi->num_alive--;
+  }
+
+  if(data->conn &&
+     data->mstate > MSTATE_DO &&
+     data->mstate < MSTATE_COMPLETED) {
+    /* Set connection owner so that the DONE function closes it.  We can
+       safely do this here since connection is killed. */
+    streamclose(data->conn, "Removed with partial response");
+  }
+
+  if(data->conn) {
+    /* multi_done() clears the association between the easy handle and the
+       connection.
+
+       Note that this ignores the return code simply because there's
+       nothing really useful to do with it anyway! */
+    (void)multi_done(data, data->result, premature);
+  }
+
+  /* The timer must be shut down before data->multi is set to NULL, else the
+     timenode will remain in the splay tree after curl_easy_cleanup is
+     called. Do it after multi_done() in case that sets another time! */
+  Curl_expire_clear(data);
+
+  if(data->connect_queue.ptr) {
+    /* the handle is in the pending or msgsent lists, so go ahead and remove
+       it */
+    if(data->mstate == MSTATE_PENDING)
+      Curl_llist_remove(&multi->pending, &data->connect_queue, NULL);
+    else
+      Curl_llist_remove(&multi->msgsent, &data->connect_queue, NULL);
+  }
+  if(in_main_list(data))
+    unlink_easy(multi, data);
+
+  if(data->dns.hostcachetype == HCACHE_MULTI) {
+    /* stop using the multi handle's DNS cache, *after* the possible
+       multi_done() call above */
+    data->dns.hostcache = NULL;
+    data->dns.hostcachetype = HCACHE_NONE;
+  }
+
+  Curl_wildcard_dtor(&data->wildcard);
+
+  /* change state without using multistate(), only to make singlesocket() do
+     what we want */
+  data->mstate = MSTATE_COMPLETED;
+
+  /* This ignores the return code even in case of problems because there's
+     nothing more to do about that, here */
+  (void)singlesocket(multi, easy); /* to let the application know what sockets
+                                      that vanish with this handle */
+
+  /* Remove the association between the connection and the handle */
+  Curl_detach_connection(data);
+
+  if(data->set.connect_only && !data->multi_easy) {
+    /* This removes a handle that was part the multi interface that used
+       CONNECT_ONLY, that connection is now left alive but since this handle
+       has bits.close set nothing can use that transfer anymore and it is
+       forbidden from reuse. And this easy handle cannot find the connection
+       anymore once removed from the multi handle
+
+       Better close the connection here, at once.
+    */
+    struct connectdata *c;
+    curl_socket_t s;
+    s = Curl_getconnectinfo(data, &c);
+    if((s != CURL_SOCKET_BAD) && c) {
+      Curl_conncache_remove_conn(data, c, TRUE);
+      Curl_disconnect(data, c, TRUE);
+    }
+  }
+
+  if(data->state.lastconnect_id != -1) {
+    /* Mark any connect-only connection for closure */
+    Curl_conncache_foreach(data, data->state.conn_cache,
+                           NULL, close_connect_only);
+  }
+
+#ifdef USE_LIBPSL
+  /* Remove the PSL association. */
+  if(data->psl == &multi->psl)
+    data->psl = NULL;
+#endif
+
+  /* as this was using a shared connection cache we clear the pointer to that
+     since we're not part of that multi handle anymore */
+  data->state.conn_cache = NULL;
+
+  data->multi = NULL; /* clear the association to this multi handle */
+
+  /* make sure there's no pending message in the queue sent from this easy
+     handle */
+  for(e = multi->msglist.head; e; e = e->next) {
+    struct Curl_message *msg = e->ptr;
+
+    if(msg->extmsg.easy_handle == easy) {
+      Curl_llist_remove(&multi->msglist, e, NULL);
+      /* there can only be one from this specific handle */
+      break;
+    }
+  }
+
+  /* NOTE NOTE NOTE
+     We do not touch the easy handle here! */
+  multi->num_easy--; /* one less to care about now */
+
+  process_pending_handles(multi);
+
+  rc = Curl_update_timer(multi);
+  if(rc)
+    return rc;
+  return CURLM_OK;
+}
+
+/* Return TRUE if the application asked for multiplexing */
+bool Curl_multiplex_wanted(const struct Curl_multi *multi)
+{
+  return (multi && (multi->multiplexing));
+}
+
+/*
+ * Curl_detach_connection() removes the given transfer from the connection.
+ *
+ * This is the only function that should clear data->conn. This will
+ * occasionally be called with the data->conn pointer already cleared.
+ */
+void Curl_detach_connection(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+  if(conn) {
+    Curl_conn_ev_data_detach(conn, data);
+    Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
+  }
+  data->conn = NULL;
+}
+
+/*
+ * Curl_attach_connection() attaches this transfer to this connection.
+ *
+ * This is the only function that should assign data->conn
+ */
+void Curl_attach_connection(struct Curl_easy *data,
+                             struct connectdata *conn)
+{
+  DEBUGASSERT(!data->conn);
+  DEBUGASSERT(conn);
+  data->conn = conn;
+  Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
+                         &data->conn_queue);
+  if(conn->handler && conn->handler->attach)
+    conn->handler->attach(data, conn);
+  Curl_conn_ev_data_attach(conn, data);
+}
+
+static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
+{
+  struct connectdata *conn = data->conn;
+  (void)socks;
+  /* Not using `conn->sockfd` as `Curl_xfer_setup()` initializes
+   * that *after* the connect. */
+  if(conn && conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD) {
+    /* Default is to wait to something from the server */
+    socks[0] = conn->sock[FIRSTSOCKET];
+    return GETSOCK_READSOCK(0);
+  }
+  return GETSOCK_BLANK;
+}
+
+static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks)
+{
+  struct connectdata *conn = data->conn;
+  if(conn && conn->handler->proto_getsock)
+    return conn->handler->proto_getsock(data, conn, socks);
+  else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
+    /* Default is to wait to something from the server */
+    socks[0] = conn->sockfd;
+    return GETSOCK_READSOCK(0);
+  }
+  return GETSOCK_BLANK;
+}
+
+static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks)
+{
+  struct connectdata *conn = data->conn;
+  if(conn && conn->handler->domore_getsock)
+    return conn->handler->domore_getsock(data, conn, socks);
+  else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
+    /* Default is that we want to send something to the server */
+    socks[0] = conn->sockfd;
+    return GETSOCK_WRITESOCK(0);
+  }
+  return GETSOCK_BLANK;
+}
+
+static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks)
+{
+  struct connectdata *conn = data->conn;
+  if(conn && conn->handler->doing_getsock)
+    return conn->handler->doing_getsock(data, conn, socks);
+  else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
+    /* Default is that we want to send something to the server */
+    socks[0] = conn->sockfd;
+    return GETSOCK_WRITESOCK(0);
+  }
+  return GETSOCK_BLANK;
+}
+
+static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
+{
+  struct connectdata *conn = data->conn;
+
+  if(!conn)
+    return GETSOCK_BLANK;
+  else if(conn->handler->perform_getsock)
+    return conn->handler->perform_getsock(data, conn, sock);
+  else {
+    /* Default is to obey the data->req.keepon flags for send/recv */
+    int bitmap = GETSOCK_BLANK;
+    unsigned sockindex = 0;
+    if(CURL_WANT_RECV(data)) {
+      DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
+      bitmap |= GETSOCK_READSOCK(sockindex);
+      sock[sockindex] = conn->sockfd;
+    }
+
+    if(CURL_WANT_SEND(data)) {
+      if((conn->sockfd != conn->writesockfd) ||
+         bitmap == GETSOCK_BLANK) {
+        /* only if they are not the same socket and we have a readable
+           one, we increase index */
+        if(bitmap != GETSOCK_BLANK)
+          sockindex++; /* increase index if we need two entries */
+
+        DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
+        sock[sockindex] = conn->writesockfd;
+      }
+      bitmap |= GETSOCK_WRITESOCK(sockindex);
+    }
+    return bitmap;
+  }
+}
+
+/* Initializes `poll_set` with the current socket poll actions needed
+ * for transfer `data`. */
+static void multi_getsock(struct Curl_easy *data,
+                          struct easy_pollset *ps)
+{
+  /* The no connection case can happen when this is called from
+     curl_multi_remove_handle() => singlesocket() => multi_getsock().
+  */
+  Curl_pollset_reset(data, ps);
+  if(!data->conn)
+    return;
+
+  switch(data->mstate) {
+  case MSTATE_INIT:
+  case MSTATE_PENDING:
+  case MSTATE_CONNECT:
+    /* nothing to poll for yet */
+    break;
+
+  case MSTATE_RESOLVING:
+    Curl_pollset_add_socks(data, ps, Curl_resolv_getsock);
+    /* connection filters are not involved in this phase */
+    break;
+
+  case MSTATE_CONNECTING:
+  case MSTATE_TUNNELING:
+    Curl_pollset_add_socks(data, ps, connecting_getsock);
+    Curl_conn_adjust_pollset(data, ps);
+    break;
+
+  case MSTATE_PROTOCONNECT:
+  case MSTATE_PROTOCONNECTING:
+    Curl_pollset_add_socks(data, ps, protocol_getsock);
+    Curl_conn_adjust_pollset(data, ps);
+    break;
+
+  case MSTATE_DO:
+  case MSTATE_DOING:
+    Curl_pollset_add_socks(data, ps, doing_getsock);
+    Curl_conn_adjust_pollset(data, ps);
+    break;
+
+  case MSTATE_DOING_MORE:
+    Curl_pollset_add_socks(data, ps, domore_getsock);
+    Curl_conn_adjust_pollset(data, ps);
+    break;
+
+  case MSTATE_DID: /* same as PERFORMING in regard to polling */
+  case MSTATE_PERFORMING:
+    Curl_pollset_add_socks(data, ps, perform_getsock);
+    Curl_conn_adjust_pollset(data, ps);
+    break;
+
+  case MSTATE_RATELIMITING:
+    /* we need to let time pass, ignore socket(s) */
+    break;
+
+  case MSTATE_DONE:
+  case MSTATE_COMPLETED:
+  case MSTATE_MSGSENT:
+    /* nothing more to poll for */
+    break;
+
+  default:
+    failf(data, "multi_getsock: unexpected multi state %d", data->mstate);
+    DEBUGASSERT(0);
+    break;
+  }
+}
+
+CURLMcode curl_multi_fdset(struct Curl_multi *multi,
+                           fd_set *read_fd_set, fd_set *write_fd_set,
+                           fd_set *exc_fd_set, int *max_fd)
+{
+  /* Scan through all the easy handles to get the file descriptors set.
+     Some easy handles may not have connected to the remote host yet,
+     and then we must make sure that is done. */
+  struct Curl_easy *data;
+  int this_max_fd = -1;
+  struct easy_pollset ps;
+  unsigned int i;
+  (void)exc_fd_set; /* not used */
+
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  if(multi->in_callback)
+    return CURLM_RECURSIVE_API_CALL;
+
+  memset(&ps, 0, sizeof(ps));
+  for(data = multi->easyp; data; data = data->next) {
+    multi_getsock(data, &ps);
+
+    for(i = 0; i < ps.num; i++) {
+      if(!FDSET_SOCK(ps.sockets[i]))
+        /* pretend it doesn't exist */
+        continue;
+      if(ps.actions[i] & CURL_POLL_IN)
+        FD_SET(ps.sockets[i], read_fd_set);
+      if(ps.actions[i] & CURL_POLL_OUT)
+        FD_SET(ps.sockets[i], write_fd_set);
+      if((int)ps.sockets[i] > this_max_fd)
+        this_max_fd = (int)ps.sockets[i];
+    }
+  }
+
+  *max_fd = this_max_fd;
+
+  return CURLM_OK;
+}
+
+#ifdef USE_WINSOCK
+/* Reset FD_WRITE for TCP sockets. Nothing is actually sent. UDP sockets can't
+ * be reset this way because an empty datagram would be sent. #9203
+ *
+ * "On Windows the internal state of FD_WRITE as returned from
+ * WSAEnumNetworkEvents is only reset after successful send()."
+ */
+static void reset_socket_fdwrite(curl_socket_t s)
+{
+  int t;
+  int l = (int)sizeof(t);
+  if(!getsockopt(s, SOL_SOCKET, SO_TYPE, (char *)&t, &l) && t == SOCK_STREAM)
+    send(s, NULL, 0, 0);
+}
+#endif
+
+#define NUM_POLLS_ON_STACK 10
+
+static CURLMcode multi_wait(struct Curl_multi *multi,
+                            struct curl_waitfd extra_fds[],
+                            unsigned int extra_nfds,
+                            int timeout_ms,
+                            int *ret,
+                            bool extrawait, /* when no socket, wait */
+                            bool use_wakeup)
+{
+  struct Curl_easy *data;
+  struct easy_pollset ps;
+  size_t i;
+  unsigned int nfds = 0;
+  unsigned int curlfds;
+  long timeout_internal;
+  int retcode = 0;
+  struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
+  struct pollfd *ufds = &a_few_on_stack[0];
+  bool ufds_malloc = FALSE;
+#ifdef USE_WINSOCK
+  WSANETWORKEVENTS wsa_events;
+  DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
+#endif
+#ifndef ENABLE_WAKEUP
+  (void)use_wakeup;
+#endif
+
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  if(multi->in_callback)
+    return CURLM_RECURSIVE_API_CALL;
+
+  if(timeout_ms < 0)
+    return CURLM_BAD_FUNCTION_ARGUMENT;
+
+  /* Count up how many fds we have from the multi handle */
+  memset(&ps, 0, sizeof(ps));
+  for(data = multi->easyp; data; data = data->next) {
+    multi_getsock(data, &ps);
+    nfds += ps.num;
+  }
+
+  /* If the internally desired timeout is actually shorter than requested from
+     the outside, then use the shorter time! But only if the internal timer
+     is actually larger than -1! */
+  (void)multi_timeout(multi, &timeout_internal);
+  if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
+    timeout_ms = (int)timeout_internal;
+
+  curlfds = nfds; /* number of internal file descriptors */
+  nfds += extra_nfds; /* add the externally provided ones */
+
+#ifdef ENABLE_WAKEUP
+#ifdef USE_WINSOCK
+  if(use_wakeup) {
+#else
+  if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
+#endif
+    ++nfds;
+  }
+#endif
+
+  if(nfds > NUM_POLLS_ON_STACK) {
+    /* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
+       big, so at 2^29 sockets this value might wrap. When a process gets
+       the capability to actually handle over 500 million sockets this
+       calculation needs a integer overflow check. */
+    ufds = malloc(nfds * sizeof(struct pollfd));
+    if(!ufds)
+      return CURLM_OUT_OF_MEMORY;
+    ufds_malloc = TRUE;
+  }
+  nfds = 0;
+
+  /* only do the second loop if we found descriptors in the first stage run
+     above */
+
+  if(curlfds) {
+    /* Add the curl handles to our pollfds first */
+    for(data = multi->easyp; data; data = data->next) {
+      multi_getsock(data, &ps);
+
+      for(i = 0; i < ps.num; i++) {
+        struct pollfd *ufd = &ufds[nfds++];
+#ifdef USE_WINSOCK
+        long mask = 0;
+#endif
+        ufd->fd = ps.sockets[i];
+        ufd->events = 0;
+        if(ps.actions[i] & CURL_POLL_IN) {
+#ifdef USE_WINSOCK
+          mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
+#endif
+          ufd->events |= POLLIN;
+        }
+        if(ps.actions[i] & CURL_POLL_OUT) {
+#ifdef USE_WINSOCK
+          mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
+          reset_socket_fdwrite(ps.sockets[i]);
+#endif
+          ufd->events |= POLLOUT;
+        }
+#ifdef USE_WINSOCK
+        if(WSAEventSelect(ps.sockets[i], multi->wsa_event, mask) != 0) {
+          if(ufds_malloc)
+            free(ufds);
+          return CURLM_INTERNAL_ERROR;
+        }
+#endif
+      }
+    }
+  }
+
+  /* Add external file descriptions from poll-like struct curl_waitfd */
+  for(i = 0; i < extra_nfds; i++) {
+#ifdef USE_WINSOCK
+    long mask = 0;
+    if(extra_fds[i].events & CURL_WAIT_POLLIN)
+      mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
+    if(extra_fds[i].events & CURL_WAIT_POLLPRI)
+      mask |= FD_OOB;
+    if(extra_fds[i].events & CURL_WAIT_POLLOUT) {
+      mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
+      reset_socket_fdwrite(extra_fds[i].fd);
+    }
+    if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0) {
+      if(ufds_malloc)
+        free(ufds);
+      return CURLM_INTERNAL_ERROR;
+    }
+#endif
+    ufds[nfds].fd = extra_fds[i].fd;
+    ufds[nfds].events = 0;
+    if(extra_fds[i].events & CURL_WAIT_POLLIN)
+      ufds[nfds].events |= POLLIN;
+    if(extra_fds[i].events & CURL_WAIT_POLLPRI)
+      ufds[nfds].events |= POLLPRI;
+    if(extra_fds[i].events & CURL_WAIT_POLLOUT)
+      ufds[nfds].events |= POLLOUT;
+    ++nfds;
+  }
+
+#ifdef ENABLE_WAKEUP
+#ifndef USE_WINSOCK
+  if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
+    ufds[nfds].fd = multi->wakeup_pair[0];
+    ufds[nfds].events = POLLIN;
+    ++nfds;
+  }
+#endif
+#endif
+
+#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
+  if(nfds || use_wakeup) {
+#else
+  if(nfds) {
+#endif
+    int pollrc;
+#ifdef USE_WINSOCK
+    if(nfds)
+      pollrc = Curl_poll(ufds, nfds, 0); /* just pre-check with WinSock */
+    else
+      pollrc = 0;
+#else
+    pollrc = Curl_poll(ufds, nfds, timeout_ms); /* wait... */
+#endif
+    if(pollrc < 0)
+      return CURLM_UNRECOVERABLE_POLL;
+
+    if(pollrc > 0) {
+      retcode = pollrc;
+#ifdef USE_WINSOCK
+    }
+    else { /* now wait... if not ready during the pre-check (pollrc == 0) */
+      WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);
+    }
+    /* With WinSock, we have to run the following section unconditionally
+       to call WSAEventSelect(fd, event, 0) on all the sockets */
+    {
+#endif
+      /* copy revents results from the poll to the curl_multi_wait poll
+         struct, the bit values of the actual underlying poll() implementation
+         may not be the same as the ones in the public libcurl API! */
+      for(i = 0; i < extra_nfds; i++) {
+        unsigned r = ufds[curlfds + i].revents;
+        unsigned short mask = 0;
+#ifdef USE_WINSOCK
+        curl_socket_t s = extra_fds[i].fd;
+        wsa_events.lNetworkEvents = 0;
+        if(WSAEnumNetworkEvents(s, NULL, &wsa_events) == 0) {
+          if(wsa_events.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE))
+            mask |= CURL_WAIT_POLLIN;
+          if(wsa_events.lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE))
+            mask |= CURL_WAIT_POLLOUT;
+          if(wsa_events.lNetworkEvents & FD_OOB)
+            mask |= CURL_WAIT_POLLPRI;
+          if(ret && !pollrc && wsa_events.lNetworkEvents)
+            retcode++;
+        }
+        WSAEventSelect(s, multi->wsa_event, 0);
+        if(!pollrc) {
+          extra_fds[i].revents = mask;
+          continue;
+        }
+#endif
+        if(r & POLLIN)
+          mask |= CURL_WAIT_POLLIN;
+        if(r & POLLOUT)
+          mask |= CURL_WAIT_POLLOUT;
+        if(r & POLLPRI)
+          mask |= CURL_WAIT_POLLPRI;
+        extra_fds[i].revents = mask;
+      }
+
+#ifdef USE_WINSOCK
+      /* Count up all our own sockets that had activity,
+         and remove them from the event. */
+      if(curlfds) {
+
+        for(data = multi->easyp; data; data = data->next) {
+          multi_getsock(data, &ps);
+
+          for(i = 0; i < ps.num; i++) {
+            wsa_events.lNetworkEvents = 0;
+            if(WSAEnumNetworkEvents(ps.sockets[i], NULL,
+                                    &wsa_events) == 0) {
+              if(ret && !pollrc && wsa_events.lNetworkEvents)
+                retcode++;
+            }
+            WSAEventSelect(ps.sockets[i], multi->wsa_event, 0);
+          }
+        }
+      }
+
+      WSAResetEvent(multi->wsa_event);
+#else
+#ifdef ENABLE_WAKEUP
+      if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
+        if(ufds[curlfds + extra_nfds].revents & POLLIN) {
+          char buf[64];
+          ssize_t nread;
+          while(1) {
+            /* the reading socket is non-blocking, try to read
+               data from it until it receives an error (except EINTR).
+               In normal cases it will get EAGAIN or EWOULDBLOCK
+               when there is no more data, breaking the loop. */
+            nread = wakeup_read(multi->wakeup_pair[0], buf, sizeof(buf));
+            if(nread <= 0) {
+              if(nread < 0 && EINTR == SOCKERRNO)
+                continue;
+              break;
+            }
+          }
+          /* do not count the wakeup socket into the returned value */
+          retcode--;
+        }
+      }
+#endif
+#endif
+    }
+  }
+
+  if(ufds_malloc)
+    free(ufds);
+  if(ret)
+    *ret = retcode;
+#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
+  if(extrawait && !nfds && !use_wakeup) {
+#else
+  if(extrawait && !nfds) {
+#endif
+    long sleep_ms = 0;
+
+    /* Avoid busy-looping when there's nothing particular to wait for */
+    if(!curl_multi_timeout(multi, &sleep_ms) && sleep_ms) {
+      if(sleep_ms > timeout_ms)
+        sleep_ms = timeout_ms;
+      /* when there are no easy handles in the multi, this holds a -1
+         timeout */
+      else if(sleep_ms < 0)
+        sleep_ms = timeout_ms;
+      Curl_wait_ms(sleep_ms);
+    }
+  }
+
+  return CURLM_OK;
+}
+
+CURLMcode curl_multi_wait(struct Curl_multi *multi,
+                          struct curl_waitfd extra_fds[],
+                          unsigned int extra_nfds,
+                          int timeout_ms,
+                          int *ret)
+{
+  return multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, FALSE,
+                    FALSE);
+}
+
+CURLMcode curl_multi_poll(struct Curl_multi *multi,
+                          struct curl_waitfd extra_fds[],
+                          unsigned int extra_nfds,
+                          int timeout_ms,
+                          int *ret)
+{
+  return multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, TRUE,
+                    TRUE);
+}
+
+CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
+{
+  /* this function is usually called from another thread,
+     it has to be careful only to access parts of the
+     Curl_multi struct that are constant */
+
+  /* GOOD_MULTI_HANDLE can be safely called */
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+#ifdef ENABLE_WAKEUP
+#ifdef USE_WINSOCK
+  if(WSASetEvent(multi->wsa_event))
+    return CURLM_OK;
+#else
+  /* the wakeup_pair variable is only written during init and cleanup,
+     making it safe to access from another thread after the init part
+     and before cleanup */
+  if(multi->wakeup_pair[1] != CURL_SOCKET_BAD) {
+    char buf[1];
+    buf[0] = 1;
+    while(1) {
+      /* swrite() is not thread-safe in general, because concurrent calls
+         can have their messages interleaved, but in this case the content
+         of the messages does not matter, which makes it ok to call.
+
+         The write socket is set to non-blocking, this way this function
+         cannot block, making it safe to call even from the same thread
+         that will call curl_multi_wait(). If swrite() returns that it
+         would block, it's considered successful because it means that
+         previous calls to this function will wake up the poll(). */
+      if(wakeup_write(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) {
+        int err = SOCKERRNO;
+        int return_success;
+#ifdef USE_WINSOCK
+        return_success = WSAEWOULDBLOCK == err;
+#else
+        if(EINTR == err)
+          continue;
+        return_success = EWOULDBLOCK == err || EAGAIN == err;
+#endif
+        if(!return_success)
+          return CURLM_WAKEUP_FAILURE;
+      }
+      return CURLM_OK;
+    }
+  }
+#endif
+#endif
+  return CURLM_WAKEUP_FAILURE;
+}
+
+/*
+ * multi_ischanged() is called
+ *
+ * Returns TRUE/FALSE whether the state is changed to trigger a CONNECT_PEND
+ * => CONNECT action.
+ *
+ * Set 'clear' to TRUE to have it also clear the state variable.
+ */
+static bool multi_ischanged(struct Curl_multi *multi, bool clear)
+{
+  bool retval = multi->recheckstate;
+  if(clear)
+    multi->recheckstate = FALSE;
+  return retval;
+}
+
+/*
+ * Curl_multi_connchanged() is called to tell that there is a connection in
+ * this multi handle that has changed state (multiplexing become possible, the
+ * number of allowed streams changed or similar), and a subsequent use of this
+ * multi handle should move CONNECT_PEND handles back to CONNECT to have them
+ * retry.
+ */
+void Curl_multi_connchanged(struct Curl_multi *multi)
+{
+  multi->recheckstate = TRUE;
+}
+
+CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
+                                 struct Curl_easy *data,
+                                 struct connectdata *conn)
+{
+  CURLMcode rc;
+
+  if(multi->in_callback)
+    return CURLM_RECURSIVE_API_CALL;
+
+  rc = curl_multi_add_handle(multi, data);
+  if(!rc) {
+    struct SingleRequest *k = &data->req;
+
+    /* pass in NULL for 'conn' here since we don't want to init the
+       connection, only this transfer */
+    Curl_init_do(data, NULL);
+
+    /* take this handle to the perform state right away */
+    multistate(data, MSTATE_PERFORMING);
+    Curl_attach_connection(data, conn);
+    k->keepon |= KEEP_RECV; /* setup to receive! */
+  }
+  return rc;
+}
+
+static CURLcode multi_do(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+
+  DEBUGASSERT(conn);
+  DEBUGASSERT(conn->handler);
+
+  if(conn->handler->do_it)
+    result = conn->handler->do_it(data, done);
+
+  return result;
+}
+
+/*
+ * multi_do_more() is called during the DO_MORE multi state. It is basically a
+ * second stage DO state which (wrongly) was introduced to support FTP's
+ * second connection.
+ *
+ * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
+ * DOING state there's more work to do!
+ */
+
+static CURLcode multi_do_more(struct Curl_easy *data, int *complete)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+
+  *complete = 0;
+
+  if(conn->handler->do_more)
+    result = conn->handler->do_more(data, complete);
+
+  return result;
+}
+
+/*
+ * Check whether a timeout occurred, and handle it if it did
+ */
+static bool multi_handle_timeout(struct Curl_easy *data,
+                                 struct curltime *now,
+                                 bool *stream_error,
+                                 CURLcode *result,
+                                 bool connect_timeout)
+{
+  timediff_t timeout_ms;
+  timeout_ms = Curl_timeleft(data, now, connect_timeout);
+
+  if(timeout_ms < 0) {
+    /* Handle timed out */
+    if(data->mstate == MSTATE_RESOLVING)
+      failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
+            " milliseconds",
+            Curl_timediff(*now, data->progress.t_startsingle));
+    else if(data->mstate == MSTATE_CONNECTING)
+      failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
+            " milliseconds",
+            Curl_timediff(*now, data->progress.t_startsingle));
+    else {
+      struct SingleRequest *k = &data->req;
+      if(k->size != -1) {
+        failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+              " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
+              CURL_FORMAT_CURL_OFF_T " bytes received",
+              Curl_timediff(*now, data->progress.t_startsingle),
+              k->bytecount, k->size);
+      }
+      else {
+        failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+              " milliseconds with %" CURL_FORMAT_CURL_OFF_T
+              " bytes received",
+              Curl_timediff(*now, data->progress.t_startsingle),
+              k->bytecount);
+      }
+    }
+
+    /* Force connection closed if the connection has indeed been used */
+    if(data->mstate > MSTATE_DO) {
+      streamclose(data->conn, "Disconnected with pending data");
+      *stream_error = TRUE;
+    }
+    *result = CURLE_OPERATION_TIMEDOUT;
+    (void)multi_done(data, *result, TRUE);
+  }
+
+  return (timeout_ms < 0);
+}
+
+/*
+ * We are doing protocol-specific connecting and this is being called over and
+ * over from the multi interface until the connection phase is done on
+ * protocol layer.
+ */
+
+static CURLcode protocol_connecting(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+
+  if(conn && conn->handler->connecting) {
+    *done = FALSE;
+    result = conn->handler->connecting(data, done);
+  }
+  else
+    *done = TRUE;
+
+  return result;
+}
+
+/*
+ * We are DOING this is being called over and over from the multi interface
+ * until the DOING phase is done on protocol layer.
+ */
+
+static CURLcode protocol_doing(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+
+  if(conn && conn->handler->doing) {
+    *done = FALSE;
+    result = conn->handler->doing(data, done);
+  }
+  else
+    *done = TRUE;
+
+  return result;
+}
+
+/*
+ * We have discovered that the TCP connection has been successful, we can now
+ * proceed with some action.
+ *
+ */
+static CURLcode protocol_connect(struct Curl_easy *data,
+                                 bool *protocol_done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  DEBUGASSERT(conn);
+  DEBUGASSERT(protocol_done);
+
+  *protocol_done = FALSE;
+
+  if(Curl_conn_is_connected(conn, FIRSTSOCKET)
+     && conn->bits.protoconnstart) {
+    /* We already are connected, get back. This may happen when the connect
+       worked fine in the first call, like when we connect to a local server
+       or proxy. Note that we don't know if the protocol is actually done.
+
+       Unless this protocol doesn't have any protocol-connect callback, as
+       then we know we're done. */
+    if(!conn->handler->connecting)
+      *protocol_done = TRUE;
+
+    return CURLE_OK;
+  }
+
+  if(!conn->bits.protoconnstart) {
+    if(conn->handler->connect_it) {
+      /* is there a protocol-specific connect() procedure? */
+
+      /* Call the protocol-specific connect function */
+      result = conn->handler->connect_it(data, protocol_done);
+    }
+    else
+      *protocol_done = TRUE;
+
+    /* it has started, possibly even completed but that knowledge isn't stored
+       in this bit! */
+    if(!result)
+      conn->bits.protoconnstart = TRUE;
+  }
+
+  return result; /* pass back status */
+}
+
+/*
+ * Curl_preconnect() is called immediately before a connect starts. When a
+ * redirect is followed, this is then called multiple times during a single
+ * transfer.
+ */
+CURLcode Curl_preconnect(struct Curl_easy *data)
+{
+  /* this used to do data->state.buffer allocation,
+     maybe remove completely now? */
+  (void)data;
+  return CURLE_OK;
+}
+
+static void set_in_callback(struct Curl_multi *multi, bool value)
+{
+  multi->in_callback = value;
+}
+
+static CURLMcode multi_runsingle(struct Curl_multi *multi,
+                                 struct curltime *nowp,
+                                 struct Curl_easy *data)
+{
+  struct Curl_message *msg = NULL;
+  bool connected;
+  bool async;
+  bool protocol_connected = FALSE;
+  bool dophase_done = FALSE;
+  CURLMcode rc;
+  CURLcode result = CURLE_OK;
+  timediff_t recv_timeout_ms;
+  timediff_t send_timeout_ms;
+  int control;
+
+  if(!GOOD_EASY_HANDLE(data))
+    return CURLM_BAD_EASY_HANDLE;
+
+  if(multi->dead) {
+    /* a multi-level callback returned error before, meaning every individual
+     transfer now has failed */
+    result = CURLE_ABORTED_BY_CALLBACK;
+    Curl_posttransfer(data);
+    multi_done(data, result, FALSE);
+    multistate(data, MSTATE_COMPLETED);
+  }
+
+  multi_warn_debug(multi, data);
+
+  do {
+    /* A "stream" here is a logical stream if the protocol can handle that
+       (HTTP/2), or the full connection for older protocols */
+    bool stream_error = FALSE;
+    rc = CURLM_OK;
+
+    if(multi_ischanged(multi, TRUE)) {
+      DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue"));
+      process_pending_handles(multi); /* multiplexed */
+    }
+
+    if(data->mstate > MSTATE_CONNECT &&
+       data->mstate < MSTATE_COMPLETED) {
+      /* Make sure we set the connection's current owner */
+      DEBUGASSERT(data->conn);
+      if(!data->conn)
+        return CURLM_INTERNAL_ERROR;
+    }
+
+    if(data->conn &&
+       (data->mstate >= MSTATE_CONNECT) &&
+       (data->mstate < MSTATE_COMPLETED)) {
+      /* Check for overall operation timeout here but defer handling the
+       * connection timeout to later, to allow for a connection to be set up
+       * in the window since we last checked timeout. This prevents us
+       * tearing down a completed connection in the case where we were slow
+       * to check the timeout (e.g. process descheduled during this loop).
+       * We set connect_timeout=FALSE to do this. */
+
+      /* we need to wait for the connect state as only then is the start time
+         stored, but we must not check already completed handles */
+      if(multi_handle_timeout(data, nowp, &stream_error, &result, FALSE)) {
+        /* Skip the statemachine and go directly to error handling section. */
+        goto statemachine_end;
+      }
+    }
+
+    switch(data->mstate) {
+    case MSTATE_INIT:
+      /* init this transfer. */
+      result = Curl_pretransfer(data);
+
+      if(!result) {
+        /* after init, go CONNECT */
+        multistate(data, MSTATE_CONNECT);
+        *nowp = Curl_pgrsTime(data, TIMER_STARTOP);
+        rc = CURLM_CALL_MULTI_PERFORM;
+      }
+      break;
+
+    case MSTATE_CONNECT:
+      /* Connect. We want to get a connection identifier filled in. */
+      /* init this transfer. */
+      result = Curl_preconnect(data);
+      if(result)
+        break;
+
+      *nowp = Curl_pgrsTime(data, TIMER_STARTSINGLE);
+      if(data->set.timeout)
+        Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
+
+      if(data->set.connecttimeout)
+        Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
+
+      result = Curl_connect(data, &async, &connected);
+      if(CURLE_NO_CONNECTION_AVAILABLE == result) {
+        /* There was no connection available. We will go to the pending
+           state and wait for an available connection. */
+        multistate(data, MSTATE_PENDING);
+
+        /* add this handle to the list of connect-pending handles */
+        Curl_llist_insert_next(&multi->pending, multi->pending.tail, data,
+                               &data->connect_queue);
+        /* unlink from the main list */
+        unlink_easy(multi, data);
+        result = CURLE_OK;
+        break;
+      }
+      else if(data->state.previouslypending) {
+        /* this transfer comes from the pending queue so try move another */
+        infof(data, "Transfer was pending, now try another");
+        process_pending_handles(data->multi);
+      }
+
+      if(!result) {
+        *nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE);
+        if(async)
+          /* We're now waiting for an asynchronous name lookup */
+          multistate(data, MSTATE_RESOLVING);
+        else {
+          /* after the connect has been sent off, go WAITCONNECT unless the
+             protocol connect is already done and we can go directly to
+             WAITDO or DO! */
+          rc = CURLM_CALL_MULTI_PERFORM;
+
+          if(connected)
+            multistate(data, MSTATE_PROTOCONNECT);
+          else {
+            multistate(data, MSTATE_CONNECTING);
+          }
+        }
+      }
+      break;
+
+    case MSTATE_RESOLVING:
+      /* awaiting an asynch name resolve to complete */
+    {
+      struct Curl_dns_entry *dns = NULL;
+      struct connectdata *conn = data->conn;
+      const char *hostname;
+
+      DEBUGASSERT(conn);
+#ifndef CURL_DISABLE_PROXY
+      if(conn->bits.httpproxy)
+        hostname = conn->http_proxy.host.name;
+      else
+#endif
+        if(conn->bits.conn_to_host)
+          hostname = conn->conn_to_host.name;
+      else
+        hostname = conn->host.name;
+
+      /* check if we have the name resolved by now */
+      dns = Curl_fetch_addr(data, hostname, conn->primary.remote_port);
+
+      if(dns) {
+#ifdef CURLRES_ASYNCH
+        data->state.async.dns = dns;
+        data->state.async.done = TRUE;
+#endif
+        result = CURLE_OK;
+        infof(data, "Hostname '%s' was found in DNS cache", hostname);
+      }
+
+      if(!dns)
+        result = Curl_resolv_check(data, &dns);
+
+      /* Update sockets here, because the socket(s) may have been
+         closed and the application thus needs to be told, even if it
+         is likely that the same socket(s) will again be used further
+         down.  If the name has not yet been resolved, it is likely
+         that new sockets have been opened in an attempt to contact
+         another resolver. */
+      rc = singlesocket(multi, data);
+      if(rc)
+        return rc;
+
+      if(dns) {
+        /* Perform the next step in the connection phase, and then move on
+           to the WAITCONNECT state */
+        result = Curl_once_resolved(data, &connected);
+
+        if(result)
+          /* if Curl_once_resolved() returns failure, the connection struct
+             is already freed and gone */
+          data->conn = NULL; /* no more connection */
+        else {
+          /* call again please so that we get the next socket setup */
+          rc = CURLM_CALL_MULTI_PERFORM;
+          if(connected)
+            multistate(data, MSTATE_PROTOCONNECT);
+          else {
+            multistate(data, MSTATE_CONNECTING);
+          }
+        }
+      }
+
+      if(result) {
+        /* failure detected */
+        stream_error = TRUE;
+        break;
+      }
+    }
+    break;
+
+#ifndef CURL_DISABLE_HTTP
+    case MSTATE_TUNNELING:
+      /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
+      DEBUGASSERT(data->conn);
+      result = Curl_http_connect(data, &protocol_connected);
+#ifndef CURL_DISABLE_PROXY
+      if(data->conn->bits.proxy_connect_closed) {
+        rc = CURLM_CALL_MULTI_PERFORM;
+        /* connect back to proxy again */
+        result = CURLE_OK;
+        multi_done(data, CURLE_OK, FALSE);
+        multistate(data, MSTATE_CONNECT);
+      }
+      else
+#endif
+        if(!result) {
+          rc = CURLM_CALL_MULTI_PERFORM;
+          /* initiate protocol connect phase */
+          multistate(data, MSTATE_PROTOCONNECT);
+        }
+      else
+        stream_error = TRUE;
+      break;
+#endif
+
+    case MSTATE_CONNECTING:
+      /* awaiting a completion of an asynch TCP connect */
+      DEBUGASSERT(data->conn);
+      result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
+      if(connected && !result) {
+        rc = CURLM_CALL_MULTI_PERFORM;
+        multistate(data, MSTATE_PROTOCONNECT);
+      }
+      else if(result) {
+        /* failure detected */
+        Curl_posttransfer(data);
+        multi_done(data, result, TRUE);
+        stream_error = TRUE;
+        break;
+      }
+      break;
+
+    case MSTATE_PROTOCONNECT:
+      if(!result && data->conn->bits.reuse) {
+        /* ftp seems to hang when protoconnect on reused connection
+         * since we handle PROTOCONNECT in general inside the filers, it
+         * seems wrong to restart this on a reused connection. */
+        multistate(data, MSTATE_DO);
+        rc = CURLM_CALL_MULTI_PERFORM;
+        break;
+      }
+      if(!result)
+        result = protocol_connect(data, &protocol_connected);
+      if(!result && !protocol_connected) {
+        /* switch to waiting state */
+        multistate(data, MSTATE_PROTOCONNECTING);
+        rc = CURLM_CALL_MULTI_PERFORM;
+      }
+      else if(!result) {
+        /* protocol connect has completed, go WAITDO or DO */
+        multistate(data, MSTATE_DO);
+        rc = CURLM_CALL_MULTI_PERFORM;
+      }
+      else {
+        /* failure detected */
+        Curl_posttransfer(data);
+        multi_done(data, result, TRUE);
+        stream_error = TRUE;
+      }
+      break;
+
+    case MSTATE_PROTOCONNECTING:
+      /* protocol-specific connect phase */
+      result = protocol_connecting(data, &protocol_connected);
+      if(!result && protocol_connected) {
+        /* after the connect has completed, go WAITDO or DO */
+        multistate(data, MSTATE_DO);
+        rc = CURLM_CALL_MULTI_PERFORM;
+      }
+      else if(result) {
+        /* failure detected */
+        Curl_posttransfer(data);
+        multi_done(data, result, TRUE);
+        stream_error = TRUE;
+      }
+      break;
+
+    case MSTATE_DO:
+      if(data->set.fprereq) {
+        int prereq_rc;
+
+        /* call the prerequest callback function */
+        Curl_set_in_callback(data, true);
+        prereq_rc = data->set.fprereq(data->set.prereq_userp,
+                                      data->info.primary.remote_ip,
+                                      data->info.primary.local_ip,
+                                      data->info.primary.remote_port,
+                                      data->info.primary.local_port);
+        Curl_set_in_callback(data, false);
+        if(prereq_rc != CURL_PREREQFUNC_OK) {
+          failf(data, "operation aborted by pre-request callback");
+          /* failure in pre-request callback - don't do any other processing */
+          result = CURLE_ABORTED_BY_CALLBACK;
+          Curl_posttransfer(data);
+          multi_done(data, result, FALSE);
+          stream_error = TRUE;
+          break;
+        }
+      }
+
+      if(data->set.connect_only == 1) {
+        /* keep connection open for application to use the socket */
+        connkeep(data->conn, "CONNECT_ONLY");
+        multistate(data, MSTATE_DONE);
+        result = CURLE_OK;
+        rc = CURLM_CALL_MULTI_PERFORM;
+      }
+      else {
+        /* Perform the protocol's DO action */
+        result = multi_do(data, &dophase_done);
+
+        /* When multi_do() returns failure, data->conn might be NULL! */
+
+        if(!result) {
+          if(!dophase_done) {
+#ifndef CURL_DISABLE_FTP
+            /* some steps needed for wildcard matching */
+            if(data->state.wildcardmatch) {
+              struct WildcardData *wc = data->wildcard;
+              if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
+                /* skip some states if it is important */
+                multi_done(data, CURLE_OK, FALSE);
+
+                /* if there's no connection left, skip the DONE state */
+                multistate(data, data->conn ?
+                           MSTATE_DONE : MSTATE_COMPLETED);
+                rc = CURLM_CALL_MULTI_PERFORM;
+                break;
+              }
+            }
+#endif
+            /* DO was not completed in one function call, we must continue
+               DOING... */
+            multistate(data, MSTATE_DOING);
+            rc = CURLM_CALL_MULTI_PERFORM;
+          }
+
+          /* after DO, go DO_DONE... or DO_MORE */
+          else if(data->conn->bits.do_more) {
+            /* we're supposed to do more, but we need to sit down, relax
+               and wait a little while first */
+            multistate(data, MSTATE_DOING_MORE);
+            rc = CURLM_CALL_MULTI_PERFORM;
+          }
+          else {
+            /* we're done with the DO, now DID */
+            multistate(data, MSTATE_DID);
+            rc = CURLM_CALL_MULTI_PERFORM;
+          }
+        }
+        else if((CURLE_SEND_ERROR == result) &&
+                data->conn->bits.reuse) {
+          /*
+           * In this situation, a connection that we were trying to use
+           * may have unexpectedly died.  If possible, send the connection
+           * back to the CONNECT phase so we can try again.
+           */
+          char *newurl = NULL;
+          followtype follow = FOLLOW_NONE;
+          CURLcode drc;
+
+          drc = Curl_retry_request(data, &newurl);
+          if(drc) {
+            /* a failure here pretty much implies an out of memory */
+            result = drc;
+            stream_error = TRUE;
+          }
+
+          Curl_posttransfer(data);
+          drc = multi_done(data, result, FALSE);
+
+          /* When set to retry the connection, we must go back to the CONNECT
+           * state */
+          if(newurl) {
+            if(!drc || (drc == CURLE_SEND_ERROR)) {
+              follow = FOLLOW_RETRY;
+              drc = Curl_follow(data, newurl, follow);
+              if(!drc) {
+                multistate(data, MSTATE_CONNECT);
+                rc = CURLM_CALL_MULTI_PERFORM;
+                result = CURLE_OK;
+              }
+              else {
+                /* Follow failed */
+                result = drc;
+              }
+            }
+            else {
+              /* done didn't return OK or SEND_ERROR */
+              result = drc;
+            }
+          }
+          else {
+            /* Have error handler disconnect conn if we can't retry */
+            stream_error = TRUE;
+          }
+          free(newurl);
+        }
+        else {
+          /* failure detected */
+          Curl_posttransfer(data);
+          if(data->conn)
+            multi_done(data, result, FALSE);
+          stream_error = TRUE;
+        }
+      }
+      break;
+
+    case MSTATE_DOING:
+      /* we continue DOING until the DO phase is complete */
+      DEBUGASSERT(data->conn);
+      result = protocol_doing(data, &dophase_done);
+      if(!result) {
+        if(dophase_done) {
+          /* after DO, go DO_DONE or DO_MORE */
+          multistate(data, data->conn->bits.do_more?
+                     MSTATE_DOING_MORE : MSTATE_DID);
+          rc = CURLM_CALL_MULTI_PERFORM;
+        } /* dophase_done */
+      }
+      else {
+        /* failure detected */
+        Curl_posttransfer(data);
+        multi_done(data, result, FALSE);
+        stream_error = TRUE;
+      }
+      break;
+
+    case MSTATE_DOING_MORE:
+      /*
+       * When we are connected, DOING MORE and then go DID
+       */
+      DEBUGASSERT(data->conn);
+      result = multi_do_more(data, &control);
+
+      if(!result) {
+        if(control) {
+          /* if positive, advance to DO_DONE
+             if negative, go back to DOING */
+          multistate(data, control == 1?
+                     MSTATE_DID : MSTATE_DOING);
+          rc = CURLM_CALL_MULTI_PERFORM;
+        }
+        /* else
+           stay in DO_MORE */
+      }
+      else {
+        /* failure detected */
+        Curl_posttransfer(data);
+        multi_done(data, result, FALSE);
+        stream_error = TRUE;
+      }
+      break;
+
+    case MSTATE_DID:
+      DEBUGASSERT(data->conn);
+      if(data->conn->bits.multiplex)
+        /* Check if we can move pending requests to send pipe */
+        process_pending_handles(multi); /*  multiplexed */
+
+      /* Only perform the transfer if there's a good socket to work with.
+         Having both BAD is a signal to skip immediately to DONE */
+      if((data->conn->sockfd != CURL_SOCKET_BAD) ||
+         (data->conn->writesockfd != CURL_SOCKET_BAD))
+        multistate(data, MSTATE_PERFORMING);
+      else {
+#ifndef CURL_DISABLE_FTP
+        if(data->state.wildcardmatch &&
+           ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
+          data->wildcard->state = CURLWC_DONE;
+        }
+#endif
+        multistate(data, MSTATE_DONE);
+      }
+      rc = CURLM_CALL_MULTI_PERFORM;
+      break;
+
+    case MSTATE_RATELIMITING: /* limit-rate exceeded in either direction */
+      DEBUGASSERT(data->conn);
+      /* if both rates are within spec, resume transfer */
+      if(Curl_pgrsUpdate(data))
+        result = CURLE_ABORTED_BY_CALLBACK;
+      else
+        result = Curl_speedcheck(data, *nowp);
+
+      if(result) {
+        if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
+           result != CURLE_HTTP2_STREAM)
+          streamclose(data->conn, "Transfer returned error");
+
+        Curl_posttransfer(data);
+        multi_done(data, result, TRUE);
+      }
+      else {
+        send_timeout_ms = 0;
+        if(data->set.max_send_speed)
+          send_timeout_ms =
+            Curl_pgrsLimitWaitTime(data->progress.uploaded,
+                                   data->progress.ul_limit_size,
+                                   data->set.max_send_speed,
+                                   data->progress.ul_limit_start,
+                                   *nowp);
+
+        recv_timeout_ms = 0;
+        if(data->set.max_recv_speed)
+          recv_timeout_ms =
+            Curl_pgrsLimitWaitTime(data->progress.downloaded,
+                                   data->progress.dl_limit_size,
+                                   data->set.max_recv_speed,
+                                   data->progress.dl_limit_start,
+                                   *nowp);
+
+        if(!send_timeout_ms && !recv_timeout_ms) {
+          multistate(data, MSTATE_PERFORMING);
+          Curl_ratelimit(data, *nowp);
+        }
+        else if(send_timeout_ms >= recv_timeout_ms)
+          Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
+        else
+          Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST);
+      }
+      break;
+
+    case MSTATE_PERFORMING:
+    {
+      char *newurl = NULL;
+      bool retry = FALSE;
+      /* check if over send speed */
+      send_timeout_ms = 0;
+      if(data->set.max_send_speed)
+        send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
+                                                 data->progress.ul_limit_size,
+                                                 data->set.max_send_speed,
+                                                 data->progress.ul_limit_start,
+                                                 *nowp);
+
+      /* check if over recv speed */
+      recv_timeout_ms = 0;
+      if(data->set.max_recv_speed)
+        recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
+                                                 data->progress.dl_limit_size,
+                                                 data->set.max_recv_speed,
+                                                 data->progress.dl_limit_start,
+                                                 *nowp);
+
+      if(send_timeout_ms || recv_timeout_ms) {
+        Curl_ratelimit(data, *nowp);
+        multistate(data, MSTATE_RATELIMITING);
+        if(send_timeout_ms >= recv_timeout_ms)
+          Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
+        else
+          Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST);
+        break;
+      }
+
+      /* read/write data if it is ready to do so */
+      result = Curl_readwrite(data);
+
+      if(data->req.done || (result == CURLE_RECV_ERROR)) {
+        /* If CURLE_RECV_ERROR happens early enough, we assume it was a race
+         * condition and the server closed the reused connection exactly when
+         * we wanted to use it, so figure out if that is indeed the case.
+         */
+        CURLcode ret = Curl_retry_request(data, &newurl);
+        if(!ret)
+          retry = (newurl)?TRUE:FALSE;
+        else if(!result)
+          result = ret;
+
+        if(retry) {
+          /* if we are to retry, set the result to OK and consider the
+             request as done */
+          result = CURLE_OK;
+          data->req.done = TRUE;
+        }
+      }
+      else if((CURLE_HTTP2_STREAM == result) &&
+              Curl_h2_http_1_1_error(data)) {
+        CURLcode ret = Curl_retry_request(data, &newurl);
+
+        if(!ret) {
+          infof(data, "Downgrades to HTTP/1.1");
+          streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
+          data->state.httpwant = CURL_HTTP_VERSION_1_1;
+          /* clear the error message bit too as we ignore the one we got */
+          data->state.errorbuf = FALSE;
+          if(!newurl)
+            /* typically for HTTP_1_1_REQUIRED error on first flight */
+            newurl = strdup(data->state.url);
+          /* if we are to retry, set the result to OK and consider the request
+             as done */
+          retry = TRUE;
+          result = CURLE_OK;
+          data->req.done = TRUE;
+        }
+        else
+          result = ret;
+      }
+
+      if(result) {
+        /*
+         * The transfer phase returned error, we mark the connection to get
+         * closed to prevent being reused. This is because we can't possibly
+         * know if the connection is in a good shape or not now.  Unless it is
+         * a protocol which uses two "channels" like FTP, as then the error
+         * happened in the data connection.
+         */
+
+        if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
+           result != CURLE_HTTP2_STREAM)
+          streamclose(data->conn, "Transfer returned error");
+
+        Curl_posttransfer(data);
+        multi_done(data, result, TRUE);
+      }
+      else if(data->req.done) {
+
+        /* call this even if the readwrite function returned error */
+        Curl_posttransfer(data);
+
+        /* When we follow redirects or is set to retry the connection, we must
+           to go back to the CONNECT state */
+        if(data->req.newurl || retry) {
+          followtype follow = FOLLOW_NONE;
+          if(!retry) {
+            /* if the URL is a follow-location and not just a retried request
+               then figure out the URL here */
+            free(newurl);
+            newurl = data->req.newurl;
+            data->req.newurl = NULL;
+            follow = FOLLOW_REDIR;
+          }
+          else
+            follow = FOLLOW_RETRY;
+          (void)multi_done(data, CURLE_OK, FALSE);
+          /* multi_done() might return CURLE_GOT_NOTHING */
+          result = Curl_follow(data, newurl, follow);
+          if(!result) {
+            multistate(data, MSTATE_CONNECT);
+            rc = CURLM_CALL_MULTI_PERFORM;
+          }
+          free(newurl);
+        }
+        else {
+          /* after the transfer is done, go DONE */
+
+          /* but first check to see if we got a location info even though we're
+             not following redirects */
+          if(data->req.location) {
+            free(newurl);
+            newurl = data->req.location;
+            data->req.location = NULL;
+            result = Curl_follow(data, newurl, FOLLOW_FAKE);
+            free(newurl);
+            if(result) {
+              stream_error = TRUE;
+              result = multi_done(data, result, TRUE);
+            }
+          }
+
+          if(!result) {
+            multistate(data, MSTATE_DONE);
+            rc = CURLM_CALL_MULTI_PERFORM;
+          }
+        }
+      }
+      else if(data->state.select_bits) {
+        /* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer
+           won't get stuck on this transfer at the expense of other concurrent
+           transfers */
+        Curl_expire(data, 0, EXPIRE_RUN_NOW);
+      }
+      break;
+    }
+
+    case MSTATE_DONE:
+      /* this state is highly transient, so run another loop after this */
+      rc = CURLM_CALL_MULTI_PERFORM;
+
+      if(data->conn) {
+        CURLcode res;
+
+        if(data->conn->bits.multiplex)
+          /* Check if we can move pending requests to connection */
+          process_pending_handles(multi); /* multiplexing */
+
+        /* post-transfer command */
+        res = multi_done(data, result, FALSE);
+
+        /* allow a previously set error code take precedence */
+        if(!result)
+          result = res;
+      }
+
+#ifndef CURL_DISABLE_FTP
+      if(data->state.wildcardmatch) {
+        if(data->wildcard->state != CURLWC_DONE) {
+          /* if a wildcard is set and we are not ending -> lets start again
+             with MSTATE_INIT */
+          multistate(data, MSTATE_INIT);
+          break;
+        }
+      }
+#endif
+      /* after we have DONE what we're supposed to do, go COMPLETED, and
+         it doesn't matter what the multi_done() returned! */
+      multistate(data, MSTATE_COMPLETED);
+      break;
+
+    case MSTATE_COMPLETED:
+      break;
+
+    case MSTATE_PENDING:
+    case MSTATE_MSGSENT:
+      /* handles in these states should NOT be in this list */
+      DEBUGASSERT(0);
+      break;
+
+    default:
+      return CURLM_INTERNAL_ERROR;
+    }
+
+    if(data->conn &&
+       data->mstate >= MSTATE_CONNECT &&
+       data->mstate < MSTATE_DO &&
+       rc != CURLM_CALL_MULTI_PERFORM &&
+       !multi_ischanged(multi, false)) {
+      /* We now handle stream timeouts if and only if this will be the last
+       * loop iteration. We only check this on the last iteration to ensure
+       * that if we know we have additional work to do immediately
+       * (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
+       * declaring the connection timed out as we may almost have a completed
+       * connection. */
+      multi_handle_timeout(data, nowp, &stream_error, &result, TRUE);
+    }
+
+statemachine_end:
+
+    if(data->mstate < MSTATE_COMPLETED) {
+      if(result) {
+        /*
+         * If an error was returned, and we aren't in completed state now,
+         * then we go to completed and consider this transfer aborted.
+         */
+
+        /* NOTE: no attempt to disconnect connections must be made
+           in the case blocks above - cleanup happens only here */
+
+        /* Check if we can move pending requests to send pipe */
+        process_pending_handles(multi); /* connection */
+
+        if(data->conn) {
+          if(stream_error) {
+            /* Don't attempt to send data over a connection that timed out */
+            bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
+            struct connectdata *conn = data->conn;
+
+            /* This is where we make sure that the conn pointer is reset.
+               We don't have to do this in every case block above where a
+               failure is detected */
+            Curl_detach_connection(data);
+
+            /* remove connection from cache */
+            Curl_conncache_remove_conn(data, conn, TRUE);
+
+            /* disconnect properly */
+            Curl_disconnect(data, conn, dead_connection);
+          }
+        }
+        else if(data->mstate == MSTATE_CONNECT) {
+          /* Curl_connect() failed */
+          (void)Curl_posttransfer(data);
+        }
+
+        multistate(data, MSTATE_COMPLETED);
+        rc = CURLM_CALL_MULTI_PERFORM;
+      }
+      /* if there's still a connection to use, call the progress function */
+      else if(data->conn && Curl_pgrsUpdate(data)) {
+        /* aborted due to progress callback return code must close the
+           connection */
+        result = CURLE_ABORTED_BY_CALLBACK;
+        streamclose(data->conn, "Aborted by callback");
+
+        /* if not yet in DONE state, go there, otherwise COMPLETED */
+        multistate(data, (data->mstate < MSTATE_DONE)?
+                   MSTATE_DONE: MSTATE_COMPLETED);
+        rc = CURLM_CALL_MULTI_PERFORM;
+      }
+    }
+
+    if(MSTATE_COMPLETED == data->mstate) {
+      if(data->set.fmultidone) {
+        /* signal via callback instead */
+        data->set.fmultidone(data, result);
+      }
+      else {
+        /* now fill in the Curl_message with this info */
+        msg = &data->msg;
+
+        msg->extmsg.msg = CURLMSG_DONE;
+        msg->extmsg.easy_handle = data;
+        msg->extmsg.data.result = result;
+
+        multi_addmsg(multi, msg);
+        DEBUGASSERT(!data->conn);
+      }
+      multistate(data, MSTATE_MSGSENT);
+
+      /* add this handle to the list of msgsent handles */
+      Curl_llist_insert_next(&multi->msgsent, multi->msgsent.tail, data,
+                             &data->connect_queue);
+      /* unlink from the main list */
+      unlink_easy(multi, data);
+      return CURLM_OK;
+    }
+  } while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
+
+  data->result = result;
+  return rc;
+}
+
+
+CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
+{
+  struct Curl_easy *data;
+  CURLMcode returncode = CURLM_OK;
+  struct Curl_tree *t;
+  struct curltime now = Curl_now();
+
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  if(multi->in_callback)
+    return CURLM_RECURSIVE_API_CALL;
+
+  data = multi->easyp;
+  if(data) {
+    CURLMcode result;
+    bool nosig = data->set.no_signal;
+    SIGPIPE_VARIABLE(pipe_st);
+    sigpipe_ignore(data, &pipe_st);
+    /* Do the loop and only alter the signal ignore state if the next handle
+       has a different NO_SIGNAL state than the previous */
+    do {
+      /* the current node might be unlinked in multi_runsingle(), get the next
+         pointer now */
+      struct Curl_easy *datanext = data->next;
+      if(data->set.no_signal != nosig) {
+        sigpipe_restore(&pipe_st);
+        sigpipe_ignore(data, &pipe_st);
+        nosig = data->set.no_signal;
+      }
+      result = multi_runsingle(multi, &now, data);
+      if(result)
+        returncode = result;
+      data = datanext; /* operate on next handle */
+    } while(data);
+    sigpipe_restore(&pipe_st);
+  }
+
+  /*
+   * Simply remove all expired timers from the splay since handles are dealt
+   * with unconditionally by this function and curl_multi_timeout() requires
+   * that already passed/handled expire times are removed from the splay.
+   *
+   * It is important that the 'now' value is set at the entry of this function
+   * and not for the current time as it may have ticked a little while since
+   * then and then we risk this loop to remove timers that actually have not
+   * been handled!
+   */
+  do {
+    multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
+    if(t)
+      /* the removed may have another timeout in queue */
+      (void)add_next_timeout(now, multi, t->payload);
+
+  } while(t);
+
+  *running_handles = multi->num_alive;
+
+  if(CURLM_OK >= returncode)
+    returncode = Curl_update_timer(multi);
+
+  return returncode;
+}
+
+/* unlink_all_msgsent_handles() detaches all those easy handles from this
+   multi handle */
+static void unlink_all_msgsent_handles(struct Curl_multi *multi)
+{
+  struct Curl_llist_element *e = multi->msgsent.head;
+  if(e) {
+    struct Curl_easy *data = e->ptr;
+    DEBUGASSERT(data->mstate == MSTATE_MSGSENT);
+    data->multi = NULL;
+  }
+}
+
+CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
+{
+  struct Curl_easy *data;
+  struct Curl_easy *nextdata;
+
+  if(GOOD_MULTI_HANDLE(multi)) {
+    if(multi->in_callback)
+      return CURLM_RECURSIVE_API_CALL;
+
+    multi->magic = 0; /* not good anymore */
+
+    unlink_all_msgsent_handles(multi);
+    process_pending_handles(multi);
+    /* First remove all remaining easy handles */
+    data = multi->easyp;
+    while(data) {
+      nextdata = data->next;
+      if(!data->state.done && data->conn)
+        /* if DONE was never called for this handle */
+        (void)multi_done(data, CURLE_OK, TRUE);
+      if(data->dns.hostcachetype == HCACHE_MULTI) {
+        /* clear out the usage of the shared DNS cache */
+        Curl_hostcache_clean(data, data->dns.hostcache);
+        data->dns.hostcache = NULL;
+        data->dns.hostcachetype = HCACHE_NONE;
+      }
+
+      /* Clear the pointer to the connection cache */
+      data->state.conn_cache = NULL;
+      data->multi = NULL; /* clear the association */
+
+#ifdef USE_LIBPSL
+      if(data->psl == &multi->psl)
+        data->psl = NULL;
+#endif
+
+      data = nextdata;
+    }
+
+    /* Close all the connections in the connection cache */
+    Curl_conncache_close_all_connections(&multi->conn_cache);
+
+    sockhash_destroy(&multi->sockhash);
+    Curl_conncache_destroy(&multi->conn_cache);
+    Curl_hash_destroy(&multi->hostcache);
+    Curl_psl_destroy(&multi->psl);
+
+#ifdef USE_WINSOCK
+    WSACloseEvent(multi->wsa_event);
+#else
+#ifdef ENABLE_WAKEUP
+    wakeup_close(multi->wakeup_pair[0]);
+    wakeup_close(multi->wakeup_pair[1]);
+#endif
+#endif
+
+#ifdef USE_SSL
+    Curl_free_multi_ssl_backend_data(multi->ssl_backend_data);
+#endif
+
+    multi_xfer_bufs_free(multi);
+    free(multi);
+
+    return CURLM_OK;
+  }
+  return CURLM_BAD_HANDLE;
+}
+
+/*
+ * curl_multi_info_read()
+ *
+ * This function is the primary way for a multi/multi_socket application to
+ * figure out if a transfer has ended. We MUST make this function as fast as
+ * possible as it will be polled frequently and we MUST NOT scan any lists in
+ * here to figure out things. We must scale fine to thousands of handles and
+ * beyond. The current design is fully O(1).
+ */
+
+CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
+{
+  struct Curl_message *msg;
+
+  *msgs_in_queue = 0; /* default to none */
+
+  if(GOOD_MULTI_HANDLE(multi) &&
+     !multi->in_callback &&
+     Curl_llist_count(&multi->msglist)) {
+    /* there is one or more messages in the list */
+    struct Curl_llist_element *e;
+
+    /* extract the head of the list to return */
+    e = multi->msglist.head;
+
+    msg = e->ptr;
+
+    /* remove the extracted entry */
+    Curl_llist_remove(&multi->msglist, e, NULL);
+
+    *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist));
+
+    return &msg->extmsg;
+  }
+  return NULL;
+}
+
+/*
+ * singlesocket() checks what sockets we deal with and their "action state"
+ * and if we have a different state in any of those sockets from last time we
+ * call the callback accordingly.
+ */
+static CURLMcode singlesocket(struct Curl_multi *multi,
+                              struct Curl_easy *data)
+{
+  struct easy_pollset cur_poll;
+  unsigned int i;
+  struct Curl_sh_entry *entry;
+  curl_socket_t s;
+  int rc;
+
+  /* Fill in the 'current' struct with the state as it is now: what sockets to
+     supervise and for what actions */
+  multi_getsock(data, &cur_poll);
+
+  /* We have 0 .. N sockets already and we get to know about the 0 .. M
+     sockets we should have from now on. Detect the differences, remove no
+     longer supervised ones and add new ones */
+
+  /* walk over the sockets we got right now */
+  for(i = 0; i < cur_poll.num; i++) {
+    unsigned char cur_action = cur_poll.actions[i];
+    unsigned char last_action = 0;
+    int comboaction;
+
+    s = cur_poll.sockets[i];
+
+    /* get it from the hash */
+    entry = sh_getentry(&multi->sockhash, s);
+    if(entry) {
+      /* check if new for this transfer */
+      unsigned int j;
+      for(j = 0; j< data->last_poll.num; j++) {
+        if(s == data->last_poll.sockets[j]) {
+          last_action = data->last_poll.actions[j];
+          break;
+        }
+      }
+    }
+    else {
+      /* this is a socket we didn't have before, add it to the hash! */
+      entry = sh_addentry(&multi->sockhash, s);
+      if(!entry)
+        /* fatal */
+        return CURLM_OUT_OF_MEMORY;
+    }
+    if(last_action && (last_action != cur_action)) {
+      /* Socket was used already, but different action now */
+      if(last_action & CURL_POLL_IN)
+        entry->readers--;
+      if(last_action & CURL_POLL_OUT)
+        entry->writers--;
+      if(cur_action & CURL_POLL_IN)
+        entry->readers++;
+      if(cur_action & CURL_POLL_OUT)
+        entry->writers++;
+    }
+    else if(!last_action) {
+      /* a new transfer using this socket */
+      entry->users++;
+      if(cur_action & CURL_POLL_IN)
+        entry->readers++;
+      if(cur_action & CURL_POLL_OUT)
+        entry->writers++;
+
+      /* add 'data' to the transfer hash on this socket! */
+      if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */
+                        sizeof(struct Curl_easy *), data)) {
+        Curl_hash_destroy(&entry->transfers);
+        return CURLM_OUT_OF_MEMORY;
+      }
+    }
+
+    comboaction = (entry->writers ? CURL_POLL_OUT : 0) |
+                   (entry->readers ? CURL_POLL_IN : 0);
+
+    /* socket existed before and has the same action set as before */
+    if(last_action && ((int)entry->action == comboaction))
+      /* same, continue */
+      continue;
+
+    if(multi->socket_cb) {
+      set_in_callback(multi, TRUE);
+      rc = multi->socket_cb(data, s, comboaction, multi->socket_userp,
+                            entry->socketp);
+
+      set_in_callback(multi, FALSE);
+      if(rc == -1) {
+        multi->dead = TRUE;
+        return CURLM_ABORTED_BY_CALLBACK;
+      }
+    }
+
+    entry->action = comboaction; /* store the current action state */
+  }
+
+  /* Check for last_poll.sockets that no longer appear in cur_poll.sockets.
+   * Need to remove the easy handle from the multi->sockhash->transfers and
+   * remove multi->sockhash entry when this was the last transfer */
+  for(i = 0; i< data->last_poll.num; i++) {
+    unsigned int j;
+    bool stillused = FALSE;
+    s = data->last_poll.sockets[i];
+    for(j = 0; j < cur_poll.num; j++) {
+      if(s == cur_poll.sockets[j]) {
+        /* this is still supervised */
+        stillused = TRUE;
+        break;
+      }
+    }
+    if(stillused)
+      continue;
+
+    entry = sh_getentry(&multi->sockhash, s);
+    /* if this is NULL here, the socket has been closed and notified so
+       already by Curl_multi_closed() */
+    if(entry) {
+      unsigned char oldactions = data->last_poll.actions[i];
+      /* this socket has been removed. Decrease user count */
+      entry->users--;
+      if(oldactions & CURL_POLL_OUT)
+        entry->writers--;
+      if(oldactions & CURL_POLL_IN)
+        entry->readers--;
+      if(!entry->users) {
+        if(multi->socket_cb) {
+          set_in_callback(multi, TRUE);
+          rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
+                                multi->socket_userp, entry->socketp);
+          set_in_callback(multi, FALSE);
+          if(rc == -1) {
+            multi->dead = TRUE;
+            return CURLM_ABORTED_BY_CALLBACK;
+          }
+        }
+        sh_delentry(entry, &multi->sockhash, s);
+      }
+      else {
+        /* still users, but remove this handle as a user of this socket */
+        if(Curl_hash_delete(&entry->transfers, (char *)&data,
+                            sizeof(struct Curl_easy *))) {
+          DEBUGASSERT(NULL);
+        }
+      }
+    }
+  } /* for loop over num */
+
+  /* Remember for next time */
+  memcpy(&data->last_poll, &cur_poll, sizeof(data->last_poll));
+  return CURLM_OK;
+}
+
+CURLcode Curl_updatesocket(struct Curl_easy *data)
+{
+  if(singlesocket(data->multi, data))
+    return CURLE_ABORTED_BY_CALLBACK;
+  return CURLE_OK;
+}
+
+
+/*
+ * Curl_multi_closed()
+ *
+ * Used by the connect code to tell the multi_socket code that one of the
+ * sockets we were using is about to be closed.  This function will then
+ * remove it from the sockethash for this handle to make the multi_socket API
+ * behave properly, especially for the case when libcurl will create another
+ * socket again and it gets the same file descriptor number.
+ */
+
+void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s)
+{
+  if(data) {
+    /* if there's still an easy handle associated with this connection */
+    struct Curl_multi *multi = data->multi;
+    if(multi) {
+      /* this is set if this connection is part of a handle that is added to
+         a multi handle, and only then this is necessary */
+      struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
+
+      if(entry) {
+        int rc = 0;
+        if(multi->socket_cb) {
+          set_in_callback(multi, TRUE);
+          rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
+                                multi->socket_userp, entry->socketp);
+          set_in_callback(multi, FALSE);
+        }
+
+        /* now remove it from the socket hash */
+        sh_delentry(entry, &multi->sockhash, s);
+        if(rc == -1)
+          /* This just marks the multi handle as "dead" without returning an
+             error code primarily because this function is used from many
+             places where propagating an error back is tricky. */
+          multi->dead = TRUE;
+      }
+    }
+  }
+}
+
+/*
+ * add_next_timeout()
+ *
+ * Each Curl_easy has a list of timeouts. The add_next_timeout() is called
+ * when it has just been removed from the splay tree because the timeout has
+ * expired. This function is then to advance in the list to pick the next
+ * timeout to use (skip the already expired ones) and add this node back to
+ * the splay tree again.
+ *
+ * The splay tree only has each sessionhandle as a single node and the nearest
+ * timeout is used to sort it on.
+ */
+static CURLMcode add_next_timeout(struct curltime now,
+                                  struct Curl_multi *multi,
+                                  struct Curl_easy *d)
+{
+  struct curltime *tv = &d->state.expiretime;
+  struct Curl_llist *list = &d->state.timeoutlist;
+  struct Curl_llist_element *e;
+  struct time_node *node = NULL;
+
+  /* move over the timeout list for this specific handle and remove all
+     timeouts that are now passed tense and store the next pending
+     timeout in *tv */
+  for(e = list->head; e;) {
+    struct Curl_llist_element *n = e->next;
+    timediff_t diff;
+    node = (struct time_node *)e->ptr;
+    diff = Curl_timediff_us(node->time, now);
+    if(diff <= 0)
+      /* remove outdated entry */
+      Curl_llist_remove(list, e, NULL);
+    else
+      /* the list is sorted so get out on the first mismatch */
+      break;
+    e = n;
+  }
+  e = list->head;
+  if(!e) {
+    /* clear the expire times within the handles that we remove from the
+       splay tree */
+    tv->tv_sec = 0;
+    tv->tv_usec = 0;
+  }
+  else {
+    /* copy the first entry to 'tv' */
+    memcpy(tv, &node->time, sizeof(*tv));
+
+    /* Insert this node again into the splay.  Keep the timer in the list in
+       case we need to recompute future timers. */
+    multi->timetree = Curl_splayinsert(*tv, multi->timetree,
+                                       &d->state.timenode);
+  }
+  return CURLM_OK;
+}
+
+static CURLMcode multi_socket(struct Curl_multi *multi,
+                              bool checkall,
+                              curl_socket_t s,
+                              int ev_bitmask,
+                              int *running_handles)
+{
+  CURLMcode result = CURLM_OK;
+  struct Curl_easy *data = NULL;
+  struct Curl_tree *t;
+  struct curltime now = Curl_now();
+  bool first = FALSE;
+  bool nosig = FALSE;
+  SIGPIPE_VARIABLE(pipe_st);
+
+  if(checkall) {
+    /* *perform() deals with running_handles on its own */
+    result = curl_multi_perform(multi, running_handles);
+
+    /* walk through each easy handle and do the socket state change magic
+       and callbacks */
+    if(result != CURLM_BAD_HANDLE) {
+      data = multi->easyp;
+      while(data && !result) {
+        result = singlesocket(multi, data);
+        data = data->next;
+      }
+    }
+
+    /* or should we fall-through and do the timer-based stuff? */
+    return result;
+  }
+  if(s != CURL_SOCKET_TIMEOUT) {
+    struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
+
+    if(!entry)
+      /* Unmatched socket, we can't act on it but we ignore this fact.  In
+         real-world tests it has been proved that libevent can in fact give
+         the application actions even though the socket was just previously
+         asked to get removed, so thus we better survive stray socket actions
+         and just move on. */
+      ;
+    else {
+      struct Curl_hash_iterator iter;
+      struct Curl_hash_element *he;
+
+      /* the socket can be shared by many transfers, iterate */
+      Curl_hash_start_iterate(&entry->transfers, &iter);
+      for(he = Curl_hash_next_element(&iter); he;
+          he = Curl_hash_next_element(&iter)) {
+        data = (struct Curl_easy *)he->ptr;
+        DEBUGASSERT(data);
+        DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);
+
+        if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
+          /* set socket event bitmask if they're not locked */
+          data->state.select_bits |= (unsigned char)ev_bitmask;
+
+        Curl_expire(data, 0, EXPIRE_RUN_NOW);
+      }
+
+      /* Now we fall-through and do the timer-based stuff, since we don't want
+         to force the user to have to deal with timeouts as long as at least
+         one connection in fact has traffic. */
+
+      data = NULL; /* set data to NULL again to avoid calling
+                      multi_runsingle() in case there's no need to */
+      now = Curl_now(); /* get a newer time since the multi_runsingle() loop
+                           may have taken some time */
+    }
+  }
+  else {
+    /* Asked to run due to time-out. Clear the 'lastcall' variable to force
+       Curl_update_timer() to trigger a callback to the app again even if the
+       same timeout is still the one to run after this call. That handles the
+       case when the application asks libcurl to run the timeout
+       prematurely. */
+    memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
+  }
+
+  /*
+   * The loop following here will go on as long as there are expire-times left
+   * to process in the splay and 'data' will be re-assigned for every expired
+   * handle we deal with.
+   */
+  do {
+    /* the first loop lap 'data' can be NULL */
+    if(data) {
+      if(!first) {
+        first = TRUE;
+        nosig = data->set.no_signal; /* initial state */
+        sigpipe_ignore(data, &pipe_st);
+      }
+      else if(data->set.no_signal != nosig) {
+        sigpipe_restore(&pipe_st);
+        sigpipe_ignore(data, &pipe_st);
+        nosig = data->set.no_signal; /* remember new state */
+      }
+      result = multi_runsingle(multi, &now, data);
+
+      if(CURLM_OK >= result) {
+        /* get the socket(s) and check if the state has been changed since
+           last */
+        result = singlesocket(multi, data);
+        if(result)
+          break;
+      }
+    }
+
+    /* Check if there's one (more) expired timer to deal with! This function
+       extracts a matching node if there is one */
+
+    multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
+    if(t) {
+      data = t->payload; /* assign this for next loop */
+      (void)add_next_timeout(now, multi, t->payload);
+    }
+
+  } while(t);
+  if(first)
+    sigpipe_restore(&pipe_st);
+
+  *running_handles = multi->num_alive;
+  return result;
+}
+
+#undef curl_multi_setopt
+CURLMcode curl_multi_setopt(struct Curl_multi *multi,
+                            CURLMoption option, ...)
+{
+  CURLMcode res = CURLM_OK;
+  va_list param;
+  unsigned long uarg;
+
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  if(multi->in_callback)
+    return CURLM_RECURSIVE_API_CALL;
+
+  va_start(param, option);
+
+  switch(option) {
+  case CURLMOPT_SOCKETFUNCTION:
+    multi->socket_cb = va_arg(param, curl_socket_callback);
+    break;
+  case CURLMOPT_SOCKETDATA:
+    multi->socket_userp = va_arg(param, void *);
+    break;
+  case CURLMOPT_PUSHFUNCTION:
+    multi->push_cb = va_arg(param, curl_push_callback);
+    break;
+  case CURLMOPT_PUSHDATA:
+    multi->push_userp = va_arg(param, void *);
+    break;
+  case CURLMOPT_PIPELINING:
+    multi->multiplexing = va_arg(param, long) & CURLPIPE_MULTIPLEX ? 1 : 0;
+    break;
+  case CURLMOPT_TIMERFUNCTION:
+    multi->timer_cb = va_arg(param, curl_multi_timer_callback);
+    break;
+  case CURLMOPT_TIMERDATA:
+    multi->timer_userp = va_arg(param, void *);
+    break;
+  case CURLMOPT_MAXCONNECTS:
+    uarg = va_arg(param, unsigned long);
+    if(uarg <= UINT_MAX)
+      multi->maxconnects = (unsigned int)uarg;
+    break;
+  case CURLMOPT_MAX_HOST_CONNECTIONS:
+    multi->max_host_connections = va_arg(param, long);
+    break;
+  case CURLMOPT_MAX_TOTAL_CONNECTIONS:
+    multi->max_total_connections = va_arg(param, long);
+    break;
+    /* options formerly used for pipelining */
+  case CURLMOPT_MAX_PIPELINE_LENGTH:
+    break;
+  case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
+    break;
+  case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
+    break;
+  case CURLMOPT_PIPELINING_SITE_BL:
+    break;
+  case CURLMOPT_PIPELINING_SERVER_BL:
+    break;
+  case CURLMOPT_MAX_CONCURRENT_STREAMS:
+    {
+      long streams = va_arg(param, long);
+      if((streams < 1) || (streams > INT_MAX))
+        streams = 100;
+      multi->max_concurrent_streams = (unsigned int)streams;
+    }
+    break;
+  default:
+    res = CURLM_UNKNOWN_OPTION;
+    break;
+  }
+  va_end(param);
+  return res;
+}
+
+/* we define curl_multi_socket() in the public multi.h header */
+#undef curl_multi_socket
+
+CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
+                            int *running_handles)
+{
+  CURLMcode result;
+  if(multi->in_callback)
+    return CURLM_RECURSIVE_API_CALL;
+  result = multi_socket(multi, FALSE, s, 0, running_handles);
+  if(CURLM_OK >= result)
+    result = Curl_update_timer(multi);
+  return result;
+}
+
+CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
+                                   int ev_bitmask, int *running_handles)
+{
+  CURLMcode result;
+  if(multi->in_callback)
+    return CURLM_RECURSIVE_API_CALL;
+  result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
+  if(CURLM_OK >= result)
+    result = Curl_update_timer(multi);
+  return result;
+}
+
+CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
+{
+  CURLMcode result;
+  if(multi->in_callback)
+    return CURLM_RECURSIVE_API_CALL;
+  result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
+  if(CURLM_OK >= result)
+    result = Curl_update_timer(multi);
+  return result;
+}
+
+static CURLMcode multi_timeout(struct Curl_multi *multi,
+                               long *timeout_ms)
+{
+  static const struct curltime tv_zero = {0, 0};
+
+  if(multi->dead) {
+    *timeout_ms = 0;
+    return CURLM_OK;
+  }
+
+  if(multi->timetree) {
+    /* we have a tree of expire times */
+    struct curltime now = Curl_now();
+
+    /* splay the lowest to the bottom */
+    multi->timetree = Curl_splay(tv_zero, multi->timetree);
+
+    if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
+      /* some time left before expiration */
+      timediff_t diff = Curl_timediff_ceil(multi->timetree->key, now);
+      /* this should be safe even on 32 bit archs, as we don't use that
+         overly long timeouts */
+      *timeout_ms = (long)diff;
+    }
+    else
+      /* 0 means immediately */
+      *timeout_ms = 0;
+  }
+  else
+    *timeout_ms = -1;
+
+  return CURLM_OK;
+}
+
+CURLMcode curl_multi_timeout(struct Curl_multi *multi,
+                             long *timeout_ms)
+{
+  /* First, make some basic checks that the CURLM handle is a good handle */
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  if(multi->in_callback)
+    return CURLM_RECURSIVE_API_CALL;
+
+  return multi_timeout(multi, timeout_ms);
+}
+
+/*
+ * Tell the application it should update its timers, if it subscribes to the
+ * update timer callback.
+ */
+CURLMcode Curl_update_timer(struct Curl_multi *multi)
+{
+  long timeout_ms;
+  int rc;
+
+  if(!multi->timer_cb || multi->dead)
+    return CURLM_OK;
+  if(multi_timeout(multi, &timeout_ms)) {
+    return CURLM_OK;
+  }
+  if(timeout_ms < 0) {
+    static const struct curltime none = {0, 0};
+    if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
+      multi->timer_lastcall = none;
+      /* there's no timeout now but there was one previously, tell the app to
+         disable it */
+      set_in_callback(multi, TRUE);
+      rc = multi->timer_cb(multi, -1, multi->timer_userp);
+      set_in_callback(multi, FALSE);
+      if(rc == -1) {
+        multi->dead = TRUE;
+        return CURLM_ABORTED_BY_CALLBACK;
+      }
+      return CURLM_OK;
+    }
+    return CURLM_OK;
+  }
+
+  /* When multi_timeout() is done, multi->timetree points to the node with the
+   * timeout we got the (relative) time-out time for. We can thus easily check
+   * if this is the same (fixed) time as we got in a previous call and then
+   * avoid calling the callback again. */
+  if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
+    return CURLM_OK;
+
+  multi->timer_lastcall = multi->timetree->key;
+
+  set_in_callback(multi, TRUE);
+  rc = multi->timer_cb(multi, timeout_ms, multi->timer_userp);
+  set_in_callback(multi, FALSE);
+  if(rc == -1) {
+    multi->dead = TRUE;
+    return CURLM_ABORTED_BY_CALLBACK;
+  }
+  return CURLM_OK;
+}
+
+/*
+ * multi_deltimeout()
+ *
+ * Remove a given timestamp from the list of timeouts.
+ */
+static void
+multi_deltimeout(struct Curl_easy *data, expire_id eid)
+{
+  struct Curl_llist_element *e;
+  struct Curl_llist *timeoutlist = &data->state.timeoutlist;
+  /* find and remove the specific node from the list */
+  for(e = timeoutlist->head; e; e = e->next) {
+    struct time_node *n = (struct time_node *)e->ptr;
+    if(n->eid == eid) {
+      Curl_llist_remove(timeoutlist, e, NULL);
+      return;
+    }
+  }
+}
+
+/*
+ * multi_addtimeout()
+ *
+ * Add a timestamp to the list of timeouts. Keep the list sorted so that head
+ * of list is always the timeout nearest in time.
+ *
+ */
+static CURLMcode
+multi_addtimeout(struct Curl_easy *data,
+                 struct curltime *stamp,
+                 expire_id eid)
+{
+  struct Curl_llist_element *e;
+  struct time_node *node;
+  struct Curl_llist_element *prev = NULL;
+  size_t n;
+  struct Curl_llist *timeoutlist = &data->state.timeoutlist;
+
+  node = &data->state.expires[eid];
+
+  /* copy the timestamp and id */
+  memcpy(&node->time, stamp, sizeof(*stamp));
+  node->eid = eid; /* also marks it as in use */
+
+  n = Curl_llist_count(timeoutlist);
+  if(n) {
+    /* find the correct spot in the list */
+    for(e = timeoutlist->head; e; e = e->next) {
+      struct time_node *check = (struct time_node *)e->ptr;
+      timediff_t diff = Curl_timediff(check->time, node->time);
+      if(diff > 0)
+        break;
+      prev = e;
+    }
+
+  }
+  /* else
+     this is the first timeout on the list */
+
+  Curl_llist_insert_next(timeoutlist, prev, node, &node->list);
+  return CURLM_OK;
+}
+
+/*
+ * Curl_expire()
+ *
+ * given a number of milliseconds from now to use to set the 'act before
+ * this'-time for the transfer, to be extracted by curl_multi_timeout()
+ *
+ * The timeout will be added to a queue of timeouts if it defines a moment in
+ * time that is later than the current head of queue.
+ *
+ * Expire replaces a former timeout using the same id if already set.
+ */
+void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
+{
+  struct Curl_multi *multi = data->multi;
+  struct curltime *nowp = &data->state.expiretime;
+  struct curltime set;
+
+  /* this is only interesting while there is still an associated multi struct
+     remaining! */
+  if(!multi)
+    return;
+
+  DEBUGASSERT(id < EXPIRE_LAST);
+
+  set = Curl_now();
+  set.tv_sec += (time_t)(milli/1000); /* might be a 64 to 32 bit conversion */
+  set.tv_usec += (unsigned int)(milli%1000)*1000;
+
+  if(set.tv_usec >= 1000000) {
+    set.tv_sec++;
+    set.tv_usec -= 1000000;
+  }
+
+  /* Remove any timer with the same id just in case. */
+  multi_deltimeout(data, id);
+
+  /* Add it to the timer list.  It must stay in the list until it has expired
+     in case we need to recompute the minimum timer later. */
+  multi_addtimeout(data, &set, id);
+
+  if(nowp->tv_sec || nowp->tv_usec) {
+    /* This means that the struct is added as a node in the splay tree.
+       Compare if the new time is earlier, and only remove-old/add-new if it
+       is. */
+    timediff_t diff = Curl_timediff(set, *nowp);
+    int rc;
+
+    if(diff > 0) {
+      /* The current splay tree entry is sooner than this new expiry time.
+         We don't need to update our splay tree entry. */
+      return;
+    }
+
+    /* Since this is an updated time, we must remove the previous entry from
+       the splay tree first and then re-add the new value */
+    rc = Curl_splayremove(multi->timetree, &data->state.timenode,
+                          &multi->timetree);
+    if(rc)
+      infof(data, "Internal error removing splay node = %d", rc);
+  }
+
+  /* Indicate that we are in the splay tree and insert the new timer expiry
+     value since it is our local minimum. */
+  *nowp = set;
+  data->state.timenode.payload = data;
+  multi->timetree = Curl_splayinsert(*nowp, multi->timetree,
+                                     &data->state.timenode);
+}
+
+/*
+ * Curl_expire_done()
+ *
+ * Removes the expire timer. Marks it as done.
+ *
+ */
+void Curl_expire_done(struct Curl_easy *data, expire_id id)
+{
+  /* remove the timer, if there */
+  multi_deltimeout(data, id);
+}
+
+/*
+ * Curl_expire_clear()
+ *
+ * Clear ALL timeout values for this handle.
+ */
+void Curl_expire_clear(struct Curl_easy *data)
+{
+  struct Curl_multi *multi = data->multi;
+  struct curltime *nowp = &data->state.expiretime;
+
+  /* this is only interesting while there is still an associated multi struct
+     remaining! */
+  if(!multi)
+    return;
+
+  if(nowp->tv_sec || nowp->tv_usec) {
+    /* Since this is an cleared time, we must remove the previous entry from
+       the splay tree */
+    struct Curl_llist *list = &data->state.timeoutlist;
+    int rc;
+
+    rc = Curl_splayremove(multi->timetree, &data->state.timenode,
+                          &multi->timetree);
+    if(rc)
+      infof(data, "Internal error clearing splay node = %d", rc);
+
+    /* flush the timeout list too */
+    while(list->size > 0) {
+      Curl_llist_remove(list, list->tail, NULL);
+    }
+
+#ifdef DEBUGBUILD
+    infof(data, "Expire cleared");
+#endif
+    nowp->tv_sec = 0;
+    nowp->tv_usec = 0;
+  }
+}
+
+
+
+
+CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
+                            void *hashp)
+{
+  struct Curl_sh_entry *there = NULL;
+
+  there = sh_getentry(&multi->sockhash, s);
+
+  if(!there)
+    return CURLM_BAD_SOCKET;
+
+  there->socketp = hashp;
+
+  return CURLM_OK;
+}
+
+size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
+{
+  return multi ? multi->max_host_connections : 0;
+}
+
+size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
+{
+  return multi ? multi->max_total_connections : 0;
+}
+
+/*
+ * When information about a connection has appeared, call this!
+ */
+
+void Curl_multiuse_state(struct Curl_easy *data,
+                         int bundlestate) /* use BUNDLE_* defines */
+{
+  struct connectdata *conn;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->multi);
+  conn = data->conn;
+  DEBUGASSERT(conn);
+  DEBUGASSERT(conn->bundle);
+
+  conn->bundle->multiuse = bundlestate;
+  process_pending_handles(data->multi);
+}
+
+/* process_pending_handles() moves all handles from PENDING
+   back into the main list and change state to CONNECT */
+static void process_pending_handles(struct Curl_multi *multi)
+{
+  struct Curl_llist_element *e = multi->pending.head;
+  if(e) {
+    struct Curl_easy *data = e->ptr;
+
+    DEBUGASSERT(data->mstate == MSTATE_PENDING);
+
+    /* put it back into the main list */
+    link_easy(multi, data);
+
+    multistate(data, MSTATE_CONNECT);
+
+    /* Remove this node from the list */
+    Curl_llist_remove(&multi->pending, e, NULL);
+
+    /* Make sure that the handle will be processed soonish. */
+    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+
+    /* mark this as having been in the pending queue */
+    data->state.previouslypending = TRUE;
+  }
+}
+
+void Curl_set_in_callback(struct Curl_easy *data, bool value)
+{
+  /* might get called when there is no data pointer! */
+  if(data) {
+    if(data->multi_easy)
+      data->multi_easy->in_callback = value;
+    else if(data->multi)
+      data->multi->in_callback = value;
+  }
+}
+
+bool Curl_is_in_callback(struct Curl_easy *easy)
+{
+  return ((easy->multi && easy->multi->in_callback) ||
+          (easy->multi_easy && easy->multi_easy->in_callback));
+}
+
+unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi)
+{
+  DEBUGASSERT(multi);
+  return multi->max_concurrent_streams;
+}
+
+struct Curl_easy **curl_multi_get_handles(struct Curl_multi *multi)
+{
+  struct Curl_easy **a = malloc(sizeof(struct Curl_easy *) *
+                                (multi->num_easy + 1));
+  if(a) {
+    unsigned int i = 0;
+    struct Curl_easy *e = multi->easyp;
+    while(e) {
+      DEBUGASSERT(i < multi->num_easy);
+      if(!e->state.internal)
+        a[i++] = e;
+      e = e->next;
+    }
+    a[i] = NULL; /* last entry is a NULL */
+  }
+  return a;
+}
+
+CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
+                                    char **pbuf, size_t *pbuflen)
+{
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->multi);
+  *pbuf = NULL;
+  *pbuflen = 0;
+  if(!data->multi) {
+    failf(data, "transfer has no multi handle");
+    return CURLE_FAILED_INIT;
+  }
+  if(!data->set.buffer_size) {
+    failf(data, "transfer buffer size is 0");
+    return CURLE_FAILED_INIT;
+  }
+  if(data->multi->xfer_buf_borrowed) {
+    failf(data, "attempt to borrow xfer_buf when already borrowed");
+    return CURLE_AGAIN;
+  }
+
+  if(data->multi->xfer_buf &&
+     data->set.buffer_size > data->multi->xfer_buf_len) {
+    /* not large enough, get a new one */
+    free(data->multi->xfer_buf);
+    data->multi->xfer_buf = NULL;
+    data->multi->xfer_buf_len = 0;
+  }
+
+  if(!data->multi->xfer_buf) {
+    data->multi->xfer_buf = malloc((size_t)data->set.buffer_size);
+    if(!data->multi->xfer_buf) {
+      failf(data, "could not allocate xfer_buf of %zu bytes",
+            (size_t)data->set.buffer_size);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    data->multi->xfer_buf_len = data->set.buffer_size;
+  }
+
+  data->multi->xfer_buf_borrowed = TRUE;
+  *pbuf = data->multi->xfer_buf;
+  *pbuflen = data->multi->xfer_buf_len;
+  return CURLE_OK;
+}
+
+void Curl_multi_xfer_buf_release(struct Curl_easy *data, char *buf)
+{
+  (void)buf;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->multi);
+  DEBUGASSERT(!buf || data->multi->xfer_buf == buf);
+  data->multi->xfer_buf_borrowed = FALSE;
+}
+
+CURLcode Curl_multi_xfer_ulbuf_borrow(struct Curl_easy *data,
+                                      char **pbuf, size_t *pbuflen)
+{
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->multi);
+  *pbuf = NULL;
+  *pbuflen = 0;
+  if(!data->multi) {
+    failf(data, "transfer has no multi handle");
+    return CURLE_FAILED_INIT;
+  }
+  if(!data->set.upload_buffer_size) {
+    failf(data, "transfer upload buffer size is 0");
+    return CURLE_FAILED_INIT;
+  }
+  if(data->multi->xfer_ulbuf_borrowed) {
+    failf(data, "attempt to borrow xfer_ulbuf when already borrowed");
+    return CURLE_AGAIN;
+  }
+
+  if(data->multi->xfer_ulbuf &&
+     data->set.upload_buffer_size > data->multi->xfer_ulbuf_len) {
+    /* not large enough, get a new one */
+    free(data->multi->xfer_ulbuf);
+    data->multi->xfer_ulbuf = NULL;
+    data->multi->xfer_ulbuf_len = 0;
+  }
+
+  if(!data->multi->xfer_ulbuf) {
+    data->multi->xfer_ulbuf = malloc((size_t)data->set.upload_buffer_size);
+    if(!data->multi->xfer_ulbuf) {
+      failf(data, "could not allocate xfer_ulbuf of %zu bytes",
+            (size_t)data->set.upload_buffer_size);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    data->multi->xfer_ulbuf_len = data->set.upload_buffer_size;
+  }
+
+  data->multi->xfer_ulbuf_borrowed = TRUE;
+  *pbuf = data->multi->xfer_ulbuf;
+  *pbuflen = data->multi->xfer_ulbuf_len;
+  return CURLE_OK;
+}
+
+void Curl_multi_xfer_ulbuf_release(struct Curl_easy *data, char *buf)
+{
+  (void)buf;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->multi);
+  DEBUGASSERT(!buf || data->multi->xfer_ulbuf == buf);
+  data->multi->xfer_ulbuf_borrowed = FALSE;
+}
+
+static void multi_xfer_bufs_free(struct Curl_multi *multi)
+{
+  DEBUGASSERT(multi);
+  Curl_safefree(multi->xfer_buf);
+  multi->xfer_buf_len = 0;
+  multi->xfer_buf_borrowed = FALSE;
+  Curl_safefree(multi->xfer_ulbuf);
+  multi->xfer_ulbuf_len = 0;
+  multi->xfer_ulbuf_borrowed = FALSE;
+}
Index: trunk/src/libs/curl-8.7.1/lib/multihandle.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/multihandle.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/multihandle.h	(revision 104083)
@@ -0,0 +1,188 @@
+#ifndef HEADER_CURL_MULTIHANDLE_H
+#define HEADER_CURL_MULTIHANDLE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "llist.h"
+#include "hash.h"
+#include "conncache.h"
+#include "psl.h"
+#include "socketpair.h"
+
+struct connectdata;
+
+struct Curl_message {
+  struct Curl_llist_element list;
+  /* the 'CURLMsg' is the part that is visible to the external user */
+  struct CURLMsg extmsg;
+};
+
+/* NOTE: if you add a state here, add the name to the statename[] array as
+   well!
+*/
+typedef enum {
+  MSTATE_INIT,         /* 0 - start in this state */
+  MSTATE_PENDING,      /* 1 - no connections, waiting for one */
+  MSTATE_CONNECT,      /* 2 - resolve/connect has been sent off */
+  MSTATE_RESOLVING,    /* 3 - awaiting the resolve to finalize */
+  MSTATE_CONNECTING,   /* 4 - awaiting the TCP connect to finalize */
+  MSTATE_TUNNELING,    /* 5 - awaiting HTTPS proxy SSL initialization to
+                          complete and/or proxy CONNECT to finalize */
+  MSTATE_PROTOCONNECT, /* 6 - initiate protocol connect procedure */
+  MSTATE_PROTOCONNECTING, /* 7 - completing the protocol-specific connect
+                             phase */
+  MSTATE_DO,           /* 8 - start send off the request (part 1) */
+  MSTATE_DOING,        /* 9 - sending off the request (part 1) */
+  MSTATE_DOING_MORE,   /* 10 - send off the request (part 2) */
+  MSTATE_DID,          /* 11 - done sending off request */
+  MSTATE_PERFORMING,   /* 12 - transfer data */
+  MSTATE_RATELIMITING, /* 13 - wait because limit-rate exceeded */
+  MSTATE_DONE,         /* 14 - post data transfer operation */
+  MSTATE_COMPLETED,    /* 15 - operation complete */
+  MSTATE_MSGSENT,      /* 16 - the operation complete message is sent */
+  MSTATE_LAST          /* 17 - not a true state, never use this */
+} CURLMstate;
+
+/* we support N sockets per easy handle. Set the corresponding bit to what
+   action we should wait for */
+#define MAX_SOCKSPEREASYHANDLE 5
+#define GETSOCK_READABLE (0x00ff)
+#define GETSOCK_WRITABLE (0xff00)
+
+#define CURLPIPE_ANY (CURLPIPE_MULTIPLEX)
+
+#if !defined(CURL_DISABLE_SOCKETPAIR)
+#define ENABLE_WAKEUP
+#endif
+
+/* value for MAXIMUM CONCURRENT STREAMS upper limit */
+#define INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1)
+
+/* Curl_multi SSL backend-specific data; declared differently by each SSL
+   backend */
+struct multi_ssl_backend_data;
+
+/* This is the struct known as CURLM on the outside */
+struct Curl_multi {
+  /* First a simple identifier to easier detect if a user mix up
+     this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
+  unsigned int magic;
+
+  /* We have a doubly-linked list with easy handles */
+  struct Curl_easy *easyp;
+  struct Curl_easy *easylp; /* last node */
+
+  unsigned int num_easy; /* amount of entries in the linked list above. */
+  unsigned int num_alive; /* amount of easy handles that are added but have
+                             not yet reached COMPLETE state */
+
+  struct Curl_llist msglist; /* a list of messages from completed transfers */
+
+  struct Curl_llist pending; /* Curl_easys that are in the
+                                MSTATE_PENDING state */
+  struct Curl_llist msgsent; /* Curl_easys that are in the
+                                MSTATE_MSGSENT state */
+
+  /* callback function and user data pointer for the *socket() API */
+  curl_socket_callback socket_cb;
+  void *socket_userp;
+
+  /* callback function and user data pointer for server push */
+  curl_push_callback push_cb;
+  void *push_userp;
+
+  /* Hostname cache */
+  struct Curl_hash hostcache;
+
+#ifdef USE_LIBPSL
+  /* PSL cache. */
+  struct PslCache psl;
+#endif
+
+  /* timetree points to the splay-tree of time nodes to figure out expire
+     times of all currently set timers */
+  struct Curl_tree *timetree;
+
+  /* buffer used for transfer data, lazy initialized */
+  char *xfer_buf; /* the actual buffer */
+  size_t xfer_buf_len;      /* the allocated length */
+  /* buffer used for upload data, lazy initialized */
+  char *xfer_ulbuf; /* the actual buffer */
+  size_t xfer_ulbuf_len;      /* the allocated length */
+
+#if defined(USE_SSL)
+  struct multi_ssl_backend_data *ssl_backend_data;
+#endif
+
+  /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
+     the pluralis form, there can be more than one easy handle waiting on the
+     same actual socket) */
+  struct Curl_hash sockhash;
+
+  /* Shared connection cache (bundles)*/
+  struct conncache conn_cache;
+
+  long max_host_connections; /* if >0, a fixed limit of the maximum number
+                                of connections per host */
+
+  long max_total_connections; /* if >0, a fixed limit of the maximum number
+                                 of connections in total */
+
+  /* timer callback and user data pointer for the *socket() API */
+  curl_multi_timer_callback timer_cb;
+  void *timer_userp;
+  struct curltime timer_lastcall; /* the fixed time for the timeout for the
+                                    previous callback */
+#ifdef USE_WINSOCK
+  WSAEVENT wsa_event; /* winsock event used for waits */
+#else
+#ifdef ENABLE_WAKEUP
+  curl_socket_t wakeup_pair[2]; /* socketpair() used for wakeup
+                                   0 is used for read, 1 is used for write */
+#endif
+#endif
+  unsigned int max_concurrent_streams;
+  unsigned int maxconnects; /* if >0, a fixed limit of the maximum number of
+                               entries we're allowed to grow the connection
+                               cache to */
+#define IPV6_UNKNOWN 0
+#define IPV6_DEAD    1
+#define IPV6_WORKS   2
+  unsigned char ipv6_up;       /* IPV6_* defined */
+  BIT(multiplexing);           /* multiplexing wanted */
+  BIT(recheckstate);           /* see Curl_multi_connchanged */
+  BIT(in_callback);            /* true while executing a callback */
+#ifdef USE_OPENSSL
+  BIT(ssl_seeded);
+#endif
+  BIT(dead); /* a callback returned error, everything needs to crash and
+                burn */
+  BIT(xfer_buf_borrowed);      /* xfer_buf is currently being borrowed */
+  BIT(xfer_ulbuf_borrowed);      /* xfer_buf is currently being borrowed */
+#ifdef DEBUGBUILD
+  BIT(warned);                 /* true after user warned of DEBUGBUILD */
+#endif
+};
+
+#endif /* HEADER_CURL_MULTIHANDLE_H */
Index: trunk/src/libs/curl-8.7.1/lib/multiif.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/multiif.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/multiif.h	(revision 104083)
@@ -0,0 +1,146 @@
+#ifndef HEADER_CURL_MULTIIF_H
+#define HEADER_CURL_MULTIIF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Prototypes for library-wide functions provided by multi.c
+ */
+
+CURLcode Curl_updatesocket(struct Curl_easy *data);
+void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id);
+void Curl_expire_clear(struct Curl_easy *data);
+void Curl_expire_done(struct Curl_easy *data, expire_id id);
+CURLMcode Curl_update_timer(struct Curl_multi *multi) WARN_UNUSED_RESULT;
+void Curl_attach_connection(struct Curl_easy *data,
+                             struct connectdata *conn);
+void Curl_detach_connection(struct Curl_easy *data);
+bool Curl_multiplex_wanted(const struct Curl_multi *multi);
+void Curl_set_in_callback(struct Curl_easy *data, bool value);
+bool Curl_is_in_callback(struct Curl_easy *easy);
+CURLcode Curl_preconnect(struct Curl_easy *data);
+
+void Curl_multi_connchanged(struct Curl_multi *multi);
+
+/* Internal version of curl_multi_init() accepts size parameters for the
+   socket, connection and dns hashes */
+struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize,
+                                     int dnssize);
+
+/* the write bits start at bit 16 for the *getsock() bitmap */
+#define GETSOCK_WRITEBITSTART 16
+
+#define GETSOCK_BLANK 0 /* no bits set */
+
+/* set the bit for the given sock number to make the bitmap for writable */
+#define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x)))
+
+/* set the bit for the given sock number to make the bitmap for readable */
+#define GETSOCK_READSOCK(x) (1 << (x))
+
+/* mask for checking if read and/or write is set for index x */
+#define GETSOCK_MASK_RW(x) (GETSOCK_READSOCK(x)|GETSOCK_WRITESOCK(x))
+
+/* Return the value of the CURLMOPT_MAX_HOST_CONNECTIONS option */
+size_t Curl_multi_max_host_connections(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */
+size_t Curl_multi_max_total_connections(struct Curl_multi *multi);
+
+void Curl_multiuse_state(struct Curl_easy *data,
+                         int bundlestate); /* use BUNDLE_* defines */
+
+/*
+ * Curl_multi_closed()
+ *
+ * Used by the connect code to tell the multi_socket code that one of the
+ * sockets we were using is about to be closed.  This function will then
+ * remove it from the sockethash for this handle to make the multi_socket API
+ * behave properly, especially for the case when libcurl will create another
+ * socket again and it gets the same file descriptor number.
+ */
+
+void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s);
+
+/*
+ * Add a handle and move it into PERFORM state at once. For pushed streams.
+ */
+CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
+                                 struct Curl_easy *data,
+                                 struct connectdata *conn);
+
+
+/* Return the value of the CURLMOPT_MAX_CONCURRENT_STREAMS option */
+unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi);
+
+/**
+ * Borrow the transfer buffer from the multi, suitable
+ * for the given transfer `data`. The buffer may only be used in one
+ * multi processing of the easy handle. It MUST be returned to the
+ * multi before it can be borrowed again.
+ * Pointers into the buffer remain only valid as long as it is borrowed.
+ *
+ * @param data    the easy handle
+ * @param pbuf    on return, the buffer to use or NULL on error
+ * @param pbuflen on return, the size of *pbuf or 0 on error
+ * @return CURLE_OK when buffer is available and is returned.
+ *         CURLE_OUT_OF_MEMORy on failure to allocate the buffer,
+ *         CURLE_FAILED_INIT if the easy handle is without multi.
+ *         CURLE_AGAIN if the buffer is borrowed already.
+ */
+CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
+                                   char **pbuf, size_t *pbuflen);
+/**
+ * Release the borrowed buffer. All references into the buffer become
+ * invalid after this.
+ * @param buf the buffer pointer borrowed for coding error checks.
+ */
+void Curl_multi_xfer_buf_release(struct Curl_easy *data, char *buf);
+
+/**
+ * Borrow the upload buffer from the multi, suitable
+ * for the given transfer `data`. The buffer may only be used in one
+ * multi processing of the easy handle. It MUST be returned to the
+ * multi before it can be borrowed again.
+ * Pointers into the buffer remain only valid as long as it is borrowed.
+ *
+ * @param data    the easy handle
+ * @param pbuf    on return, the buffer to use or NULL on error
+ * @param pbuflen on return, the size of *pbuf or 0 on error
+ * @return CURLE_OK when buffer is available and is returned.
+ *         CURLE_OUT_OF_MEMORy on failure to allocate the buffer,
+ *         CURLE_FAILED_INIT if the easy handle is without multi.
+ *         CURLE_AGAIN if the buffer is borrowed already.
+ */
+CURLcode Curl_multi_xfer_ulbuf_borrow(struct Curl_easy *data,
+                                      char **pbuf, size_t *pbuflen);
+
+/**
+ * Release the borrowed upload buffer. All references into the buffer become
+ * invalid after this.
+ * @param buf the upload buffer pointer borrowed for coding error checks.
+ */
+void Curl_multi_xfer_ulbuf_release(struct Curl_easy *data, char *buf);
+
+#endif /* HEADER_CURL_MULTIIF_H */
Index: trunk/src/libs/curl-8.7.1/lib/netrc.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/netrc.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/netrc.c	(revision 104083)
@@ -0,0 +1,353 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#ifndef CURL_DISABLE_NETRC
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#include <curl/curl.h>
+#include "netrc.h"
+#include "strtok.h"
+#include "strcase.h"
+#include "curl_get_line.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Get user and password from .netrc when given a machine name */
+
+enum host_lookup_state {
+  NOTHING,
+  HOSTFOUND,    /* the 'machine' keyword was found */
+  HOSTVALID,    /* this is "our" machine! */
+  MACDEF
+};
+
+#define NETRC_FILE_MISSING 1
+#define NETRC_FAILED -1
+#define NETRC_SUCCESS 0
+
+#define MAX_NETRC_LINE 4096
+
+/*
+ * Returns zero on success.
+ */
+static int parsenetrc(const char *host,
+                      char **loginp,
+                      char **passwordp,
+                      char *netrcfile)
+{
+  FILE *file;
+  int retcode = NETRC_FILE_MISSING;
+  char *login = *loginp;
+  char *password = *passwordp;
+  bool specific_login = (login && *login != 0);
+  bool login_alloc = FALSE;
+  bool password_alloc = FALSE;
+  enum host_lookup_state state = NOTHING;
+
+  char state_login = 0;      /* Found a login keyword */
+  char state_password = 0;   /* Found a password keyword */
+  int state_our_login = TRUE;  /* With specific_login, found *our* login
+                                  name (or login-less line) */
+
+  DEBUGASSERT(netrcfile);
+
+  file = fopen(netrcfile, FOPEN_READTEXT);
+  if(file) {
+    bool done = FALSE;
+    struct dynbuf buf;
+    Curl_dyn_init(&buf, MAX_NETRC_LINE);
+
+    while(!done && Curl_get_line(&buf, file)) {
+      char *tok;
+      char *tok_end;
+      bool quoted;
+      char *netrcbuffer = Curl_dyn_ptr(&buf);
+      if(state == MACDEF) {
+        if((netrcbuffer[0] == '\n') || (netrcbuffer[0] == '\r'))
+          state = NOTHING;
+        else
+          continue;
+      }
+      tok = netrcbuffer;
+      while(tok) {
+        while(ISBLANK(*tok))
+          tok++;
+        /* tok is first non-space letter */
+        if(!*tok || (*tok == '#'))
+          /* end of line or the rest is a comment */
+          break;
+
+        /* leading double-quote means quoted string */
+        quoted = (*tok == '\"');
+
+        tok_end = tok;
+        if(!quoted) {
+          while(!ISSPACE(*tok_end))
+            tok_end++;
+          *tok_end = 0;
+        }
+        else {
+          bool escape = FALSE;
+          bool endquote = FALSE;
+          char *store = tok;
+          tok_end++; /* pass the leading quote */
+          while(*tok_end) {
+            char s = *tok_end;
+            if(escape) {
+              escape = FALSE;
+              switch(s) {
+              case 'n':
+                s = '\n';
+                break;
+              case 'r':
+                s = '\r';
+                break;
+              case 't':
+                s = '\t';
+                break;
+              }
+            }
+            else if(s == '\\') {
+              escape = TRUE;
+              tok_end++;
+              continue;
+            }
+            else if(s == '\"') {
+              tok_end++; /* pass the ending quote */
+              endquote = TRUE;
+              break;
+            }
+            *store++ = s;
+            tok_end++;
+          }
+          *store = 0;
+          if(escape || !endquote) {
+            /* bad syntax, get out */
+            retcode = NETRC_FAILED;
+            goto out;
+          }
+        }
+
+        if((login && *login) && (password && *password)) {
+          done = TRUE;
+          break;
+        }
+
+        switch(state) {
+        case NOTHING:
+          if(strcasecompare("macdef", tok)) {
+            /* Define a macro. A macro is defined with the specified name; its
+               contents begin with the next .netrc line and continue until a
+               null line (consecutive new-line characters) is encountered. */
+            state = MACDEF;
+          }
+          else if(strcasecompare("machine", tok)) {
+            /* the next tok is the machine name, this is in itself the
+               delimiter that starts the stuff entered for this machine,
+               after this we need to search for 'login' and
+               'password'. */
+            state = HOSTFOUND;
+          }
+          else if(strcasecompare("default", tok)) {
+            state = HOSTVALID;
+            retcode = NETRC_SUCCESS; /* we did find our host */
+          }
+          break;
+        case MACDEF:
+          if(!strlen(tok)) {
+            state = NOTHING;
+          }
+          break;
+        case HOSTFOUND:
+          if(strcasecompare(host, tok)) {
+            /* and yes, this is our host! */
+            state = HOSTVALID;
+            retcode = NETRC_SUCCESS; /* we did find our host */
+          }
+          else
+            /* not our host */
+            state = NOTHING;
+          break;
+        case HOSTVALID:
+          /* we are now parsing sub-keywords concerning "our" host */
+          if(state_login) {
+            if(specific_login) {
+              state_our_login = !Curl_timestrcmp(login, tok);
+            }
+            else if(!login || Curl_timestrcmp(login, tok)) {
+              if(login_alloc) {
+                free(login);
+                login_alloc = FALSE;
+              }
+              login = strdup(tok);
+              if(!login) {
+                retcode = NETRC_FAILED; /* allocation failed */
+                goto out;
+              }
+              login_alloc = TRUE;
+            }
+            state_login = 0;
+          }
+          else if(state_password) {
+            if((state_our_login || !specific_login)
+               && (!password || Curl_timestrcmp(password, tok))) {
+              if(password_alloc) {
+                free(password);
+                password_alloc = FALSE;
+              }
+              password = strdup(tok);
+              if(!password) {
+                retcode = NETRC_FAILED; /* allocation failed */
+                goto out;
+              }
+              password_alloc = TRUE;
+            }
+            state_password = 0;
+          }
+          else if(strcasecompare("login", tok))
+            state_login = 1;
+          else if(strcasecompare("password", tok))
+            state_password = 1;
+          else if(strcasecompare("machine", tok)) {
+            /* ok, there's machine here go => */
+            state = HOSTFOUND;
+            state_our_login = FALSE;
+          }
+          break;
+        } /* switch (state) */
+        tok = ++tok_end;
+      }
+    } /* while Curl_get_line() */
+
+out:
+    Curl_dyn_free(&buf);
+    if(!retcode) {
+      /* success */
+      if(login_alloc) {
+        if(*loginp)
+          free(*loginp);
+        *loginp = login;
+      }
+      if(password_alloc) {
+        if(*passwordp)
+          free(*passwordp);
+        *passwordp = password;
+      }
+    }
+    else {
+      if(login_alloc)
+        free(login);
+      if(password_alloc)
+        free(password);
+    }
+    fclose(file);
+  }
+
+  return retcode;
+}
+
+/*
+ * @unittest: 1304
+ *
+ * *loginp and *passwordp MUST be allocated if they aren't NULL when passed
+ * in.
+ */
+int Curl_parsenetrc(const char *host, char **loginp, char **passwordp,
+                    char *netrcfile)
+{
+  int retcode = 1;
+  char *filealloc = NULL;
+
+  if(!netrcfile) {
+#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
+    char pwbuf[1024];
+#endif
+    char *home = NULL;
+    char *homea = curl_getenv("HOME"); /* portable environment reader */
+    if(homea) {
+      home = homea;
+#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
+    }
+    else {
+      struct passwd pw, *pw_res;
+      if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res)
+         && pw_res) {
+        home = pw.pw_dir;
+      }
+#elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
+    }
+    else {
+      struct passwd *pw;
+      pw = getpwuid(geteuid());
+      if(pw) {
+        home = pw->pw_dir;
+      }
+#elif defined(_WIN32)
+    }
+    else {
+      homea = curl_getenv("USERPROFILE");
+      if(homea) {
+        home = homea;
+      }
+#endif
+    }
+
+    if(!home)
+      return retcode; /* no home directory found (or possibly out of
+                         memory) */
+
+    filealloc = curl_maprintf("%s%s.netrc", home, DIR_CHAR);
+    if(!filealloc) {
+      free(homea);
+      return -1;
+    }
+    retcode = parsenetrc(host, loginp, passwordp, filealloc);
+    free(filealloc);
+#ifdef _WIN32
+    if(retcode == NETRC_FILE_MISSING) {
+      /* fallback to the old-style "_netrc" file */
+      filealloc = curl_maprintf("%s%s_netrc", home, DIR_CHAR);
+      if(!filealloc) {
+        free(homea);
+        return -1;
+      }
+      retcode = parsenetrc(host, loginp, passwordp, filealloc);
+      free(filealloc);
+    }
+#endif
+    free(homea);
+  }
+  else
+    retcode = parsenetrc(host, loginp, passwordp, netrcfile);
+  return retcode;
+}
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/netrc.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/netrc.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/netrc.h	(revision 104083)
@@ -0,0 +1,43 @@
+#ifndef HEADER_CURL_NETRC_H
+#define HEADER_CURL_NETRC_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#ifndef CURL_DISABLE_NETRC
+
+/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
+int Curl_parsenetrc(const char *host, char **loginp,
+                    char **passwordp, char *filename);
+  /* Assume: (*passwordp)[0]=0, host[0] != 0.
+   * If (*loginp)[0] = 0, search for login and password within a machine
+   * section in the netrc.
+   * If (*loginp)[0] != 0, search for password within machine and login.
+   */
+#else
+/* disabled */
+#define Curl_parsenetrc(a,b,c,d,e,f) 1
+#endif
+
+#endif /* HEADER_CURL_NETRC_H */
Index: trunk/src/libs/curl-8.7.1/lib/nonblock.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/nonblock.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/nonblock.c	(revision 104083)
@@ -0,0 +1,84 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "nonblock.h"
+
+/*
+ * curlx_nonblock() set the given socket to either blocking or non-blocking
+ * mode based on the 'nonblock' boolean argument. This function is highly
+ * portable.
+ */
+int curlx_nonblock(curl_socket_t sockfd,    /* operate on this */
+                   int nonblock   /* TRUE or FALSE */)
+{
+#if defined(HAVE_FCNTL_O_NONBLOCK)
+  /* most recent unix versions */
+  int flags;
+  flags = sfcntl(sockfd, F_GETFL, 0);
+  if(nonblock)
+    return sfcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+  return sfcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
+
+#elif defined(HAVE_IOCTL_FIONBIO)
+
+  /* older unix versions */
+  int flags = nonblock ? 1 : 0;
+  return ioctl(sockfd, FIONBIO, &flags);
+
+#elif defined(HAVE_IOCTLSOCKET_FIONBIO)
+
+  /* Windows */
+  unsigned long flags = nonblock ? 1UL : 0UL;
+  return ioctlsocket(sockfd, FIONBIO, &flags);
+
+#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
+
+  /* Amiga */
+  long flags = nonblock ? 1L : 0L;
+  return IoctlSocket(sockfd, FIONBIO, (char *)&flags);
+
+#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
+
+  /* Orbis OS */
+  long b = nonblock ? 1L : 0L;
+  return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
+
+#else
+#  error "no non-blocking method was found/used/set"
+#endif
+}
Index: trunk/src/libs/curl-8.7.1/lib/nonblock.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/nonblock.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/nonblock.h	(revision 104083)
@@ -0,0 +1,32 @@
+#ifndef HEADER_CURL_NONBLOCK_H
+#define HEADER_CURL_NONBLOCK_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h> /* for curl_socket_t */
+
+int curlx_nonblock(curl_socket_t sockfd,    /* operate on this */
+                   int nonblock   /* TRUE or FALSE */);
+
+#endif /* HEADER_CURL_NONBLOCK_H */
Index: trunk/src/libs/curl-8.7.1/lib/noproxy.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/noproxy.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/noproxy.c	(revision 104083)
@@ -0,0 +1,265 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_PROXY
+
+#include "inet_pton.h"
+#include "strcase.h"
+#include "noproxy.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+/*
+ * Curl_cidr4_match() returns TRUE if the given IPv4 address is within the
+ * specified CIDR address range.
+ */
+UNITTEST bool Curl_cidr4_match(const char *ipv4,    /* 1.2.3.4 address */
+                               const char *network, /* 1.2.3.4 address */
+                               unsigned int bits)
+{
+  unsigned int address = 0;
+  unsigned int check = 0;
+
+  if(bits > 32)
+    /* strange input */
+    return FALSE;
+
+  if(1 != Curl_inet_pton(AF_INET, ipv4, &address))
+    return FALSE;
+  if(1 != Curl_inet_pton(AF_INET, network, &check))
+    return FALSE;
+
+  if(bits && (bits != 32)) {
+    unsigned int mask = 0xffffffff << (32 - bits);
+    unsigned int haddr = htonl(address);
+    unsigned int hcheck = htonl(check);
+#if 0
+    fprintf(stderr, "Host %s (%x) network %s (%x) bits %u mask %x => %x\n",
+            ipv4, haddr, network, hcheck, bits, mask,
+            (haddr ^ hcheck) & mask);
+#endif
+    if((haddr ^ hcheck) & mask)
+      return FALSE;
+    return TRUE;
+  }
+  return (address == check);
+}
+
+UNITTEST bool Curl_cidr6_match(const char *ipv6,
+                               const char *network,
+                               unsigned int bits)
+{
+#ifdef ENABLE_IPV6
+  int bytes;
+  int rest;
+  unsigned char address[16];
+  unsigned char check[16];
+
+  if(!bits)
+    bits = 128;
+
+  bytes = bits/8;
+  rest = bits & 0x07;
+  if(1 != Curl_inet_pton(AF_INET6, ipv6, address))
+    return FALSE;
+  if(1 != Curl_inet_pton(AF_INET6, network, check))
+    return FALSE;
+  if((bytes > 16) || ((bytes == 16) && rest))
+    return FALSE;
+  if(bytes && memcmp(address, check, bytes))
+    return FALSE;
+  if(rest && !((address[bytes] ^ check[bytes]) & (0xff << (8 - rest))))
+    return FALSE;
+
+  return TRUE;
+#else
+  (void)ipv6;
+  (void)network;
+  (void)bits;
+  return FALSE;
+#endif
+}
+
+enum nametype {
+  TYPE_HOST,
+  TYPE_IPV4,
+  TYPE_IPV6
+};
+
+/****************************************************************
+* Checks if the host is in the noproxy list. returns TRUE if it matches and
+* therefore the proxy should NOT be used.
+****************************************************************/
+bool Curl_check_noproxy(const char *name, const char *no_proxy,
+                        bool *spacesep)
+{
+  char hostip[128];
+  *spacesep = FALSE;
+  /*
+   * If we don't have a hostname at all, like for example with a FILE
+   * transfer, we have nothing to interrogate the noproxy list with.
+   */
+  if(!name || name[0] == '\0')
+    return FALSE;
+
+  /* no_proxy=domain1.dom,host.domain2.dom
+   *   (a comma-separated list of hosts which should
+   *   not be proxied, or an asterisk to override
+   *   all proxy variables)
+   */
+  if(no_proxy && no_proxy[0]) {
+    const char *p = no_proxy;
+    size_t namelen;
+    enum nametype type = TYPE_HOST;
+    if(!strcmp("*", no_proxy))
+      return TRUE;
+
+    /* NO_PROXY was specified and it wasn't just an asterisk */
+
+    if(name[0] == '[') {
+      char *endptr;
+      /* IPv6 numerical address */
+      endptr = strchr(name, ']');
+      if(!endptr)
+        return FALSE;
+      name++;
+      namelen = endptr - name;
+      if(namelen >= sizeof(hostip))
+        return FALSE;
+      memcpy(hostip, name, namelen);
+      hostip[namelen] = 0;
+      name = hostip;
+      type = TYPE_IPV6;
+    }
+    else {
+      unsigned int address;
+      namelen = strlen(name);
+      if(1 == Curl_inet_pton(AF_INET, name, &address))
+        type = TYPE_IPV4;
+      else {
+        /* ignore trailing dots in the host name */
+        if(name[namelen - 1] == '.')
+          namelen--;
+      }
+    }
+
+    while(*p) {
+      const char *token;
+      size_t tokenlen = 0;
+      bool match = FALSE;
+
+      /* pass blanks */
+      while(*p && ISBLANK(*p))
+        p++;
+
+      token = p;
+      /* pass over the pattern */
+      while(*p && !ISBLANK(*p) && (*p != ',')) {
+        p++;
+        tokenlen++;
+      }
+
+      if(tokenlen) {
+        switch(type) {
+        case TYPE_HOST:
+          /* ignore trailing dots in the token to check */
+          if(token[tokenlen - 1] == '.')
+            tokenlen--;
+
+          if(tokenlen && (*token == '.')) {
+            /* ignore leading token dot as well */
+            token++;
+            tokenlen--;
+          }
+          /* A: example.com matches 'example.com'
+             B: www.example.com matches 'example.com'
+             C: nonexample.com DOES NOT match 'example.com'
+          */
+          if(tokenlen == namelen)
+            /* case A, exact match */
+            match = strncasecompare(token, name, namelen);
+          else if(tokenlen < namelen) {
+            /* case B, tailmatch domain */
+            match = (name[namelen - tokenlen - 1] == '.') &&
+              strncasecompare(token, name + (namelen - tokenlen),
+                              tokenlen);
+          }
+          /* case C passes through, not a match */
+          break;
+        case TYPE_IPV4:
+        case TYPE_IPV6: {
+          const char *check = token;
+          char *slash;
+          unsigned int bits = 0;
+          char checkip[128];
+          if(tokenlen >= sizeof(checkip))
+            /* this cannot match */
+            break;
+          /* copy the check name to a temp buffer */
+          memcpy(checkip, check, tokenlen);
+          checkip[tokenlen] = 0;
+          check = checkip;
+
+          slash = strchr(check, '/');
+          /* if the slash is part of this token, use it */
+          if(slash) {
+            bits = atoi(slash + 1);
+            *slash = 0; /* null terminate there */
+          }
+          if(type == TYPE_IPV6)
+            match = Curl_cidr6_match(name, check, bits);
+          else
+            match = Curl_cidr4_match(name, check, bits);
+          break;
+        }
+        }
+        if(match)
+          return TRUE;
+      } /* if(tokenlen) */
+      /* pass blanks after pattern */
+      while(ISBLANK(*p))
+        p++;
+      /* if not a comma! */
+      if(*p && (*p != ',')) {
+        *spacesep = TRUE;
+        continue;
+      }
+      /* pass any number of commas */
+      while(*p == ',')
+        p++;
+    } /* while(*p) */
+  } /* NO_PROXY was specified and it wasn't just an asterisk */
+
+  return FALSE;
+}
+
+#endif /* CURL_DISABLE_PROXY */
Index: trunk/src/libs/curl-8.7.1/lib/noproxy.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/noproxy.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/noproxy.h	(revision 104083)
@@ -0,0 +1,45 @@
+#ifndef HEADER_CURL_NOPROXY_H
+#define HEADER_CURL_NOPROXY_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_PROXY
+
+#ifdef DEBUGBUILD
+
+UNITTEST bool Curl_cidr4_match(const char *ipv4,    /* 1.2.3.4 address */
+                               const char *network, /* 1.2.3.4 address */
+                               unsigned int bits);
+UNITTEST bool Curl_cidr6_match(const char *ipv6,
+                               const char *network,
+                               unsigned int bits);
+#endif
+
+bool Curl_check_noproxy(const char *name, const char *no_proxy,
+                        bool *spacesep);
+
+#endif
+
+#endif /* HEADER_CURL_NOPROXY_H */
Index: trunk/src/libs/curl-8.7.1/lib/openldap.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/openldap.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/openldap.c	(revision 104083)
@@ -0,0 +1,1219 @@
+/***************************************************************************
+ *                      _   _ ____  _
+ *  Project         ___| | | |  _ \| |
+ *                 / __| | | | |_) | |
+ *                | (__| |_| |  _ <| |___
+ *                 \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Howard Chu, <hyc@openldap.org>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)
+
+/*
+ * Notice that USE_OPENLDAP is only a source code selection switch. When
+ * libcurl is built with USE_OPENLDAP defined the libcurl source code that
+ * gets compiled is the code from openldap.c, otherwise the code that gets
+ * compiled is the code from ldap.c.
+ *
+ * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
+ * might be required for compilation and runtime. In order to use ancient
+ * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
+ */
+
+#include <ldap.h>
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "sendf.h"
+#include "vtls/vtls.h"
+#include "transfer.h"
+#include "curl_ldap.h"
+#include "curl_base64.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "curl_sasl.h"
+#include "strcase.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Uncommenting this will enable the built-in debug logging of the openldap
+ * library. The debug log level can be set using the CURL_OPENLDAP_TRACE
+ * environment variable. The debug output is written to stderr.
+ *
+ * The library supports the following debug flags:
+ * LDAP_DEBUG_NONE         0x0000
+ * LDAP_DEBUG_TRACE        0x0001
+ * LDAP_DEBUG_CONSTRUCT    0x0002
+ * LDAP_DEBUG_DESTROY      0x0004
+ * LDAP_DEBUG_PARAMETER    0x0008
+ * LDAP_DEBUG_ANY          0xffff
+ *
+ * For example, use CURL_OPENLDAP_TRACE=0 for no debug,
+ * CURL_OPENLDAP_TRACE=2 for LDAP_DEBUG_CONSTRUCT messages only,
+ * CURL_OPENLDAP_TRACE=65535 for all debug message levels.
+ */
+/* #define CURL_OPENLDAP_DEBUG */
+
+/* Machine states. */
+typedef enum {
+  OLDAP_STOP,           /* Do nothing state, stops the state machine */
+  OLDAP_SSL,            /* Performing SSL handshake. */
+  OLDAP_STARTTLS,       /* STARTTLS request sent. */
+  OLDAP_TLS,            /* Performing TLS handshake. */
+  OLDAP_MECHS,          /* Get SASL authentication mechanisms. */
+  OLDAP_SASL,           /* SASL binding reply. */
+  OLDAP_BIND,           /* Simple bind reply. */
+  OLDAP_BINDV2,         /* Simple bind reply in protocol version 2. */
+  OLDAP_LAST            /* Never used */
+} ldapstate;
+
+#ifndef _LDAP_PVT_H
+extern int ldap_pvt_url_scheme2proto(const char *);
+extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
+                        LDAP **ld);
+#endif
+
+static CURLcode oldap_setup_connection(struct Curl_easy *data,
+                                       struct connectdata *conn);
+static CURLcode oldap_do(struct Curl_easy *data, bool *done);
+static CURLcode oldap_done(struct Curl_easy *data, CURLcode, bool);
+static CURLcode oldap_connect(struct Curl_easy *data, bool *done);
+static CURLcode oldap_connecting(struct Curl_easy *data, bool *done);
+static CURLcode oldap_disconnect(struct Curl_easy *data,
+                                 struct connectdata *conn, bool dead);
+
+static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech,
+                                   const struct bufref *initresp);
+static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
+                                    const struct bufref *resp);
+static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech);
+static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out);
+
+static Curl_recv oldap_recv;
+
+/*
+ * LDAP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldap = {
+  "LDAP",                               /* scheme */
+  oldap_setup_connection,               /* setup_connection */
+  oldap_do,                             /* do_it */
+  oldap_done,                           /* done */
+  ZERO_NULL,                            /* do_more */
+  oldap_connect,                        /* connect_it */
+  oldap_connecting,                     /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  oldap_disconnect,                     /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_LDAP,                            /* defport */
+  CURLPROTO_LDAP,                       /* protocol */
+  CURLPROTO_LDAP,                       /* family */
+  PROTOPT_NONE                          /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * LDAPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldaps = {
+  "LDAPS",                              /* scheme */
+  oldap_setup_connection,               /* setup_connection */
+  oldap_do,                             /* do_it */
+  oldap_done,                           /* done */
+  ZERO_NULL,                            /* do_more */
+  oldap_connect,                        /* connect_it */
+  oldap_connecting,                     /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  oldap_disconnect,                     /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_LDAPS,                           /* defport */
+  CURLPROTO_LDAPS,                      /* protocol */
+  CURLPROTO_LDAP,                       /* family */
+  PROTOPT_SSL                           /* flags */
+};
+#endif
+
+/* SASL parameters for the ldap protocol */
+static const struct SASLproto saslldap = {
+  "ldap",                     /* The service name */
+  oldap_perform_auth,         /* Send authentication command */
+  oldap_continue_auth,        /* Send authentication continuation */
+  oldap_cancel_auth,          /* Send authentication cancellation */
+  oldap_get_message,          /* Get SASL response message */
+  0,                          /* Maximum initial response length (no max) */
+  LDAP_SASL_BIND_IN_PROGRESS, /* Code received when continuation is expected */
+  LDAP_SUCCESS,               /* Code to receive upon authentication success */
+  SASL_AUTH_NONE,             /* Default mechanisms */
+  0                           /* Configuration flags */
+};
+
+struct ldapconninfo {
+  struct SASL sasl;          /* SASL-related parameters */
+  LDAP *ld;                  /* Openldap connection handle. */
+  Curl_recv *recv;           /* For stacking SSL handler */
+  Curl_send *send;
+  struct berval *servercred; /* SASL data from server. */
+  ldapstate state;           /* Current machine state. */
+  int proto;                 /* LDAP_PROTO_TCP/LDAP_PROTO_UDP/LDAP_PROTO_IPC */
+  int msgid;                 /* Current message id. */
+};
+
+struct ldapreqinfo {
+  int msgid;
+  int nument;
+};
+
+/*
+ * oldap_state()
+ *
+ * This is the ONLY way to change LDAP state!
+ */
+static void oldap_state(struct Curl_easy *data, ldapstate newstate)
+{
+  struct ldapconninfo *ldapc = data->conn->proto.ldapc;
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[] = {
+    "STOP",
+    "SSL",
+    "STARTTLS",
+    "TLS",
+    "MECHS",
+    "SASL",
+    "BIND",
+    "BINDV2",
+    /* LAST */
+  };
+
+  if(ldapc->state != newstate)
+    infof(data, "LDAP %p state change from %s to %s",
+          (void *)ldapc, names[ldapc->state], names[newstate]);
+#endif
+
+  ldapc->state = newstate;
+}
+
+/* Map some particular LDAP error codes to CURLcode values. */
+static CURLcode oldap_map_error(int rc, CURLcode result)
+{
+  switch(rc) {
+  case LDAP_NO_MEMORY:
+    result = CURLE_OUT_OF_MEMORY;
+    break;
+  case LDAP_INVALID_CREDENTIALS:
+    result = CURLE_LOGIN_DENIED;
+    break;
+  case LDAP_PROTOCOL_ERROR:
+    result = CURLE_UNSUPPORTED_PROTOCOL;
+    break;
+  case LDAP_INSUFFICIENT_ACCESS:
+    result = CURLE_REMOTE_ACCESS_DENIED;
+    break;
+  }
+  return result;
+}
+
+static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp)
+{
+  CURLcode result = CURLE_OK;
+  int rc = LDAP_URL_ERR_BADURL;
+  static const char * const url_errs[] = {
+    "success",
+    "out of memory",
+    "bad parameter",
+    "unrecognized scheme",
+    "unbalanced delimiter",
+    "bad URL",
+    "bad host or port",
+    "bad or missing attributes",
+    "bad or missing scope",
+    "bad or missing filter",
+    "bad or missing extensions"
+  };
+
+  *ludp = NULL;
+  if(!data->state.up.user && !data->state.up.password &&
+     !data->state.up.options)
+    rc = ldap_url_parse(data->state.url, ludp);
+  if(rc != LDAP_URL_SUCCESS) {
+    const char *msg = "url parsing problem";
+
+    result = rc == LDAP_URL_ERR_MEM? CURLE_OUT_OF_MEMORY: CURLE_URL_MALFORMAT;
+    rc -= LDAP_URL_SUCCESS;
+    if((size_t) rc < sizeof(url_errs) / sizeof(url_errs[0]))
+      msg = url_errs[rc];
+    failf(data, "LDAP local: %s", msg);
+  }
+  return result;
+}
+
+/* Parse the login options. */
+static CURLcode oldap_parse_login_options(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  const char *ptr = conn->options;
+
+  while(!result && ptr && *ptr) {
+    const char *key = ptr;
+    const char *value;
+
+    while(*ptr && *ptr != '=')
+      ptr++;
+
+    value = ptr + 1;
+
+    while(*ptr && *ptr != ';')
+      ptr++;
+
+    if(checkprefix("AUTH=", key))
+      result = Curl_sasl_parse_url_auth_option(&li->sasl, value, ptr - value);
+    else
+      result = CURLE_SETOPT_OPTION_SYNTAX;
+
+    if(*ptr == ';')
+      ptr++;
+  }
+
+  return result == CURLE_URL_MALFORMAT? CURLE_SETOPT_OPTION_SYNTAX: result;
+}
+
+static CURLcode oldap_setup_connection(struct Curl_easy *data,
+                                       struct connectdata *conn)
+{
+  CURLcode result;
+  LDAPURLDesc *lud;
+  (void)conn;
+
+  /* Early URL syntax check. */
+  result = oldap_url_parse(data, &lud);
+  ldap_free_urldesc(lud);
+
+  return result;
+}
+
+/*
+ * Get the SASL authentication challenge from the server credential buffer.
+ */
+static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out)
+{
+  struct berval *servercred = data->conn->proto.ldapc->servercred;
+
+  if(!servercred || !servercred->bv_val)
+    return CURLE_WEIRD_SERVER_REPLY;
+  Curl_bufref_set(out, servercred->bv_val, servercred->bv_len, NULL);
+  return CURLE_OK;
+}
+
+/*
+ * Sends an initial SASL bind request to the server.
+ */
+static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech,
+                                   const struct bufref *initresp)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  CURLcode result = CURLE_OK;
+  struct berval cred;
+  struct berval *pcred = &cred;
+  int rc;
+
+  cred.bv_val = (char *) Curl_bufref_ptr(initresp);
+  cred.bv_len = Curl_bufref_len(initresp);
+  if(!cred.bv_val)
+    pcred = NULL;
+  rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
+  if(rc != LDAP_SUCCESS)
+    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
+  return result;
+}
+
+/*
+ * Sends SASL continuation.
+ */
+static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
+                                    const struct bufref *resp)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  CURLcode result = CURLE_OK;
+  struct berval cred;
+  struct berval *pcred = &cred;
+  int rc;
+
+  cred.bv_val = (char *) Curl_bufref_ptr(resp);
+  cred.bv_len = Curl_bufref_len(resp);
+  if(!cred.bv_val)
+    pcred = NULL;
+  rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
+  if(rc != LDAP_SUCCESS)
+    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
+  return result;
+}
+
+/*
+ * Sends SASL bind cancellation.
+ */
+static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech)
+{
+  struct ldapconninfo *li = data->conn->proto.ldapc;
+  CURLcode result = CURLE_OK;
+  int rc = ldap_sasl_bind(li->ld, NULL, LDAP_SASL_NULL, NULL, NULL, NULL,
+                          &li->msgid);
+
+  (void)mech;
+  if(rc != LDAP_SUCCESS)
+    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
+  return result;
+}
+
+/* Starts LDAP simple bind. */
+static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  char *binddn = NULL;
+  struct berval passwd;
+  int rc;
+
+  passwd.bv_val = NULL;
+  passwd.bv_len = 0;
+
+  if(data->state.aptr.user) {
+    binddn = conn->user;
+    passwd.bv_val = conn->passwd;
+    passwd.bv_len = strlen(passwd.bv_val);
+  }
+
+  rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
+                      NULL, NULL, &li->msgid);
+  if(rc == LDAP_SUCCESS)
+    oldap_state(data, newstate);
+  else
+    result = oldap_map_error(rc,
+                             data->state.aptr.user?
+                             CURLE_LOGIN_DENIED: CURLE_LDAP_CANNOT_BIND);
+  return result;
+}
+
+/* Query the supported SASL authentication mechanisms. */
+static CURLcode oldap_perform_mechs(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct ldapconninfo *li = data->conn->proto.ldapc;
+  int rc;
+  static const char * const supportedSASLMechanisms[] = {
+    "supportedSASLMechanisms",
+    NULL
+  };
+
+  rc = ldap_search_ext(li->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
+                       (char **) supportedSASLMechanisms, 0,
+                       NULL, NULL, NULL, 0, &li->msgid);
+  if(rc == LDAP_SUCCESS)
+    oldap_state(data, OLDAP_MECHS);
+  else
+    result = oldap_map_error(rc, CURLE_LOGIN_DENIED);
+  return result;
+}
+
+/* Starts SASL bind. */
+static CURLcode oldap_perform_sasl(struct Curl_easy *data)
+{
+  saslprogress progress = SASL_IDLE;
+  struct ldapconninfo *li = data->conn->proto.ldapc;
+  CURLcode result = Curl_sasl_start(&li->sasl, data, TRUE, &progress);
+
+  oldap_state(data, OLDAP_SASL);
+  if(!result && progress != SASL_INPROGRESS)
+    result = CURLE_LOGIN_DENIED;
+  return result;
+}
+
+#ifdef USE_SSL
+static Sockbuf_IO ldapsb_tls;
+
+static bool ssl_installed(struct connectdata *conn)
+{
+  return conn->proto.ldapc->recv != NULL;
+}
+
+static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  bool ssldone = 0;
+
+  result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
+  if(!result) {
+    oldap_state(data, newstate);
+
+    if(ssldone) {
+      Sockbuf *sb;
+
+      /* Install the libcurl SSL handlers into the sockbuf. */
+      ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
+      ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
+      li->recv = conn->recv[FIRSTSOCKET];
+      li->send = conn->send[FIRSTSOCKET];
+    }
+  }
+
+  return result;
+}
+
+/* Send the STARTTLS request */
+static CURLcode oldap_perform_starttls(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct ldapconninfo *li = data->conn->proto.ldapc;
+  int rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid);
+
+  if(rc == LDAP_SUCCESS)
+    oldap_state(data, OLDAP_STARTTLS);
+  else
+    result = oldap_map_error(rc, CURLE_USE_SSL_FAILED);
+  return result;
+}
+#endif
+
+static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li;
+  static const int version = LDAP_VERSION3;
+  int rc;
+  char *hosturl;
+#ifdef CURL_OPENLDAP_DEBUG
+  static int do_trace = -1;
+#endif
+
+  (void)done;
+
+  DEBUGASSERT(!conn->proto.ldapc);
+  li = calloc(1, sizeof(struct ldapconninfo));
+  if(!li)
+    return CURLE_OUT_OF_MEMORY;
+  else {
+    CURLcode result;
+    li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme);
+    conn->proto.ldapc = li;
+
+    /* Initialize the SASL storage */
+    Curl_sasl_init(&li->sasl, data, &saslldap);
+
+    /* Clear the TLS upgraded flag */
+    conn->bits.tls_upgraded = FALSE;
+
+    result = oldap_parse_login_options(conn);
+    if(result)
+      return result;
+  }
+
+  hosturl = aprintf("ldap%s://%s:%d",
+                    conn->handler->flags & PROTOPT_SSL? "s": "",
+                    conn->host.name, conn->remote_port);
+  if(!hosturl)
+    return CURLE_OUT_OF_MEMORY;
+
+  rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
+  if(rc) {
+    failf(data, "LDAP local: Cannot connect to %s, %s",
+          hosturl, ldap_err2string(rc));
+    free(hosturl);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  free(hosturl);
+
+#ifdef CURL_OPENLDAP_DEBUG
+  if(do_trace < 0) {
+    const char *env = getenv("CURL_OPENLDAP_TRACE");
+    do_trace = (env && strtol(env, NULL, 10) > 0);
+  }
+  if(do_trace)
+    ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);
+#endif
+
+  /* Try version 3 first. */
+  ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+
+  /* Do not chase referrals. */
+  ldap_set_option(li->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
+
+#ifdef USE_SSL
+  if(conn->handler->flags & PROTOPT_SSL)
+    return oldap_ssl_connect(data, OLDAP_SSL);
+
+  if(data->set.use_ssl) {
+    CURLcode result = oldap_perform_starttls(data);
+
+    if(!result || data->set.use_ssl != CURLUSESSL_TRY)
+      return result;
+  }
+#endif
+
+  if(li->sasl.prefmech != SASL_AUTH_NONE)
+    return oldap_perform_mechs(data);
+
+  /* Force bind even if anonymous bind is not needed in protocol version 3
+     to detect missing version 3 support. */
+  return oldap_perform_bind(data, OLDAP_BIND);
+}
+
+/* Handle the supported SASL mechanisms query response */
+static CURLcode oldap_state_mechs_resp(struct Curl_easy *data,
+                                       LDAPMessage *msg, int code)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  int rc;
+  BerElement *ber = NULL;
+  CURLcode result = CURLE_OK;
+  struct berval bv, *bvals;
+
+  switch(ldap_msgtype(msg)) {
+  case LDAP_RES_SEARCH_ENTRY:
+    /* Got a list of supported SASL mechanisms. */
+    if(code != LDAP_SUCCESS && code != LDAP_NO_RESULTS_RETURNED)
+      return CURLE_LOGIN_DENIED;
+
+    rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv);
+    if(rc < 0)
+      return oldap_map_error(rc, CURLE_BAD_CONTENT_ENCODING);
+    for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals);
+        rc == LDAP_SUCCESS;
+        rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) {
+      int i;
+
+      if(!bv.bv_val)
+        break;
+
+      if(bvals) {
+        for(i = 0; bvals[i].bv_val; i++) {
+          size_t llen;
+          unsigned short mech = Curl_sasl_decode_mech((char *) bvals[i].bv_val,
+                                                      bvals[i].bv_len, &llen);
+          if(bvals[i].bv_len == llen)
+            li->sasl.authmechs |= mech;
+        }
+        ber_memfree(bvals);
+      }
+    }
+    ber_free(ber, 0);
+    break;
+
+  case LDAP_RES_SEARCH_RESULT:
+    switch(code) {
+    case LDAP_SIZELIMIT_EXCEEDED:
+      infof(data, "Too many authentication mechanisms\n");
+      FALLTHROUGH();
+    case LDAP_SUCCESS:
+    case LDAP_NO_RESULTS_RETURNED:
+      if(Curl_sasl_can_authenticate(&li->sasl, data))
+        result = oldap_perform_sasl(data);
+      else
+        result = CURLE_LOGIN_DENIED;
+      break;
+    default:
+      result = oldap_map_error(code, CURLE_LOGIN_DENIED);
+      break;
+    }
+    break;
+  default:
+    break;
+  }
+  return result;
+}
+
+/* Handle a SASL bind response. */
+static CURLcode oldap_state_sasl_resp(struct Curl_easy *data,
+                                      LDAPMessage *msg, int code)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  CURLcode result = CURLE_OK;
+  saslprogress progress;
+  int rc;
+
+  li->servercred = NULL;
+  rc = ldap_parse_sasl_bind_result(li->ld, msg, &li->servercred, 0);
+  if(rc != LDAP_SUCCESS) {
+    failf(data, "LDAP local: sasl ldap_parse_result %s", ldap_err2string(rc));
+    result = oldap_map_error(rc, CURLE_LOGIN_DENIED);
+  }
+  else {
+    result = Curl_sasl_continue(&li->sasl, data, code, &progress);
+    if(!result && progress != SASL_INPROGRESS)
+      oldap_state(data, OLDAP_STOP);
+  }
+
+  if(li->servercred)
+    ber_bvfree(li->servercred);
+  return result;
+}
+
+/* Handle a simple bind response. */
+static CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg,
+                                      int code)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  CURLcode result = CURLE_OK;
+  struct berval *bv = NULL;
+  int rc;
+
+  if(code != LDAP_SUCCESS)
+    return oldap_map_error(code, CURLE_LDAP_CANNOT_BIND);
+
+  rc = ldap_parse_sasl_bind_result(li->ld, msg, &bv, 0);
+  if(rc != LDAP_SUCCESS) {
+    failf(data, "LDAP local: bind ldap_parse_sasl_bind_result %s",
+          ldap_err2string(rc));
+    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
+  }
+  else
+    oldap_state(data, OLDAP_STOP);
+
+  if(bv)
+    ber_bvfree(bv);
+  return result;
+}
+
+static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  LDAPMessage *msg = NULL;
+  struct timeval tv = {0, 0};
+  int code = LDAP_SUCCESS;
+  int rc;
+
+  if(li->state != OLDAP_SSL && li->state != OLDAP_TLS) {
+    /* Get response to last command. */
+    rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, &tv, &msg);
+    switch(rc) {
+    case 0:                               /* Timed out. */
+      return CURLE_OK;
+    case LDAP_RES_SEARCH_ENTRY:
+    case LDAP_RES_SEARCH_REFERENCE:
+      break;
+    default:
+      li->msgid = 0;                      /* Nothing to abandon upon error. */
+      if(rc < 0) {
+        failf(data, "LDAP local: connecting ldap_result %s",
+              ldap_err2string(rc));
+        return oldap_map_error(rc, CURLE_COULDNT_CONNECT);
+      }
+      break;
+    }
+
+    /* Get error code from message. */
+    rc = ldap_parse_result(li->ld, msg, &code, NULL, NULL, NULL, NULL, 0);
+    if(rc)
+      code = rc;
+    else {
+      /* store the latest code for later retrieval */
+      data->info.httpcode = code;
+    }
+
+    /* If protocol version 3 is not supported, fallback to version 2. */
+    if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2 &&
+#ifdef USE_SSL
+       (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY) &&
+#endif
+       li->sasl.prefmech == SASL_AUTH_NONE) {
+      static const int version = LDAP_VERSION2;
+
+      ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+      ldap_msgfree(msg);
+      return oldap_perform_bind(data, OLDAP_BINDV2);
+    }
+  }
+
+  /* Handle response message according to current state. */
+  switch(li->state) {
+
+#ifdef USE_SSL
+  case OLDAP_SSL:
+    result = oldap_ssl_connect(data, OLDAP_SSL);
+    if(!result && ssl_installed(conn)) {
+      if(li->sasl.prefmech != SASL_AUTH_NONE)
+        result = oldap_perform_mechs(data);
+      else
+        result = oldap_perform_bind(data, OLDAP_BIND);
+    }
+    break;
+  case OLDAP_STARTTLS:
+    if(code != LDAP_SUCCESS) {
+      if(data->set.use_ssl != CURLUSESSL_TRY)
+        result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
+      else if(li->sasl.prefmech != SASL_AUTH_NONE)
+        result = oldap_perform_mechs(data);
+      else
+        result = oldap_perform_bind(data, OLDAP_BIND);
+      break;
+    }
+    result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
+    if(result)
+      break;
+    FALLTHROUGH();
+  case OLDAP_TLS:
+    result = oldap_ssl_connect(data, OLDAP_TLS);
+    if(result)
+      result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
+    else if(ssl_installed(conn)) {
+      conn->bits.tls_upgraded = TRUE;
+      if(li->sasl.prefmech != SASL_AUTH_NONE)
+        result = oldap_perform_mechs(data);
+      else if(data->state.aptr.user)
+        result = oldap_perform_bind(data, OLDAP_BIND);
+      else {
+        /* Version 3 supported: no bind required */
+        oldap_state(data, OLDAP_STOP);
+        result = CURLE_OK;
+      }
+    }
+    break;
+#endif
+
+  case OLDAP_MECHS:
+    result = oldap_state_mechs_resp(data, msg, code);
+    break;
+  case OLDAP_SASL:
+    result = oldap_state_sasl_resp(data, msg, code);
+    break;
+  case OLDAP_BIND:
+  case OLDAP_BINDV2:
+    result = oldap_state_bind_resp(data, msg, code);
+    break;
+  default:
+    /* internal error */
+    result = CURLE_COULDNT_CONNECT;
+    break;
+  }
+
+  ldap_msgfree(msg);
+
+  *done = li->state == OLDAP_STOP;
+  if(*done)
+    conn->recv[FIRSTSOCKET] = oldap_recv;
+
+  if(result && li->msgid) {
+    ldap_abandon_ext(li->ld, li->msgid, NULL, NULL);
+    li->msgid = 0;
+  }
+  return result;
+}
+
+static CURLcode oldap_disconnect(struct Curl_easy *data,
+                                 struct connectdata *conn,
+                                 bool dead_connection)
+{
+  struct ldapconninfo *li = conn->proto.ldapc;
+  (void) dead_connection;
+#ifndef USE_SSL
+  (void)data;
+#endif
+
+  if(li) {
+    if(li->ld) {
+#ifdef USE_SSL
+      if(ssl_installed(conn)) {
+        Sockbuf *sb;
+        ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
+        ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
+      }
+#endif
+      ldap_unbind_ext(li->ld, NULL, NULL);
+      li->ld = NULL;
+    }
+    Curl_sasl_cleanup(conn, li->sasl.authused);
+    conn->proto.ldapc = NULL;
+    free(li);
+  }
+  return CURLE_OK;
+}
+
+static CURLcode oldap_do(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  struct ldapreqinfo *lr;
+  CURLcode result;
+  int rc;
+  LDAPURLDesc *lud;
+  int msgid;
+
+  connkeep(conn, "OpenLDAP do");
+
+  infof(data, "LDAP local: %s", data->state.url);
+
+  result = oldap_url_parse(data, &lud);
+  if(!result) {
+#ifdef USE_SSL
+    if(ssl_installed(conn)) {
+      Sockbuf *sb;
+      /* re-install the libcurl SSL handlers into the sockbuf. */
+      ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
+      ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
+    }
+#endif
+
+    rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope,
+                         lud->lud_filter, lud->lud_attrs, 0,
+                         NULL, NULL, NULL, 0, &msgid);
+    ldap_free_urldesc(lud);
+    if(rc != LDAP_SUCCESS) {
+      failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
+      result = CURLE_LDAP_SEARCH_FAILED;
+    }
+    else {
+      lr = calloc(1, sizeof(struct ldapreqinfo));
+      if(!lr) {
+        ldap_abandon_ext(li->ld, msgid, NULL, NULL);
+        result = CURLE_OUT_OF_MEMORY;
+      }
+      else {
+        lr->msgid = msgid;
+        data->req.p.ldap = lr;
+        Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
+        *done = TRUE;
+      }
+    }
+  }
+  return result;
+}
+
+static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
+                           bool premature)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapreqinfo *lr = data->req.p.ldap;
+
+  (void)res;
+  (void)premature;
+
+  if(lr) {
+    /* if there was a search in progress, abandon it */
+    if(lr->msgid) {
+      struct ldapconninfo *li = conn->proto.ldapc;
+      ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
+      lr->msgid = 0;
+    }
+    data->req.p.ldap = NULL;
+    free(lr);
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode client_write(struct Curl_easy *data,
+                             const char *prefix, size_t plen,
+                             const char *value, size_t len,
+                             const char *suffix, size_t slen)
+{
+  CURLcode result = CURLE_OK;
+
+  if(prefix) {
+    /* If we have a zero-length value and the prefix ends with a space
+       separator, drop the latter. */
+    if(!len && plen && prefix[plen - 1] == ' ')
+      plen--;
+    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) prefix, plen);
+  }
+  if(!result && value) {
+    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) value, len);
+  }
+  if(!result && suffix) {
+    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) suffix, slen);
+  }
+  return result;
+}
+
+static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
+                          size_t len, CURLcode *err)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  struct ldapreqinfo *lr = data->req.p.ldap;
+  int rc;
+  LDAPMessage *msg = NULL;
+  BerElement *ber = NULL;
+  struct timeval tv = {0, 0};
+  struct berval bv, *bvals;
+  int binary = 0;
+  CURLcode result = CURLE_AGAIN;
+  int code;
+  char *info = NULL;
+
+  (void)len;
+  (void)buf;
+  (void)sockindex;
+
+  rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_ONE, &tv, &msg);
+  if(rc < 0) {
+    failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
+    result = CURLE_RECV_ERROR;
+  }
+
+  *err = result;
+
+  /* error or timed out */
+  if(!msg)
+    return -1;
+
+  result = CURLE_OK;
+
+  switch(ldap_msgtype(msg)) {
+  case LDAP_RES_SEARCH_RESULT:
+    lr->msgid = 0;
+    rc = ldap_parse_result(li->ld, msg, &code, NULL, &info, NULL, NULL, 0);
+    if(rc) {
+      failf(data, "LDAP local: search ldap_parse_result %s",
+            ldap_err2string(rc));
+      result = CURLE_LDAP_SEARCH_FAILED;
+      break;
+    }
+
+    /* store the latest code for later retrieval */
+    data->info.httpcode = code;
+
+    switch(code) {
+    case LDAP_SIZELIMIT_EXCEEDED:
+      infof(data, "There are more than %d entries", lr->nument);
+      FALLTHROUGH();
+    case LDAP_SUCCESS:
+      data->req.size = data->req.bytecount;
+      break;
+    default:
+      failf(data, "LDAP remote: search failed %s %s", ldap_err2string(code),
+            info ? info : "");
+      result = CURLE_LDAP_SEARCH_FAILED;
+      break;
+    }
+    if(info)
+      ldap_memfree(info);
+    break;
+  case LDAP_RES_SEARCH_ENTRY:
+    lr->nument++;
+    rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv);
+    if(rc < 0) {
+      result = CURLE_RECV_ERROR;
+      break;
+    }
+
+    result = client_write(data, STRCONST("DN: "), bv.bv_val, bv.bv_len,
+                          STRCONST("\n"));
+    if(result)
+      break;
+
+    for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals);
+        rc == LDAP_SUCCESS;
+        rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) {
+      int i;
+
+      if(!bv.bv_val)
+        break;
+
+      if(!bvals) {
+        result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
+                              STRCONST(":\n"));
+        if(result)
+          break;
+        continue;
+      }
+
+      binary = bv.bv_len > 7 &&
+               !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7);
+
+      for(i = 0; bvals[i].bv_val != NULL; i++) {
+        int binval = 0;
+
+        result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
+                              STRCONST(":"));
+        if(result)
+          break;
+
+        if(!binary) {
+          /* check for leading or trailing whitespace */
+          if(ISBLANK(bvals[i].bv_val[0]) ||
+             ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1]))
+            binval = 1;
+          else {
+            /* check for unprintable characters */
+            unsigned int j;
+            for(j = 0; j < bvals[i].bv_len; j++)
+              if(!ISPRINT(bvals[i].bv_val[j])) {
+                binval = 1;
+                break;
+              }
+          }
+        }
+        if(binary || binval) {
+          char *val_b64 = NULL;
+          size_t val_b64_sz = 0;
+
+          /* Binary value, encode to base64. */
+          if(bvals[i].bv_len)
+            result = Curl_base64_encode(bvals[i].bv_val, bvals[i].bv_len,
+                                        &val_b64, &val_b64_sz);
+          if(!result)
+            result = client_write(data, STRCONST(": "), val_b64, val_b64_sz,
+                                  STRCONST("\n"));
+          free(val_b64);
+        }
+        else
+          result = client_write(data, STRCONST(" "),
+                                bvals[i].bv_val, bvals[i].bv_len,
+                                STRCONST("\n"));
+        if(result)
+          break;
+      }
+
+      ber_memfree(bvals);
+      bvals = NULL;
+      if(!result)
+        result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0);
+      if(result)
+        break;
+    }
+
+    ber_free(ber, 0);
+
+    if(!result)
+      result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0);
+    if(!result)
+      result = CURLE_AGAIN;
+    break;
+  }
+
+  ldap_msgfree(msg);
+  *err = result;
+  return result? -1: 0;
+}
+
+#ifdef USE_SSL
+static int
+ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg)
+{
+  sbiod->sbiod_pvt = arg;
+  return 0;
+}
+
+static int
+ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
+{
+  sbiod->sbiod_pvt = NULL;
+  return 0;
+}
+
+/* We don't need to do anything because libcurl does it already */
+static int
+ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
+{
+  (void)sbiod;
+  return 0;
+}
+
+static int
+ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
+{
+  (void)arg;
+  if(opt == LBER_SB_OPT_DATA_READY) {
+    struct Curl_easy *data = sbiod->sbiod_pvt;
+    return Curl_conn_data_pending(data, FIRSTSOCKET);
+  }
+  return 0;
+}
+
+static ber_slen_t
+ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+  struct Curl_easy *data = sbiod->sbiod_pvt;
+  ber_slen_t ret = 0;
+  if(data) {
+    struct connectdata *conn = data->conn;
+    if(conn) {
+      struct ldapconninfo *li = conn->proto.ldapc;
+      CURLcode err = CURLE_RECV_ERROR;
+
+      ret = (li->recv)(data, FIRSTSOCKET, buf, len, &err);
+      if(ret < 0 && err == CURLE_AGAIN) {
+        SET_SOCKERRNO(EWOULDBLOCK);
+      }
+    }
+  }
+  return ret;
+}
+
+static ber_slen_t
+ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+  struct Curl_easy *data = sbiod->sbiod_pvt;
+  ber_slen_t ret = 0;
+  if(data) {
+    struct connectdata *conn = data->conn;
+    if(conn) {
+      struct ldapconninfo *li = conn->proto.ldapc;
+      CURLcode err = CURLE_SEND_ERROR;
+      ret = (li->send)(data, FIRSTSOCKET, buf, len, &err);
+      if(ret < 0 && err == CURLE_AGAIN) {
+        SET_SOCKERRNO(EWOULDBLOCK);
+      }
+    }
+  }
+  return ret;
+}
+
+static Sockbuf_IO ldapsb_tls =
+{
+  ldapsb_tls_setup,
+  ldapsb_tls_remove,
+  ldapsb_tls_ctrl,
+  ldapsb_tls_read,
+  ldapsb_tls_write,
+  ldapsb_tls_close
+};
+#endif /* USE_SSL */
+
+#endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */
Index: trunk/src/libs/curl-8.7.1/lib/parsedate.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/parsedate.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/parsedate.c	(revision 104083)
@@ -0,0 +1,644 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+/*
+  A brief summary of the date string formats this parser groks:
+
+  RFC 2616 3.3.1
+
+  Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
+  Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+  Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
+
+  we support dates without week day name:
+
+  06 Nov 1994 08:49:37 GMT
+  06-Nov-94 08:49:37 GMT
+  Nov  6 08:49:37 1994
+
+  without the time zone:
+
+  06 Nov 1994 08:49:37
+  06-Nov-94 08:49:37
+
+  weird order:
+
+  1994 Nov 6 08:49:37  (GNU date fails)
+  GMT 08:49:37 06-Nov-94 Sunday
+  94 6 Nov 08:49:37    (GNU date fails)
+
+  time left out:
+
+  1994 Nov 6
+  06-Nov-94
+  Sun Nov 6 94
+
+  unusual separators:
+
+  1994.Nov.6
+  Sun/Nov/6/94/GMT
+
+  commonly used time zone names:
+
+  Sun, 06 Nov 1994 08:49:37 CET
+  06 Nov 1994 08:49:37 EST
+
+  time zones specified using RFC822 style:
+
+  Sun, 12 Sep 2004 15:05:58 -0700
+  Sat, 11 Sep 2004 21:32:11 +0200
+
+  compact numerical date strings:
+
+  20040912 15:05:58 -0700
+  20040911 +0200
+
+*/
+
+#include "curl_setup.h"
+
+#include <limits.h>
+
+#include <curl/curl.h>
+#include "strcase.h"
+#include "warnless.h"
+#include "parsedate.h"
+
+/*
+ * parsedate()
+ *
+ * Returns:
+ *
+ * PARSEDATE_OK     - a fine conversion
+ * PARSEDATE_FAIL   - failed to convert
+ * PARSEDATE_LATER  - time overflow at the far end of time_t
+ * PARSEDATE_SOONER - time underflow at the low end of time_t
+ */
+
+static int parsedate(const char *date, time_t *output);
+
+#define PARSEDATE_OK     0
+#define PARSEDATE_FAIL   -1
+#define PARSEDATE_LATER  1
+#define PARSEDATE_SOONER 2
+
+#if !defined(CURL_DISABLE_PARSEDATE) || !defined(CURL_DISABLE_FTP) || \
+  !defined(CURL_DISABLE_FILE)
+/* These names are also used by FTP and FILE code */
+const char * const Curl_wkday[] =
+{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
+const char * const Curl_month[]=
+{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+#endif
+
+#ifndef CURL_DISABLE_PARSEDATE
+static const char * const weekday[] =
+{ "Monday", "Tuesday", "Wednesday", "Thursday",
+  "Friday", "Saturday", "Sunday" };
+
+struct tzinfo {
+  char name[5];
+  int offset; /* +/- in minutes */
+};
+
+/* Here's a bunch of frequently used time zone names. These were supported
+   by the old getdate parser. */
+#define tDAYZONE -60       /* offset for daylight savings time */
+static const struct tzinfo tz[]= {
+  {"GMT", 0},              /* Greenwich Mean */
+  {"UT",  0},              /* Universal Time */
+  {"UTC", 0},              /* Universal (Coordinated) */
+  {"WET", 0},              /* Western European */
+  {"BST", 0 tDAYZONE},     /* British Summer */
+  {"WAT", 60},             /* West Africa */
+  {"AST", 240},            /* Atlantic Standard */
+  {"ADT", 240 tDAYZONE},   /* Atlantic Daylight */
+  {"EST", 300},            /* Eastern Standard */
+  {"EDT", 300 tDAYZONE},   /* Eastern Daylight */
+  {"CST", 360},            /* Central Standard */
+  {"CDT", 360 tDAYZONE},   /* Central Daylight */
+  {"MST", 420},            /* Mountain Standard */
+  {"MDT", 420 tDAYZONE},   /* Mountain Daylight */
+  {"PST", 480},            /* Pacific Standard */
+  {"PDT", 480 tDAYZONE},   /* Pacific Daylight */
+  {"YST", 540},            /* Yukon Standard */
+  {"YDT", 540 tDAYZONE},   /* Yukon Daylight */
+  {"HST", 600},            /* Hawaii Standard */
+  {"HDT", 600 tDAYZONE},   /* Hawaii Daylight */
+  {"CAT", 600},            /* Central Alaska */
+  {"AHST", 600},           /* Alaska-Hawaii Standard */
+  {"NT",  660},            /* Nome */
+  {"IDLW", 720},           /* International Date Line West */
+  {"CET", -60},            /* Central European */
+  {"MET", -60},            /* Middle European */
+  {"MEWT", -60},           /* Middle European Winter */
+  {"MEST", -60 tDAYZONE},  /* Middle European Summer */
+  {"CEST", -60 tDAYZONE},  /* Central European Summer */
+  {"MESZ", -60 tDAYZONE},  /* Middle European Summer */
+  {"FWT", -60},            /* French Winter */
+  {"FST", -60 tDAYZONE},   /* French Summer */
+  {"EET", -120},           /* Eastern Europe, USSR Zone 1 */
+  {"WAST", -420},          /* West Australian Standard */
+  {"WADT", -420 tDAYZONE}, /* West Australian Daylight */
+  {"CCT", -480},           /* China Coast, USSR Zone 7 */
+  {"JST", -540},           /* Japan Standard, USSR Zone 8 */
+  {"EAST", -600},          /* Eastern Australian Standard */
+  {"EADT", -600 tDAYZONE}, /* Eastern Australian Daylight */
+  {"GST", -600},           /* Guam Standard, USSR Zone 9 */
+  {"NZT", -720},           /* New Zealand */
+  {"NZST", -720},          /* New Zealand Standard */
+  {"NZDT", -720 tDAYZONE}, /* New Zealand Daylight */
+  {"IDLE", -720},          /* International Date Line East */
+  /* Next up: Military timezone names. RFC822 allowed these, but (as noted in
+     RFC 1123) had their signs wrong. Here we use the correct signs to match
+     actual military usage.
+   */
+  {"A",  1 * 60},         /* Alpha */
+  {"B",  2 * 60},         /* Bravo */
+  {"C",  3 * 60},         /* Charlie */
+  {"D",  4 * 60},         /* Delta */
+  {"E",  5 * 60},         /* Echo */
+  {"F",  6 * 60},         /* Foxtrot */
+  {"G",  7 * 60},         /* Golf */
+  {"H",  8 * 60},         /* Hotel */
+  {"I",  9 * 60},         /* India */
+  /* "J", Juliet is not used as a timezone, to indicate the observer's local
+     time */
+  {"K", 10 * 60},         /* Kilo */
+  {"L", 11 * 60},         /* Lima */
+  {"M", 12 * 60},         /* Mike */
+  {"N",  -1 * 60},         /* November */
+  {"O",  -2 * 60},         /* Oscar */
+  {"P",  -3 * 60},         /* Papa */
+  {"Q",  -4 * 60},         /* Quebec */
+  {"R",  -5 * 60},         /* Romeo */
+  {"S",  -6 * 60},         /* Sierra */
+  {"T",  -7 * 60},         /* Tango */
+  {"U",  -8 * 60},         /* Uniform */
+  {"V",  -9 * 60},         /* Victor */
+  {"W", -10 * 60},         /* Whiskey */
+  {"X", -11 * 60},         /* X-ray */
+  {"Y", -12 * 60},         /* Yankee */
+  {"Z", 0},                /* Zulu, zero meridian, a.k.a. UTC */
+};
+
+/* returns:
+   -1 no day
+   0 monday - 6 sunday
+*/
+
+static int checkday(const char *check, size_t len)
+{
+  int i;
+  const char * const *what;
+  if(len > 3)
+    what = &weekday[0];
+  else if(len == 3)
+    what = &Curl_wkday[0];
+  else
+    return -1; /* too short */
+  for(i = 0; i<7; i++) {
+    size_t ilen = strlen(what[0]);
+    if((ilen == len) &&
+       strncasecompare(check, what[0], len))
+      return i;
+    what++;
+  }
+  return -1;
+}
+
+static int checkmonth(const char *check, size_t len)
+{
+  int i;
+  const char * const *what = &Curl_month[0];
+  if(len != 3)
+    return -1; /* not a month */
+
+  for(i = 0; i<12; i++) {
+    if(strncasecompare(check, what[0], 3))
+      return i;
+    what++;
+  }
+  return -1; /* return the offset or -1, no real offset is -1 */
+}
+
+/* return the time zone offset between GMT and the input one, in number
+   of seconds or -1 if the timezone wasn't found/legal */
+
+static int checktz(const char *check, size_t len)
+{
+  unsigned int i;
+  const struct tzinfo *what = tz;
+  if(len > 4) /* longer than any valid timezone */
+    return -1;
+
+  for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
+    size_t ilen = strlen(what->name);
+    if((ilen == len) &&
+       strncasecompare(check, what->name, len))
+      return what->offset*60;
+    what++;
+  }
+  return -1;
+}
+
+static void skip(const char **date)
+{
+  /* skip everything that aren't letters or digits */
+  while(**date && !ISALNUM(**date))
+    (*date)++;
+}
+
+enum assume {
+  DATE_MDAY,
+  DATE_YEAR,
+  DATE_TIME
+};
+
+/*
+ * time2epoch: time stamp to seconds since epoch in GMT time zone.  Similar to
+ * mktime but for GMT only.
+ */
+static time_t time2epoch(int sec, int min, int hour,
+                         int mday, int mon, int year)
+{
+  static const int month_days_cumulative [12] =
+    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+  int leap_days = year - (mon <= 1);
+  leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400)
+               - (1969 / 4) + (1969 / 100) - (1969 / 400));
+  return ((((time_t) (year - 1970) * 365
+            + leap_days + month_days_cumulative[mon] + mday - 1) * 24
+           + hour) * 60 + min) * 60 + sec;
+}
+
+/* Returns the value of a single-digit or two-digit decimal number, return
+   then pointer to after the number. The 'date' pointer is known to point to a
+   digit. */
+static int oneortwodigit(const char *date, const char **endp)
+{
+  int num = date[0] - '0';
+  if(ISDIGIT(date[1])) {
+    *endp = &date[2];
+    return num*10 + (date[1] - '0');
+  }
+  *endp = &date[1];
+  return num;
+}
+
+
+/* HH:MM:SS or HH:MM and accept single-digits too */
+static bool match_time(const char *date,
+                       int *h, int *m, int *s, char **endp)
+{
+  const char *p;
+  int hh, mm, ss = 0;
+  hh = oneortwodigit(date, &p);
+  if((hh < 24) && (*p == ':') && ISDIGIT(p[1])) {
+    mm = oneortwodigit(&p[1], &p);
+    if(mm < 60) {
+      if((*p == ':') && ISDIGIT(p[1])) {
+        ss = oneortwodigit(&p[1], &p);
+        if(ss <= 60) {
+          /* valid HH:MM:SS */
+          goto match;
+        }
+      }
+      else {
+        /* valid HH:MM */
+        goto match;
+      }
+    }
+  }
+  return FALSE; /* not a time string */
+match:
+  *h = hh;
+  *m = mm;
+  *s = ss;
+  *endp = (char *)p;
+  return TRUE;
+}
+
+/*
+ * parsedate()
+ *
+ * Returns:
+ *
+ * PARSEDATE_OK     - a fine conversion
+ * PARSEDATE_FAIL   - failed to convert
+ * PARSEDATE_LATER  - time overflow at the far end of time_t
+ * PARSEDATE_SOONER - time underflow at the low end of time_t
+ */
+
+/* Wednesday is the longest name this parser knows about */
+#define NAME_LEN 12
+
+static int parsedate(const char *date, time_t *output)
+{
+  time_t t = 0;
+  int wdaynum = -1;  /* day of the week number, 0-6 (mon-sun) */
+  int monnum = -1;   /* month of the year number, 0-11 */
+  int mdaynum = -1; /* day of month, 1 - 31 */
+  int hournum = -1;
+  int minnum = -1;
+  int secnum = -1;
+  int yearnum = -1;
+  int tzoff = -1;
+  enum assume dignext = DATE_MDAY;
+  const char *indate = date; /* save the original pointer */
+  int part = 0; /* max 6 parts */
+
+  while(*date && (part < 6)) {
+    bool found = FALSE;
+
+    skip(&date);
+
+    if(ISALPHA(*date)) {
+      /* a name coming up */
+      size_t len = 0;
+      const char *p = date;
+      while(ISALPHA(*p) && (len < NAME_LEN)) {
+        p++;
+        len++;
+      }
+
+      if(len != NAME_LEN) {
+        if(wdaynum == -1) {
+          wdaynum = checkday(date, len);
+          if(wdaynum != -1)
+            found = TRUE;
+        }
+        if(!found && (monnum == -1)) {
+          monnum = checkmonth(date, len);
+          if(monnum != -1)
+            found = TRUE;
+        }
+
+        if(!found && (tzoff == -1)) {
+          /* this just must be a time zone string */
+          tzoff = checktz(date, len);
+          if(tzoff != -1)
+            found = TRUE;
+        }
+      }
+      if(!found)
+        return PARSEDATE_FAIL; /* bad string */
+
+      date += len;
+    }
+    else if(ISDIGIT(*date)) {
+      /* a digit */
+      int val;
+      char *end;
+      if((secnum == -1) &&
+         match_time(date, &hournum, &minnum, &secnum, &end)) {
+        /* time stamp */
+        date = end;
+      }
+      else {
+        long lval;
+        int error;
+        int old_errno;
+
+        old_errno = errno;
+        errno = 0;
+        lval = strtol(date, &end, 10);
+        error = errno;
+        if(errno != old_errno)
+          errno = old_errno;
+
+        if(error)
+          return PARSEDATE_FAIL;
+
+#if LONG_MAX != INT_MAX
+        if((lval > (long)INT_MAX) || (lval < (long)INT_MIN))
+          return PARSEDATE_FAIL;
+#endif
+
+        val = curlx_sltosi(lval);
+
+        if((tzoff == -1) &&
+           ((end - date) == 4) &&
+           (val <= 1400) &&
+           (indate< date) &&
+           ((date[-1] == '+' || date[-1] == '-'))) {
+          /* four digits and a value less than or equal to 1400 (to take into
+             account all sorts of funny time zone diffs) and it is preceded
+             with a plus or minus. This is a time zone indication.  1400 is
+             picked since +1300 is frequently used and +1400 is mentioned as
+             an edge number in the document "ISO C 200X Proposal: Timezone
+             Functions" at http://david.tribble.com/text/c0xtimezone.html If
+             anyone has a more authoritative source for the exact maximum time
+             zone offsets, please speak up! */
+          found = TRUE;
+          tzoff = (val/100 * 60 + val%100)*60;
+
+          /* the + and - prefix indicates the local time compared to GMT,
+             this we need their reversed math to get what we want */
+          tzoff = date[-1]=='+'?-tzoff:tzoff;
+        }
+
+        if(((end - date) == 8) &&
+           (yearnum == -1) &&
+           (monnum == -1) &&
+           (mdaynum == -1)) {
+          /* 8 digits, no year, month or day yet. This is YYYYMMDD */
+          found = TRUE;
+          yearnum = val/10000;
+          monnum = (val%10000)/100-1; /* month is 0 - 11 */
+          mdaynum = val%100;
+        }
+
+        if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) {
+          if((val > 0) && (val<32)) {
+            mdaynum = val;
+            found = TRUE;
+          }
+          dignext = DATE_YEAR;
+        }
+
+        if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) {
+          yearnum = val;
+          found = TRUE;
+          if(yearnum < 100) {
+            if(yearnum > 70)
+              yearnum += 1900;
+            else
+              yearnum += 2000;
+          }
+          if(mdaynum == -1)
+            dignext = DATE_MDAY;
+        }
+
+        if(!found)
+          return PARSEDATE_FAIL;
+
+        date = end;
+      }
+    }
+
+    part++;
+  }
+
+  if(-1 == secnum)
+    secnum = minnum = hournum = 0; /* no time, make it zero */
+
+  if((-1 == mdaynum) ||
+     (-1 == monnum) ||
+     (-1 == yearnum))
+    /* lacks vital info, fail */
+    return PARSEDATE_FAIL;
+
+#ifdef HAVE_TIME_T_UNSIGNED
+  if(yearnum < 1970) {
+    /* only positive numbers cannot return earlier */
+    *output = TIME_T_MIN;
+    return PARSEDATE_SOONER;
+  }
+#endif
+
+#if (SIZEOF_TIME_T < 5)
+
+#ifdef HAVE_TIME_T_UNSIGNED
+  /* an unsigned 32 bit time_t can only hold dates to 2106 */
+  if(yearnum > 2105) {
+    *output = TIME_T_MAX;
+    return PARSEDATE_LATER;
+  }
+#else
+  /* a signed 32 bit time_t can only hold dates to the beginning of 2038 */
+  if(yearnum > 2037) {
+    *output = TIME_T_MAX;
+    return PARSEDATE_LATER;
+  }
+  if(yearnum < 1903) {
+    *output = TIME_T_MIN;
+    return PARSEDATE_SOONER;
+  }
+#endif
+
+#else
+  /* The Gregorian calendar was introduced 1582 */
+  if(yearnum < 1583)
+    return PARSEDATE_FAIL;
+#endif
+
+  if((mdaynum > 31) || (monnum > 11) ||
+     (hournum > 23) || (minnum > 59) || (secnum > 60))
+    return PARSEDATE_FAIL; /* clearly an illegal date */
+
+  /* time2epoch() returns a time_t. time_t is often 32 bits, sometimes even on
+     architectures that feature 64 bit 'long' but ultimately time_t is the
+     correct data type to use.
+  */
+  t = time2epoch(secnum, minnum, hournum, mdaynum, monnum, yearnum);
+
+  /* Add the time zone diff between local time zone and GMT. */
+  if(tzoff == -1)
+    tzoff = 0;
+
+  if((tzoff > 0) && (t > TIME_T_MAX - tzoff)) {
+    *output = TIME_T_MAX;
+    return PARSEDATE_LATER; /* time_t overflow */
+  }
+
+  t += tzoff;
+
+  *output = t;
+
+  return PARSEDATE_OK;
+}
+#else
+/* disabled */
+static int parsedate(const char *date, time_t *output)
+{
+  (void)date;
+  *output = 0;
+  return PARSEDATE_OK; /* a lie */
+}
+#endif
+
+time_t curl_getdate(const char *p, const time_t *now)
+{
+  time_t parsed = -1;
+  int rc = parsedate(p, &parsed);
+  (void)now; /* legacy argument from the past that we ignore */
+
+  if(rc == PARSEDATE_OK) {
+    if(parsed == -1)
+      /* avoid returning -1 for a working scenario */
+      parsed++;
+    return parsed;
+  }
+  /* everything else is fail */
+  return -1;
+}
+
+/* Curl_getdate_capped() differs from curl_getdate() in that this will return
+   TIME_T_MAX in case the parsed time value was too big, instead of an
+   error. */
+
+time_t Curl_getdate_capped(const char *p)
+{
+  time_t parsed = -1;
+  int rc = parsedate(p, &parsed);
+
+  switch(rc) {
+  case PARSEDATE_OK:
+    if(parsed == -1)
+      /* avoid returning -1 for a working scenario */
+      parsed++;
+    return parsed;
+  case PARSEDATE_LATER:
+    /* this returns the maximum time value */
+    return parsed;
+  default:
+    return -1; /* everything else is fail */
+  }
+  /* UNREACHABLE */
+}
+
+/*
+ * Curl_gmtime() is a gmtime() replacement for portability. Do not use the
+ * gmtime_r() or gmtime() functions anywhere else but here.
+ *
+ */
+
+CURLcode Curl_gmtime(time_t intime, struct tm *store)
+{
+  const struct tm *tm;
+#ifdef HAVE_GMTIME_R
+  /* thread-safe version */
+  tm = (struct tm *)gmtime_r(&intime, store);
+#else
+  /* !checksrc! disable BANNEDFUNC 1 */
+  tm = gmtime(&intime);
+  if(tm)
+    *store = *tm; /* copy the pointed struct to the local copy */
+#endif
+
+  if(!tm)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  return CURLE_OK;
+}
Index: trunk/src/libs/curl-8.7.1/lib/parsedate.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/parsedate.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/parsedate.h	(revision 104083)
@@ -0,0 +1,38 @@
+#ifndef HEADER_CURL_PARSEDATE_H
+#define HEADER_CURL_PARSEDATE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+extern const char * const Curl_wkday[7];
+extern const char * const Curl_month[12];
+
+CURLcode Curl_gmtime(time_t intime, struct tm *store);
+
+/* Curl_getdate_capped() differs from curl_getdate() in that this will return
+   TIME_T_MAX in case the parsed time value was too big, instead of an
+   error. */
+
+time_t Curl_getdate_capped(const char *p);
+
+#endif /* HEADER_CURL_PARSEDATE_H */
Index: trunk/src/libs/curl-8.7.1/lib/pingpong.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/pingpong.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/pingpong.c	(revision 104083)
@@ -0,0 +1,438 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ *   'pingpong' is for generic back-and-forth support functions used by FTP,
+ *   IMAP, POP3, SMTP and whatever more that likes them.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "urldata.h"
+#include "cfilters.h"
+#include "sendf.h"
+#include "select.h"
+#include "progress.h"
+#include "speedcheck.h"
+#include "pingpong.h"
+#include "multiif.h"
+#include "vtls/vtls.h"
+#include "strdup.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef USE_PINGPONG
+
+/* Returns timeout in ms. 0 or negative number means the timeout has already
+   triggered */
+timediff_t Curl_pp_state_timeout(struct Curl_easy *data,
+                                 struct pingpong *pp, bool disconnecting)
+{
+  struct connectdata *conn = data->conn;
+  timediff_t timeout_ms; /* in milliseconds */
+  timediff_t response_time = (data->set.server_response_timeout)?
+    data->set.server_response_timeout: pp->response_time;
+
+  /* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
+     remaining time, or use pp->response because SERVER_RESPONSE_TIMEOUT is
+     supposed to govern the response for any given server response, not for
+     the time from connect to the given server response. */
+
+  /* Without a requested timeout, we only wait 'response_time' seconds for the
+     full response to arrive before we bail out */
+  timeout_ms = response_time -
+    Curl_timediff(Curl_now(), pp->response); /* spent time */
+
+  if(data->set.timeout && !disconnecting) {
+    /* if timeout is requested, find out how much remaining time we have */
+    timediff_t timeout2_ms = data->set.timeout - /* timeout time */
+      Curl_timediff(Curl_now(), conn->now); /* spent time */
+
+    /* pick the lowest number */
+    timeout_ms = CURLMIN(timeout_ms, timeout2_ms);
+  }
+
+  return timeout_ms;
+}
+
+/*
+ * Curl_pp_statemach()
+ */
+CURLcode Curl_pp_statemach(struct Curl_easy *data,
+                           struct pingpong *pp, bool block,
+                           bool disconnecting)
+{
+  struct connectdata *conn = data->conn;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  int rc;
+  timediff_t interval_ms;
+  timediff_t timeout_ms = Curl_pp_state_timeout(data, pp, disconnecting);
+  CURLcode result = CURLE_OK;
+
+  if(timeout_ms <= 0) {
+    failf(data, "server response timeout");
+    return CURLE_OPERATION_TIMEDOUT; /* already too little time */
+  }
+
+  if(block) {
+    interval_ms = 1000;  /* use 1 second timeout intervals */
+    if(timeout_ms < interval_ms)
+      interval_ms = timeout_ms;
+  }
+  else
+    interval_ms = 0; /* immediate */
+
+  if(Curl_conn_data_pending(data, FIRSTSOCKET))
+    rc = 1;
+  else if(pp->overflow)
+    /* We are receiving and there is data in the cache so just read it */
+    rc = 1;
+  else if(!pp->sendleft && Curl_conn_data_pending(data, FIRSTSOCKET))
+    /* We are receiving and there is data ready in the SSL library */
+    rc = 1;
+  else
+    rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
+                           CURL_SOCKET_BAD,
+                           pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
+                           interval_ms);
+
+  if(block) {
+    /* if we didn't wait, we don't have to spend time on this now */
+    if(Curl_pgrsUpdate(data))
+      result = CURLE_ABORTED_BY_CALLBACK;
+    else
+      result = Curl_speedcheck(data, Curl_now());
+
+    if(result)
+      return result;
+  }
+
+  if(rc == -1) {
+    failf(data, "select/poll error");
+    result = CURLE_OUT_OF_MEMORY;
+  }
+  else if(rc)
+    result = pp->statemachine(data, data->conn);
+
+  return result;
+}
+
+/* initialize stuff to prepare for reading a fresh new response */
+void Curl_pp_init(struct pingpong *pp)
+{
+  pp->nread_resp = 0;
+  pp->response = Curl_now(); /* start response time-out now! */
+  pp->pending_resp = TRUE;
+  Curl_dyn_init(&pp->sendbuf, DYN_PINGPPONG_CMD);
+  Curl_dyn_init(&pp->recvbuf, DYN_PINGPPONG_CMD);
+}
+
+/***********************************************************************
+ *
+ * Curl_pp_vsendf()
+ *
+ * Send the formatted string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_vsendf(struct Curl_easy *data,
+                        struct pingpong *pp,
+                        const char *fmt,
+                        va_list args)
+{
+  size_t bytes_written = 0;
+  size_t write_len;
+  char *s;
+  CURLcode result;
+  struct connectdata *conn = data->conn;
+
+#ifdef HAVE_GSSAPI
+  enum protection_level data_sec;
+#endif
+
+  DEBUGASSERT(pp->sendleft == 0);
+  DEBUGASSERT(pp->sendsize == 0);
+  DEBUGASSERT(pp->sendthis == NULL);
+
+  if(!conn)
+    /* can't send without a connection! */
+    return CURLE_SEND_ERROR;
+
+  Curl_dyn_reset(&pp->sendbuf);
+  result = Curl_dyn_vaddf(&pp->sendbuf, fmt, args);
+  if(result)
+    return result;
+
+  /* append CRLF */
+  result = Curl_dyn_addn(&pp->sendbuf, "\r\n", 2);
+  if(result)
+    return result;
+
+  pp->pending_resp = TRUE;
+  write_len = Curl_dyn_len(&pp->sendbuf);
+  s = Curl_dyn_ptr(&pp->sendbuf);
+
+#ifdef HAVE_GSSAPI
+  conn->data_prot = PROT_CMD;
+#endif
+  result = Curl_conn_send(data, FIRSTSOCKET, s, write_len, &bytes_written);
+  if(result == CURLE_AGAIN) {
+    bytes_written = 0;
+  }
+  else if(result)
+    return result;
+#ifdef HAVE_GSSAPI
+  data_sec = conn->data_prot;
+  DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
+  conn->data_prot = (unsigned char)data_sec;
+#endif
+
+  Curl_debug(data, CURLINFO_HEADER_OUT, s, bytes_written);
+
+  if(bytes_written != write_len) {
+    /* the whole chunk was not sent, keep it around and adjust sizes */
+    pp->sendthis = s;
+    pp->sendsize = write_len;
+    pp->sendleft = write_len - bytes_written;
+  }
+  else {
+    pp->sendthis = NULL;
+    pp->sendleft = pp->sendsize = 0;
+    pp->response = Curl_now();
+  }
+
+  return CURLE_OK;
+}
+
+
+/***********************************************************************
+ *
+ * Curl_pp_sendf()
+ *
+ * Send the formatted string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_sendf(struct Curl_easy *data, struct pingpong *pp,
+                       const char *fmt, ...)
+{
+  CURLcode result;
+  va_list ap;
+  va_start(ap, fmt);
+
+  result = Curl_pp_vsendf(data, pp, fmt, ap);
+
+  va_end(ap);
+
+  return result;
+}
+
+static CURLcode pingpong_read(struct Curl_easy *data,
+                              int sockindex,
+                              char *buffer,
+                              size_t buflen,
+                              ssize_t *nread)
+{
+  CURLcode result;
+#ifdef HAVE_GSSAPI
+  enum protection_level prot = data->conn->data_prot;
+  data->conn->data_prot = PROT_CLEAR;
+#endif
+  result = Curl_conn_recv(data, sockindex, buffer, buflen, nread);
+#ifdef HAVE_GSSAPI
+  DEBUGASSERT(prot  > PROT_NONE && prot < PROT_LAST);
+  data->conn->data_prot = (unsigned char)prot;
+#endif
+  return result;
+}
+
+/*
+ * Curl_pp_readresp()
+ *
+ * Reads a piece of a server response.
+ */
+CURLcode Curl_pp_readresp(struct Curl_easy *data,
+                          int sockindex,
+                          struct pingpong *pp,
+                          int *code, /* return the server code if done */
+                          size_t *size) /* size of the response */
+{
+  struct connectdata *conn = data->conn;
+  CURLcode result = CURLE_OK;
+
+  *code = 0; /* 0 for errors or not done */
+  *size = 0;
+
+  if(pp->nfinal) {
+    /* a previous call left this many bytes in the beginning of the buffer as
+       that was the final line; now ditch that */
+    size_t full = Curl_dyn_len(&pp->recvbuf);
+
+    /* trim off the "final" leading part */
+    Curl_dyn_tail(&pp->recvbuf, full -  pp->nfinal);
+
+    pp->nfinal = 0; /* now gone */
+  }
+  if(!pp->overflow) {
+    ssize_t gotbytes = 0;
+    char buffer[900];
+
+    result = pingpong_read(data, sockindex, buffer, sizeof(buffer), &gotbytes);
+    if(result == CURLE_AGAIN)
+      return CURLE_OK;
+
+    if(result)
+      return result;
+
+    if(gotbytes <= 0) {
+      failf(data, "response reading failed (errno: %d)", SOCKERRNO);
+      return CURLE_RECV_ERROR;
+    }
+
+    result = Curl_dyn_addn(&pp->recvbuf, buffer, gotbytes);
+    if(result)
+      return result;
+
+    data->req.headerbytecount += (unsigned int)gotbytes;
+
+    pp->nread_resp += gotbytes;
+  }
+
+  do {
+    char *line = Curl_dyn_ptr(&pp->recvbuf);
+    char *nl = memchr(line, '\n', Curl_dyn_len(&pp->recvbuf));
+    if(nl) {
+      /* a newline is CRLF in pp-talk, so the CR is ignored as
+         the line isn't really terminated until the LF comes */
+      size_t length = nl - line + 1;
+
+      /* output debug output if that is requested */
+#ifdef HAVE_GSSAPI
+      if(!conn->sec_complete)
+#endif
+        Curl_debug(data, CURLINFO_HEADER_IN, line, length);
+
+      /*
+       * Pass all response-lines to the callback function registered for
+       * "headers". The response lines can be seen as a kind of headers.
+       */
+      result = Curl_client_write(data, CLIENTWRITE_INFO, line, length);
+      if(result)
+        return result;
+
+      if(pp->endofresp(data, conn, line, length, code)) {
+        /* When at "end of response", keep the endofresp line first in the
+           buffer since it will be accessed outside (by pingpong
+           parsers). Store the overflow counter to inform about additional
+           data in this buffer after the endofresp line. */
+        pp->nfinal = length;
+        if(Curl_dyn_len(&pp->recvbuf) > length)
+          pp->overflow = Curl_dyn_len(&pp->recvbuf) - length;
+        else
+          pp->overflow = 0;
+        *size = pp->nread_resp; /* size of the response */
+        pp->nread_resp = 0; /* restart */
+        break;
+      }
+      if(Curl_dyn_len(&pp->recvbuf) > length)
+        /* keep the remaining piece */
+        Curl_dyn_tail((&pp->recvbuf), Curl_dyn_len(&pp->recvbuf) - length);
+      else
+        Curl_dyn_reset(&pp->recvbuf);
+    }
+    else {
+      /* without a newline, there is no overflow */
+      pp->overflow = 0;
+      break;
+    }
+
+  } while(1); /* while there's buffer left to scan */
+
+  pp->pending_resp = FALSE;
+
+  return result;
+}
+
+int Curl_pp_getsock(struct Curl_easy *data,
+                    struct pingpong *pp, curl_socket_t *socks)
+{
+  struct connectdata *conn = data->conn;
+  socks[0] = conn->sock[FIRSTSOCKET];
+
+  if(pp->sendleft) {
+    /* write mode */
+    return GETSOCK_WRITESOCK(0);
+  }
+
+  /* read mode */
+  return GETSOCK_READSOCK(0);
+}
+
+CURLcode Curl_pp_flushsend(struct Curl_easy *data,
+                           struct pingpong *pp)
+{
+  /* we have a piece of a command still left to send */
+  size_t written;
+  CURLcode result;
+
+  result = Curl_conn_send(data, FIRSTSOCKET,
+                          pp->sendthis + pp->sendsize - pp->sendleft,
+                          pp->sendleft, &written);
+  if(result == CURLE_AGAIN) {
+    result = CURLE_OK;
+    written = 0;
+  }
+  if(result)
+    return result;
+
+  if(written != pp->sendleft) {
+    /* only a fraction was sent */
+    pp->sendleft -= written;
+  }
+  else {
+    pp->sendthis = NULL;
+    pp->sendleft = pp->sendsize = 0;
+    pp->response = Curl_now();
+  }
+  return CURLE_OK;
+}
+
+CURLcode Curl_pp_disconnect(struct pingpong *pp)
+{
+  Curl_dyn_free(&pp->sendbuf);
+  Curl_dyn_free(&pp->recvbuf);
+  return CURLE_OK;
+}
+
+bool Curl_pp_moredata(struct pingpong *pp)
+{
+  return (!pp->sendleft && Curl_dyn_len(&pp->recvbuf) > pp->nfinal);
+}
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/pingpong.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/pingpong.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/pingpong.h	(revision 104083)
@@ -0,0 +1,160 @@
+#ifndef HEADER_CURL_PINGPONG_H
+#define HEADER_CURL_PINGPONG_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_FTP) || \
+  !defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_SMTP)
+#define USE_PINGPONG
+#endif
+
+/* forward-declaration, this is defined in urldata.h */
+struct connectdata;
+
+typedef enum {
+  PPTRANSFER_BODY, /* yes do transfer a body */
+  PPTRANSFER_INFO, /* do still go through to get info/headers */
+  PPTRANSFER_NONE  /* don't get anything and don't get info */
+} curl_pp_transfer;
+
+/*
+ * 'pingpong' is the generic struct used for protocols doing server<->client
+ * conversations in a back-and-forth style such as FTP, IMAP, POP3, SMTP etc.
+ *
+ * It holds response cache and non-blocking sending data.
+ */
+struct pingpong {
+  size_t nread_resp;  /* number of bytes currently read of a server response */
+  bool pending_resp;  /* set TRUE when a server response is pending or in
+                         progress, and is cleared once the last response is
+                         read */
+  char *sendthis; /* pointer to a buffer that is to be sent to the server */
+  size_t sendleft; /* number of bytes left to send from the sendthis buffer */
+  size_t sendsize; /* total size of the sendthis buffer */
+  struct curltime response; /* set to Curl_now() when a command has been sent
+                               off, used to time-out response reading */
+  timediff_t response_time; /* When no timeout is given, this is the amount of
+                               milliseconds we await for a server response. */
+  struct dynbuf sendbuf;
+  struct dynbuf recvbuf;
+  size_t overflow; /* number of bytes left after a final response line */
+  size_t nfinal;   /* number of bytes in the final response line, which
+                      after a match is first in the receice buffer */
+
+  /* Function pointers the protocols MUST implement and provide for the
+     pingpong layer to function */
+
+  CURLcode (*statemachine)(struct Curl_easy *data, struct connectdata *conn);
+  bool (*endofresp)(struct Curl_easy *data, struct connectdata *conn,
+                    char *ptr, size_t len, int *code);
+};
+
+#define PINGPONG_SETUP(pp,s,e)                   \
+  do {                                           \
+    pp->response_time = RESP_TIMEOUT;            \
+    pp->statemachine = s;                        \
+    pp->endofresp = e;                           \
+  } while(0)
+
+/*
+ * Curl_pp_statemach()
+ *
+ * called repeatedly until done. Set 'wait' to make it wait a while on the
+ * socket if there's no traffic.
+ */
+CURLcode Curl_pp_statemach(struct Curl_easy *data, struct pingpong *pp,
+                           bool block, bool disconnecting);
+
+/* initialize stuff to prepare for reading a fresh new response */
+void Curl_pp_init(struct pingpong *pp);
+
+/* Returns timeout in ms. 0 or negative number means the timeout has already
+   triggered */
+timediff_t Curl_pp_state_timeout(struct Curl_easy *data,
+                                 struct pingpong *pp, bool disconnecting);
+
+
+/***********************************************************************
+ *
+ * Curl_pp_sendf()
+ *
+ * Send the formatted string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_sendf(struct Curl_easy *data,
+                       struct pingpong *pp,
+                       const char *fmt, ...) CURL_PRINTF(3, 4);
+
+/***********************************************************************
+ *
+ * Curl_pp_vsendf()
+ *
+ * Send the formatted string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_vsendf(struct Curl_easy *data,
+                        struct pingpong *pp,
+                        const char *fmt,
+                        va_list args) CURL_PRINTF(3, 0);
+
+/*
+ * Curl_pp_readresp()
+ *
+ * Reads a piece of a server response.
+ */
+CURLcode Curl_pp_readresp(struct Curl_easy *data,
+                          int sockindex,
+                          struct pingpong *pp,
+                          int *code, /* return the server code if done */
+                          size_t *size); /* size of the response */
+
+
+CURLcode Curl_pp_flushsend(struct Curl_easy *data,
+                           struct pingpong *pp);
+
+/* call this when a pingpong connection is disconnected */
+CURLcode Curl_pp_disconnect(struct pingpong *pp);
+
+int Curl_pp_getsock(struct Curl_easy *data, struct pingpong *pp,
+                    curl_socket_t *socks);
+
+
+/***********************************************************************
+ *
+ * Curl_pp_moredata()
+ *
+ * Returns whether there are still more data in the cache and so a call
+ * to Curl_pp_readresp() will not block.
+ */
+bool Curl_pp_moredata(struct pingpong *pp);
+
+#endif /* HEADER_CURL_PINGPONG_H */
Index: trunk/src/libs/curl-8.7.1/lib/pop3.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/pop3.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/pop3.c	(revision 104083)
@@ -0,0 +1,1582 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC1734 POP3 Authentication
+ * RFC1939 POP3 protocol
+ * RFC2195 CRAM-MD5 authentication
+ * RFC2384 POP URL Scheme
+ * RFC2449 POP3 Extension Mechanism
+ * RFC2595 Using TLS with IMAP, POP3 and ACAP
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC4422 Simple Authentication and Security Layer (SASL)
+ * RFC4616 PLAIN authentication
+ * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
+ * RFC5034 POP3 SASL Authentication Mechanism
+ * RFC6749 OAuth 2.0 Authorization Framework
+ * RFC8314 Use of TLS for Email Submission and Access
+ * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_POP3
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "pop3.h"
+#include "strtoofft.h"
+#include "strcase.h"
+#include "vtls/vtls.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "select.h"
+#include "multiif.h"
+#include "url.h"
+#include "bufref.h"
+#include "curl_sasl.h"
+#include "curl_md5.h"
+#include "warnless.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Local API functions */
+static CURLcode pop3_regular_transfer(struct Curl_easy *data, bool *done);
+static CURLcode pop3_do(struct Curl_easy *data, bool *done);
+static CURLcode pop3_done(struct Curl_easy *data, CURLcode status,
+                          bool premature);
+static CURLcode pop3_connect(struct Curl_easy *data, bool *done);
+static CURLcode pop3_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
+static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done);
+static int pop3_getsock(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks);
+static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done);
+static CURLcode pop3_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static CURLcode pop3_parse_url_options(struct connectdata *conn);
+static CURLcode pop3_parse_url_path(struct Curl_easy *data);
+static CURLcode pop3_parse_custom_request(struct Curl_easy *data);
+static CURLcode pop3_perform_auth(struct Curl_easy *data, const char *mech,
+                                  const struct bufref *initresp);
+static CURLcode pop3_continue_auth(struct Curl_easy *data, const char *mech,
+                                   const struct bufref *resp);
+static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech);
+static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out);
+
+/*
+ * POP3 protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_pop3 = {
+  "POP3",                           /* scheme */
+  pop3_setup_connection,            /* setup_connection */
+  pop3_do,                          /* do_it */
+  pop3_done,                        /* done */
+  ZERO_NULL,                        /* do_more */
+  pop3_connect,                     /* connect_it */
+  pop3_multi_statemach,             /* connecting */
+  pop3_doing,                       /* doing */
+  pop3_getsock,                     /* proto_getsock */
+  pop3_getsock,                     /* doing_getsock */
+  ZERO_NULL,                        /* domore_getsock */
+  ZERO_NULL,                        /* perform_getsock */
+  pop3_disconnect,                  /* disconnect */
+  ZERO_NULL,                        /* write_resp */
+  ZERO_NULL,                        /* connection_check */
+  ZERO_NULL,                        /* attach connection */
+  PORT_POP3,                        /* defport */
+  CURLPROTO_POP3,                   /* protocol */
+  CURLPROTO_POP3,                   /* family */
+  PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
+  PROTOPT_URLOPTIONS
+};
+
+#ifdef USE_SSL
+/*
+ * POP3S protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_pop3s = {
+  "POP3S",                          /* scheme */
+  pop3_setup_connection,            /* setup_connection */
+  pop3_do,                          /* do_it */
+  pop3_done,                        /* done */
+  ZERO_NULL,                        /* do_more */
+  pop3_connect,                     /* connect_it */
+  pop3_multi_statemach,             /* connecting */
+  pop3_doing,                       /* doing */
+  pop3_getsock,                     /* proto_getsock */
+  pop3_getsock,                     /* doing_getsock */
+  ZERO_NULL,                        /* domore_getsock */
+  ZERO_NULL,                        /* perform_getsock */
+  pop3_disconnect,                  /* disconnect */
+  ZERO_NULL,                        /* write_resp */
+  ZERO_NULL,                        /* connection_check */
+  ZERO_NULL,                        /* attach connection */
+  PORT_POP3S,                       /* defport */
+  CURLPROTO_POP3S,                  /* protocol */
+  CURLPROTO_POP3,                   /* family */
+  PROTOPT_CLOSEACTION | PROTOPT_SSL
+  | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
+};
+#endif
+
+/* SASL parameters for the pop3 protocol */
+static const struct SASLproto saslpop3 = {
+  "pop",                /* The service name */
+  pop3_perform_auth,    /* Send authentication command */
+  pop3_continue_auth,   /* Send authentication continuation */
+  pop3_cancel_auth,     /* Send authentication cancellation */
+  pop3_get_message,     /* Get SASL response message */
+  255 - 8,              /* Max line len - strlen("AUTH ") - 1 space - crlf */
+  '*',                  /* Code received when continuation is expected */
+  '+',                  /* Code to receive upon authentication success */
+  SASL_AUTH_DEFAULT,    /* Default mechanisms */
+  SASL_FLAG_BASE64      /* Configuration flags */
+};
+
+#ifdef USE_SSL
+static void pop3_to_pop3s(struct connectdata *conn)
+{
+  /* Change the connection handler */
+  conn->handler = &Curl_handler_pop3s;
+
+  /* Set the connection's upgraded to TLS flag */
+  conn->bits.tls_upgraded = TRUE;
+}
+#else
+#define pop3_to_pop3s(x) Curl_nop_stmt
+#endif
+
+/***********************************************************************
+ *
+ * pop3_endofresp()
+ *
+ * Checks for an ending POP3 status code at the start of the given string, but
+ * also detects the APOP timestamp from the server greeting and various
+ * capabilities from the CAPA response including the supported authentication
+ * types and allowed SASL mechanisms.
+ */
+static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn,
+                           char *line, size_t len, int *resp)
+{
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  (void)data;
+
+  /* Do we have an error response? */
+  if(len >= 4 && !memcmp("-ERR", line, 4)) {
+    *resp = '-';
+
+    return TRUE;
+  }
+
+  /* Are we processing CAPA command responses? */
+  if(pop3c->state == POP3_CAPA) {
+    /* Do we have the terminating line? */
+    if(len >= 1 && line[0] == '.')
+      /* Treat the response as a success */
+      *resp = '+';
+    else
+      /* Treat the response as an untagged continuation */
+      *resp = '*';
+
+    return TRUE;
+  }
+
+  /* Do we have a success response? */
+  if(len >= 3 && !memcmp("+OK", line, 3)) {
+    *resp = '+';
+
+    return TRUE;
+  }
+
+  /* Do we have a continuation response? */
+  if(len >= 1 && line[0] == '+') {
+    *resp = '*';
+
+    return TRUE;
+  }
+
+  return FALSE; /* Nothing for us */
+}
+
+/***********************************************************************
+ *
+ * pop3_get_message()
+ *
+ * Gets the authentication message from the response buffer.
+ */
+static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out)
+{
+  char *message = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
+  size_t len = data->conn->proto.pop3c.pp.nfinal;
+
+  if(len > 2) {
+    /* Find the start of the message */
+    len -= 2;
+    for(message += 2; *message == ' ' || *message == '\t'; message++, len--)
+      ;
+
+    /* Find the end of the message */
+    while(len--)
+      if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
+         message[len] != '\t')
+        break;
+
+    /* Terminate the message */
+    message[++len] = '\0';
+    Curl_bufref_set(out, message, len, NULL);
+  }
+  else
+    /* junk input => zero length output */
+    Curl_bufref_set(out, "", 0, NULL);
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * pop3_state()
+ *
+ * This is the ONLY way to change POP3 state!
+ */
+static void pop3_state(struct Curl_easy *data, pop3state newstate)
+{
+  struct pop3_conn *pop3c = &data->conn->proto.pop3c;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[] = {
+    "STOP",
+    "SERVERGREET",
+    "CAPA",
+    "STARTTLS",
+    "UPGRADETLS",
+    "AUTH",
+    "APOP",
+    "USER",
+    "PASS",
+    "COMMAND",
+    "QUIT",
+    /* LAST */
+  };
+
+  if(pop3c->state != newstate)
+    infof(data, "POP3 %p state change from %s to %s",
+          (void *)pop3c, names[pop3c->state], names[newstate]);
+#endif
+
+  pop3c->state = newstate;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_capa()
+ *
+ * Sends the CAPA command in order to obtain a list of server side supported
+ * capabilities.
+ */
+static CURLcode pop3_perform_capa(struct Curl_easy *data,
+                                  struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+  pop3c->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
+  pop3c->sasl.authused = SASL_AUTH_NONE;  /* Clear the auth. mechanism used */
+  pop3c->tls_supported = FALSE;           /* Clear the TLS capability */
+
+  /* Send the CAPA command */
+  result = Curl_pp_sendf(data, &pop3c->pp, "%s", "CAPA");
+
+  if(!result)
+    pop3_state(data, POP3_CAPA);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_starttls()
+ *
+ * Sends the STLS command to start the upgrade to TLS.
+ */
+static CURLcode pop3_perform_starttls(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  /* Send the STLS command */
+  CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "STLS");
+
+  if(!result)
+    pop3_state(data, POP3_STARTTLS);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_upgrade_tls()
+ *
+ * Performs the upgrade to TLS.
+ */
+static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data,
+                                         struct connectdata *conn)
+{
+  /* Start the SSL connection */
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  CURLcode result;
+  bool ssldone = FALSE;
+
+  if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
+    result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
+    if(result)
+      goto out;
+  }
+
+  result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
+
+  if(!result) {
+    pop3c->ssldone = ssldone;
+    if(pop3c->state != POP3_UPGRADETLS)
+      pop3_state(data, POP3_UPGRADETLS);
+
+    if(pop3c->ssldone) {
+      pop3_to_pop3s(conn);
+      result = pop3_perform_capa(data, conn);
+    }
+  }
+out:
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_user()
+ *
+ * Sends a clear text USER command to authenticate with.
+ */
+static CURLcode pop3_perform_user(struct Curl_easy *data,
+                                  struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+
+  /* Check we have a username and password to authenticate with and end the
+     connect phase if we don't */
+  if(!data->state.aptr.user) {
+    pop3_state(data, POP3_STOP);
+
+    return result;
+  }
+
+  /* Send the USER command */
+  result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "USER %s",
+                         conn->user ? conn->user : "");
+  if(!result)
+    pop3_state(data, POP3_USER);
+
+  return result;
+}
+
+#ifndef CURL_DISABLE_DIGEST_AUTH
+/***********************************************************************
+ *
+ * pop3_perform_apop()
+ *
+ * Sends an APOP command to authenticate with.
+ */
+static CURLcode pop3_perform_apop(struct Curl_easy *data,
+                                  struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  size_t i;
+  struct MD5_context *ctxt;
+  unsigned char digest[MD5_DIGEST_LEN];
+  char secret[2 * MD5_DIGEST_LEN + 1];
+
+  /* Check we have a username and password to authenticate with and end the
+     connect phase if we don't */
+  if(!data->state.aptr.user) {
+    pop3_state(data, POP3_STOP);
+
+    return result;
+  }
+
+  /* Create the digest */
+  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  if(!ctxt)
+    return CURLE_OUT_OF_MEMORY;
+
+  Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
+                  curlx_uztoui(strlen(pop3c->apoptimestamp)));
+
+  Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
+                  curlx_uztoui(strlen(conn->passwd)));
+
+  /* Finalise the digest */
+  Curl_MD5_final(ctxt, digest);
+
+  /* Convert the calculated 16 octet digest into a 32 byte hex string */
+  for(i = 0; i < MD5_DIGEST_LEN; i++)
+    msnprintf(&secret[2 * i], 3, "%02x", digest[i]);
+
+  result = Curl_pp_sendf(data, &pop3c->pp, "APOP %s %s", conn->user, secret);
+
+  if(!result)
+    pop3_state(data, POP3_APOP);
+
+  return result;
+}
+#endif
+
+/***********************************************************************
+ *
+ * pop3_perform_auth()
+ *
+ * Sends an AUTH command allowing the client to login with the given SASL
+ * authentication mechanism.
+ */
+static CURLcode pop3_perform_auth(struct Curl_easy *data,
+                                  const char *mech,
+                                  const struct bufref *initresp)
+{
+  CURLcode result = CURLE_OK;
+  struct pop3_conn *pop3c = &data->conn->proto.pop3c;
+  const char *ir = (const char *) Curl_bufref_ptr(initresp);
+
+  if(ir) {                                  /* AUTH <mech> ...<crlf> */
+    /* Send the AUTH command with the initial response */
+    result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, ir);
+  }
+  else {
+    /* Send the AUTH command */
+    result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s", mech);
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_continue_auth()
+ *
+ * Sends SASL continuation data.
+ */
+static CURLcode pop3_continue_auth(struct Curl_easy *data,
+                                   const char *mech,
+                                   const struct bufref *resp)
+{
+  struct pop3_conn *pop3c = &data->conn->proto.pop3c;
+
+  (void)mech;
+
+  return Curl_pp_sendf(data, &pop3c->pp,
+                       "%s", (const char *) Curl_bufref_ptr(resp));
+}
+
+/***********************************************************************
+ *
+ * pop3_cancel_auth()
+ *
+ * Sends SASL cancellation.
+ */
+static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech)
+{
+  struct pop3_conn *pop3c = &data->conn->proto.pop3c;
+
+  (void)mech;
+
+  return Curl_pp_sendf(data, &pop3c->pp, "*");
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_authentication()
+ *
+ * Initiates the authentication sequence, with the appropriate SASL
+ * authentication mechanism, falling back to APOP and clear text should a
+ * common mechanism not be available between the client and server.
+ */
+static CURLcode pop3_perform_authentication(struct Curl_easy *data,
+                                            struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  saslprogress progress = SASL_IDLE;
+
+  /* Check we have enough data to authenticate with and end the
+     connect phase if we don't */
+  if(!Curl_sasl_can_authenticate(&pop3c->sasl, data)) {
+    pop3_state(data, POP3_STOP);
+    return result;
+  }
+
+  if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
+    /* Calculate the SASL login details */
+    result = Curl_sasl_start(&pop3c->sasl, data, FALSE, &progress);
+
+    if(!result)
+      if(progress == SASL_INPROGRESS)
+        pop3_state(data, POP3_AUTH);
+  }
+
+  if(!result && progress == SASL_IDLE) {
+#ifndef CURL_DISABLE_DIGEST_AUTH
+    if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
+      /* Perform APOP authentication */
+      result = pop3_perform_apop(data, conn);
+    else
+#endif
+    if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
+      /* Perform clear text authentication */
+      result = pop3_perform_user(data, conn);
+    else {
+      /* Other mechanisms not supported */
+      infof(data, "No known authentication mechanisms supported");
+      result = CURLE_LOGIN_DENIED;
+    }
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_command()
+ *
+ * Sends a POP3 based command.
+ */
+static CURLcode pop3_perform_command(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct POP3 *pop3 = data->req.p.pop3;
+  const char *command = NULL;
+
+  /* Calculate the default command */
+  if(pop3->id[0] == '\0' || data->set.list_only) {
+    command = "LIST";
+
+    if(pop3->id[0] != '\0')
+      /* Message specific LIST so skip the BODY transfer */
+      pop3->transfer = PPTRANSFER_INFO;
+  }
+  else
+    command = "RETR";
+
+  /* Send the command */
+  if(pop3->id[0] != '\0')
+    result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s %s",
+                           (pop3->custom && pop3->custom[0] != '\0' ?
+                            pop3->custom : command), pop3->id);
+  else
+    result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s",
+                           (pop3->custom && pop3->custom[0] != '\0' ?
+                            pop3->custom : command));
+
+  if(!result)
+    pop3_state(data, POP3_COMMAND);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_quit()
+ *
+ * Performs the quit action prior to sclose() be called.
+ */
+static CURLcode pop3_perform_quit(struct Curl_easy *data,
+                                  struct connectdata *conn)
+{
+  /* Send the QUIT command */
+  CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "QUIT");
+
+  if(!result)
+    pop3_state(data, POP3_QUIT);
+
+  return result;
+}
+
+/* For the initial server greeting */
+static CURLcode pop3_state_servergreet_resp(struct Curl_easy *data,
+                                            int pop3code,
+                                            pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
+  size_t len = data->conn->proto.pop3c.pp.nfinal;
+
+  (void)instate; /* no use for this yet */
+
+  if(pop3code != '+') {
+    failf(data, "Got unexpected pop3-server response");
+    result = CURLE_WEIRD_SERVER_REPLY;
+  }
+  else if(len > 3) {
+    /* Does the server support APOP authentication? */
+    char *lt;
+    char *gt = NULL;
+
+    /* Look for the APOP timestamp */
+    lt = memchr(line, '<', len);
+    if(lt)
+      /* search the remainder for '>' */
+      gt = memchr(lt, '>', len - (lt - line));
+    if(gt) {
+      /* the length of the timestamp, including the brackets */
+      size_t timestamplen = gt - lt + 1;
+      char *at = memchr(lt, '@', timestamplen);
+      /* If the timestamp does not contain '@' it is not (as required by
+         RFC-1939) conformant to the RFC-822 message id syntax, and we
+         therefore do not use APOP authentication. */
+      if(at) {
+        /* dupe the timestamp */
+        pop3c->apoptimestamp = Curl_memdup0(lt, timestamplen);
+        if(!pop3c->apoptimestamp)
+          return CURLE_OUT_OF_MEMORY;
+        /* Store the APOP capability */
+        pop3c->authtypes |= POP3_TYPE_APOP;
+      }
+    }
+
+    if(!result)
+      result = pop3_perform_capa(data, conn);
+  }
+
+  return result;
+}
+
+/* For CAPA responses */
+static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code,
+                                     pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
+  size_t len = data->conn->proto.pop3c.pp.nfinal;
+
+  (void)instate; /* no use for this yet */
+
+  /* Do we have a untagged continuation response? */
+  if(pop3code == '*') {
+    /* Does the server support the STLS capability? */
+    if(len >= 4 && !memcmp(line, "STLS", 4))
+      pop3c->tls_supported = TRUE;
+
+    /* Does the server support clear text authentication? */
+    else if(len >= 4 && !memcmp(line, "USER", 4))
+      pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
+
+    /* Does the server support SASL based authentication? */
+    else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
+      pop3c->authtypes |= POP3_TYPE_SASL;
+
+      /* Advance past the SASL keyword */
+      line += 5;
+      len -= 5;
+
+      /* Loop through the data line */
+      for(;;) {
+        size_t llen;
+        size_t wordlen;
+        unsigned short mechbit;
+
+        while(len &&
+              (*line == ' ' || *line == '\t' ||
+               *line == '\r' || *line == '\n')) {
+
+          line++;
+          len--;
+        }
+
+        if(!len)
+          break;
+
+        /* Extract the word */
+        for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
+              line[wordlen] != '\t' && line[wordlen] != '\r' &&
+              line[wordlen] != '\n';)
+          wordlen++;
+
+        /* Test the word for a matching authentication mechanism */
+        mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
+        if(mechbit && llen == wordlen)
+          pop3c->sasl.authmechs |= mechbit;
+
+        line += wordlen;
+        len -= wordlen;
+      }
+    }
+  }
+  else {
+    /* Clear text is supported when CAPA isn't recognised */
+    if(pop3code != '+')
+      pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
+
+    if(!data->set.use_ssl || Curl_conn_is_ssl(conn, FIRSTSOCKET))
+      result = pop3_perform_authentication(data, conn);
+    else if(pop3code == '+' && pop3c->tls_supported)
+      /* Switch to TLS connection now */
+      result = pop3_perform_starttls(data, conn);
+    else if(data->set.use_ssl <= CURLUSESSL_TRY)
+      /* Fallback and carry on with authentication */
+      result = pop3_perform_authentication(data, conn);
+    else {
+      failf(data, "STLS not supported.");
+      result = CURLE_USE_SSL_FAILED;
+    }
+  }
+
+  return result;
+}
+
+/* For STARTTLS responses */
+static CURLcode pop3_state_starttls_resp(struct Curl_easy *data,
+                                         struct connectdata *conn,
+                                         int pop3code,
+                                         pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  (void)instate; /* no use for this yet */
+
+  /* Pipelining in response is forbidden. */
+  if(data->conn->proto.pop3c.pp.overflow)
+    return CURLE_WEIRD_SERVER_REPLY;
+
+  if(pop3code != '+') {
+    if(data->set.use_ssl != CURLUSESSL_TRY) {
+      failf(data, "STARTTLS denied");
+      result = CURLE_USE_SSL_FAILED;
+    }
+    else
+      result = pop3_perform_authentication(data, conn);
+  }
+  else
+    result = pop3_perform_upgrade_tls(data, conn);
+
+  return result;
+}
+
+/* For SASL authentication responses */
+static CURLcode pop3_state_auth_resp(struct Curl_easy *data,
+                                     int pop3code,
+                                     pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  saslprogress progress;
+
+  (void)instate; /* no use for this yet */
+
+  result = Curl_sasl_continue(&pop3c->sasl, data, pop3code, &progress);
+  if(!result)
+    switch(progress) {
+    case SASL_DONE:
+      pop3_state(data, POP3_STOP);  /* Authenticated */
+      break;
+    case SASL_IDLE:            /* No mechanism left after cancellation */
+#ifndef CURL_DISABLE_DIGEST_AUTH
+      if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
+        /* Perform APOP authentication */
+        result = pop3_perform_apop(data, conn);
+      else
+#endif
+      if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
+        /* Perform clear text authentication */
+        result = pop3_perform_user(data, conn);
+      else {
+        failf(data, "Authentication cancelled");
+        result = CURLE_LOGIN_DENIED;
+      }
+      break;
+    default:
+      break;
+    }
+
+  return result;
+}
+
+#ifndef CURL_DISABLE_DIGEST_AUTH
+/* For APOP responses */
+static CURLcode pop3_state_apop_resp(struct Curl_easy *data, int pop3code,
+                                     pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  (void)instate; /* no use for this yet */
+
+  if(pop3code != '+') {
+    failf(data, "Authentication failed: %d", pop3code);
+    result = CURLE_LOGIN_DENIED;
+  }
+  else
+    /* End of connect phase */
+    pop3_state(data, POP3_STOP);
+
+  return result;
+}
+#endif
+
+/* For USER responses */
+static CURLcode pop3_state_user_resp(struct Curl_easy *data, int pop3code,
+                                     pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  (void)instate; /* no use for this yet */
+
+  if(pop3code != '+') {
+    failf(data, "Access denied. %c", pop3code);
+    result = CURLE_LOGIN_DENIED;
+  }
+  else
+    /* Send the PASS command */
+    result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "PASS %s",
+                           conn->passwd ? conn->passwd : "");
+  if(!result)
+    pop3_state(data, POP3_PASS);
+
+  return result;
+}
+
+/* For PASS responses */
+static CURLcode pop3_state_pass_resp(struct Curl_easy *data, int pop3code,
+                                     pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  (void)instate; /* no use for this yet */
+
+  if(pop3code != '+') {
+    failf(data, "Access denied. %c", pop3code);
+    result = CURLE_LOGIN_DENIED;
+  }
+  else
+    /* End of connect phase */
+    pop3_state(data, POP3_STOP);
+
+  return result;
+}
+
+/* For command responses */
+static CURLcode pop3_state_command_resp(struct Curl_easy *data,
+                                        int pop3code,
+                                        pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct POP3 *pop3 = data->req.p.pop3;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  struct pingpong *pp = &pop3c->pp;
+
+  (void)instate; /* no use for this yet */
+
+  if(pop3code != '+') {
+    pop3_state(data, POP3_STOP);
+    return CURLE_WEIRD_SERVER_REPLY;
+  }
+
+  /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
+     EOB string so count this is two matching bytes. This is necessary to make
+     the code detect the EOB if the only data than comes now is %2e CR LF like
+     when there is no body to return. */
+  pop3c->eob = 2;
+
+  /* But since this initial CR LF pair is not part of the actual body, we set
+     the strip counter here so that these bytes won't be delivered. */
+  pop3c->strip = 2;
+
+  if(pop3->transfer == PPTRANSFER_BODY) {
+    /* POP3 download */
+    Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
+
+    if(pp->overflow) {
+      /* The recv buffer contains data that is actually body content so send
+         it as such. Note that there may even be additional "headers" after
+         the body */
+
+      /* keep only the overflow */
+      Curl_dyn_tail(&pp->recvbuf, pp->overflow);
+      pp->nfinal = 0; /* done */
+
+      if(!data->req.no_body) {
+        result = Curl_pop3_write(data, Curl_dyn_ptr(&pp->recvbuf),
+                                 Curl_dyn_len(&pp->recvbuf));
+        if(result)
+          return result;
+      }
+
+      /* reset the buffer */
+      Curl_dyn_reset(&pp->recvbuf);
+      pp->overflow = 0;
+    }
+  }
+  else
+    pp->overflow = 0;
+
+  /* End of DO phase */
+  pop3_state(data, POP3_STOP);
+
+  return result;
+}
+
+static CURLcode pop3_statemachine(struct Curl_easy *data,
+                                  struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  int pop3code;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  struct pingpong *pp = &pop3c->pp;
+  size_t nread = 0;
+  (void)data;
+
+  /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
+  if(pop3c->state == POP3_UPGRADETLS)
+    return pop3_perform_upgrade_tls(data, conn);
+
+  /* Flush any data that needs to be sent */
+  if(pp->sendleft)
+    return Curl_pp_flushsend(data, pp);
+
+ do {
+    /* Read the response from the server */
+   result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &pop3code, &nread);
+   if(result)
+     return result;
+
+    if(!pop3code)
+      break;
+
+    /* We have now received a full POP3 server response */
+    switch(pop3c->state) {
+    case POP3_SERVERGREET:
+      result = pop3_state_servergreet_resp(data, pop3code, pop3c->state);
+      break;
+
+    case POP3_CAPA:
+      result = pop3_state_capa_resp(data, pop3code, pop3c->state);
+      break;
+
+    case POP3_STARTTLS:
+      result = pop3_state_starttls_resp(data, conn, pop3code, pop3c->state);
+      break;
+
+    case POP3_AUTH:
+      result = pop3_state_auth_resp(data, pop3code, pop3c->state);
+      break;
+
+#ifndef CURL_DISABLE_DIGEST_AUTH
+    case POP3_APOP:
+      result = pop3_state_apop_resp(data, pop3code, pop3c->state);
+      break;
+#endif
+
+    case POP3_USER:
+      result = pop3_state_user_resp(data, pop3code, pop3c->state);
+      break;
+
+    case POP3_PASS:
+      result = pop3_state_pass_resp(data, pop3code, pop3c->state);
+      break;
+
+    case POP3_COMMAND:
+      result = pop3_state_command_resp(data, pop3code, pop3c->state);
+      break;
+
+    case POP3_QUIT:
+      pop3_state(data, POP3_STOP);
+      break;
+
+    default:
+      /* internal error */
+      pop3_state(data, POP3_STOP);
+      break;
+    }
+  } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp));
+
+  return result;
+}
+
+/* Called repeatedly until done from multi.c */
+static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+  if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
+    bool ssldone = FALSE;
+    result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
+    pop3c->ssldone = ssldone;
+    if(result || !pop3c->ssldone)
+      return result;
+  }
+
+  result = Curl_pp_statemach(data, &pop3c->pp, FALSE, FALSE);
+  *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
+
+  return result;
+}
+
+static CURLcode pop3_block_statemach(struct Curl_easy *data,
+                                     struct connectdata *conn,
+                                     bool disconnecting)
+{
+  CURLcode result = CURLE_OK;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+  while(pop3c->state != POP3_STOP && !result)
+    result = Curl_pp_statemach(data, &pop3c->pp, TRUE, disconnecting);
+
+  return result;
+}
+
+/* Allocate and initialize the POP3 struct for the current Curl_easy if
+   required */
+static CURLcode pop3_init(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct POP3 *pop3;
+
+  pop3 = data->req.p.pop3 = calloc(1, sizeof(struct POP3));
+  if(!pop3)
+    result = CURLE_OUT_OF_MEMORY;
+
+  return result;
+}
+
+/* For the POP3 "protocol connect" and "doing" phases only */
+static int pop3_getsock(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks)
+{
+  return Curl_pp_getsock(data, &conn->proto.pop3c.pp, socks);
+}
+
+/***********************************************************************
+ *
+ * pop3_connect()
+ *
+ * This function should do everything that is to be considered a part of the
+ * connection phase.
+ *
+ * The variable 'done' points to will be TRUE if the protocol-layer connect
+ * phase is done when this function returns, or FALSE if not.
+ */
+static CURLcode pop3_connect(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  struct pingpong *pp = &pop3c->pp;
+
+  *done = FALSE; /* default to not done yet */
+
+  /* We always support persistent connections in POP3 */
+  connkeep(conn, "POP3 default");
+
+  PINGPONG_SETUP(pp, pop3_statemachine, pop3_endofresp);
+
+  /* Set the default preferred authentication type and mechanism */
+  pop3c->preftype = POP3_TYPE_ANY;
+  Curl_sasl_init(&pop3c->sasl, data, &saslpop3);
+
+  /* Initialise the pingpong layer */
+  Curl_pp_init(pp);
+
+  /* Parse the URL options */
+  result = pop3_parse_url_options(conn);
+  if(result)
+    return result;
+
+  /* Start off waiting for the server greeting response */
+  pop3_state(data, POP3_SERVERGREET);
+
+  result = pop3_multi_statemach(data, done);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode pop3_done(struct Curl_easy *data, CURLcode status,
+                          bool premature)
+{
+  CURLcode result = CURLE_OK;
+  struct POP3 *pop3 = data->req.p.pop3;
+
+  (void)premature;
+
+  if(!pop3)
+    return CURLE_OK;
+
+  if(status) {
+    connclose(data->conn, "POP3 done with bad status");
+    result = status;         /* use the already set error code */
+  }
+
+  /* Cleanup our per-request based variables */
+  Curl_safefree(pop3->id);
+  Curl_safefree(pop3->custom);
+
+  /* Clear the transfer mode for the next request */
+  pop3->transfer = PPTRANSFER_BODY;
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform()
+ *
+ * This is the actual DO function for POP3. Get a message/listing according to
+ * the options previously setup.
+ */
+static CURLcode pop3_perform(struct Curl_easy *data, bool *connected,
+                             bool *dophase_done)
+{
+  /* This is POP3 and no proxy */
+  CURLcode result = CURLE_OK;
+  struct POP3 *pop3 = data->req.p.pop3;
+
+  DEBUGF(infof(data, "DO phase starts"));
+
+  if(data->req.no_body) {
+    /* Requested no body means no transfer */
+    pop3->transfer = PPTRANSFER_INFO;
+  }
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* Start the first command in the DO phase */
+  result = pop3_perform_command(data);
+  if(result)
+    return result;
+
+  /* Run the state-machine */
+  result = pop3_multi_statemach(data, dophase_done);
+  *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
+
+  if(*dophase_done)
+    DEBUGF(infof(data, "DO phase is complete"));
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (pop3_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode pop3_do(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  *done = FALSE; /* default to false */
+
+  /* Parse the URL path */
+  result = pop3_parse_url_path(data);
+  if(result)
+    return result;
+
+  /* Parse the custom request */
+  result = pop3_parse_custom_request(data);
+  if(result)
+    return result;
+
+  result = pop3_regular_transfer(data, done);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_disconnect()
+ *
+ * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode pop3_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead_connection)
+{
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  (void)data;
+
+  /* We cannot send quit unconditionally. If this connection is stale or
+     bad in any way, sending quit and waiting around here will make the
+     disconnect wait in vain and cause more problems than we need to. */
+
+  if(!dead_connection && conn->bits.protoconnstart) {
+    if(!pop3_perform_quit(data, conn))
+      (void)pop3_block_statemach(data, conn, TRUE); /* ignore errors on QUIT */
+  }
+
+  /* Disconnect from the server */
+  Curl_pp_disconnect(&pop3c->pp);
+
+  /* Cleanup the SASL module */
+  Curl_sasl_cleanup(conn, pop3c->sasl.authused);
+
+  /* Cleanup our connection based variables */
+  Curl_safefree(pop3c->apoptimestamp);
+
+  return CURLE_OK;
+}
+
+/* Call this when the DO phase has completed */
+static CURLcode pop3_dophase_done(struct Curl_easy *data, bool connected)
+{
+  (void)data;
+  (void)connected;
+
+  return CURLE_OK;
+}
+
+/* Called from multi.c while DOing */
+static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done)
+{
+  CURLcode result = pop3_multi_statemach(data, dophase_done);
+
+  if(result)
+    DEBUGF(infof(data, "DO phase failed"));
+  else if(*dophase_done) {
+    result = pop3_dophase_done(data, FALSE /* not connected */);
+
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ */
+static CURLcode pop3_regular_transfer(struct Curl_easy *data,
+                                      bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+  bool connected = FALSE;
+
+  /* Make sure size is unknown at this point */
+  data->req.size = -1;
+
+  /* Set the progress data */
+  Curl_pgrsSetUploadCounter(data, 0);
+  Curl_pgrsSetDownloadCounter(data, 0);
+  Curl_pgrsSetUploadSize(data, -1);
+  Curl_pgrsSetDownloadSize(data, -1);
+
+  /* Carry out the perform */
+  result = pop3_perform(data, &connected, dophase_done);
+
+  /* Perform post DO phase operations if necessary */
+  if(!result && *dophase_done)
+    result = pop3_dophase_done(data, connected);
+
+  return result;
+}
+
+static CURLcode pop3_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  /* Initialise the POP3 layer */
+  CURLcode result = pop3_init(data);
+  if(result)
+    return result;
+
+  /* Clear the TLS upgraded flag */
+  conn->bits.tls_upgraded = FALSE;
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * pop3_parse_url_options()
+ *
+ * Parse the URL login options.
+ */
+static CURLcode pop3_parse_url_options(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  const char *ptr = conn->options;
+
+  while(!result && ptr && *ptr) {
+    const char *key = ptr;
+    const char *value;
+
+    while(*ptr && *ptr != '=')
+      ptr++;
+
+    value = ptr + 1;
+
+    while(*ptr && *ptr != ';')
+      ptr++;
+
+    if(strncasecompare(key, "AUTH=", 5)) {
+      result = Curl_sasl_parse_url_auth_option(&pop3c->sasl,
+                                               value, ptr - value);
+
+      if(result && strncasecompare(value, "+APOP", ptr - value)) {
+        pop3c->preftype = POP3_TYPE_APOP;
+        pop3c->sasl.prefmech = SASL_AUTH_NONE;
+        result = CURLE_OK;
+      }
+    }
+    else
+      result = CURLE_URL_MALFORMAT;
+
+    if(*ptr == ';')
+      ptr++;
+  }
+
+  if(pop3c->preftype != POP3_TYPE_APOP)
+    switch(pop3c->sasl.prefmech) {
+    case SASL_AUTH_NONE:
+      pop3c->preftype = POP3_TYPE_NONE;
+      break;
+    case SASL_AUTH_DEFAULT:
+      pop3c->preftype = POP3_TYPE_ANY;
+      break;
+    default:
+      pop3c->preftype = POP3_TYPE_SASL;
+      break;
+    }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ */
+static CURLcode pop3_parse_url_path(struct Curl_easy *data)
+{
+  /* The POP3 struct is already initialised in pop3_connect() */
+  struct POP3 *pop3 = data->req.p.pop3;
+  const char *path = &data->state.up.path[1]; /* skip leading path */
+
+  /* URL decode the path for the message ID */
+  return Curl_urldecode(path, 0, &pop3->id, NULL, REJECT_CTRL);
+}
+
+/***********************************************************************
+ *
+ * pop3_parse_custom_request()
+ *
+ * Parse the custom request.
+ */
+static CURLcode pop3_parse_custom_request(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct POP3 *pop3 = data->req.p.pop3;
+  const char *custom = data->set.str[STRING_CUSTOMREQUEST];
+
+  /* URL decode the custom request */
+  if(custom)
+    result = Curl_urldecode(custom, 0, &pop3->custom, NULL, REJECT_CTRL);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * Curl_pop3_write()
+ *
+ * This function scans the body after the end-of-body and writes everything
+ * until the end is found.
+ */
+CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread)
+{
+  /* This code could be made into a special function in the handler struct */
+  CURLcode result = CURLE_OK;
+  struct SingleRequest *k = &data->req;
+  struct connectdata *conn = data->conn;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  bool strip_dot = FALSE;
+  size_t last = 0;
+  size_t i;
+
+  /* Search through the buffer looking for the end-of-body marker which is
+     5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
+     the eob so the server will have prefixed it with an extra dot which we
+     need to strip out. Additionally the marker could of course be spread out
+     over 5 different data chunks. */
+  for(i = 0; i < nread; i++) {
+    size_t prev = pop3c->eob;
+
+    switch(str[i]) {
+    case 0x0d:
+      if(pop3c->eob == 0) {
+        pop3c->eob++;
+
+        if(i) {
+          /* Write out the body part that didn't match */
+          result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
+                                     i - last);
+
+          if(result)
+            return result;
+
+          last = i;
+        }
+      }
+      else if(pop3c->eob == 3)
+        pop3c->eob++;
+      else
+        /* If the character match wasn't at position 0 or 3 then restart the
+           pattern matching */
+        pop3c->eob = 1;
+      break;
+
+    case 0x0a:
+      if(pop3c->eob == 1 || pop3c->eob == 4)
+        pop3c->eob++;
+      else
+        /* If the character match wasn't at position 1 or 4 then start the
+           search again */
+        pop3c->eob = 0;
+      break;
+
+    case 0x2e:
+      if(pop3c->eob == 2)
+        pop3c->eob++;
+      else if(pop3c->eob == 3) {
+        /* We have an extra dot after the CRLF which we need to strip off */
+        strip_dot = TRUE;
+        pop3c->eob = 0;
+      }
+      else
+        /* If the character match wasn't at position 2 then start the search
+           again */
+        pop3c->eob = 0;
+      break;
+
+    default:
+      pop3c->eob = 0;
+      break;
+    }
+
+    /* Did we have a partial match which has subsequently failed? */
+    if(prev && prev >= pop3c->eob) {
+      /* Strip can only be non-zero for the very first mismatch after CRLF
+         and then both prev and strip are equal and nothing will be output
+         below */
+      while(prev && pop3c->strip) {
+        prev--;
+        pop3c->strip--;
+      }
+
+      if(prev) {
+        /* If the partial match was the CRLF and dot then only write the CRLF
+           as the server would have inserted the dot */
+        if(strip_dot && prev - 1 > 0) {
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
+                                     prev - 1);
+        }
+        else if(!strip_dot) {
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
+                                     prev);
+        }
+        else {
+          result = CURLE_OK;
+        }
+
+        if(result)
+          return result;
+
+        last = i;
+        strip_dot = FALSE;
+      }
+    }
+  }
+
+  if(pop3c->eob == POP3_EOB_LEN) {
+    /* We have a full match so the transfer is done, however we must transfer
+    the CRLF at the start of the EOB as this is considered to be part of the
+    message as per RFC-1939, sect. 3 */
+    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
+
+    k->keepon &= ~KEEP_RECV;
+    pop3c->eob = 0;
+
+    return result;
+  }
+
+  if(pop3c->eob)
+    /* While EOB is matching nothing should be output */
+    return CURLE_OK;
+
+  if(nread - last) {
+    result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
+                               nread - last);
+  }
+
+  return result;
+}
+
+#endif /* CURL_DISABLE_POP3 */
Index: trunk/src/libs/curl-8.7.1/lib/pop3.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/pop3.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/pop3.h	(revision 104083)
@@ -0,0 +1,97 @@
+#ifndef HEADER_CURL_POP3_H
+#define HEADER_CURL_POP3_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "pingpong.h"
+#include "curl_sasl.h"
+
+/****************************************************************************
+ * POP3 unique setup
+ ***************************************************************************/
+typedef enum {
+  POP3_STOP,         /* do nothing state, stops the state machine */
+  POP3_SERVERGREET,  /* waiting for the initial greeting immediately after
+                        a connect */
+  POP3_CAPA,
+  POP3_STARTTLS,
+  POP3_UPGRADETLS,   /* asynchronously upgrade the connection to SSL/TLS
+                       (multi mode only) */
+  POP3_AUTH,
+  POP3_APOP,
+  POP3_USER,
+  POP3_PASS,
+  POP3_COMMAND,
+  POP3_QUIT,
+  POP3_LAST          /* never used */
+} pop3state;
+
+/* This POP3 struct is used in the Curl_easy. All POP3 data that is
+   connection-oriented must be in pop3_conn to properly deal with the fact that
+   perhaps the Curl_easy is changed between the times the connection is
+   used. */
+struct POP3 {
+  curl_pp_transfer transfer;
+  char *id;               /* Message ID */
+  char *custom;           /* Custom Request */
+};
+
+/* pop3_conn is used for struct connection-oriented data in the connectdata
+   struct */
+struct pop3_conn {
+  struct pingpong pp;
+  pop3state state;        /* Always use pop3.c:state() to change state! */
+  size_t eob;             /* Number of bytes of the EOB (End Of Body) that
+                             have been received so far */
+  size_t strip;           /* Number of bytes from the start to ignore as
+                             non-body */
+  struct SASL sasl;       /* SASL-related storage */
+  char *apoptimestamp;    /* APOP timestamp from the server greeting */
+  unsigned char authtypes; /* Accepted authentication types */
+  unsigned char preftype;  /* Preferred authentication type */
+  BIT(ssldone);           /* Is connect() over SSL done? */
+  BIT(tls_supported);     /* StartTLS capability supported by server */
+};
+
+extern const struct Curl_handler Curl_handler_pop3;
+extern const struct Curl_handler Curl_handler_pop3s;
+
+/* Authentication type flags */
+#define POP3_TYPE_CLEARTEXT (1 << 0)
+#define POP3_TYPE_APOP      (1 << 1)
+#define POP3_TYPE_SASL      (1 << 2)
+
+/* Authentication type values */
+#define POP3_TYPE_NONE      0
+#define POP3_TYPE_ANY       (POP3_TYPE_CLEARTEXT|POP3_TYPE_APOP|POP3_TYPE_SASL)
+
+/* This is the 5-bytes End-Of-Body marker for POP3 */
+#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a"
+#define POP3_EOB_LEN 5
+
+/* This function scans the body after the end-of-body and writes everything
+ * until the end is found */
+CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread);
+
+#endif /* HEADER_CURL_POP3_H */
Index: trunk/src/libs/curl-8.7.1/lib/progress.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/progress.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/progress.c	(revision 104083)
@@ -0,0 +1,633 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "urldata.h"
+#include "sendf.h"
+#include "multiif.h"
+#include "progress.h"
+#include "timeval.h"
+#include "curl_printf.h"
+
+/* check rate limits within this many recent milliseconds, at minimum. */
+#define MIN_RATE_LIMIT_PERIOD 3000
+
+#ifndef CURL_DISABLE_PROGRESS_METER
+/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero
+   byte) */
+static void time2str(char *r, curl_off_t seconds)
+{
+  curl_off_t h;
+  if(seconds <= 0) {
+    strcpy(r, "--:--:--");
+    return;
+  }
+  h = seconds / CURL_OFF_T_C(3600);
+  if(h <= CURL_OFF_T_C(99)) {
+    curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60);
+    curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60));
+    msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T
+              ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s);
+  }
+  else {
+    /* this equals to more than 99 hours, switch to a more suitable output
+       format to fit within the limits. */
+    curl_off_t d = seconds / CURL_OFF_T_C(86400);
+    h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600);
+    if(d <= CURL_OFF_T_C(999))
+      msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T
+                "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h);
+    else
+      msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d);
+  }
+}
+
+/* The point of this function would be to return a string of the input data,
+   but never longer than 5 columns (+ one zero byte).
+   Add suffix k, M, G when suitable... */
+static char *max5data(curl_off_t bytes, char *max5)
+{
+#define ONE_KILOBYTE  CURL_OFF_T_C(1024)
+#define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE)
+#define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE)
+#define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE)
+#define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE)
+
+  if(bytes < CURL_OFF_T_C(100000))
+    msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes);
+
+  else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
+    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE);
+
+  else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
+    /* 'XX.XM' is good as long as we're less than 100 megs */
+    msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
+              CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
+              (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
+
+  else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
+    /* 'XXXXM' is good until we're at 10000MB or above */
+    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
+
+  else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
+    /* 10000 MB - 100 GB, we show it as XX.XG */
+    msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
+              CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE,
+              (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );
+
+  else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
+    /* up to 10000GB, display without decimal: XXXXG */
+    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE);
+
+  else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
+    /* up to 10000TB, display without decimal: XXXXT */
+    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE);
+
+  else
+    /* up to 10000PB, display without decimal: XXXXP */
+    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);
+
+  /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can
+     hold, but our data type is signed so 8192PB will be the maximum. */
+
+  return max5;
+}
+#endif
+
+/*
+
+   New proposed interface, 9th of February 2000:
+
+   pgrsStartNow() - sets start time
+   pgrsSetDownloadSize(x) - known expected download size
+   pgrsSetUploadSize(x) - known expected upload size
+   pgrsSetDownloadCounter() - amount of data currently downloaded
+   pgrsSetUploadCounter() - amount of data currently uploaded
+   pgrsUpdate() - show progress
+   pgrsDone() - transfer complete
+
+*/
+
+int Curl_pgrsDone(struct Curl_easy *data)
+{
+  int rc;
+  data->progress.lastshow = 0;
+  rc = Curl_pgrsUpdate(data); /* the final (forced) update */
+  if(rc)
+    return rc;
+
+  if(!(data->progress.flags & PGRS_HIDE) &&
+     !data->progress.callback)
+    /* only output if we don't use a progress callback and we're not
+     * hidden */
+    fprintf(data->set.err, "\n");
+
+  data->progress.speeder_c = 0; /* reset the progress meter display */
+  return 0;
+}
+
+/* reset the known transfer sizes */
+void Curl_pgrsResetTransferSizes(struct Curl_easy *data)
+{
+  Curl_pgrsSetDownloadSize(data, -1);
+  Curl_pgrsSetUploadSize(data, -1);
+}
+
+/*
+ *
+ * Curl_pgrsTimeWas(). Store the timestamp time at the given label.
+ */
+void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
+                      struct curltime timestamp)
+{
+  timediff_t *delta = NULL;
+
+  switch(timer) {
+  default:
+  case TIMER_NONE:
+    /* mistake filter */
+    break;
+  case TIMER_STARTOP:
+    /* This is set at the start of a transfer */
+    data->progress.t_startop = timestamp;
+    break;
+  case TIMER_STARTSINGLE:
+    /* This is set at the start of each single transfer */
+    data->progress.t_startsingle = timestamp;
+    data->progress.is_t_startransfer_set = false;
+    break;
+  case TIMER_POSTQUEUE:
+    /* Set when the transfer starts (after potentially having been brought
+       back from the waiting queue). It needs to count from t_startop and not
+       t_startsingle since the latter is reset when a connection is brought
+       back from the pending queue. */
+    data->progress.t_postqueue =
+      Curl_timediff_us(timestamp, data->progress.t_startop);
+    break;
+  case TIMER_STARTACCEPT:
+    data->progress.t_acceptdata = timestamp;
+    break;
+  case TIMER_NAMELOOKUP:
+    delta = &data->progress.t_nslookup;
+    break;
+  case TIMER_CONNECT:
+    delta = &data->progress.t_connect;
+    break;
+  case TIMER_APPCONNECT:
+    delta = &data->progress.t_appconnect;
+    break;
+  case TIMER_PRETRANSFER:
+    delta = &data->progress.t_pretransfer;
+    break;
+  case TIMER_STARTTRANSFER:
+    delta = &data->progress.t_starttransfer;
+    /* prevent updating t_starttransfer unless:
+     *   1) this is the first time we're setting t_starttransfer
+     *   2) a redirect has occurred since the last time t_starttransfer was set
+     * This prevents repeated invocations of the function from incorrectly
+     * changing the t_starttransfer time.
+     */
+    if(data->progress.is_t_startransfer_set) {
+      return;
+    }
+    else {
+      data->progress.is_t_startransfer_set = true;
+      break;
+    }
+  case TIMER_POSTRANSFER:
+    /* this is the normal end-of-transfer thing */
+    break;
+  case TIMER_REDIRECT:
+    data->progress.t_redirect = Curl_timediff_us(timestamp,
+                                                 data->progress.start);
+    break;
+  }
+  if(delta) {
+    timediff_t us = Curl_timediff_us(timestamp, data->progress.t_startsingle);
+    if(us < 1)
+      us = 1; /* make sure at least one microsecond passed */
+    *delta += us;
+  }
+}
+
+/*
+ *
+ * Curl_pgrsTime(). Store the current time at the given label. This fetches a
+ * fresh "now" and returns it.
+ *
+ * @unittest: 1399
+ */
+struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer)
+{
+  struct curltime now = Curl_now();
+
+  Curl_pgrsTimeWas(data, timer, now);
+  return now;
+}
+
+void Curl_pgrsStartNow(struct Curl_easy *data)
+{
+  data->progress.speeder_c = 0; /* reset the progress meter display */
+  data->progress.start = Curl_now();
+  data->progress.is_t_startransfer_set = false;
+  data->progress.ul_limit_start = data->progress.start;
+  data->progress.dl_limit_start = data->progress.start;
+  data->progress.ul_limit_size = 0;
+  data->progress.dl_limit_size = 0;
+  data->progress.downloaded = 0;
+  data->progress.uploaded = 0;
+  /* clear all bits except HIDE and HEADERS_OUT */
+  data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT;
+  Curl_ratelimit(data, data->progress.start);
+}
+
+/*
+ * This is used to handle speed limits, calculating how many milliseconds to
+ * wait until we're back under the speed limit, if needed.
+ *
+ * The way it works is by having a "starting point" (time & amount of data
+ * transferred by then) used in the speed computation, to be used instead of
+ * the start of the transfer.  This starting point is regularly moved as
+ * transfer goes on, to keep getting accurate values (instead of average over
+ * the entire transfer).
+ *
+ * This function takes the current amount of data transferred, the amount at
+ * the starting point, the limit (in bytes/s), the time of the starting point
+ * and the current time.
+ *
+ * Returns 0 if no waiting is needed or when no waiting is needed but the
+ * starting point should be reset (to current); or the number of milliseconds
+ * to wait to get back under the speed limit.
+ */
+timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
+                                  curl_off_t startsize,
+                                  curl_off_t limit,
+                                  struct curltime start,
+                                  struct curltime now)
+{
+  curl_off_t size = cursize - startsize;
+  timediff_t minimum;
+  timediff_t actual;
+
+  if(!limit || !size)
+    return 0;
+
+  /*
+   * 'minimum' is the number of milliseconds 'size' should take to download to
+   * stay below 'limit'.
+   */
+  if(size < CURL_OFF_T_MAX/1000)
+    minimum = (timediff_t) (CURL_OFF_T_C(1000) * size / limit);
+  else {
+    minimum = (timediff_t) (size / limit);
+    if(minimum < TIMEDIFF_T_MAX/1000)
+      minimum *= 1000;
+    else
+      minimum = TIMEDIFF_T_MAX;
+  }
+
+  /*
+   * 'actual' is the time in milliseconds it took to actually download the
+   * last 'size' bytes.
+   */
+  actual = Curl_timediff_ceil(now, start);
+  if(actual < minimum) {
+    /* if it downloaded the data faster than the limit, make it wait the
+       difference */
+    return (minimum - actual);
+  }
+
+  return 0;
+}
+
+/*
+ * Set the number of downloaded bytes so far.
+ */
+CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
+{
+  data->progress.downloaded = size;
+  return CURLE_OK;
+}
+
+/*
+ * Update the timestamp and sizestamp to use for rate limit calculations.
+ */
+void Curl_ratelimit(struct Curl_easy *data, struct curltime now)
+{
+  /* don't set a new stamp unless the time since last update is long enough */
+  if(data->set.max_recv_speed) {
+    if(Curl_timediff(now, data->progress.dl_limit_start) >=
+       MIN_RATE_LIMIT_PERIOD) {
+      data->progress.dl_limit_start = now;
+      data->progress.dl_limit_size = data->progress.downloaded;
+    }
+  }
+  if(data->set.max_send_speed) {
+    if(Curl_timediff(now, data->progress.ul_limit_start) >=
+       MIN_RATE_LIMIT_PERIOD) {
+      data->progress.ul_limit_start = now;
+      data->progress.ul_limit_size = data->progress.uploaded;
+    }
+  }
+}
+
+/*
+ * Set the number of uploaded bytes so far.
+ */
+void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size)
+{
+  data->progress.uploaded = size;
+}
+
+void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size)
+{
+  if(size >= 0) {
+    data->progress.size_dl = size;
+    data->progress.flags |= PGRS_DL_SIZE_KNOWN;
+  }
+  else {
+    data->progress.size_dl = 0;
+    data->progress.flags &= ~PGRS_DL_SIZE_KNOWN;
+  }
+}
+
+void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
+{
+  if(size >= 0) {
+    data->progress.size_ul = size;
+    data->progress.flags |= PGRS_UL_SIZE_KNOWN;
+  }
+  else {
+    data->progress.size_ul = 0;
+    data->progress.flags &= ~PGRS_UL_SIZE_KNOWN;
+  }
+}
+
+/* returns the average speed in bytes / second */
+static curl_off_t trspeed(curl_off_t size, /* number of bytes */
+                          curl_off_t us)   /* microseconds */
+{
+  if(us < 1)
+    return size * 1000000;
+  else if(size < CURL_OFF_T_MAX/1000000)
+    return (size * 1000000) / us;
+  else if(us >= 1000000)
+    return size / (us / 1000000);
+  else
+    return CURL_OFF_T_MAX;
+}
+
+/* returns TRUE if it's time to show the progress meter */
+static bool progress_calc(struct Curl_easy *data, struct curltime now)
+{
+  bool timetoshow = FALSE;
+  struct Progress * const p = &data->progress;
+
+  /* The time spent so far (from the start) in microseconds */
+  p->timespent = Curl_timediff_us(now, p->start);
+  p->dlspeed = trspeed(p->downloaded, p->timespent);
+  p->ulspeed = trspeed(p->uploaded, p->timespent);
+
+  /* Calculations done at most once a second, unless end is reached */
+  if(p->lastshow != now.tv_sec) {
+    int countindex; /* amount of seconds stored in the speeder array */
+    int nowindex = p->speeder_c% CURR_TIME;
+    p->lastshow = now.tv_sec;
+    timetoshow = TRUE;
+
+    /* Let's do the "current speed" thing, with the dl + ul speeds
+       combined. Store the speed at entry 'nowindex'. */
+    p->speeder[ nowindex ] = p->downloaded + p->uploaded;
+
+    /* remember the exact time for this moment */
+    p->speeder_time [ nowindex ] = now;
+
+    /* advance our speeder_c counter, which is increased every time we get
+       here and we expect it to never wrap as 2^32 is a lot of seconds! */
+    p->speeder_c++;
+
+    /* figure out how many index entries of data we have stored in our speeder
+       array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
+       transfer. Imagine, after one second we have filled in two entries,
+       after two seconds we've filled in three entries etc. */
+    countindex = ((p->speeder_c >= CURR_TIME)? CURR_TIME:p->speeder_c) - 1;
+
+    /* first of all, we don't do this if there's no counted seconds yet */
+    if(countindex) {
+      int checkindex;
+      timediff_t span_ms;
+      curl_off_t amount;
+
+      /* Get the index position to compare with the 'nowindex' position.
+         Get the oldest entry possible. While we have less than CURR_TIME
+         entries, the first entry will remain the oldest. */
+      checkindex = (p->speeder_c >= CURR_TIME)? p->speeder_c%CURR_TIME:0;
+
+      /* Figure out the exact time for the time span */
+      span_ms = Curl_timediff(now, p->speeder_time[checkindex]);
+      if(0 == span_ms)
+        span_ms = 1; /* at least one millisecond MUST have passed */
+
+      /* Calculate the average speed the last 'span_ms' milliseconds */
+      amount = p->speeder[nowindex]- p->speeder[checkindex];
+
+      if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */)
+        /* the 'amount' value is bigger than would fit in 32 bits if
+           multiplied with 1000, so we use the double math for this */
+        p->current_speed = (curl_off_t)
+          ((double)amount/((double)span_ms/1000.0));
+      else
+        /* the 'amount' value is small enough to fit within 32 bits even
+           when multiplied with 1000 */
+        p->current_speed = amount*CURL_OFF_T_C(1000)/span_ms;
+    }
+    else
+      /* the first second we use the average */
+      p->current_speed = p->ulspeed + p->dlspeed;
+
+  } /* Calculations end */
+  return timetoshow;
+}
+
+#ifndef CURL_DISABLE_PROGRESS_METER
+static void progress_meter(struct Curl_easy *data)
+{
+  char max5[6][10];
+  curl_off_t dlpercen = 0;
+  curl_off_t ulpercen = 0;
+  curl_off_t total_percen = 0;
+  curl_off_t total_transfer;
+  curl_off_t total_expected_transfer;
+  char time_left[10];
+  char time_total[10];
+  char time_spent[10];
+  curl_off_t ulestimate = 0;
+  curl_off_t dlestimate = 0;
+  curl_off_t total_estimate;
+  curl_off_t timespent =
+    (curl_off_t)data->progress.timespent/1000000; /* seconds */
+
+  if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
+    if(data->state.resume_from) {
+      fprintf(data->set.err,
+              "** Resuming transfer from byte position %"
+              CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
+    }
+    fprintf(data->set.err,
+            "  %% Total    %% Received %% Xferd  Average Speed   "
+            "Time    Time     Time  Current\n"
+            "                                 Dload  Upload   "
+            "Total   Spent    Left  Speed\n");
+    data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
+  }
+
+  /* Figure out the estimated time of arrival for the upload */
+  if((data->progress.flags & PGRS_UL_SIZE_KNOWN) &&
+     (data->progress.ulspeed > CURL_OFF_T_C(0))) {
+    ulestimate = data->progress.size_ul / data->progress.ulspeed;
+
+    if(data->progress.size_ul > CURL_OFF_T_C(10000))
+      ulpercen = data->progress.uploaded /
+        (data->progress.size_ul/CURL_OFF_T_C(100));
+    else if(data->progress.size_ul > CURL_OFF_T_C(0))
+      ulpercen = (data->progress.uploaded*100) /
+        data->progress.size_ul;
+  }
+
+  /* ... and the download */
+  if((data->progress.flags & PGRS_DL_SIZE_KNOWN) &&
+     (data->progress.dlspeed > CURL_OFF_T_C(0))) {
+    dlestimate = data->progress.size_dl / data->progress.dlspeed;
+
+    if(data->progress.size_dl > CURL_OFF_T_C(10000))
+      dlpercen = data->progress.downloaded /
+        (data->progress.size_dl/CURL_OFF_T_C(100));
+    else if(data->progress.size_dl > CURL_OFF_T_C(0))
+      dlpercen = (data->progress.downloaded*100) /
+        data->progress.size_dl;
+  }
+
+  /* Now figure out which of them is slower and use that one for the
+     total estimate! */
+  total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
+
+  /* create the three time strings */
+  time2str(time_left, total_estimate > 0?(total_estimate - timespent):0);
+  time2str(time_total, total_estimate);
+  time2str(time_spent, timespent);
+
+  /* Get the total amount of data expected to get transferred */
+  total_expected_transfer =
+    ((data->progress.flags & PGRS_UL_SIZE_KNOWN)?
+     data->progress.size_ul:data->progress.uploaded)+
+    ((data->progress.flags & PGRS_DL_SIZE_KNOWN)?
+     data->progress.size_dl:data->progress.downloaded);
+
+  /* We have transferred this much so far */
+  total_transfer = data->progress.downloaded + data->progress.uploaded;
+
+  /* Get the percentage of data transferred so far */
+  if(total_expected_transfer > CURL_OFF_T_C(10000))
+    total_percen = total_transfer /
+      (total_expected_transfer/CURL_OFF_T_C(100));
+  else if(total_expected_transfer > CURL_OFF_T_C(0))
+    total_percen = (total_transfer*100) / total_expected_transfer;
+
+  fprintf(data->set.err,
+          "\r"
+          "%3" CURL_FORMAT_CURL_OFF_T " %s  "
+          "%3" CURL_FORMAT_CURL_OFF_T " %s  "
+          "%3" CURL_FORMAT_CURL_OFF_T " %s  %s  %s %s %s %s %s",
+          total_percen,  /* 3 letters */                /* total % */
+          max5data(total_expected_transfer, max5[2]),   /* total size */
+          dlpercen,      /* 3 letters */                /* rcvd % */
+          max5data(data->progress.downloaded, max5[0]), /* rcvd size */
+          ulpercen,      /* 3 letters */                /* xfer % */
+          max5data(data->progress.uploaded, max5[1]),   /* xfer size */
+          max5data(data->progress.dlspeed, max5[3]),    /* avrg dl speed */
+          max5data(data->progress.ulspeed, max5[4]),    /* avrg ul speed */
+          time_total,    /* 8 letters */                /* total time */
+          time_spent,    /* 8 letters */                /* time spent */
+          time_left,     /* 8 letters */                /* time left */
+          max5data(data->progress.current_speed, max5[5])
+    );
+
+  /* we flush the output stream to make it appear as soon as possible */
+  fflush(data->set.err);
+}
+#else
+ /* progress bar disabled */
+#define progress_meter(x) Curl_nop_stmt
+#endif
+
+
+/*
+ * Curl_pgrsUpdate() returns 0 for success or the value returned by the
+ * progress callback!
+ */
+int Curl_pgrsUpdate(struct Curl_easy *data)
+{
+  struct curltime now = Curl_now(); /* what time is it */
+  bool showprogress = progress_calc(data, now);
+  if(!(data->progress.flags & PGRS_HIDE)) {
+    if(data->set.fxferinfo) {
+      int result;
+      /* There's a callback set, call that */
+      Curl_set_in_callback(data, true);
+      result = data->set.fxferinfo(data->set.progress_client,
+                                   data->progress.size_dl,
+                                   data->progress.downloaded,
+                                   data->progress.size_ul,
+                                   data->progress.uploaded);
+      Curl_set_in_callback(data, false);
+      if(result != CURL_PROGRESSFUNC_CONTINUE) {
+        if(result)
+          failf(data, "Callback aborted");
+        return result;
+      }
+    }
+    else if(data->set.fprogress) {
+      int result;
+      /* The older deprecated callback is set, call that */
+      Curl_set_in_callback(data, true);
+      result = data->set.fprogress(data->set.progress_client,
+                                   (double)data->progress.size_dl,
+                                   (double)data->progress.downloaded,
+                                   (double)data->progress.size_ul,
+                                   (double)data->progress.uploaded);
+      Curl_set_in_callback(data, false);
+      if(result != CURL_PROGRESSFUNC_CONTINUE) {
+        if(result)
+          failf(data, "Callback aborted");
+        return result;
+      }
+    }
+
+    if(showprogress)
+      progress_meter(data);
+  }
+
+  return 0;
+}
Index: trunk/src/libs/curl-8.7.1/lib/progress.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/progress.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/progress.h	(revision 104083)
@@ -0,0 +1,77 @@
+#ifndef HEADER_CURL_PROGRESS_H
+#define HEADER_CURL_PROGRESS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "timeval.h"
+
+
+typedef enum {
+  TIMER_NONE,
+  TIMER_STARTOP,
+  TIMER_STARTSINGLE, /* start of transfer, might get queued */
+  TIMER_POSTQUEUE,   /* start, immediately after dequeue */
+  TIMER_NAMELOOKUP,
+  TIMER_CONNECT,
+  TIMER_APPCONNECT,
+  TIMER_PRETRANSFER,
+  TIMER_STARTTRANSFER,
+  TIMER_POSTRANSFER,
+  TIMER_STARTACCEPT,
+  TIMER_REDIRECT,
+  TIMER_LAST /* must be last */
+} timerid;
+
+int Curl_pgrsDone(struct Curl_easy *data);
+void Curl_pgrsStartNow(struct Curl_easy *data);
+void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size);
+void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size);
+
+/* It is fine to not check the return code if 'size' is set to 0 */
+CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size);
+
+void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
+void Curl_ratelimit(struct Curl_easy *data, struct curltime now);
+int Curl_pgrsUpdate(struct Curl_easy *data);
+void Curl_pgrsResetTransferSizes(struct Curl_easy *data);
+struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer);
+timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
+                                  curl_off_t startsize,
+                                  curl_off_t limit,
+                                  struct curltime start,
+                                  struct curltime now);
+/**
+ * Update progress timer with the elapsed time from its start to `timestamp`.
+ * This allows updating timers later and is used by happy eyeballing, where
+ * we only want to record the winner's times.
+ */
+void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
+                      struct curltime timestamp);
+
+#define PGRS_HIDE    (1<<4)
+#define PGRS_UL_SIZE_KNOWN (1<<5)
+#define PGRS_DL_SIZE_KNOWN (1<<6)
+#define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */
+
+#endif /* HEADER_CURL_PROGRESS_H */
Index: trunk/src/libs/curl-8.7.1/lib/psl.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/psl.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/psl.c	(revision 104083)
@@ -0,0 +1,113 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#ifdef USE_LIBPSL
+
+#include "psl.h"
+#include "share.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+void Curl_psl_destroy(struct PslCache *pslcache)
+{
+  if(pslcache->psl) {
+    if(pslcache->dynamic)
+      psl_free((psl_ctx_t *) pslcache->psl);
+    pslcache->psl = NULL;
+    pslcache->dynamic = FALSE;
+  }
+}
+
+static time_t now_seconds(void)
+{
+  struct curltime now = Curl_now();
+
+  return now.tv_sec;
+}
+
+const psl_ctx_t *Curl_psl_use(struct Curl_easy *easy)
+{
+  struct PslCache *pslcache = easy->psl;
+  const psl_ctx_t *psl;
+  time_t now;
+
+  if(!pslcache)
+    return NULL;
+
+  Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SHARED);
+  now = now_seconds();
+  if(!pslcache->psl || pslcache->expires <= now) {
+    /* Let a chance to other threads to do the job: avoids deadlock. */
+    Curl_share_unlock(easy, CURL_LOCK_DATA_PSL);
+
+    /* Update cache: this needs an exclusive lock. */
+    Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SINGLE);
+
+    /* Recheck in case another thread did the job. */
+    now = now_seconds();
+    if(!pslcache->psl || pslcache->expires <= now) {
+      bool dynamic = FALSE;
+      time_t expires = TIME_T_MAX;
+
+#if defined(PSL_VERSION_NUMBER) && PSL_VERSION_NUMBER >= 0x001000
+      psl = psl_latest(NULL);
+      dynamic = psl != NULL;
+      /* Take care of possible time computation overflow. */
+      expires = now < TIME_T_MAX - PSL_TTL? now + PSL_TTL: TIME_T_MAX;
+
+      /* Only get the built-in PSL if we do not already have the "latest". */
+      if(!psl && !pslcache->dynamic)
+#endif
+
+        psl = psl_builtin();
+
+      if(psl) {
+        Curl_psl_destroy(pslcache);
+        pslcache->psl = psl;
+        pslcache->dynamic = dynamic;
+        pslcache->expires = expires;
+      }
+    }
+    Curl_share_unlock(easy, CURL_LOCK_DATA_PSL);  /* Release exclusive lock. */
+    Curl_share_lock(easy, CURL_LOCK_DATA_PSL, CURL_LOCK_ACCESS_SHARED);
+  }
+  psl = pslcache->psl;
+  if(!psl)
+    Curl_share_unlock(easy, CURL_LOCK_DATA_PSL);
+  return psl;
+}
+
+void Curl_psl_release(struct Curl_easy *easy)
+{
+  Curl_share_unlock(easy, CURL_LOCK_DATA_PSL);
+}
+
+#endif /* USE_LIBPSL */
Index: trunk/src/libs/curl-8.7.1/lib/psl.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/psl.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/psl.h	(revision 104083)
@@ -0,0 +1,49 @@
+#ifndef HEADER_PSL_H
+#define HEADER_PSL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifdef USE_LIBPSL
+#include <libpsl.h>
+
+#define PSL_TTL (72 * 3600)     /* PSL time to live before a refresh. */
+
+struct PslCache {
+  const psl_ctx_t *psl; /* The PSL. */
+  time_t expires; /* Time this PSL life expires. */
+  bool dynamic; /* PSL should be released when no longer needed. */
+};
+
+const psl_ctx_t *Curl_psl_use(struct Curl_easy *easy);
+void Curl_psl_release(struct Curl_easy *easy);
+void Curl_psl_destroy(struct PslCache *pslcache);
+
+#else
+
+#define Curl_psl_use(easy) NULL
+#define Curl_psl_release(easy)
+#define Curl_psl_destroy(pslcache)
+
+#endif /* USE_LIBPSL */
+#endif /* HEADER_PSL_H */
Index: trunk/src/libs/curl-8.7.1/lib/rand.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/rand.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/rand.c	(revision 104083)
@@ -0,0 +1,291 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <limits.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "vtls/vtls.h"
+#include "sendf.h"
+#include "timeval.h"
+#include "rand.h"
+#include "escape.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef _WIN32
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
+#  define HAVE_WIN_BCRYPTGENRANDOM
+#  include <bcrypt.h>
+#  ifdef _MSC_VER
+#    pragma comment(lib, "bcrypt.lib")
+#  endif
+#  ifndef BCRYPT_USE_SYSTEM_PREFERRED_RNG
+#  define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002
+#  endif
+#  ifndef STATUS_SUCCESS
+#  define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
+#  endif
+#elif defined(USE_WIN32_CRYPTO)
+#  include <wincrypt.h>
+#  ifdef _MSC_VER
+#    pragma comment(lib, "advapi32.lib")
+#  endif
+#endif
+
+CURLcode Curl_win32_random(unsigned char *entropy, size_t length)
+{
+  memset(entropy, 0, length);
+
+#if defined(HAVE_WIN_BCRYPTGENRANDOM)
+  if(BCryptGenRandom(NULL, entropy, (ULONG)length,
+                     BCRYPT_USE_SYSTEM_PREFERRED_RNG) != STATUS_SUCCESS)
+    return CURLE_FAILED_INIT;
+
+  return CURLE_OK;
+#elif defined(USE_WIN32_CRYPTO)
+  {
+    HCRYPTPROV hCryptProv = 0;
+
+    if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
+                            CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+      return CURLE_FAILED_INIT;
+
+    if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
+      CryptReleaseContext(hCryptProv, 0UL);
+      return CURLE_FAILED_INIT;
+    }
+
+    CryptReleaseContext(hCryptProv, 0UL);
+  }
+  return CURLE_OK;
+#else
+  return CURLE_NOT_BUILT_IN;
+#endif
+}
+#endif
+
+static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
+{
+  CURLcode result = CURLE_OK;
+  static unsigned int randseed;
+  static bool seeded = FALSE;
+
+#ifdef CURLDEBUG
+  char *force_entropy = getenv("CURL_ENTROPY");
+  if(force_entropy) {
+    if(!seeded) {
+      unsigned int seed = 0;
+      size_t elen = strlen(force_entropy);
+      size_t clen = sizeof(seed);
+      size_t min = elen < clen ? elen : clen;
+      memcpy((char *)&seed, force_entropy, min);
+      randseed = ntohl(seed);
+      seeded = TRUE;
+    }
+    else
+      randseed++;
+    *rnd = randseed;
+    return CURLE_OK;
+  }
+#endif
+
+  /* data may be NULL! */
+  result = Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd));
+  if(result != CURLE_NOT_BUILT_IN)
+    /* only if there is no random function in the TLS backend do the non crypto
+       version, otherwise return result */
+    return result;
+
+  /* ---- non-cryptographic version following ---- */
+
+#ifdef _WIN32
+  if(!seeded) {
+    result = Curl_win32_random((unsigned char *)rnd, sizeof(*rnd));
+    if(result != CURLE_NOT_BUILT_IN)
+      return result;
+  }
+#endif
+
+#if defined(HAVE_ARC4RANDOM) && !defined(USE_OPENSSL)
+  if(!seeded) {
+    *rnd = (unsigned int)arc4random();
+    return CURLE_OK;
+  }
+#endif
+
+#if defined(RANDOM_FILE) && !defined(_WIN32)
+  if(!seeded) {
+    /* if there's a random file to read a seed from, use it */
+    int fd = open(RANDOM_FILE, O_RDONLY);
+    if(fd > -1) {
+      /* read random data into the randseed variable */
+      ssize_t nread = read(fd, &randseed, sizeof(randseed));
+      if(nread == sizeof(randseed))
+        seeded = TRUE;
+      close(fd);
+    }
+  }
+#endif
+
+  if(!seeded) {
+    struct curltime now = Curl_now();
+    infof(data, "WARNING: using weak random seed");
+    randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
+    randseed = randseed * 1103515245 + 12345;
+    randseed = randseed * 1103515245 + 12345;
+    randseed = randseed * 1103515245 + 12345;
+    seeded = TRUE;
+  }
+
+  {
+    unsigned int r;
+    /* Return an unsigned 32-bit pseudo-random number. */
+    r = randseed = randseed * 1103515245 + 12345;
+    *rnd = (r << 16) | ((r >> 16) & 0xFFFF);
+  }
+  return CURLE_OK;
+}
+
+/*
+ * Curl_rand() stores 'num' number of random unsigned characters in the buffer
+ * 'rnd' points to.
+ *
+ * If libcurl is built without TLS support or with a TLS backend that lacks a
+ * proper random API (rustls or mbedTLS), this function will use "weak"
+ * random.
+ *
+ * When built *with* TLS support and a backend that offers strong random, it
+ * will return error if it cannot provide strong random values.
+ *
+ * NOTE: 'data' may be passed in as NULL when coming from external API without
+ * easy handle!
+ *
+ */
+
+CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num)
+{
+  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
+
+  DEBUGASSERT(num);
+
+  while(num) {
+    unsigned int r;
+    size_t left = num < sizeof(unsigned int) ? num : sizeof(unsigned int);
+
+    result = randit(data, &r);
+    if(result)
+      return result;
+
+    while(left) {
+      *rnd++ = (unsigned char)(r & 0xFF);
+      r >>= 8;
+      --num;
+      --left;
+    }
+  }
+
+  return result;
+}
+
+/*
+ * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random
+ * hexadecimal digits PLUS a null-terminating byte. It must be an odd number
+ * size.
+ */
+
+CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
+                       size_t num)
+{
+  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
+  unsigned char buffer[128];
+  DEBUGASSERT(num > 1);
+
+#ifdef __clang_analyzer__
+  /* This silences a scan-build warning about accessing this buffer with
+     uninitialized memory. */
+  memset(buffer, 0, sizeof(buffer));
+#endif
+
+  if((num/2 >= sizeof(buffer)) || !(num&1)) {
+    /* make sure it fits in the local buffer and that it is an odd number! */
+    DEBUGF(infof(data, "invalid buffer size with Curl_rand_hex"));
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
+  num--; /* save one for null-termination */
+
+  result = Curl_rand(data, buffer, num/2);
+  if(result)
+    return result;
+
+  Curl_hexencode(buffer, num/2, rnd, num + 1);
+  return result;
+}
+
+/*
+ * Curl_rand_alnum() fills the 'rnd' buffer with a given 'num' size with random
+ * alphanumerical chars PLUS a null-terminating byte.
+ */
+
+static const char alnum[] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd,
+                         size_t num)
+{
+  CURLcode result = CURLE_OK;
+  const int alnumspace = sizeof(alnum) - 1;
+  unsigned int r;
+  DEBUGASSERT(num > 1);
+
+  num--; /* save one for null-termination */
+
+  while(num) {
+    do {
+      result = randit(data, &r);
+      if(result)
+        return result;
+    } while(r >= (UINT_MAX - UINT_MAX % alnumspace));
+
+    *rnd++ = alnum[r % alnumspace];
+    num--;
+  }
+  *rnd = 0;
+
+  return result;
+}
Index: trunk/src/libs/curl-8.7.1/lib/rand.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/rand.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/rand.h	(revision 104083)
@@ -0,0 +1,50 @@
+#ifndef HEADER_CURL_RAND_H
+#define HEADER_CURL_RAND_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num);
+
+/*
+ * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random
+ * hexadecimal digits PLUS a null-terminating byte. It must be an odd number
+ * size.
+ */
+CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
+                       size_t num);
+
+/*
+ * Curl_rand_alnum() fills the 'rnd' buffer with a given 'num' size with random
+ * alphanumerical chars PLUS a null-terminating byte.
+ */
+CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd,
+                         size_t num);
+
+#ifdef _WIN32
+/* Random generator shared between the Schannel vtls and Curl_rand*()
+   functions */
+CURLcode Curl_win32_random(unsigned char *entropy, size_t length);
+#endif
+
+#endif /* HEADER_CURL_RAND_H */
Index: trunk/src/libs/curl-8.7.1/lib/rename.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/rename.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/rename.c	(revision 104083)
@@ -0,0 +1,73 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "rename.h"
+
+#include "curl_setup.h"
+
+#if (!defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_COOKIES)) || \
+  !defined(CURL_DISABLE_ALTSVC)
+
+#include "curl_multibyte.h"
+#include "timeval.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* return 0 on success, 1 on error */
+int Curl_rename(const char *oldpath, const char *newpath)
+{
+#ifdef _WIN32
+  /* rename() on Windows doesn't overwrite, so we can't use it here.
+     MoveFileEx() will overwrite and is usually atomic, however it fails
+     when there are open handles to the file. */
+  const int max_wait_ms = 1000;
+  struct curltime start = Curl_now();
+  TCHAR *tchar_oldpath = curlx_convert_UTF8_to_tchar((char *)oldpath);
+  TCHAR *tchar_newpath = curlx_convert_UTF8_to_tchar((char *)newpath);
+  for(;;) {
+    timediff_t diff;
+    if(MoveFileEx(tchar_oldpath, tchar_newpath, MOVEFILE_REPLACE_EXISTING)) {
+      curlx_unicodefree(tchar_oldpath);
+      curlx_unicodefree(tchar_newpath);
+      break;
+    }
+    diff = Curl_timediff(Curl_now(), start);
+    if(diff < 0 || diff > max_wait_ms) {
+      curlx_unicodefree(tchar_oldpath);
+      curlx_unicodefree(tchar_newpath);
+      return 1;
+    }
+    Sleep(1);
+  }
+#else
+  if(rename(oldpath, newpath))
+    return 1;
+#endif
+  return 0;
+}
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/rename.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/rename.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/rename.h	(revision 104083)
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_RENAME_H
+#define HEADER_CURL_RENAME_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+int Curl_rename(const char *oldpath, const char *newpath);
+
+#endif /* HEADER_CURL_RENAME_H */
Index: trunk/src/libs/curl-8.7.1/lib/rtsp.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/rtsp.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/rtsp.c	(revision 104083)
@@ -0,0 +1,1039 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_RTSP) && !defined(USE_HYPER)
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "multiif.h"
+#include "http.h"
+#include "url.h"
+#include "progress.h"
+#include "rtsp.h"
+#include "strcase.h"
+#include "select.h"
+#include "connect.h"
+#include "cfilters.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define RTP_PKT_LENGTH(p) ((((unsigned int)((unsigned char)((p)[2]))) << 8) | \
+                            ((unsigned int)((unsigned char)((p)[3]))))
+
+/* protocol-specific functions set up to be called by the main engine */
+static CURLcode rtsp_do(struct Curl_easy *data, bool *done);
+static CURLcode rtsp_done(struct Curl_easy *data, CURLcode, bool premature);
+static CURLcode rtsp_connect(struct Curl_easy *data, bool *done);
+static CURLcode rtsp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
+static int rtsp_getsock_do(struct Curl_easy *data,
+                           struct connectdata *conn, curl_socket_t *socks);
+
+/*
+ * Parse and write out an RTSP response.
+ * @param data     the transfer
+ * @param conn     the connection
+ * @param buf      data read from connection
+ * @param blen     amount of data in buf
+ * @param is_eos   TRUE iff this is the last write
+ * @param readmore out, TRUE iff complete buf was consumed and more data
+ *                 is needed
+ */
+static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
+                                    const char *buf,
+                                    size_t blen,
+                                    bool is_eos);
+
+static CURLcode rtsp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static unsigned int rtsp_conncheck(struct Curl_easy *data,
+                                   struct connectdata *check,
+                                   unsigned int checks_to_perform);
+
+/* this returns the socket to wait for in the DO and DOING state for the multi
+   interface and then we're always _sending_ a request and thus we wait for
+   the single socket to become writable only */
+static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
+                           curl_socket_t *socks)
+{
+  /* write mode */
+  (void)data;
+  socks[0] = conn->sock[FIRSTSOCKET];
+  return GETSOCK_WRITESOCK(0);
+}
+
+static
+CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len);
+static
+CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport);
+
+
+/*
+ * RTSP handler interface.
+ */
+const struct Curl_handler Curl_handler_rtsp = {
+  "RTSP",                               /* scheme */
+  rtsp_setup_connection,                /* setup_connection */
+  rtsp_do,                              /* do_it */
+  rtsp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  rtsp_connect,                         /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  rtsp_getsock_do,                      /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  rtsp_disconnect,                      /* disconnect */
+  rtsp_rtp_write_resp,                  /* write_resp */
+  rtsp_conncheck,                       /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_RTSP,                            /* defport */
+  CURLPROTO_RTSP,                       /* protocol */
+  CURLPROTO_RTSP,                       /* family */
+  PROTOPT_NONE                          /* flags */
+};
+
+#define MAX_RTP_BUFFERSIZE 1000000 /* arbitrary */
+
+static CURLcode rtsp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  struct RTSP *rtsp;
+  (void)conn;
+
+  data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP));
+  if(!rtsp)
+    return CURLE_OUT_OF_MEMORY;
+
+  Curl_dyn_init(&conn->proto.rtspc.buf, MAX_RTP_BUFFERSIZE);
+  return CURLE_OK;
+}
+
+
+/*
+ * Function to check on various aspects of a connection.
+ */
+static unsigned int rtsp_conncheck(struct Curl_easy *data,
+                                   struct connectdata *conn,
+                                   unsigned int checks_to_perform)
+{
+  unsigned int ret_val = CONNRESULT_NONE;
+  (void)data;
+
+  if(checks_to_perform & CONNCHECK_ISDEAD) {
+    bool input_pending;
+    if(!Curl_conn_is_alive(data, conn, &input_pending))
+      ret_val |= CONNRESULT_DEAD;
+  }
+
+  return ret_val;
+}
+
+
+static CURLcode rtsp_connect(struct Curl_easy *data, bool *done)
+{
+  CURLcode httpStatus;
+
+  httpStatus = Curl_http_connect(data, done);
+
+  /* Initialize the CSeq if not already done */
+  if(data->state.rtsp_next_client_CSeq == 0)
+    data->state.rtsp_next_client_CSeq = 1;
+  if(data->state.rtsp_next_server_CSeq == 0)
+    data->state.rtsp_next_server_CSeq = 1;
+
+  data->conn->proto.rtspc.rtp_channel = -1;
+
+  return httpStatus;
+}
+
+static CURLcode rtsp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead)
+{
+  (void) dead;
+  (void) data;
+  Curl_dyn_free(&conn->proto.rtspc.buf);
+  return CURLE_OK;
+}
+
+
+static CURLcode rtsp_done(struct Curl_easy *data,
+                          CURLcode status, bool premature)
+{
+  struct RTSP *rtsp = data->req.p.rtsp;
+  CURLcode httpStatus;
+
+  /* Bypass HTTP empty-reply checks on receive */
+  if(data->set.rtspreq == RTSPREQ_RECEIVE)
+    premature = TRUE;
+
+  httpStatus = Curl_http_done(data, status, premature);
+
+  if(rtsp && !status && !httpStatus) {
+    /* Check the sequence numbers */
+    long CSeq_sent = rtsp->CSeq_sent;
+    long CSeq_recv = rtsp->CSeq_recv;
+    if((data->set.rtspreq != RTSPREQ_RECEIVE) && (CSeq_sent != CSeq_recv)) {
+      failf(data,
+            "The CSeq of this request %ld did not match the response %ld",
+            CSeq_sent, CSeq_recv);
+      return CURLE_RTSP_CSEQ_ERROR;
+    }
+    if(data->set.rtspreq == RTSPREQ_RECEIVE &&
+       (data->conn->proto.rtspc.rtp_channel == -1)) {
+      infof(data, "Got an RTP Receive with a CSeq of %ld", CSeq_recv);
+    }
+  }
+
+  return httpStatus;
+}
+
+static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  CURLcode result = CURLE_OK;
+  Curl_RtspReq rtspreq = data->set.rtspreq;
+  struct RTSP *rtsp = data->req.p.rtsp;
+  struct dynbuf req_buffer;
+
+  const char *p_request = NULL;
+  const char *p_session_id = NULL;
+  const char *p_accept = NULL;
+  const char *p_accept_encoding = NULL;
+  const char *p_range = NULL;
+  const char *p_referrer = NULL;
+  const char *p_stream_uri = NULL;
+  const char *p_transport = NULL;
+  const char *p_uagent = NULL;
+  const char *p_proxyuserpwd = NULL;
+  const char *p_userpwd = NULL;
+
+  *done = TRUE;
+  /* Initialize a dynamic send buffer */
+  Curl_dyn_init(&req_buffer, DYN_RTSP_REQ_HEADER);
+
+  rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq;
+  rtsp->CSeq_recv = 0;
+
+  /* Setup the first_* fields to allow auth details get sent
+     to this origin */
+
+  if(!data->state.first_host) {
+    data->state.first_host = strdup(conn->host.name);
+    if(!data->state.first_host)
+      return CURLE_OUT_OF_MEMORY;
+
+    data->state.first_remote_port = conn->remote_port;
+    data->state.first_remote_protocol = conn->handler->protocol;
+  }
+
+  /* Setup the 'p_request' pointer to the proper p_request string
+   * Since all RTSP requests are included here, there is no need to
+   * support custom requests like HTTP.
+   **/
+  data->req.no_body = TRUE; /* most requests don't contain a body */
+  switch(rtspreq) {
+  default:
+    failf(data, "Got invalid RTSP request");
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  case RTSPREQ_OPTIONS:
+    p_request = "OPTIONS";
+    break;
+  case RTSPREQ_DESCRIBE:
+    p_request = "DESCRIBE";
+    data->req.no_body = FALSE;
+    break;
+  case RTSPREQ_ANNOUNCE:
+    p_request = "ANNOUNCE";
+    break;
+  case RTSPREQ_SETUP:
+    p_request = "SETUP";
+    break;
+  case RTSPREQ_PLAY:
+    p_request = "PLAY";
+    break;
+  case RTSPREQ_PAUSE:
+    p_request = "PAUSE";
+    break;
+  case RTSPREQ_TEARDOWN:
+    p_request = "TEARDOWN";
+    break;
+  case RTSPREQ_GET_PARAMETER:
+    /* GET_PARAMETER's no_body status is determined later */
+    p_request = "GET_PARAMETER";
+    data->req.no_body = FALSE;
+    break;
+  case RTSPREQ_SET_PARAMETER:
+    p_request = "SET_PARAMETER";
+    break;
+  case RTSPREQ_RECORD:
+    p_request = "RECORD";
+    break;
+  case RTSPREQ_RECEIVE:
+    p_request = "";
+    /* Treat interleaved RTP as body */
+    data->req.no_body = FALSE;
+    break;
+  case RTSPREQ_LAST:
+    failf(data, "Got invalid RTSP request: RTSPREQ_LAST");
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
+  if(rtspreq == RTSPREQ_RECEIVE) {
+    Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, -1);
+    goto out;
+  }
+
+  p_session_id = data->set.str[STRING_RTSP_SESSION_ID];
+  if(!p_session_id &&
+     (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) {
+    failf(data, "Refusing to issue an RTSP request [%s] without a session ID.",
+          p_request);
+    result = CURLE_BAD_FUNCTION_ARGUMENT;
+    goto out;
+  }
+
+  /* Stream URI. Default to server '*' if not specified */
+  if(data->set.str[STRING_RTSP_STREAM_URI]) {
+    p_stream_uri = data->set.str[STRING_RTSP_STREAM_URI];
+  }
+  else {
+    p_stream_uri = "*";
+  }
+
+  /* Transport Header for SETUP requests */
+  p_transport = Curl_checkheaders(data, STRCONST("Transport"));
+  if(rtspreq == RTSPREQ_SETUP && !p_transport) {
+    /* New Transport: setting? */
+    if(data->set.str[STRING_RTSP_TRANSPORT]) {
+      Curl_safefree(data->state.aptr.rtsp_transport);
+
+      data->state.aptr.rtsp_transport =
+        aprintf("Transport: %s\r\n",
+                data->set.str[STRING_RTSP_TRANSPORT]);
+      if(!data->state.aptr.rtsp_transport)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    else {
+      failf(data,
+            "Refusing to issue an RTSP SETUP without a Transport: header.");
+      result = CURLE_BAD_FUNCTION_ARGUMENT;
+      goto out;
+    }
+
+    p_transport = data->state.aptr.rtsp_transport;
+  }
+
+  /* Accept Headers for DESCRIBE requests */
+  if(rtspreq == RTSPREQ_DESCRIBE) {
+    /* Accept Header */
+    p_accept = Curl_checkheaders(data, STRCONST("Accept"))?
+      NULL:"Accept: application/sdp\r\n";
+
+    /* Accept-Encoding header */
+    if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
+       data->set.str[STRING_ENCODING]) {
+      Curl_safefree(data->state.aptr.accept_encoding);
+      data->state.aptr.accept_encoding =
+        aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
+
+      if(!data->state.aptr.accept_encoding) {
+        result = CURLE_OUT_OF_MEMORY;
+        goto out;
+      }
+      p_accept_encoding = data->state.aptr.accept_encoding;
+    }
+  }
+
+  /* The User-Agent string might have been allocated in url.c already, because
+     it might have been used in the proxy connect, but if we have got a header
+     with the user-agent string specified, we erase the previously made string
+     here. */
+  if(Curl_checkheaders(data, STRCONST("User-Agent")) &&
+     data->state.aptr.uagent) {
+    Curl_safefree(data->state.aptr.uagent);
+  }
+  else if(!Curl_checkheaders(data, STRCONST("User-Agent")) &&
+          data->set.str[STRING_USERAGENT]) {
+    p_uagent = data->state.aptr.uagent;
+  }
+
+  /* setup the authentication headers */
+  result = Curl_http_output_auth(data, conn, p_request, HTTPREQ_GET,
+                                 p_stream_uri, FALSE);
+  if(result)
+    goto out;
+
+  p_proxyuserpwd = data->state.aptr.proxyuserpwd;
+  p_userpwd = data->state.aptr.userpwd;
+
+  /* Referrer */
+  Curl_safefree(data->state.aptr.ref);
+  if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer")))
+    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
+
+  p_referrer = data->state.aptr.ref;
+
+  /*
+   * Range Header
+   * Only applies to PLAY, PAUSE, RECORD
+   *
+   * Go ahead and use the Range stuff supplied for HTTP
+   */
+  if(data->state.use_range &&
+     (rtspreq  & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) {
+
+    /* Check to see if there is a range set in the custom headers */
+    if(!Curl_checkheaders(data, STRCONST("Range")) && data->state.range) {
+      Curl_safefree(data->state.aptr.rangeline);
+      data->state.aptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
+      p_range = data->state.aptr.rangeline;
+    }
+  }
+
+  /*
+   * Sanity check the custom headers
+   */
+  if(Curl_checkheaders(data, STRCONST("CSeq"))) {
+    failf(data, "CSeq cannot be set as a custom header.");
+    result = CURLE_RTSP_CSEQ_ERROR;
+    goto out;
+  }
+  if(Curl_checkheaders(data, STRCONST("Session"))) {
+    failf(data, "Session ID cannot be set as a custom header.");
+    result = CURLE_BAD_FUNCTION_ARGUMENT;
+    goto out;
+  }
+
+  result =
+    Curl_dyn_addf(&req_buffer,
+                  "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */
+                  "CSeq: %ld\r\n", /* CSeq */
+                  p_request, p_stream_uri, rtsp->CSeq_sent);
+  if(result)
+    goto out;
+
+  /*
+   * Rather than do a normal alloc line, keep the session_id unformatted
+   * to make comparison easier
+   */
+  if(p_session_id) {
+    result = Curl_dyn_addf(&req_buffer, "Session: %s\r\n", p_session_id);
+    if(result)
+      goto out;
+  }
+
+  /*
+   * Shared HTTP-like options
+   */
+  result = Curl_dyn_addf(&req_buffer,
+                         "%s" /* transport */
+                         "%s" /* accept */
+                         "%s" /* accept-encoding */
+                         "%s" /* range */
+                         "%s" /* referrer */
+                         "%s" /* user-agent */
+                         "%s" /* proxyuserpwd */
+                         "%s" /* userpwd */
+                         ,
+                         p_transport ? p_transport : "",
+                         p_accept ? p_accept : "",
+                         p_accept_encoding ? p_accept_encoding : "",
+                         p_range ? p_range : "",
+                         p_referrer ? p_referrer : "",
+                         p_uagent ? p_uagent : "",
+                         p_proxyuserpwd ? p_proxyuserpwd : "",
+                         p_userpwd ? p_userpwd : "");
+
+  /*
+   * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM
+   * with basic and digest, it will be freed anyway by the next request
+   */
+  Curl_safefree(data->state.aptr.userpwd);
+
+  if(result)
+    goto out;
+
+  if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) {
+    result = Curl_add_timecondition(data, &req_buffer);
+    if(result)
+      goto out;
+  }
+
+  result = Curl_add_custom_headers(data, FALSE, &req_buffer);
+  if(result)
+    goto out;
+
+  if(rtspreq == RTSPREQ_ANNOUNCE ||
+     rtspreq == RTSPREQ_SET_PARAMETER ||
+     rtspreq == RTSPREQ_GET_PARAMETER) {
+    curl_off_t req_clen; /* request content length */
+
+    if(data->state.upload) {
+      req_clen = data->state.infilesize;
+      data->state.httpreq = HTTPREQ_PUT;
+      result = Curl_creader_set_fread(data, req_clen);
+      if(result)
+        goto out;
+    }
+    else {
+      if(data->set.postfields) {
+        size_t plen = strlen(data->set.postfields);
+        req_clen = (curl_off_t)plen;
+        result = Curl_creader_set_buf(data, data->set.postfields, plen);
+      }
+      else if(data->state.infilesize >= 0) {
+        req_clen = data->state.infilesize;
+        result = Curl_creader_set_fread(data, req_clen);
+      }
+      else {
+        req_clen = 0;
+        result = Curl_creader_set_null(data);
+      }
+      if(result)
+        goto out;
+    }
+
+    if(req_clen > 0) {
+      /* As stated in the http comments, it is probably not wise to
+       * actually set a custom Content-Length in the headers */
+      if(!Curl_checkheaders(data, STRCONST("Content-Length"))) {
+        result =
+          Curl_dyn_addf(&req_buffer,
+                        "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
+                        req_clen);
+        if(result)
+          goto out;
+      }
+
+      if(rtspreq == RTSPREQ_SET_PARAMETER ||
+         rtspreq == RTSPREQ_GET_PARAMETER) {
+        if(!Curl_checkheaders(data, STRCONST("Content-Type"))) {
+          result = Curl_dyn_addn(&req_buffer,
+                                 STRCONST("Content-Type: "
+                                          "text/parameters\r\n"));
+          if(result)
+            goto out;
+        }
+      }
+
+      if(rtspreq == RTSPREQ_ANNOUNCE) {
+        if(!Curl_checkheaders(data, STRCONST("Content-Type"))) {
+          result = Curl_dyn_addn(&req_buffer,
+                                 STRCONST("Content-Type: "
+                                          "application/sdp\r\n"));
+          if(result)
+            goto out;
+        }
+      }
+    }
+    else if(rtspreq == RTSPREQ_GET_PARAMETER) {
+      /* Check for an empty GET_PARAMETER (heartbeat) request */
+      data->state.httpreq = HTTPREQ_HEAD;
+      data->req.no_body = TRUE;
+    }
+  }
+  else {
+    result = Curl_creader_set_null(data);
+    if(result)
+      goto out;
+  }
+
+  /* Finish the request buffer */
+  result = Curl_dyn_addn(&req_buffer, STRCONST("\r\n"));
+  if(result)
+    goto out;
+
+  Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
+
+  /* issue the request */
+  result = Curl_req_send(data, &req_buffer);
+  if(result) {
+    failf(data, "Failed sending RTSP request");
+    goto out;
+  }
+
+  /* Increment the CSeq on success */
+  data->state.rtsp_next_client_CSeq++;
+
+  if(data->req.writebytecount) {
+    /* if a request-body has been sent off, we make sure this progress is
+       noted properly */
+    Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
+    if(Curl_pgrsUpdate(data))
+      result = CURLE_ABORTED_BY_CALLBACK;
+  }
+out:
+  Curl_dyn_free(&req_buffer);
+  return result;
+}
+
+/**
+ * write any BODY bytes missing to the client, ignore the rest.
+ */
+static CURLcode rtp_write_body_junk(struct Curl_easy *data,
+                                    const char *buf,
+                                    size_t blen)
+{
+  struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
+  curl_off_t body_remain;
+  bool in_body;
+
+  in_body = (data->req.headerline && !rtspc->in_header) &&
+            (data->req.size >= 0) &&
+            (data->req.bytecount < data->req.size);
+  body_remain = in_body? (data->req.size - data->req.bytecount) : 0;
+  DEBUGASSERT(body_remain >= 0);
+  if(body_remain) {
+    if((curl_off_t)blen > body_remain)
+      blen = (size_t)body_remain;
+    return Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen);
+  }
+  return CURLE_OK;
+}
+
+static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
+                                     const char *buf,
+                                     size_t blen,
+                                     size_t *pconsumed)
+{
+  struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
+  CURLcode result = CURLE_OK;
+  size_t skip_len = 0;
+
+  *pconsumed = 0;
+  while(blen) {
+    bool in_body = (data->req.headerline && !rtspc->in_header) &&
+                   (data->req.size >= 0) &&
+                   (data->req.bytecount < data->req.size);
+    switch(rtspc->state) {
+
+    case RTP_PARSE_SKIP: {
+      DEBUGASSERT(Curl_dyn_len(&rtspc->buf) == 0);
+      while(blen && buf[0] != '$') {
+        if(!in_body && buf[0] == 'R' &&
+           data->set.rtspreq != RTSPREQ_RECEIVE) {
+          if(strncmp(buf, "RTSP/", (blen < 5) ? blen : 5) == 0) {
+            /* This could be the next response, no consume and return */
+            if(*pconsumed) {
+              DEBUGF(infof(data, "RTP rtsp_filter_rtp[SKIP] RTSP/ prefix, "
+                           "skipping %zd bytes of junk", *pconsumed));
+            }
+            rtspc->state = RTP_PARSE_SKIP;
+            rtspc->in_header = TRUE;
+            goto out;
+          }
+        }
+        /* junk/BODY, consume without buffering */
+        *pconsumed += 1;
+        ++buf;
+        --blen;
+        ++skip_len;
+      }
+      if(blen && buf[0] == '$') {
+        /* possible start of an RTP message, buffer */
+        if(skip_len) {
+          /* end of junk/BODY bytes, flush */
+          result = rtp_write_body_junk(data,
+                                       (char *)(buf - skip_len), skip_len);
+          skip_len = 0;
+          if(result)
+            goto out;
+        }
+        if(Curl_dyn_addn(&rtspc->buf, buf, 1)) {
+          result = CURLE_OUT_OF_MEMORY;
+          goto out;
+        }
+        *pconsumed += 1;
+        ++buf;
+        --blen;
+        rtspc->state = RTP_PARSE_CHANNEL;
+      }
+      break;
+    }
+
+    case RTP_PARSE_CHANNEL: {
+      int idx = ((unsigned char)buf[0]) / 8;
+      int off = ((unsigned char)buf[0]) % 8;
+      DEBUGASSERT(Curl_dyn_len(&rtspc->buf) == 1);
+      if(!(data->state.rtp_channel_mask[idx] & (1 << off))) {
+        /* invalid channel number, junk or BODY data */
+        rtspc->state = RTP_PARSE_SKIP;
+        DEBUGASSERT(skip_len == 0);
+        /* we do not consume this byte, it is BODY data */
+        DEBUGF(infof(data, "RTSP: invalid RTP channel %d, skipping", idx));
+        if(*pconsumed == 0) {
+          /* We did not consume the initial '$' in our buffer, but had
+           * it from an earlier call. We cannot un-consume it and have
+           * to write it directly as BODY data */
+          result = rtp_write_body_junk(data, Curl_dyn_ptr(&rtspc->buf), 1);
+          if(result)
+            goto out;
+        }
+        else {
+          /* count the '$' as skip and continue */
+          skip_len = 1;
+        }
+        Curl_dyn_free(&rtspc->buf);
+        break;
+      }
+      /* a valid channel, so we expect this to be a real RTP message */
+      rtspc->rtp_channel = (unsigned char)buf[0];
+      if(Curl_dyn_addn(&rtspc->buf, buf, 1)) {
+        result = CURLE_OUT_OF_MEMORY;
+        goto out;
+      }
+      *pconsumed += 1;
+      ++buf;
+      --blen;
+      rtspc->state = RTP_PARSE_LEN;
+      break;
+    }
+
+    case RTP_PARSE_LEN: {
+      size_t rtp_len = Curl_dyn_len(&rtspc->buf);
+      const char *rtp_buf;
+      DEBUGASSERT(rtp_len >= 2 && rtp_len < 4);
+      if(Curl_dyn_addn(&rtspc->buf, buf, 1)) {
+        result = CURLE_OUT_OF_MEMORY;
+        goto out;
+      }
+      *pconsumed += 1;
+      ++buf;
+      --blen;
+      if(rtp_len == 2)
+        break;
+      rtp_buf = Curl_dyn_ptr(&rtspc->buf);
+      rtspc->rtp_len = RTP_PKT_LENGTH(rtp_buf) + 4;
+      rtspc->state = RTP_PARSE_DATA;
+      break;
+    }
+
+    case RTP_PARSE_DATA: {
+      size_t rtp_len = Curl_dyn_len(&rtspc->buf);
+      size_t needed;
+      DEBUGASSERT(rtp_len < rtspc->rtp_len);
+      needed = rtspc->rtp_len - rtp_len;
+      if(needed <= blen) {
+        if(Curl_dyn_addn(&rtspc->buf, buf, needed)) {
+          result = CURLE_OUT_OF_MEMORY;
+          goto out;
+        }
+        *pconsumed += needed;
+        buf += needed;
+        blen -= needed;
+        /* complete RTP message in buffer */
+        DEBUGF(infof(data, "RTP write channel %d rtp_len %zu",
+                     rtspc->rtp_channel, rtspc->rtp_len));
+        result = rtp_client_write(data, Curl_dyn_ptr(&rtspc->buf),
+                                  rtspc->rtp_len);
+        Curl_dyn_free(&rtspc->buf);
+        rtspc->state = RTP_PARSE_SKIP;
+        if(result)
+          goto out;
+      }
+      else {
+        if(Curl_dyn_addn(&rtspc->buf, buf, blen)) {
+          result = CURLE_OUT_OF_MEMORY;
+          goto out;
+        }
+        *pconsumed += blen;
+        buf += blen;
+        blen = 0;
+      }
+      break;
+    }
+
+    default:
+      DEBUGASSERT(0);
+      return CURLE_RECV_ERROR;
+    }
+  }
+out:
+  if(!result && skip_len)
+    result = rtp_write_body_junk(data, (char *)(buf - skip_len), skip_len);
+  return result;
+}
+
+static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
+                                    const char *buf,
+                                    size_t blen,
+                                    bool is_eos)
+{
+  struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
+  CURLcode result = CURLE_OK;
+  size_t consumed = 0;
+
+  if(!data->req.header)
+    rtspc->in_header = FALSE;
+  if(!blen) {
+    goto out;
+  }
+
+  DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, eos=%d)",
+               blen, rtspc->in_header, is_eos));
+
+  /* If header parsing is not onging, extract RTP messages */
+  if(!rtspc->in_header) {
+    result = rtsp_filter_rtp(data, buf, blen, &consumed);
+    if(result)
+      goto out;
+    buf += consumed;
+    blen -= consumed;
+    /* either we consumed all or are at the start of header parsing */
+    if(blen && !data->req.header)
+      DEBUGF(infof(data, "RTSP: %zu bytes, possibly excess in response body",
+                   blen));
+  }
+
+  /* we want to parse headers, do so */
+  if(data->req.header && blen) {
+    rtspc->in_header = TRUE;
+    result = Curl_http_write_resp_hds(data, buf, blen, &consumed);
+    if(result)
+      goto out;
+
+    buf += consumed;
+    blen -= consumed;
+
+    if(!data->req.header)
+      rtspc->in_header = FALSE;
+
+    if(!rtspc->in_header) {
+      /* If header parsing is done, extract interleaved RTP messages */
+      if(data->req.size <= -1) {
+        /* Respect section 4.4 of rfc2326: If the Content-Length header is
+           absent, a length 0 must be assumed. */
+        data->req.size = 0;
+        data->req.download_done = TRUE;
+      }
+      result = rtsp_filter_rtp(data, buf, blen, &consumed);
+      if(result)
+        goto out;
+      blen -= consumed;
+    }
+  }
+
+  if(rtspc->state != RTP_PARSE_SKIP)
+    data->req.done = FALSE;
+  /* we SHOULD have consumed all bytes, unless the response is borked.
+   * In which case we write out the left over bytes, letting the client
+   * writer deal with it (it will report EXCESS and fail the transfer). */
+  DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, done=%d "
+               " rtspc->state=%d, req.size=%" CURL_FORMAT_CURL_OFF_T ")",
+               blen, rtspc->in_header, data->req.done, rtspc->state,
+               data->req.size));
+  if(!result && (is_eos || blen)) {
+    result = Curl_client_write(data, CLIENTWRITE_BODY|
+                               (is_eos? CLIENTWRITE_EOS:0),
+                               (char *)buf, blen);
+  }
+
+out:
+  if((data->set.rtspreq == RTSPREQ_RECEIVE) &&
+     (rtspc->state == RTP_PARSE_SKIP)) {
+    /* In special mode RECEIVE, we just process one chunk of network
+     * data, so we stop the transfer here, if we have no incomplete
+     * RTP message pending. */
+    data->req.download_done = TRUE;
+  }
+  return result;
+}
+
+static
+CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len)
+{
+  size_t wrote;
+  curl_write_callback writeit;
+  void *user_ptr;
+
+  if(len == 0) {
+    failf(data, "Cannot write a 0 size RTP packet.");
+    return CURLE_WRITE_ERROR;
+  }
+
+  /* If the user has configured CURLOPT_INTERLEAVEFUNCTION then use that
+     function and any configured CURLOPT_INTERLEAVEDATA to write out the RTP
+     data. Otherwise, use the CURLOPT_WRITEFUNCTION with the CURLOPT_WRITEDATA
+     pointer to write out the RTP data. */
+  if(data->set.fwrite_rtp) {
+    writeit = data->set.fwrite_rtp;
+    user_ptr = data->set.rtp_out;
+  }
+  else {
+    writeit = data->set.fwrite_func;
+    user_ptr = data->set.out;
+  }
+
+  Curl_set_in_callback(data, true);
+  wrote = writeit((char *)ptr, 1, len, user_ptr);
+  Curl_set_in_callback(data, false);
+
+  if(CURL_WRITEFUNC_PAUSE == wrote) {
+    failf(data, "Cannot pause RTP");
+    return CURLE_WRITE_ERROR;
+  }
+
+  if(wrote != len) {
+    failf(data, "Failed writing RTP data");
+    return CURLE_WRITE_ERROR;
+  }
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
+{
+  if(checkprefix("CSeq:", header)) {
+    long CSeq = 0;
+    char *endp;
+    char *p = &header[5];
+    while(ISBLANK(*p))
+      p++;
+    CSeq = strtol(p, &endp, 10);
+    if(p != endp) {
+      struct RTSP *rtsp = data->req.p.rtsp;
+      rtsp->CSeq_recv = CSeq; /* mark the request */
+      data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
+    }
+    else {
+      failf(data, "Unable to read the CSeq header: [%s]", header);
+      return CURLE_RTSP_CSEQ_ERROR;
+    }
+  }
+  else if(checkprefix("Session:", header)) {
+    char *start;
+    char *end;
+    size_t idlen;
+
+    /* Find the first non-space letter */
+    start = header + 8;
+    while(*start && ISBLANK(*start))
+      start++;
+
+    if(!*start) {
+      failf(data, "Got a blank Session ID");
+      return CURLE_RTSP_SESSION_ERROR;
+    }
+
+    /* Find the end of Session ID
+     *
+     * Allow any non whitespace content, up to the field separator or end of
+     * line. RFC 2326 isn't 100% clear on the session ID and for example
+     * gstreamer does url-encoded session ID's not covered by the standard.
+     */
+    end = start;
+    while(*end && *end != ';' && !ISSPACE(*end))
+      end++;
+    idlen = end - start;
+
+    if(data->set.str[STRING_RTSP_SESSION_ID]) {
+
+      /* If the Session ID is set, then compare */
+      if(strlen(data->set.str[STRING_RTSP_SESSION_ID]) != idlen ||
+         strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], idlen)) {
+        failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]",
+              start, data->set.str[STRING_RTSP_SESSION_ID]);
+        return CURLE_RTSP_SESSION_ERROR;
+      }
+    }
+    else {
+      /* If the Session ID is not set, and we find it in a response, then set
+       * it.
+       */
+
+      /* Copy the id substring into a new buffer */
+      data->set.str[STRING_RTSP_SESSION_ID] = Curl_memdup0(start, idlen);
+      if(!data->set.str[STRING_RTSP_SESSION_ID])
+        return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  else if(checkprefix("Transport:", header)) {
+    CURLcode result;
+    result = rtsp_parse_transport(data, header + 10);
+    if(result)
+      return result;
+  }
+  return CURLE_OK;
+}
+
+static
+CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport)
+{
+  /* If we receive multiple Transport response-headers, the linterleaved
+     channels of each response header is recorded and used together for
+     subsequent data validity checks.*/
+  /* e.g.: ' RTP/AVP/TCP;unicast;interleaved=5-6' */
+  char *start;
+  char *end;
+  start = transport;
+  while(start && *start) {
+    while(*start && ISBLANK(*start) )
+      start++;
+    end = strchr(start, ';');
+    if(checkprefix("interleaved=", start)) {
+      long chan1, chan2, chan;
+      char *endp;
+      char *p = start + 12;
+      chan1 = strtol(p, &endp, 10);
+      if(p != endp && chan1 >= 0 && chan1 <= 255) {
+        unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;
+        chan2 = chan1;
+        if(*endp == '-') {
+          p = endp + 1;
+          chan2 = strtol(p, &endp, 10);
+          if(p == endp || chan2 < 0 || chan2 > 255) {
+            infof(data, "Unable to read the interleaved parameter from "
+                  "Transport header: [%s]", transport);
+            chan2 = chan1;
+          }
+        }
+        for(chan = chan1; chan <= chan2; chan++) {
+          long idx = chan / 8;
+          long off = chan % 8;
+          rtp_channel_mask[idx] |= (unsigned char)(1 << off);
+        }
+      }
+      else {
+        infof(data, "Unable to read the interleaved parameter from "
+              "Transport header: [%s]", transport);
+      }
+      break;
+    }
+    /* skip to next parameter */
+    start = (!end) ? end : (end + 1);
+  }
+  return CURLE_OK;
+}
+
+
+#endif /* CURL_DISABLE_RTSP or using Hyper */
Index: trunk/src/libs/curl-8.7.1/lib/rtsp.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/rtsp.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/rtsp.h	(revision 104083)
@@ -0,0 +1,80 @@
+#ifndef HEADER_CURL_RTSP_H
+#define HEADER_CURL_RTSP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#ifdef USE_HYPER
+#define CURL_DISABLE_RTSP 1
+#endif
+
+#ifndef CURL_DISABLE_RTSP
+
+extern const struct Curl_handler Curl_handler_rtsp;
+
+CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header);
+
+#else
+/* disabled */
+#define Curl_rtsp_parseheader(x,y) CURLE_NOT_BUILT_IN
+
+#endif /* CURL_DISABLE_RTSP */
+
+typedef enum {
+  RTP_PARSE_SKIP,
+  RTP_PARSE_CHANNEL,
+  RTP_PARSE_LEN,
+  RTP_PARSE_DATA
+} rtp_parse_st;
+/*
+ * RTSP Connection data
+ *
+ * Currently, only used for tracking incomplete RTP data reads
+ */
+struct rtsp_conn {
+  struct dynbuf buf;
+  int rtp_channel;
+  size_t rtp_len;
+  rtp_parse_st state;
+  BIT(in_header);
+};
+
+/****************************************************************************
+ * RTSP unique setup
+ ***************************************************************************/
+struct RTSP {
+  /*
+   * http_wrapper MUST be the first element of this structure for the wrap
+   * logic to work. In this way, we get a cheap polymorphism because
+   * &(data->state.proto.rtsp) == &(data->state.proto.http) per the C spec
+   *
+   * HTTP functions can safely treat this as an HTTP struct, but RTSP aware
+   * functions can also index into the later elements.
+   */
+  struct HTTP http_wrapper; /* wrap HTTP to do the heavy lifting */
+
+  long CSeq_sent; /* CSeq of this request */
+  long CSeq_recv; /* CSeq received */
+};
+
+
+#endif /* HEADER_CURL_RTSP_H */
Index: trunk/src/libs/curl-8.7.1/lib/select.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/select.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/select.c	(revision 104083)
@@ -0,0 +1,403 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <limits.h>
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#elif defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
+#error "We can't compile without select() or poll() support."
+#endif
+
+#ifdef MSDOS
+#include <dos.h>  /* delay() */
+#endif
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "connect.h"
+#include "select.h"
+#include "timediff.h"
+#include "warnless.h"
+
+/*
+ * Internal function used for waiting a specific amount of ms
+ * in Curl_socket_check() and Curl_poll() when no file descriptor
+ * is provided to wait on, just being used to delay execution.
+ * WinSock select() and poll() timeout mechanisms need a valid
+ * socket descriptor in a not null file descriptor set to work.
+ * Waiting indefinitely with this function is not allowed, a
+ * zero or negative timeout value will return immediately.
+ * Timeout resolution, accuracy, as well as maximum supported
+ * value is system dependent, neither factor is a critical issue
+ * for the intended use of this function in the library.
+ *
+ * Return values:
+ *   -1 = system call error, or invalid timeout value
+ *    0 = specified timeout has elapsed, or interrupted
+ */
+int Curl_wait_ms(timediff_t timeout_ms)
+{
+  int r = 0;
+
+  if(!timeout_ms)
+    return 0;
+  if(timeout_ms < 0) {
+    SET_SOCKERRNO(EINVAL);
+    return -1;
+  }
+#if defined(MSDOS)
+  delay(timeout_ms);
+#elif defined(_WIN32)
+  /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */
+#if TIMEDIFF_T_MAX >= ULONG_MAX
+  if(timeout_ms >= ULONG_MAX)
+    timeout_ms = ULONG_MAX-1;
+    /* don't use ULONG_MAX, because that is equal to INFINITE */
+#endif
+  Sleep((ULONG)timeout_ms);
+#else
+#if defined(HAVE_POLL_FINE)
+  /* prevent overflow, timeout_ms is typecast to int. */
+#if TIMEDIFF_T_MAX > INT_MAX
+  if(timeout_ms > INT_MAX)
+    timeout_ms = INT_MAX;
+#endif
+  r = poll(NULL, 0, (int)timeout_ms);
+#else
+  {
+    struct timeval pending_tv;
+    r = select(0, NULL, NULL, NULL, curlx_mstotv(&pending_tv, timeout_ms));
+  }
+#endif /* HAVE_POLL_FINE */
+#endif /* USE_WINSOCK */
+  if(r) {
+    if((r == -1) && (SOCKERRNO == EINTR))
+      /* make EINTR from select or poll not a "lethal" error */
+      r = 0;
+    else
+      r = -1;
+  }
+  return r;
+}
+
+#ifndef HAVE_POLL_FINE
+/*
+ * This is a wrapper around select() to aid in Windows compatibility.
+ * A negative timeout value makes this function wait indefinitely,
+ * unless no valid file descriptor is given, when this happens the
+ * negative timeout is ignored and the function times out immediately.
+ *
+ * Return values:
+ *   -1 = system call error or fd >= FD_SETSIZE
+ *    0 = timeout
+ *    N = number of signalled file descriptors
+ */
+static int our_select(curl_socket_t maxfd,   /* highest socket number */
+                      fd_set *fds_read,      /* sockets ready for reading */
+                      fd_set *fds_write,     /* sockets ready for writing */
+                      fd_set *fds_err,       /* sockets with errors */
+                      timediff_t timeout_ms) /* milliseconds to wait */
+{
+  struct timeval pending_tv;
+  struct timeval *ptimeout;
+
+#ifdef USE_WINSOCK
+  /* WinSock select() can't handle zero events.  See the comment below. */
+  if((!fds_read || fds_read->fd_count == 0) &&
+     (!fds_write || fds_write->fd_count == 0) &&
+     (!fds_err || fds_err->fd_count == 0)) {
+    /* no sockets, just wait */
+    return Curl_wait_ms(timeout_ms);
+  }
+#endif
+
+  ptimeout = curlx_mstotv(&pending_tv, timeout_ms);
+
+#ifdef USE_WINSOCK
+  /* WinSock select() must not be called with an fd_set that contains zero
+    fd flags, or it will return WSAEINVAL.  But, it also can't be called
+    with no fd_sets at all!  From the documentation:
+
+    Any two of the parameters, readfds, writefds, or exceptfds, can be
+    given as null. At least one must be non-null, and any non-null
+    descriptor set must contain at least one handle to a socket.
+
+    It is unclear why WinSock doesn't just handle this for us instead of
+    calling this an error. Luckily, with WinSock, we can _also_ ask how
+    many bits are set on an fd_set. So, let's just check it beforehand.
+  */
+  return select((int)maxfd + 1,
+                fds_read && fds_read->fd_count ? fds_read : NULL,
+                fds_write && fds_write->fd_count ? fds_write : NULL,
+                fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout);
+#else
+  return select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout);
+#endif
+}
+
+#endif
+
+/*
+ * Wait for read or write events on a set of file descriptors. It uses poll()
+ * when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
+ * otherwise select() is used.  An error is returned if select() is being used
+ * and a file descriptor is too large for FD_SETSIZE.
+ *
+ * A negative timeout value makes this function wait indefinitely,
+ * unless no valid file descriptor is given, when this happens the
+ * negative timeout is ignored and the function times out immediately.
+ *
+ * Return values:
+ *   -1 = system call error or fd >= FD_SETSIZE
+ *    0 = timeout
+ *    [bitmask] = action as described below
+ *
+ * CURL_CSELECT_IN - first socket is readable
+ * CURL_CSELECT_IN2 - second socket is readable
+ * CURL_CSELECT_OUT - write socket is writable
+ * CURL_CSELECT_ERR - an error condition occurred
+ */
+int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
+                      curl_socket_t readfd1,
+                      curl_socket_t writefd, /* socket to write to */
+                      timediff_t timeout_ms) /* milliseconds to wait */
+{
+  struct pollfd pfd[3];
+  int num;
+  int r;
+
+  if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
+     (writefd == CURL_SOCKET_BAD)) {
+    /* no sockets, just wait */
+    return Curl_wait_ms(timeout_ms);
+  }
+
+  /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
+     time in this function does not need to be measured. This happens
+     when function is called with a zero timeout or a negative timeout
+     value indicating a blocking call should be performed. */
+
+  num = 0;
+  if(readfd0 != CURL_SOCKET_BAD) {
+    pfd[num].fd = readfd0;
+    pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
+    pfd[num].revents = 0;
+    num++;
+  }
+  if(readfd1 != CURL_SOCKET_BAD) {
+    pfd[num].fd = readfd1;
+    pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
+    pfd[num].revents = 0;
+    num++;
+  }
+  if(writefd != CURL_SOCKET_BAD) {
+    pfd[num].fd = writefd;
+    pfd[num].events = POLLWRNORM|POLLOUT|POLLPRI;
+    pfd[num].revents = 0;
+    num++;
+  }
+
+  r = Curl_poll(pfd, num, timeout_ms);
+  if(r <= 0)
+    return r;
+
+  r = 0;
+  num = 0;
+  if(readfd0 != CURL_SOCKET_BAD) {
+    if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
+      r |= CURL_CSELECT_IN;
+    if(pfd[num].revents & (POLLPRI|POLLNVAL))
+      r |= CURL_CSELECT_ERR;
+    num++;
+  }
+  if(readfd1 != CURL_SOCKET_BAD) {
+    if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
+      r |= CURL_CSELECT_IN2;
+    if(pfd[num].revents & (POLLPRI|POLLNVAL))
+      r |= CURL_CSELECT_ERR;
+    num++;
+  }
+  if(writefd != CURL_SOCKET_BAD) {
+    if(pfd[num].revents & (POLLWRNORM|POLLOUT))
+      r |= CURL_CSELECT_OUT;
+    if(pfd[num].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL))
+      r |= CURL_CSELECT_ERR;
+  }
+
+  return r;
+}
+
+/*
+ * This is a wrapper around poll().  If poll() does not exist, then
+ * select() is used instead.  An error is returned if select() is
+ * being used and a file descriptor is too large for FD_SETSIZE.
+ * A negative timeout value makes this function wait indefinitely,
+ * unless no valid file descriptor is given, when this happens the
+ * negative timeout is ignored and the function times out immediately.
+ *
+ * Return values:
+ *   -1 = system call error or fd >= FD_SETSIZE
+ *    0 = timeout
+ *    N = number of structures with non zero revent fields
+ */
+int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
+{
+#ifdef HAVE_POLL_FINE
+  int pending_ms;
+#else
+  fd_set fds_read;
+  fd_set fds_write;
+  fd_set fds_err;
+  curl_socket_t maxfd;
+#endif
+  bool fds_none = TRUE;
+  unsigned int i;
+  int r;
+
+  if(ufds) {
+    for(i = 0; i < nfds; i++) {
+      if(ufds[i].fd != CURL_SOCKET_BAD) {
+        fds_none = FALSE;
+        break;
+      }
+    }
+  }
+  if(fds_none) {
+    /* no sockets, just wait */
+    return Curl_wait_ms(timeout_ms);
+  }
+
+  /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
+     time in this function does not need to be measured. This happens
+     when function is called with a zero timeout or a negative timeout
+     value indicating a blocking call should be performed. */
+
+#ifdef HAVE_POLL_FINE
+
+  /* prevent overflow, timeout_ms is typecast to int. */
+#if TIMEDIFF_T_MAX > INT_MAX
+  if(timeout_ms > INT_MAX)
+    timeout_ms = INT_MAX;
+#endif
+  if(timeout_ms > 0)
+    pending_ms = (int)timeout_ms;
+  else if(timeout_ms < 0)
+    pending_ms = -1;
+  else
+    pending_ms = 0;
+  r = poll(ufds, nfds, pending_ms);
+  if(r <= 0) {
+    if((r == -1) && (SOCKERRNO == EINTR))
+      /* make EINTR from select or poll not a "lethal" error */
+      r = 0;
+    return r;
+  }
+
+  for(i = 0; i < nfds; i++) {
+    if(ufds[i].fd == CURL_SOCKET_BAD)
+      continue;
+    if(ufds[i].revents & POLLHUP)
+      ufds[i].revents |= POLLIN;
+    if(ufds[i].revents & POLLERR)
+      ufds[i].revents |= POLLIN|POLLOUT;
+  }
+
+#else  /* HAVE_POLL_FINE */
+
+  FD_ZERO(&fds_read);
+  FD_ZERO(&fds_write);
+  FD_ZERO(&fds_err);
+  maxfd = (curl_socket_t)-1;
+
+  for(i = 0; i < nfds; i++) {
+    ufds[i].revents = 0;
+    if(ufds[i].fd == CURL_SOCKET_BAD)
+      continue;
+    VERIFY_SOCK(ufds[i].fd);
+    if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI|
+                         POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
+      if(ufds[i].fd > maxfd)
+        maxfd = ufds[i].fd;
+      if(ufds[i].events & (POLLRDNORM|POLLIN))
+        FD_SET(ufds[i].fd, &fds_read);
+      if(ufds[i].events & (POLLWRNORM|POLLOUT))
+        FD_SET(ufds[i].fd, &fds_write);
+      if(ufds[i].events & (POLLRDBAND|POLLPRI))
+        FD_SET(ufds[i].fd, &fds_err);
+    }
+  }
+
+  /*
+     Note also that WinSock ignores the first argument, so we don't worry
+     about the fact that maxfd is computed incorrectly with WinSock (since
+     curl_socket_t is unsigned in such cases and thus -1 is the largest
+     value).
+  */
+  r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
+  if(r <= 0) {
+    if((r == -1) && (SOCKERRNO == EINTR))
+      /* make EINTR from select or poll not a "lethal" error */
+      r = 0;
+    return r;
+  }
+
+  r = 0;
+  for(i = 0; i < nfds; i++) {
+    ufds[i].revents = 0;
+    if(ufds[i].fd == CURL_SOCKET_BAD)
+      continue;
+    if(FD_ISSET(ufds[i].fd, &fds_read)) {
+      if(ufds[i].events & POLLRDNORM)
+        ufds[i].revents |= POLLRDNORM;
+      if(ufds[i].events & POLLIN)
+        ufds[i].revents |= POLLIN;
+    }
+    if(FD_ISSET(ufds[i].fd, &fds_write)) {
+      if(ufds[i].events & POLLWRNORM)
+        ufds[i].revents |= POLLWRNORM;
+      if(ufds[i].events & POLLOUT)
+        ufds[i].revents |= POLLOUT;
+    }
+    if(FD_ISSET(ufds[i].fd, &fds_err)) {
+      if(ufds[i].events & POLLRDBAND)
+        ufds[i].revents |= POLLRDBAND;
+      if(ufds[i].events & POLLPRI)
+        ufds[i].revents |= POLLPRI;
+    }
+    if(ufds[i].revents)
+      r++;
+  }
+
+#endif  /* HAVE_POLL_FINE */
+
+  return r;
+}
Index: trunk/src/libs/curl-8.7.1/lib/select.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/select.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/select.h	(revision 104083)
@@ -0,0 +1,114 @@
+#ifndef HEADER_CURL_SELECT_H
+#define HEADER_CURL_SELECT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#elif defined(HAVE_SYS_POLL_H)
+#include <sys/poll.h>
+#endif
+
+/*
+ * Definition of pollfd struct and constants for platforms lacking them.
+ */
+
+#if !defined(HAVE_SYS_POLL_H) && \
+    !defined(HAVE_POLL_H) && \
+    !defined(POLLIN)
+
+#define POLLIN      0x01
+#define POLLPRI     0x02
+#define POLLOUT     0x04
+#define POLLERR     0x08
+#define POLLHUP     0x10
+#define POLLNVAL    0x20
+
+struct pollfd
+{
+    curl_socket_t fd;
+    short   events;
+    short   revents;
+};
+
+#endif
+
+#ifndef POLLRDNORM
+#define POLLRDNORM POLLIN
+#endif
+
+#ifndef POLLWRNORM
+#define POLLWRNORM POLLOUT
+#endif
+
+#ifndef POLLRDBAND
+#define POLLRDBAND POLLPRI
+#endif
+
+/* there are three CSELECT defines that are defined in the public header that
+   are exposed to users, but this *IN2 bit is only ever used internally and
+   therefore defined here */
+#define CURL_CSELECT_IN2 (CURL_CSELECT_ERR << 1)
+
+int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2,
+                      curl_socket_t writefd,
+                      timediff_t timeout_ms);
+#define SOCKET_READABLE(x,z) \
+  Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, z)
+#define SOCKET_WRITABLE(x,z) \
+  Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, z)
+
+int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms);
+int Curl_wait_ms(timediff_t timeout_ms);
+
+/*
+   With Winsock the valid range is [0..INVALID_SOCKET-1] according to
+   https://docs.microsoft.com/en-us/windows/win32/winsock/socket-data-type-2
+*/
+#ifdef USE_WINSOCK
+#define VALID_SOCK(s) ((s) < INVALID_SOCKET)
+#define FDSET_SOCK(x) 1
+#define VERIFY_SOCK(x) do { \
+  if(!VALID_SOCK(x)) { \
+    SET_SOCKERRNO(WSAEINVAL); \
+    return -1; \
+  } \
+} while(0)
+#else
+#define VALID_SOCK(s) ((s) >= 0)
+
+/* If the socket is small enough to get set or read from an fdset */
+#define FDSET_SOCK(s) ((s) < FD_SETSIZE)
+
+#define VERIFY_SOCK(x) do {                     \
+    if(!VALID_SOCK(x) || !FDSET_SOCK(x)) {      \
+      SET_SOCKERRNO(EINVAL);                    \
+      return -1;                                \
+    }                                           \
+  } while(0)
+#endif
+
+#endif /* HEADER_CURL_SELECT_H */
Index: trunk/src/libs/curl-8.7.1/lib/sendf.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/sendf.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/sendf.c	(revision 104083)
@@ -0,0 +1,1342 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_LINUX_TCP_H
+#include <linux/tcp.h>
+#elif defined(HAVE_NETINET_TCP_H)
+#include <netinet/tcp.h>
+#endif
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "content_encoding.h"
+#include "cw-out.h"
+#include "vtls/vtls.h"
+#include "vssh/ssh.h"
+#include "easyif.h"
+#include "multiif.h"
+#include "strerror.h"
+#include "select.h"
+#include "strdup.h"
+#include "http2.h"
+#include "progress.h"
+#include "warnless.h"
+#include "ws.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+static CURLcode do_init_writer_stack(struct Curl_easy *data);
+
+/* Curl_client_write() sends data to the write callback(s)
+
+   The bit pattern defines to what "streams" to write to. Body and/or header.
+   The defines are in sendf.h of course.
+ */
+CURLcode Curl_client_write(struct Curl_easy *data,
+                           int type, const char *buf, size_t blen)
+{
+  CURLcode result;
+
+  /* it is one of those, at least */
+  DEBUGASSERT(type & (CLIENTWRITE_BODY|CLIENTWRITE_HEADER|CLIENTWRITE_INFO));
+  /* BODY is only BODY (with optional EOS) */
+  DEBUGASSERT(!(type & CLIENTWRITE_BODY) ||
+              ((type & ~(CLIENTWRITE_BODY|CLIENTWRITE_EOS)) == 0));
+  /* INFO is only INFO (with optional EOS) */
+  DEBUGASSERT(!(type & CLIENTWRITE_INFO) ||
+              ((type & ~(CLIENTWRITE_INFO|CLIENTWRITE_EOS)) == 0));
+
+  if(!data->req.writer_stack) {
+    result = do_init_writer_stack(data);
+    if(result)
+      return result;
+    DEBUGASSERT(data->req.writer_stack);
+  }
+
+  return Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
+}
+
+static void cl_reset_writer(struct Curl_easy *data)
+{
+  struct Curl_cwriter *writer = data->req.writer_stack;
+  while(writer) {
+    data->req.writer_stack = writer->next;
+    writer->cwt->do_close(data, writer);
+    free(writer);
+    writer = data->req.writer_stack;
+  }
+}
+
+static void cl_reset_reader(struct Curl_easy *data)
+{
+  struct Curl_creader *reader = data->req.reader_stack;
+  while(reader) {
+    data->req.reader_stack = reader->next;
+    reader->crt->do_close(data, reader);
+    free(reader);
+    reader = data->req.reader_stack;
+  }
+}
+
+void Curl_client_cleanup(struct Curl_easy *data)
+{
+  DEBUGF(infof(data, "Curl_client_cleanup()"));
+  cl_reset_reader(data);
+  cl_reset_writer(data);
+
+  data->req.bytecount = 0;
+  data->req.headerline = 0;
+}
+
+void Curl_client_reset(struct Curl_easy *data)
+{
+  if(data->req.rewind_read) {
+    /* already requested */
+    DEBUGF(infof(data, "Curl_client_reset(), will rewind_read"));
+  }
+  else {
+    DEBUGF(infof(data, "Curl_client_reset(), clear readers"));
+    cl_reset_reader(data);
+  }
+  cl_reset_writer(data);
+
+  data->req.bytecount = 0;
+  data->req.headerline = 0;
+}
+
+CURLcode Curl_client_start(struct Curl_easy *data)
+{
+  if(data->req.rewind_read) {
+    struct Curl_creader *r = data->req.reader_stack;
+    CURLcode result = CURLE_OK;
+
+    DEBUGF(infof(data, "client start, rewind readers"));
+    while(r) {
+      result = r->crt->rewind(data, r);
+      if(result) {
+        failf(data, "rewind of client reader '%s' failed: %d",
+              r->crt->name, result);
+        return result;
+      }
+      r = r->next;
+    }
+    data->req.rewind_read = FALSE;
+    cl_reset_reader(data);
+  }
+  return CURLE_OK;
+}
+
+bool Curl_creader_will_rewind(struct Curl_easy *data)
+{
+  return data->req.rewind_read;
+}
+
+void Curl_creader_set_rewind(struct Curl_easy *data, bool enable)
+{
+  data->req.rewind_read = !!enable;
+}
+
+/* Write data using an unencoding writer stack. "nbytes" is not
+   allowed to be 0. */
+CURLcode Curl_cwriter_write(struct Curl_easy *data,
+                             struct Curl_cwriter *writer, int type,
+                             const char *buf, size_t nbytes)
+{
+  if(!writer)
+    return CURLE_WRITE_ERROR;
+  return writer->cwt->do_write(data, writer, type, buf, nbytes);
+}
+
+CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
+                               struct Curl_cwriter *writer)
+{
+  (void)data;
+  (void)writer;
+  return CURLE_OK;
+}
+
+CURLcode Curl_cwriter_def_write(struct Curl_easy *data,
+                                struct Curl_cwriter *writer, int type,
+                                const char *buf, size_t nbytes)
+{
+  return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+}
+
+void Curl_cwriter_def_close(struct Curl_easy *data,
+                            struct Curl_cwriter *writer)
+{
+  (void) data;
+  (void) writer;
+}
+
+static size_t get_max_body_write_len(struct Curl_easy *data, curl_off_t limit)
+{
+  if(limit != -1) {
+    /* How much more are we allowed to write? */
+    curl_off_t remain_diff;
+    remain_diff = limit - data->req.bytecount;
+    if(remain_diff < 0) {
+      /* already written too much! */
+      return 0;
+    }
+#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
+    else if(remain_diff > SSIZE_T_MAX) {
+      return SIZE_T_MAX;
+    }
+#endif
+    else {
+      return (size_t)remain_diff;
+    }
+  }
+  return SIZE_T_MAX;
+}
+
+struct cw_download_ctx {
+  struct Curl_cwriter super;
+  BIT(started_response);
+};
+/* Download client writer in phase CURL_CW_PROTOCOL that
+ * sees the "real" download body data. */
+static CURLcode cw_download_write(struct Curl_easy *data,
+                                  struct Curl_cwriter *writer, int type,
+                                  const char *buf, size_t nbytes)
+{
+  struct cw_download_ctx *ctx = writer->ctx;
+  CURLcode result;
+  size_t nwrite, excess_len = 0;
+  bool is_connect = !!(type & CLIENTWRITE_CONNECT);
+
+  if(!is_connect && !ctx->started_response) {
+    Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+    ctx->started_response = TRUE;
+  }
+
+  if(!(type & CLIENTWRITE_BODY)) {
+    if(is_connect && data->set.suppress_connect_headers)
+      return CURLE_OK;
+    return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+  }
+
+  /* Here, we deal with REAL BODY bytes. All filtering and transfer
+   * encodings have been applied and only the true content, e.g. BODY,
+   * bytes are passed here.
+   * This allows us to check sizes, update stats, etc. independent
+   * from the protocol in play. */
+
+  if(data->req.no_body && nbytes > 0) {
+    /* BODY arrives although we want none, bail out */
+    streamclose(data->conn, "ignoring body");
+    DEBUGF(infof(data, "did not want a BODY, but seeing %zu bytes",
+                 nbytes));
+    data->req.download_done = TRUE;
+    if(data->info.header_size)
+      /* if headers have been received, this is fine */
+      return CURLE_OK;
+    return CURLE_WEIRD_SERVER_REPLY;
+  }
+
+  /* Determine if we see any bytes in excess to what is allowed.
+   * We write the allowed bytes and handle excess further below.
+   * This gives deterministic BODY writes on varying buffer receive
+   * lengths. */
+  nwrite = nbytes;
+  if(-1 != data->req.maxdownload) {
+    size_t wmax = get_max_body_write_len(data, data->req.maxdownload);
+    if(nwrite > wmax) {
+      excess_len = nbytes - wmax;
+      nwrite = wmax;
+    }
+
+    if(nwrite == wmax) {
+      data->req.download_done = TRUE;
+    }
+  }
+
+  /* Error on too large filesize is handled below, after writing
+   * the permitted bytes */
+  if(data->set.max_filesize) {
+    size_t wmax = get_max_body_write_len(data, data->set.max_filesize);
+    if(nwrite > wmax) {
+      nwrite = wmax;
+    }
+  }
+
+  if(!data->req.ignorebody && (nwrite || (type & CLIENTWRITE_EOS))) {
+    result = Curl_cwriter_write(data, writer->next, type, buf, nwrite);
+    if(result)
+      return result;
+  }
+  /* Update stats, write and report progress */
+  data->req.bytecount += nwrite;
+  ++data->req.bodywrites;
+  result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
+  if(result)
+    return result;
+
+  if(excess_len) {
+    if(!data->req.ignorebody) {
+      infof(data,
+            "Excess found writing body:"
+            " excess = %zu"
+            ", size = %" CURL_FORMAT_CURL_OFF_T
+            ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
+            ", bytecount = %" CURL_FORMAT_CURL_OFF_T,
+            excess_len, data->req.size, data->req.maxdownload,
+            data->req.bytecount);
+      connclose(data->conn, "excess found in a read");
+    }
+  }
+  else if(nwrite < nbytes) {
+    failf(data, "Exceeded the maximum allowed file size "
+          "(%" CURL_FORMAT_CURL_OFF_T ") with %"
+          CURL_FORMAT_CURL_OFF_T " bytes",
+          data->set.max_filesize, data->req.bytecount);
+    return CURLE_FILESIZE_EXCEEDED;
+  }
+
+  return CURLE_OK;
+}
+
+static const struct Curl_cwtype cw_download = {
+  "download",
+  NULL,
+  Curl_cwriter_def_init,
+  cw_download_write,
+  Curl_cwriter_def_close,
+  sizeof(struct cw_download_ctx)
+};
+
+/* RAW client writer in phase CURL_CW_RAW that
+ * enabled tracing of raw data. */
+static CURLcode cw_raw_write(struct Curl_easy *data,
+                             struct Curl_cwriter *writer, int type,
+                             const char *buf, size_t nbytes)
+{
+  if(type & CLIENTWRITE_BODY && data->set.verbose && !data->req.ignorebody) {
+    Curl_debug(data, CURLINFO_DATA_IN, (char *)buf, nbytes);
+  }
+  return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+}
+
+static const struct Curl_cwtype cw_raw = {
+  "raw",
+  NULL,
+  Curl_cwriter_def_init,
+  cw_raw_write,
+  Curl_cwriter_def_close,
+  sizeof(struct Curl_cwriter)
+};
+
+/* Create an unencoding writer stage using the given handler. */
+CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
+                                   struct Curl_easy *data,
+                                   const struct Curl_cwtype *cwt,
+                                   Curl_cwriter_phase phase)
+{
+  struct Curl_cwriter *writer = NULL;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  void *p;
+
+  DEBUGASSERT(cwt->cwriter_size >= sizeof(struct Curl_cwriter));
+  p = calloc(1, cwt->cwriter_size);
+  if(!p)
+    goto out;
+
+  writer = (struct Curl_cwriter *)p;
+  writer->cwt = cwt;
+  writer->ctx = p;
+  writer->phase = phase;
+  result = cwt->do_init(data, writer);
+
+out:
+  *pwriter = result? NULL : writer;
+  if(result)
+    free(writer);
+  return result;
+}
+
+void Curl_cwriter_free(struct Curl_easy *data,
+                             struct Curl_cwriter *writer)
+{
+  if(writer) {
+    writer->cwt->do_close(data, writer);
+    free(writer);
+  }
+}
+
+size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase)
+{
+  struct Curl_cwriter *w;
+  size_t n = 0;
+
+  for(w = data->req.writer_stack; w; w = w->next) {
+    if(w->phase == phase)
+      ++n;
+  }
+  return n;
+}
+
+static CURLcode do_init_writer_stack(struct Curl_easy *data)
+{
+  struct Curl_cwriter *writer;
+  CURLcode result;
+
+  DEBUGASSERT(!data->req.writer_stack);
+  result = Curl_cwriter_create(&data->req.writer_stack,
+                               data, &Curl_cwt_out, CURL_CW_CLIENT);
+  if(result)
+    return result;
+
+  result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
+  if(result)
+    return result;
+  result = Curl_cwriter_add(data, writer);
+  if(result) {
+    Curl_cwriter_free(data, writer);
+  }
+
+  result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
+  if(result)
+    return result;
+  result = Curl_cwriter_add(data, writer);
+  if(result) {
+    Curl_cwriter_free(data, writer);
+  }
+  return result;
+}
+
+CURLcode Curl_cwriter_add(struct Curl_easy *data,
+                          struct Curl_cwriter *writer)
+{
+  CURLcode result;
+  struct Curl_cwriter **anchor = &data->req.writer_stack;
+
+  if(!*anchor) {
+    result = do_init_writer_stack(data);
+    if(result)
+      return result;
+  }
+
+  /* Insert the writer as first in its phase.
+   * Skip existing writers of lower phases. */
+  while(*anchor && (*anchor)->phase < writer->phase)
+    anchor = &((*anchor)->next);
+  writer->next = *anchor;
+  *anchor = writer;
+  return CURLE_OK;
+}
+
+struct Curl_cwriter *Curl_cwriter_get_by_name(struct Curl_easy *data,
+                                              const char *name)
+{
+  struct Curl_cwriter *writer;
+  for(writer = data->req.writer_stack; writer; writer = writer->next) {
+    if(!strcmp(name, writer->cwt->name))
+      return writer;
+  }
+  return NULL;
+}
+
+struct Curl_cwriter *Curl_cwriter_get_by_type(struct Curl_easy *data,
+                                              const struct Curl_cwtype *cwt)
+{
+  struct Curl_cwriter *writer;
+  for(writer = data->req.writer_stack; writer; writer = writer->next) {
+    if(writer->cwt == cwt)
+      return writer;
+  }
+  return NULL;
+}
+
+void Curl_cwriter_remove_by_name(struct Curl_easy *data,
+                                 const char *name)
+{
+  struct Curl_cwriter **anchor = &data->req.writer_stack;
+
+  while(*anchor) {
+    if(!strcmp(name, (*anchor)->cwt->name)) {
+      struct Curl_cwriter *w = (*anchor);
+      *anchor = w->next;
+      Curl_cwriter_free(data, w);
+      continue;
+    }
+    anchor = &((*anchor)->next);
+  }
+}
+
+CURLcode Curl_creader_read(struct Curl_easy *data,
+                           struct Curl_creader *reader,
+                           char *buf, size_t blen, size_t *nread, bool *eos)
+{
+  if(!reader)
+    return CURLE_READ_ERROR;
+  return reader->crt->do_read(data, reader, buf, blen, nread, eos);
+}
+
+CURLcode Curl_creader_def_init(struct Curl_easy *data,
+                               struct Curl_creader *reader)
+{
+  (void)data;
+  (void)reader;
+  return CURLE_OK;
+}
+
+void Curl_creader_def_close(struct Curl_easy *data,
+                            struct Curl_creader *reader)
+{
+  (void)data;
+  (void)reader;
+}
+
+CURLcode Curl_creader_def_read(struct Curl_easy *data,
+                               struct Curl_creader *reader,
+                               char *buf, size_t blen,
+                               size_t *nread, bool *eos)
+{
+  if(reader->next)
+    return reader->next->crt->do_read(data, reader->next, buf, blen,
+                                      nread, eos);
+  else {
+    *nread = 0;
+    *eos = FALSE;
+    return CURLE_READ_ERROR;
+  }
+}
+
+bool Curl_creader_def_needs_rewind(struct Curl_easy *data,
+                                   struct Curl_creader *reader)
+{
+  (void)data;
+  (void)reader;
+  return FALSE;
+}
+
+curl_off_t Curl_creader_def_total_length(struct Curl_easy *data,
+                                         struct Curl_creader *reader)
+{
+  return reader->next?
+         reader->next->crt->total_length(data, reader->next) : -1;
+}
+
+CURLcode Curl_creader_def_resume_from(struct Curl_easy *data,
+                                      struct Curl_creader *reader,
+                                      curl_off_t offset)
+{
+  (void)data;
+  (void)reader;
+  (void)offset;
+  return CURLE_READ_ERROR;
+}
+
+CURLcode Curl_creader_def_rewind(struct Curl_easy *data,
+                                 struct Curl_creader *reader)
+{
+  (void)data;
+  (void)reader;
+  return CURLE_OK;
+}
+
+CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
+                                  struct Curl_creader *reader)
+{
+  (void)data;
+  (void)reader;
+  return CURLE_OK;
+}
+
+void Curl_creader_def_done(struct Curl_easy *data,
+                           struct Curl_creader *reader, int premature)
+{
+  (void)data;
+  (void)reader;
+  (void)premature;
+}
+
+struct cr_in_ctx {
+  struct Curl_creader super;
+  curl_read_callback read_cb;
+  void *cb_user_data;
+  curl_off_t total_len;
+  curl_off_t read_len;
+  CURLcode error_result;
+  BIT(seen_eos);
+  BIT(errored);
+  BIT(has_used_cb);
+};
+
+static CURLcode cr_in_init(struct Curl_easy *data, struct Curl_creader *reader)
+{
+  struct cr_in_ctx *ctx = reader->ctx;
+  (void)data;
+  ctx->read_cb = data->state.fread_func;
+  ctx->cb_user_data = data->state.in;
+  ctx->total_len = -1;
+  ctx->read_len = 0;
+  return CURLE_OK;
+}
+
+/* Real client reader to installed client callbacks. */
+static CURLcode cr_in_read(struct Curl_easy *data,
+                           struct Curl_creader *reader,
+                           char *buf, size_t blen,
+                           size_t *pnread, bool *peos)
+{
+  struct cr_in_ctx *ctx = reader->ctx;
+  size_t nread;
+
+  /* Once we have errored, we will return the same error forever */
+  if(ctx->errored) {
+    *pnread = 0;
+    *peos = FALSE;
+    return ctx->error_result;
+  }
+  if(ctx->seen_eos) {
+    *pnread = 0;
+    *peos = TRUE;
+    return CURLE_OK;
+  }
+  /* respect length limitations */
+  if(ctx->total_len >= 0) {
+    curl_off_t remain = ctx->total_len - ctx->read_len;
+    if(remain <= 0)
+      blen = 0;
+    else if(remain < (curl_off_t)blen)
+      blen = (size_t)remain;
+  }
+  nread = 0;
+  if(ctx->read_cb && blen) {
+    Curl_set_in_callback(data, true);
+    nread = ctx->read_cb(buf, 1, blen, ctx->cb_user_data);
+    Curl_set_in_callback(data, false);
+    ctx->has_used_cb = TRUE;
+  }
+
+  switch(nread) {
+  case 0:
+    if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
+      failf(data, "client read function EOF fail, only "
+            "only %"CURL_FORMAT_CURL_OFF_T"/%"CURL_FORMAT_CURL_OFF_T
+            " of needed bytes read", ctx->read_len, ctx->total_len);
+      return CURLE_READ_ERROR;
+    }
+    *pnread = 0;
+    *peos = TRUE;
+    ctx->seen_eos = TRUE;
+    break;
+
+  case CURL_READFUNC_ABORT:
+    failf(data, "operation aborted by callback");
+    *pnread = 0;
+    *peos = FALSE;
+    ctx->errored = TRUE;
+    ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
+    return CURLE_ABORTED_BY_CALLBACK;
+
+  case CURL_READFUNC_PAUSE:
+    if(data->conn->handler->flags & PROTOPT_NONETWORK) {
+      /* protocols that work without network cannot be paused. This is
+         actually only FILE:// just now, and it can't pause since the transfer
+         isn't done using the "normal" procedure. */
+      failf(data, "Read callback asked for PAUSE when not supported");
+      return CURLE_READ_ERROR;
+    }
+    /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
+    data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
+    *pnread = 0;
+    *peos = FALSE;
+    break; /* nothing was read */
+
+  default:
+    if(nread > blen) {
+      /* the read function returned a too large value */
+      failf(data, "read function returned funny value");
+      *pnread = 0;
+      *peos = FALSE;
+      ctx->errored = TRUE;
+      ctx->error_result = CURLE_READ_ERROR;
+      return CURLE_READ_ERROR;
+    }
+    ctx->read_len += nread;
+    if(ctx->total_len >= 0)
+      ctx->seen_eos = (ctx->read_len >= ctx->total_len);
+    *pnread = nread;
+    *peos = ctx->seen_eos;
+    break;
+  }
+  DEBUGF(infof(data, "cr_in_read(len=%zu, total=%"CURL_FORMAT_CURL_OFF_T
+         ", read=%"CURL_FORMAT_CURL_OFF_T") -> %d, %zu, %d",
+         blen, ctx->total_len, ctx->read_len, CURLE_OK, *pnread, *peos));
+  return CURLE_OK;
+}
+
+static bool cr_in_needs_rewind(struct Curl_easy *data,
+                               struct Curl_creader *reader)
+{
+  struct cr_in_ctx *ctx = reader->ctx;
+  (void)data;
+  return ctx->has_used_cb;
+}
+
+static curl_off_t cr_in_total_length(struct Curl_easy *data,
+                                     struct Curl_creader *reader)
+{
+  struct cr_in_ctx *ctx = reader->ctx;
+  (void)data;
+  return ctx->total_len;
+}
+
+static CURLcode cr_in_resume_from(struct Curl_easy *data,
+                                  struct Curl_creader *reader,
+                                  curl_off_t offset)
+{
+  struct cr_in_ctx *ctx = reader->ctx;
+  int seekerr = CURL_SEEKFUNC_CANTSEEK;
+
+  DEBUGASSERT(data->conn);
+  /* already started reading? */
+  if(ctx->read_len)
+    return CURLE_READ_ERROR;
+
+  if(data->set.seek_func) {
+    Curl_set_in_callback(data, true);
+    seekerr = data->set.seek_func(data->set.seek_client, offset, SEEK_SET);
+    Curl_set_in_callback(data, false);
+  }
+
+  if(seekerr != CURL_SEEKFUNC_OK) {
+    curl_off_t passed = 0;
+
+    if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+      failf(data, "Could not seek stream");
+      return CURLE_READ_ERROR;
+    }
+    /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+    do {
+      char scratch[4*1024];
+      size_t readthisamountnow =
+        (offset - passed > (curl_off_t)sizeof(scratch)) ?
+        sizeof(scratch) :
+        curlx_sotouz(offset - passed);
+      size_t actuallyread;
+
+      Curl_set_in_callback(data, true);
+      actuallyread = ctx->read_cb(scratch, 1, readthisamountnow,
+                                  ctx->cb_user_data);
+      Curl_set_in_callback(data, false);
+
+      passed += actuallyread;
+      if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+        /* this checks for greater-than only to make sure that the
+           CURL_READFUNC_ABORT return code still aborts */
+        failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T
+              " bytes from the input", passed);
+        return CURLE_READ_ERROR;
+      }
+    } while(passed < offset);
+  }
+
+  /* now, decrease the size of the read */
+  if(ctx->total_len > 0) {
+    ctx->total_len -= offset;
+
+    if(ctx->total_len <= 0) {
+      failf(data, "File already completely uploaded");
+      return CURLE_PARTIAL_FILE;
+    }
+  }
+  /* we've passed, proceed as normal */
+  return CURLE_OK;
+}
+
+static CURLcode cr_in_rewind(struct Curl_easy *data,
+                             struct Curl_creader *reader)
+{
+  struct cr_in_ctx *ctx = reader->ctx;
+
+  /* If we never invoked the callback, there is noting to rewind */
+  if(!ctx->has_used_cb)
+    return CURLE_OK;
+
+  if(data->set.seek_func) {
+    int err;
+
+    Curl_set_in_callback(data, true);
+    err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
+    Curl_set_in_callback(data, false);
+    DEBUGF(infof(data, "cr_in, rewind via set.seek_func -> %d", err));
+    if(err) {
+      failf(data, "seek callback returned error %d", (int)err);
+      return CURLE_SEND_FAIL_REWIND;
+    }
+  }
+  else if(data->set.ioctl_func) {
+    curlioerr err;
+
+    Curl_set_in_callback(data, true);
+    err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
+                                 data->set.ioctl_client);
+    Curl_set_in_callback(data, false);
+    DEBUGF(infof(data, "cr_in, rewind via set.ioctl_func -> %d", (int)err));
+    if(err) {
+      failf(data, "ioctl callback returned error %d", (int)err);
+      return CURLE_SEND_FAIL_REWIND;
+    }
+  }
+  else {
+    /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
+       given FILE * stream and we can actually attempt to rewind that
+       ourselves with fseek() */
+    if(data->state.fread_func == (curl_read_callback)fread) {
+      int err = fseek(data->state.in, 0, SEEK_SET);
+      DEBUGF(infof(data, "cr_in, rewind via fseek -> %d(%d)",
+             (int)err, (int)errno));
+      if(-1 != err)
+        /* successful rewind */
+        return CURLE_OK;
+    }
+
+    /* no callback set or failure above, makes us fail at once */
+    failf(data, "necessary data rewind wasn't possible");
+    return CURLE_SEND_FAIL_REWIND;
+  }
+  return CURLE_OK;
+}
+
+
+static const struct Curl_crtype cr_in = {
+  "cr-in",
+  cr_in_init,
+  cr_in_read,
+  Curl_creader_def_close,
+  cr_in_needs_rewind,
+  cr_in_total_length,
+  cr_in_resume_from,
+  cr_in_rewind,
+  Curl_creader_def_unpause,
+  Curl_creader_def_done,
+  sizeof(struct cr_in_ctx)
+};
+
+CURLcode Curl_creader_create(struct Curl_creader **preader,
+                             struct Curl_easy *data,
+                             const struct Curl_crtype *crt,
+                             Curl_creader_phase phase)
+{
+  struct Curl_creader *reader = NULL;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  void *p;
+
+  DEBUGASSERT(crt->creader_size >= sizeof(struct Curl_creader));
+  p = calloc(1, crt->creader_size);
+  if(!p)
+    goto out;
+
+  reader = (struct Curl_creader *)p;
+  reader->crt = crt;
+  reader->ctx = p;
+  reader->phase = phase;
+  result = crt->do_init(data, reader);
+
+out:
+  *preader = result? NULL : reader;
+  if(result)
+    free(reader);
+  return result;
+}
+
+void Curl_creader_free(struct Curl_easy *data, struct Curl_creader *reader)
+{
+  if(reader) {
+    reader->crt->do_close(data, reader);
+    free(reader);
+  }
+}
+
+struct cr_lc_ctx {
+  struct Curl_creader super;
+  struct bufq buf;
+  BIT(read_eos);  /* we read an EOS from the next reader */
+  BIT(eos);       /* we have returned an EOS */
+};
+
+static CURLcode cr_lc_init(struct Curl_easy *data, struct Curl_creader *reader)
+{
+  struct cr_lc_ctx *ctx = reader->ctx;
+  (void)data;
+  Curl_bufq_init2(&ctx->buf, (16 * 1024), 1, BUFQ_OPT_SOFT_LIMIT);
+  return CURLE_OK;
+}
+
+static void cr_lc_close(struct Curl_easy *data, struct Curl_creader *reader)
+{
+  struct cr_lc_ctx *ctx = reader->ctx;
+  (void)data;
+  Curl_bufq_free(&ctx->buf);
+}
+
+/* client reader doing line end conversions. */
+static CURLcode cr_lc_read(struct Curl_easy *data,
+                           struct Curl_creader *reader,
+                           char *buf, size_t blen,
+                           size_t *pnread, bool *peos)
+{
+  struct cr_lc_ctx *ctx = reader->ctx;
+  CURLcode result;
+  size_t nread, i, start, n;
+  bool eos;
+
+  if(ctx->eos) {
+    *pnread = 0;
+    *peos = TRUE;
+    return CURLE_OK;
+  }
+
+  if(Curl_bufq_is_empty(&ctx->buf)) {
+    if(ctx->read_eos) {
+      ctx->eos = TRUE;
+      *pnread = 0;
+      *peos = TRUE;
+      return CURLE_OK;
+    }
+    /* Still getting data form the next reader, ctx->buf is empty */
+    result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);
+    if(result)
+      return result;
+    ctx->read_eos = eos;
+
+    if(!nread || !memchr(buf, '\n', nread)) {
+      /* nothing to convert, return this right away */
+      if(ctx->read_eos)
+        ctx->eos = TRUE;
+      *pnread = nread;
+      *peos = ctx->eos;
+      return CURLE_OK;
+    }
+
+    /* at least one \n needs conversion to '\r\n', place into ctx->buf */
+    for(i = start = 0; i < nread; ++i) {
+      if(buf[i] != '\n')
+        continue;
+      /* on a soft limit bufq, we do not need to check length */
+      result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
+      if(!result)
+        result = Curl_bufq_cwrite(&ctx->buf, STRCONST("\r\n"), &n);
+      if(result)
+        return result;
+      start = i + 1;
+      if(!data->set.crlf && (data->state.infilesize != -1)) {
+        /* we're here only because FTP is in ASCII mode...
+           bump infilesize for the LF we just added */
+        data->state.infilesize++;
+        /* comment: this might work for FTP, but in HTTP we could not change
+         * the content length after having started the request... */
+      }
+    }
+  }
+
+  DEBUGASSERT(!Curl_bufq_is_empty(&ctx->buf));
+  *peos = FALSE;
+  result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
+  if(!result && ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
+    /* no more data, read all, done. */
+    ctx->eos = TRUE;
+    *peos = TRUE;
+  }
+  return result;
+}
+
+static curl_off_t cr_lc_total_length(struct Curl_easy *data,
+                                     struct Curl_creader *reader)
+{
+  /* this reader changes length depending on input */
+  (void)data;
+  (void)reader;
+  return -1;
+}
+
+static const struct Curl_crtype cr_lc = {
+  "cr-lineconv",
+  cr_lc_init,
+  cr_lc_read,
+  cr_lc_close,
+  Curl_creader_def_needs_rewind,
+  cr_lc_total_length,
+  Curl_creader_def_resume_from,
+  Curl_creader_def_rewind,
+  Curl_creader_def_unpause,
+  Curl_creader_def_done,
+  sizeof(struct cr_lc_ctx)
+};
+
+static CURLcode cr_lc_add(struct Curl_easy *data)
+{
+  struct Curl_creader *reader = NULL;
+  CURLcode result;
+
+  result = Curl_creader_create(&reader, data, &cr_lc,
+                               CURL_CR_CONTENT_ENCODE);
+  if(!result)
+    result = Curl_creader_add(data, reader);
+
+  if(result && reader)
+    Curl_creader_free(data, reader);
+  return result;
+}
+
+static CURLcode do_init_reader_stack(struct Curl_easy *data,
+                                     struct Curl_creader *r)
+{
+  CURLcode result = CURLE_OK;
+  curl_off_t clen;
+
+  DEBUGASSERT(r);
+  DEBUGASSERT(r->crt);
+  DEBUGASSERT(r->phase == CURL_CR_CLIENT);
+  DEBUGASSERT(!data->req.reader_stack);
+
+  data->req.reader_stack = r;
+  clen = r->crt->total_length(data, r);
+  /* if we do not have 0 length init, and crlf conversion is wanted,
+   * add the reader for it */
+  if(clen && (data->set.crlf
+#ifdef CURL_DO_LINEEND_CONV
+     || data->state.prefer_ascii
+#endif
+    )) {
+    result = cr_lc_add(data);
+    if(result)
+      return result;
+  }
+
+  return result;
+}
+
+CURLcode Curl_creader_set_fread(struct Curl_easy *data, curl_off_t len)
+{
+  CURLcode result;
+  struct Curl_creader *r;
+  struct cr_in_ctx *ctx;
+
+  result = Curl_creader_create(&r, data, &cr_in, CURL_CR_CLIENT);
+  if(result)
+    return result;
+  ctx = r->ctx;
+  ctx->total_len = len;
+
+  cl_reset_reader(data);
+  return do_init_reader_stack(data, r);
+}
+
+CURLcode Curl_creader_add(struct Curl_easy *data,
+                          struct Curl_creader *reader)
+{
+  CURLcode result;
+  struct Curl_creader **anchor = &data->req.reader_stack;
+
+  if(!*anchor) {
+    result = Curl_creader_set_fread(data, data->state.infilesize);
+    if(result)
+      return result;
+  }
+
+  /* Insert the writer as first in its phase.
+   * Skip existing readers of lower phases. */
+  while(*anchor && (*anchor)->phase < reader->phase)
+    anchor = &((*anchor)->next);
+  reader->next = *anchor;
+  *anchor = reader;
+  return CURLE_OK;
+}
+
+CURLcode Curl_creader_set(struct Curl_easy *data, struct Curl_creader *r)
+{
+  CURLcode result;
+
+  DEBUGASSERT(r);
+  DEBUGASSERT(r->crt);
+  DEBUGASSERT(r->phase == CURL_CR_CLIENT);
+
+  cl_reset_reader(data);
+  result = do_init_reader_stack(data, r);
+  if(result)
+    Curl_creader_free(data, r);
+  return result;
+}
+
+CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
+                          size_t *nread, bool *eos)
+{
+  CURLcode result;
+
+  DEBUGASSERT(buf);
+  DEBUGASSERT(blen);
+  DEBUGASSERT(nread);
+  DEBUGASSERT(eos);
+
+  if(!data->req.reader_stack) {
+    result = Curl_creader_set_fread(data, data->state.infilesize);
+    if(result)
+      return result;
+    DEBUGASSERT(data->req.reader_stack);
+  }
+
+  result = Curl_creader_read(data, data->req.reader_stack, buf, blen,
+                             nread, eos);
+  return result;
+}
+
+bool Curl_creader_needs_rewind(struct Curl_easy *data)
+{
+  struct Curl_creader *reader = data->req.reader_stack;
+  while(reader) {
+    if(reader->crt->needs_rewind(data, reader))
+      return TRUE;
+    reader = reader->next;
+  }
+  return FALSE;
+}
+
+static CURLcode cr_null_read(struct Curl_easy *data,
+                             struct Curl_creader *reader,
+                             char *buf, size_t blen,
+                             size_t *pnread, bool *peos)
+{
+  (void)data;
+  (void)reader;
+  (void)buf;
+  (void)blen;
+  *pnread = 0;
+  *peos = TRUE;
+  return CURLE_OK;
+}
+
+static curl_off_t cr_null_total_length(struct Curl_easy *data,
+                                       struct Curl_creader *reader)
+{
+  /* this reader changes length depending on input */
+  (void)data;
+  (void)reader;
+  return 0;
+}
+
+static const struct Curl_crtype cr_null = {
+  "cr-null",
+  Curl_creader_def_init,
+  cr_null_read,
+  Curl_creader_def_close,
+  Curl_creader_def_needs_rewind,
+  cr_null_total_length,
+  Curl_creader_def_resume_from,
+  Curl_creader_def_rewind,
+  Curl_creader_def_unpause,
+  Curl_creader_def_done,
+  sizeof(struct Curl_creader)
+};
+
+CURLcode Curl_creader_set_null(struct Curl_easy *data)
+{
+  struct Curl_creader *r;
+  CURLcode result;
+
+  result = Curl_creader_create(&r, data, &cr_null, CURL_CR_CLIENT);
+  if(result)
+    return result;
+
+  cl_reset_reader(data);
+  return do_init_reader_stack(data, r);
+}
+
+struct cr_buf_ctx {
+  struct Curl_creader super;
+  const char *buf;
+  size_t blen;
+  size_t index;
+};
+
+static CURLcode cr_buf_read(struct Curl_easy *data,
+                            struct Curl_creader *reader,
+                            char *buf, size_t blen,
+                            size_t *pnread, bool *peos)
+{
+  struct cr_buf_ctx *ctx = reader->ctx;
+  size_t nread = ctx->blen - ctx->index;
+
+  (void)data;
+  if(!nread || !ctx->buf) {
+    *pnread = 0;
+    *peos = TRUE;
+  }
+  else {
+    if(nread > blen)
+      nread = blen;
+    memcpy(buf, ctx->buf + ctx->index, nread);
+    *pnread = nread;
+    ctx->index += nread;
+    *peos = (ctx->index == ctx->blen);
+  }
+  return CURLE_OK;
+}
+
+static bool cr_buf_needs_rewind(struct Curl_easy *data,
+                                struct Curl_creader *reader)
+{
+  struct cr_buf_ctx *ctx = reader->ctx;
+  (void)data;
+  return ctx->index > 0;
+}
+
+static curl_off_t cr_buf_total_length(struct Curl_easy *data,
+                                      struct Curl_creader *reader)
+{
+  struct cr_buf_ctx *ctx = reader->ctx;
+  (void)data;
+  return (curl_off_t)ctx->blen;
+}
+
+static CURLcode cr_buf_resume_from(struct Curl_easy *data,
+                                   struct Curl_creader *reader,
+                                   curl_off_t offset)
+{
+  struct cr_buf_ctx *ctx = reader->ctx;
+  size_t boffset;
+
+  (void)data;
+  DEBUGASSERT(data->conn);
+  /* already started reading? */
+  if(ctx->index)
+    return CURLE_READ_ERROR;
+  if(offset <= 0)
+    return CURLE_OK;
+  boffset = (size_t)offset;
+  if(boffset > ctx->blen)
+    return CURLE_READ_ERROR;
+
+  ctx->buf += boffset;
+  ctx->blen -= boffset;
+  return CURLE_OK;
+}
+
+static const struct Curl_crtype cr_buf = {
+  "cr-buf",
+  Curl_creader_def_init,
+  cr_buf_read,
+  Curl_creader_def_close,
+  cr_buf_needs_rewind,
+  cr_buf_total_length,
+  cr_buf_resume_from,
+  Curl_creader_def_rewind,
+  Curl_creader_def_unpause,
+  Curl_creader_def_done,
+  sizeof(struct cr_buf_ctx)
+};
+
+CURLcode Curl_creader_set_buf(struct Curl_easy *data,
+                               const char *buf, size_t blen)
+{
+  CURLcode result;
+  struct Curl_creader *r;
+  struct cr_buf_ctx *ctx;
+
+  result = Curl_creader_create(&r, data, &cr_buf, CURL_CR_CLIENT);
+  if(result)
+    return result;
+  ctx = r->ctx;
+  ctx->buf = buf;
+  ctx->blen = blen;
+  ctx->index = 0;
+
+  cl_reset_reader(data);
+  return do_init_reader_stack(data, r);
+}
+
+curl_off_t Curl_creader_total_length(struct Curl_easy *data)
+{
+  struct Curl_creader *r = data->req.reader_stack;
+  return r? r->crt->total_length(data, r) : -1;
+}
+
+curl_off_t Curl_creader_client_length(struct Curl_easy *data)
+{
+  struct Curl_creader *r = data->req.reader_stack;
+  while(r && r->phase != CURL_CR_CLIENT)
+    r = r->next;
+  return r? r->crt->total_length(data, r) : -1;
+}
+
+CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset)
+{
+  struct Curl_creader *r = data->req.reader_stack;
+  while(r && r->phase != CURL_CR_CLIENT)
+    r = r->next;
+  return r? r->crt->resume_from(data, r, offset) : CURLE_READ_ERROR;
+}
+
+CURLcode Curl_creader_unpause(struct Curl_easy *data)
+{
+  struct Curl_creader *reader = data->req.reader_stack;
+  CURLcode result = CURLE_OK;
+
+  while(reader) {
+    result = reader->crt->unpause(data, reader);
+    if(result)
+      break;
+    reader = reader->next;
+  }
+  return result;
+}
+
+void Curl_creader_done(struct Curl_easy *data, int premature)
+{
+  struct Curl_creader *reader = data->req.reader_stack;
+  while(reader) {
+    reader->crt->done(data, reader, premature);
+    reader = reader->next;
+  }
+}
+
+struct Curl_creader *Curl_creader_get_by_type(struct Curl_easy *data,
+                                              const struct Curl_crtype *crt)
+{
+  struct Curl_creader *r;
+  for(r = data->req.reader_stack; r; r = r->next) {
+    if(r->crt == crt)
+      return r;
+  }
+  return NULL;
+
+}
Index: trunk/src/libs/curl-8.7.1/lib/sendf.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/sendf.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/sendf.h	(revision 104083)
@@ -0,0 +1,397 @@
+#ifndef HEADER_CURL_SENDF_H
+#define HEADER_CURL_SENDF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "curl_trc.h"
+
+/**
+ * Type of data that is being written to the client (application)
+ * - data written can be either BODY or META data
+ * - META data is either INFO or HEADER
+ * - INFO is meta information, e.g. not BODY, that cannot be interpreted
+ *   as headers of a response. Example FTP/IMAP pingpong answers.
+ * - HEADER can have additional bits set (more than one)
+ *   - STATUS special "header", e.g. response status line in HTTP
+ *   - CONNECT header was received during proxying the connection
+ *   - 1XX header is part of an intermediate response, e.g. HTTP 1xx code
+ *   - TRAILER header is trailing response data, e.g. HTTP trailers
+ * BODY, INFO and HEADER should not be mixed, as this would lead to
+ * confusion on how to interpret/format/convert the data.
+ */
+#define CLIENTWRITE_BODY    (1<<0) /* non-meta information, BODY */
+#define CLIENTWRITE_INFO    (1<<1) /* meta information, not a HEADER */
+#define CLIENTWRITE_HEADER  (1<<2) /* meta information, HEADER */
+#define CLIENTWRITE_STATUS  (1<<3) /* a special status HEADER */
+#define CLIENTWRITE_CONNECT (1<<4) /* a CONNECT related HEADER */
+#define CLIENTWRITE_1XX     (1<<5) /* a 1xx response related HEADER */
+#define CLIENTWRITE_TRAILER (1<<6) /* a trailer HEADER */
+#define CLIENTWRITE_EOS     (1<<7) /* End Of transfer download Stream */
+
+/**
+ * Write `len` bytes at `prt` to the client. `type` indicates what
+ * kind of data is being written.
+ */
+CURLcode Curl_client_write(struct Curl_easy *data, int type, const char *ptr,
+                           size_t len) WARN_UNUSED_RESULT;
+
+/**
+ * Free all resources related to client writing.
+ */
+void Curl_client_cleanup(struct Curl_easy *data);
+
+/**
+ * Reset readers and writer chains, keep rewind information
+ * when necessary.
+ */
+void Curl_client_reset(struct Curl_easy *data);
+
+/**
+ * A new request is starting, perform any ops like rewinding
+ * previous readers when needed.
+ */
+CURLcode Curl_client_start(struct Curl_easy *data);
+
+/**
+ * Client Writers - a chain passing transfer BODY data to the client.
+ * Main application: HTTP and related protocols
+ * Other uses: monitoring of download progress
+ *
+ * Writers in the chain are order by their `phase`. First come all
+ * writers in CURL_CW_RAW, followed by any in CURL_CW_TRANSFER_DECODE,
+ * followed by any in CURL_CW_PROTOCOL, etc.
+ *
+ * When adding a writer, it is inserted as first in its phase. This means
+ * the order of adding writers of the same phase matters, but writers for
+ * different phases may be added in any order.
+ *
+ * Writers which do modify the BODY data written are expected to be of
+ * phases TRANSFER_DECODE or CONTENT_DECODE. The other phases are intended
+ * for monitoring writers. Which do *not* modify the data but gather
+ * statistics or update progress reporting.
+ */
+
+/* Phase a writer operates at. */
+typedef enum {
+  CURL_CW_RAW,  /* raw data written, before any decoding */
+  CURL_CW_TRANSFER_DECODE, /* remove transfer-encodings */
+  CURL_CW_PROTOCOL, /* after transfer, but before content decoding */
+  CURL_CW_CONTENT_DECODE, /* remove content-encodings */
+  CURL_CW_CLIENT  /* data written to client */
+} Curl_cwriter_phase;
+
+/* Client Writer Type, provides the implementation */
+struct Curl_cwtype {
+  const char *name;        /* writer name. */
+  const char *alias;       /* writer name alias, maybe NULL. */
+  CURLcode (*do_init)(struct Curl_easy *data,
+                      struct Curl_cwriter *writer);
+  CURLcode (*do_write)(struct Curl_easy *data,
+                       struct Curl_cwriter *writer, int type,
+                       const char *buf, size_t nbytes);
+  void (*do_close)(struct Curl_easy *data,
+                   struct Curl_cwriter *writer);
+  size_t cwriter_size;  /* sizeof() allocated struct Curl_cwriter */
+};
+
+/* Client writer instance, allocated on creation.
+ * `void *ctx` is the pointer from the allocation of
+ * the `struct Curl_cwriter` itself. This is suitable for "downcasting"
+ * by the writers implementation. See https://github.com/curl/curl/pull/13054
+ * for the alignment problems that arise otherwise.
+ */
+struct Curl_cwriter {
+  const struct Curl_cwtype *cwt;  /* type implementation */
+  struct Curl_cwriter *next;  /* Downstream writer. */
+  void *ctx;                  /* allocated instance pointer */
+  Curl_cwriter_phase phase; /* phase at which it operates */
+};
+
+/**
+ * Create a new cwriter instance with given type and phase. Is not
+ * inserted into the writer chain by this call.
+ * Invokes `writer->do_init()`.
+ */
+CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
+                             struct Curl_easy *data,
+                             const struct Curl_cwtype *ce_handler,
+                             Curl_cwriter_phase phase);
+
+/**
+ * Free a cwriter instance.
+ * Invokes `writer->do_close()`.
+ */
+void Curl_cwriter_free(struct Curl_easy *data,
+                       struct Curl_cwriter *writer);
+
+/**
+ * Count the number of writers installed of the given phase.
+ */
+size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase);
+
+/**
+ * Adds a writer to the transfer's writer chain.
+ * The writers `phase` determines where in the chain it is inserted.
+ */
+CURLcode Curl_cwriter_add(struct Curl_easy *data,
+                          struct Curl_cwriter *writer);
+
+/**
+ * Look up an installed client writer on `data` by its type.
+ * @return first writer with that type or NULL
+ */
+struct Curl_cwriter *Curl_cwriter_get_by_type(struct Curl_easy *data,
+                                              const struct Curl_cwtype *cwt);
+
+void Curl_cwriter_remove_by_name(struct Curl_easy *data,
+                                 const char *name);
+
+struct Curl_cwriter *Curl_cwriter_get_by_name(struct Curl_easy *data,
+                                              const char *name);
+
+/**
+ * Convenience method for calling `writer->do_write()` that
+ * checks for NULL writer.
+ */
+CURLcode Curl_cwriter_write(struct Curl_easy *data,
+                            struct Curl_cwriter *writer, int type,
+                            const char *buf, size_t nbytes);
+
+/**
+ * Default implementations for do_init, do_write, do_close that
+ * do nothing and pass the data through.
+ */
+CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
+                               struct Curl_cwriter *writer);
+CURLcode Curl_cwriter_def_write(struct Curl_easy *data,
+                                struct Curl_cwriter *writer, int type,
+                                const char *buf, size_t nbytes);
+void Curl_cwriter_def_close(struct Curl_easy *data,
+                            struct Curl_cwriter *writer);
+
+
+
+/* Client Reader Type, provides the implementation */
+struct Curl_crtype {
+  const char *name;        /* writer name. */
+  CURLcode (*do_init)(struct Curl_easy *data, struct Curl_creader *reader);
+  CURLcode (*do_read)(struct Curl_easy *data, struct Curl_creader *reader,
+                      char *buf, size_t blen, size_t *nread, bool *eos);
+  void (*do_close)(struct Curl_easy *data, struct Curl_creader *reader);
+  bool (*needs_rewind)(struct Curl_easy *data, struct Curl_creader *reader);
+  curl_off_t (*total_length)(struct Curl_easy *data,
+                             struct Curl_creader *reader);
+  CURLcode (*resume_from)(struct Curl_easy *data,
+                          struct Curl_creader *reader, curl_off_t offset);
+  CURLcode (*rewind)(struct Curl_easy *data, struct Curl_creader *reader);
+  CURLcode (*unpause)(struct Curl_easy *data, struct Curl_creader *reader);
+  void (*done)(struct Curl_easy *data,
+               struct Curl_creader *reader, int premature);
+  size_t creader_size;  /* sizeof() allocated struct Curl_creader */
+};
+
+/* Phase a reader operates at. */
+typedef enum {
+  CURL_CR_NET,  /* data send to the network (connection filters) */
+  CURL_CR_TRANSFER_ENCODE, /* add transfer-encodings */
+  CURL_CR_PROTOCOL, /* before transfer, but after content decoding */
+  CURL_CR_CONTENT_ENCODE, /* add content-encodings */
+  CURL_CR_CLIENT  /* data read from client */
+} Curl_creader_phase;
+
+/* Client reader instance, allocated on creation.
+ * `void *ctx` is the pointer from the allocation of
+ * the `struct Curl_cwriter` itself. This is suitable for "downcasting"
+ * by the writers implementation. See https://github.com/curl/curl/pull/13054
+ * for the alignment problems that arise otherwise.
+ */
+struct Curl_creader {
+  const struct Curl_crtype *crt;  /* type implementation */
+  struct Curl_creader *next;  /* Downstream reader. */
+  void *ctx;
+  Curl_creader_phase phase; /* phase at which it operates */
+};
+
+/**
+ * Default implementations for do_init, do_write, do_close that
+ * do nothing and pass the data through.
+ */
+CURLcode Curl_creader_def_init(struct Curl_easy *data,
+                               struct Curl_creader *reader);
+void Curl_creader_def_close(struct Curl_easy *data,
+                            struct Curl_creader *reader);
+CURLcode Curl_creader_def_read(struct Curl_easy *data,
+                               struct Curl_creader *reader,
+                               char *buf, size_t blen,
+                               size_t *nread, bool *eos);
+bool Curl_creader_def_needs_rewind(struct Curl_easy *data,
+                                   struct Curl_creader *reader);
+curl_off_t Curl_creader_def_total_length(struct Curl_easy *data,
+                                         struct Curl_creader *reader);
+CURLcode Curl_creader_def_resume_from(struct Curl_easy *data,
+                                      struct Curl_creader *reader,
+                                      curl_off_t offset);
+CURLcode Curl_creader_def_rewind(struct Curl_easy *data,
+                                 struct Curl_creader *reader);
+CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
+                                  struct Curl_creader *reader);
+void Curl_creader_def_done(struct Curl_easy *data,
+                           struct Curl_creader *reader, int premature);
+
+/**
+ * Convenience method for calling `reader->do_read()` that
+ * checks for NULL reader.
+ */
+CURLcode Curl_creader_read(struct Curl_easy *data,
+                           struct Curl_creader *reader,
+                           char *buf, size_t blen, size_t *nread, bool *eos);
+
+/**
+ * Create a new creader instance with given type and phase. Is not
+ * inserted into the writer chain by this call.
+ * Invokes `reader->do_init()`.
+ */
+CURLcode Curl_creader_create(struct Curl_creader **preader,
+                             struct Curl_easy *data,
+                             const struct Curl_crtype *cr_handler,
+                             Curl_creader_phase phase);
+
+/**
+ * Free a creader instance.
+ * Invokes `reader->do_close()`.
+ */
+void Curl_creader_free(struct Curl_easy *data, struct Curl_creader *reader);
+
+/**
+ * Adds a reader to the transfer's reader chain.
+ * The readers `phase` determines where in the chain it is inserted.
+ */
+CURLcode Curl_creader_add(struct Curl_easy *data,
+                          struct Curl_creader *reader);
+
+/**
+ * Set the given reader, which needs to be of type CURL_CR_CLIENT,
+ * as the new first reader. Discard any installed readers and init
+ * the reader chain anew.
+ * The function takes ownership of `r`.
+ */
+CURLcode Curl_creader_set(struct Curl_easy *data, struct Curl_creader *r);
+
+/**
+ * Read at most `blen` bytes at `buf` from the client.
+ * @param date    the transfer to read client bytes for
+ * @param buf     the memory location to read to
+ * @param blen    the amount of memory at `buf`
+ * @param nread   on return the number of bytes read into `buf`
+ * @param eos     TRUE iff bytes are the end of data from client
+ * @return CURLE_OK on successful read (even 0 length) or error
+ */
+CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
+                          size_t *nread, bool *eos) WARN_UNUSED_RESULT;
+
+/**
+ * TRUE iff client reader needs rewing before it can be used for
+ * a retry request.
+ */
+bool Curl_creader_needs_rewind(struct Curl_easy *data);
+
+/**
+ * TRUE iff client reader will rewind at next start
+ */
+bool Curl_creader_will_rewind(struct Curl_easy *data);
+
+/**
+ * En-/disable rewind of client reader at next start.
+ */
+void Curl_creader_set_rewind(struct Curl_easy *data, bool enable);
+
+/**
+ * Get the total length of bytes provided by the installed readers.
+ * This is independent of the amount already delivered and is calculated
+ * by all readers in the stack. If a reader like "chunked" or
+ * "crlf conversion" is installed, the returned length will be -1.
+ * @return -1 if length is indeterminate
+ */
+curl_off_t Curl_creader_total_length(struct Curl_easy *data);
+
+/**
+ * Get the total length of bytes provided by the reader at phase
+ * CURL_CR_CLIENT. This may not match the amount of bytes read
+ * for a request, depending if other, encoding readers are also installed.
+ * However it allows for rough estimation of the overall length.
+ * @return -1 if length is indeterminate
+ */
+curl_off_t Curl_creader_client_length(struct Curl_easy *data);
+
+/**
+ * Ask the installed reader at phase CURL_CR_CLIENT to start
+ * reading from the given offset. On success, this will reduce
+ * the `total_length()` by the amount.
+ * @param date    the transfer to read client bytes for
+ * param offset   the offset where to start reads from, negative
+ *                values will be ignored.
+ * @return CURLE_OK if offset could be set
+ *         CURLE_READ_ERROR if not supported by reader or seek/read failed
+ *                          of offset larger then total length
+ *         CURLE_PARTIAL_FILE if offset led to 0 total length
+ */
+CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset);
+
+/**
+ * Unpause all installed readers.
+ */
+CURLcode Curl_creader_unpause(struct Curl_easy *data);
+
+/**
+ * Tell all client readers that they are done.
+ */
+void Curl_creader_done(struct Curl_easy *data, int premature);
+
+/**
+ * Look up an installed client reader on `data` by its type.
+ * @return first reader with that type or NULL
+ */
+struct Curl_creader *Curl_creader_get_by_type(struct Curl_easy *data,
+                                              const struct Curl_crtype *crt);
+
+
+/**
+ * Set the client reader to provide 0 bytes, immediate EOS.
+ */
+CURLcode Curl_creader_set_null(struct Curl_easy *data);
+
+/**
+ * Set the client reader the reads from fread callback.
+ */
+CURLcode Curl_creader_set_fread(struct Curl_easy *data, curl_off_t len);
+
+/**
+ * Set the client reader the reads from the supplied buf (NOT COPIED).
+ */
+CURLcode Curl_creader_set_buf(struct Curl_easy *data,
+                              const char *buf, size_t blen);
+
+#endif /* HEADER_CURL_SENDF_H */
Index: trunk/src/libs/curl-8.7.1/lib/setopt.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/setopt.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/setopt.c	(revision 104083)
@@ -0,0 +1,3175 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <limits.h>
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_LINUX_TCP_H
+#include <linux/tcp.h>
+#elif defined(HAVE_NETINET_TCP_H)
+#include <netinet/tcp.h>
+#endif
+
+#include "urldata.h"
+#include "url.h"
+#include "progress.h"
+#include "content_encoding.h"
+#include "strcase.h"
+#include "share.h"
+#include "vtls/vtls.h"
+#include "warnless.h"
+#include "sendf.h"
+#include "http2.h"
+#include "setopt.h"
+#include "multiif.h"
+#include "altsvc.h"
+#include "hsts.h"
+#include "tftp.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+CURLcode Curl_setstropt(char **charp, const char *s)
+{
+  /* Release the previous storage at `charp' and replace by a dynamic storage
+     copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
+
+  Curl_safefree(*charp);
+
+  if(s) {
+    if(strlen(s) > CURL_MAX_INPUT_LENGTH)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+
+    *charp = strdup(s);
+    if(!*charp)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_setblobopt(struct curl_blob **blobp,
+                         const struct curl_blob *blob)
+{
+  /* free the previous storage at `blobp' and replace by a dynamic storage
+     copy of blob. If CURL_BLOB_COPY is set, the data is copied. */
+
+  Curl_safefree(*blobp);
+
+  if(blob) {
+    struct curl_blob *nblob;
+    if(blob->len > CURL_MAX_INPUT_LENGTH)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    nblob = (struct curl_blob *)
+      malloc(sizeof(struct curl_blob) +
+             ((blob->flags & CURL_BLOB_COPY) ? blob->len : 0));
+    if(!nblob)
+      return CURLE_OUT_OF_MEMORY;
+    *nblob = *blob;
+    if(blob->flags & CURL_BLOB_COPY) {
+      /* put the data after the blob struct in memory */
+      nblob->data = (char *)nblob + sizeof(struct curl_blob);
+      memcpy(nblob->data, blob->data, blob->len);
+    }
+
+    *blobp = nblob;
+    return CURLE_OK;
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
+{
+  CURLcode result = CURLE_OK;
+  char *user = NULL;
+  char *passwd = NULL;
+
+  /* Parse the login details if specified. It not then we treat NULL as a hint
+     to clear the existing data */
+  if(option) {
+    size_t len = strlen(option);
+    if(len > CURL_MAX_INPUT_LENGTH)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+
+    result = Curl_parse_login_details(option, len,
+                                      (userp ? &user : NULL),
+                                      (passwdp ? &passwd : NULL),
+                                      NULL);
+  }
+
+  if(!result) {
+    /* Store the username part of option if required */
+    if(userp) {
+      if(!user && option && option[0] == ':') {
+        /* Allocate an empty string instead of returning NULL as user name */
+        user = strdup("");
+        if(!user)
+          result = CURLE_OUT_OF_MEMORY;
+      }
+
+      Curl_safefree(*userp);
+      *userp = user;
+    }
+
+    /* Store the password part of option if required */
+    if(passwdp) {
+      Curl_safefree(*passwdp);
+      *passwdp = passwd;
+    }
+  }
+
+  return result;
+}
+
+#define C_SSLVERSION_VALUE(x) (x & 0xffff)
+#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000)
+
+static CURLcode protocol2num(const char *str, curl_prot_t *val)
+{
+  /*
+   * We are asked to cherry-pick protocols, so play it safe and disallow all
+   * protocols to start with, and re-add the wanted ones back in.
+   */
+  *val = 0;
+
+  if(!str)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  if(curl_strequal(str, "all")) {
+    *val = ~(curl_prot_t) 0;
+    return CURLE_OK;
+  }
+
+  do {
+    const char *token = str;
+    size_t tlen;
+
+    str = strchr(str, ',');
+    tlen = str? (size_t) (str - token): strlen(token);
+    if(tlen) {
+      const struct Curl_handler *h = Curl_getn_scheme_handler(token, tlen);
+
+      if(!h)
+        return CURLE_UNSUPPORTED_PROTOCOL;
+
+      *val |= h->protocol;
+    }
+  } while(str && str++);
+
+  if(!*val)
+    /* no protocol listed */
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  return CURLE_OK;
+}
+
+/*
+ * Do not make Curl_vsetopt() static: it is called from
+ * packages/OS400/ccsidcurl.c.
+ */
+CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
+{
+  char *argptr;
+  CURLcode result = CURLE_OK;
+  long arg;
+  unsigned long uarg;
+  curl_off_t bigsize;
+
+  switch(option) {
+  case CURLOPT_DNS_CACHE_TIMEOUT:
+    arg = va_arg(param, long);
+    if(arg < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    else if(arg > INT_MAX)
+      arg = INT_MAX;
+
+    data->set.dns_cache_timeout = (int)arg;
+    break;
+  case CURLOPT_CA_CACHE_TIMEOUT:
+    arg = va_arg(param, long);
+    if(arg < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    else if(arg > INT_MAX)
+      arg = INT_MAX;
+
+    data->set.general_ssl.ca_cache_timeout = (int)arg;
+    break;
+  case CURLOPT_DNS_USE_GLOBAL_CACHE:
+    /* deprecated */
+    break;
+  case CURLOPT_SSL_CIPHER_LIST:
+    /* set a list of cipher we want to use in the SSL connection */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST],
+                            va_arg(param, char *));
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSL_CIPHER_LIST:
+    /* set a list of cipher we want to use in the SSL connection for proxy */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY],
+                            va_arg(param, char *));
+    break;
+#endif
+  case CURLOPT_TLS13_CIPHERS:
+    if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) {
+      /* set preferred list of TLS 1.3 cipher suites */
+      result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST],
+                              va_arg(param, char *));
+    }
+    else
+      return CURLE_NOT_BUILT_IN;
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_TLS13_CIPHERS:
+    if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) {
+      /* set preferred list of TLS 1.3 cipher suites for proxy */
+      result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_PROXY],
+                              va_arg(param, char *));
+    }
+    else
+      return CURLE_NOT_BUILT_IN;
+    break;
+#endif
+  case CURLOPT_RANDOM_FILE:
+    break;
+  case CURLOPT_EGDSOCKET:
+    break;
+  case CURLOPT_MAXCONNECTS:
+    /*
+     * Set the absolute number of maximum simultaneous alive connection that
+     * libcurl is allowed to have.
+     */
+    uarg = va_arg(param, unsigned long);
+    if(uarg > UINT_MAX)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.maxconnects = (unsigned int)uarg;
+    break;
+  case CURLOPT_FORBID_REUSE:
+    /*
+     * When this transfer is done, it must not be left to be reused by a
+     * subsequent transfer but shall be closed immediately.
+     */
+    data->set.reuse_forbid = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_FRESH_CONNECT:
+    /*
+     * This transfer shall not use a previously cached connection but
+     * should be made with a fresh new connect!
+     */
+    data->set.reuse_fresh = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_VERBOSE:
+    /*
+     * Verbose means infof() calls that give a lot of information about
+     * the connection and transfer procedures as well as internal choices.
+     */
+    data->set.verbose = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_HEADER:
+    /*
+     * Set to include the header in the general data output stream.
+     */
+    data->set.include_header = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_NOPROGRESS:
+    /*
+     * Shut off the internal supported progress meter
+     */
+    data->set.hide_progress = (0 != va_arg(param, long));
+    if(data->set.hide_progress)
+      data->progress.flags |= PGRS_HIDE;
+    else
+      data->progress.flags &= ~PGRS_HIDE;
+    break;
+  case CURLOPT_NOBODY:
+    /*
+     * Do not include the body part in the output data stream.
+     */
+    data->set.opt_no_body = (0 != va_arg(param, long));
+#ifndef CURL_DISABLE_HTTP
+    if(data->set.opt_no_body)
+      /* in HTTP lingo, no body means using the HEAD request... */
+      data->set.method = HTTPREQ_HEAD;
+    else if(data->set.method == HTTPREQ_HEAD)
+      data->set.method = HTTPREQ_GET;
+#endif
+    break;
+  case CURLOPT_FAILONERROR:
+    /*
+     * Don't output the >=400 error code HTML-page, but instead only
+     * return error.
+     */
+    data->set.http_fail_on_error = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_KEEP_SENDING_ON_ERROR:
+    data->set.http_keep_sending_on_error = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_UPLOAD:
+  case CURLOPT_PUT:
+    /*
+     * We want to sent data to the remote host. If this is HTTP, that equals
+     * using the PUT request.
+     */
+    arg = va_arg(param, long);
+    if(arg) {
+      /* If this is HTTP, PUT is what's needed to "upload" */
+      data->set.method = HTTPREQ_PUT;
+      data->set.opt_no_body = FALSE; /* this is implied */
+    }
+    else
+      /* In HTTP, the opposite of upload is GET (unless NOBODY is true as
+         then this can be changed to HEAD later on) */
+      data->set.method = HTTPREQ_GET;
+    break;
+  case CURLOPT_REQUEST_TARGET:
+    result = Curl_setstropt(&data->set.str[STRING_TARGET],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_FILETIME:
+    /*
+     * Try to get the file time of the remote document. The time will
+     * later (possibly) become available using curl_easy_getinfo().
+     */
+    data->set.get_filetime = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_SERVER_RESPONSE_TIMEOUT:
+    /*
+     * Option that specifies how quickly a server response must be obtained
+     * before it is considered failure. For pingpong protocols.
+     */
+    arg = va_arg(param, long);
+    if((arg >= 0) && (arg <= (INT_MAX/1000)))
+      data->set.server_response_timeout = (unsigned int)arg * 1000;
+    else
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+  case CURLOPT_SERVER_RESPONSE_TIMEOUT_MS:
+    /*
+     * Option that specifies how quickly a server response must be obtained
+     * before it is considered failure. For pingpong protocols.
+     */
+    arg = va_arg(param, long);
+    if((arg >= 0) && (arg <= INT_MAX))
+      data->set.server_response_timeout = (unsigned int)arg;
+    else
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+#ifndef CURL_DISABLE_TFTP
+  case CURLOPT_TFTP_NO_OPTIONS:
+    /*
+     * Option that prevents libcurl from sending TFTP option requests to the
+     * server.
+     */
+    data->set.tftp_no_options = va_arg(param, long) != 0;
+    break;
+  case CURLOPT_TFTP_BLKSIZE:
+    /*
+     * TFTP option that specifies the block size to use for data transmission.
+     */
+    arg = va_arg(param, long);
+    if(arg > TFTP_BLKSIZE_MAX || arg < TFTP_BLKSIZE_MIN)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.tftp_blksize = arg;
+    break;
+#endif
+#ifndef CURL_DISABLE_NETRC
+  case CURLOPT_NETRC:
+    /*
+     * Parse the $HOME/.netrc file
+     */
+    arg = va_arg(param, long);
+    if((arg < CURL_NETRC_IGNORED) || (arg >= CURL_NETRC_LAST))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.use_netrc = (unsigned char)arg;
+    break;
+  case CURLOPT_NETRC_FILE:
+    /*
+     * Use this file instead of the $HOME/.netrc file
+     */
+    result = Curl_setstropt(&data->set.str[STRING_NETRC_FILE],
+                            va_arg(param, char *));
+    break;
+#endif
+  case CURLOPT_TRANSFERTEXT:
+    /*
+     * This option was previously named 'FTPASCII'. Renamed to work with
+     * more protocols than merely FTP.
+     *
+     * Transfer using ASCII (instead of BINARY).
+     */
+    data->set.prefer_ascii = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_TIMECONDITION:
+    /*
+     * Set HTTP time condition. This must be one of the defines in the
+     * curl/curl.h header file.
+     */
+    arg = va_arg(param, long);
+    if((arg < CURL_TIMECOND_NONE) || (arg >= CURL_TIMECOND_LAST))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.timecondition = (unsigned char)(curl_TimeCond)arg;
+    break;
+  case CURLOPT_TIMEVALUE:
+    /*
+     * This is the value to compare with the remote document with the
+     * method set with CURLOPT_TIMECONDITION
+     */
+    data->set.timevalue = (time_t)va_arg(param, long);
+    break;
+
+  case CURLOPT_TIMEVALUE_LARGE:
+    /*
+     * This is the value to compare with the remote document with the
+     * method set with CURLOPT_TIMECONDITION
+     */
+    data->set.timevalue = (time_t)va_arg(param, curl_off_t);
+    break;
+
+  case CURLOPT_SSLVERSION:
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSLVERSION:
+#endif
+    /*
+     * Set explicit SSL version to try to connect with, as some SSL
+     * implementations are lame.
+     */
+#ifdef USE_SSL
+    {
+      long version, version_max;
+      struct ssl_primary_config *primary = &data->set.ssl.primary;
+#ifndef CURL_DISABLE_PROXY
+      if(option != CURLOPT_SSLVERSION)
+        primary = &data->set.proxy_ssl.primary;
+#endif
+
+      arg = va_arg(param, long);
+
+      version = C_SSLVERSION_VALUE(arg);
+      version_max = C_SSLVERSION_MAX_VALUE(arg);
+
+      if(version < CURL_SSLVERSION_DEFAULT ||
+         version == CURL_SSLVERSION_SSLv2 ||
+         version == CURL_SSLVERSION_SSLv3 ||
+         version >= CURL_SSLVERSION_LAST ||
+         version_max < CURL_SSLVERSION_MAX_NONE ||
+         version_max >= CURL_SSLVERSION_MAX_LAST)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+
+      primary->version = (unsigned char)version;
+      primary->version_max = (unsigned int)version_max;
+    }
+#else
+    result = CURLE_NOT_BUILT_IN;
+#endif
+    break;
+
+    /* MQTT "borrows" some of the HTTP options */
+#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT)
+  case CURLOPT_COPYPOSTFIELDS:
+    /*
+     * A string with POST data. Makes curl HTTP POST. Even if it is NULL.
+     * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to
+     *  CURLOPT_COPYPOSTFIELDS and not altered later.
+     */
+    argptr = va_arg(param, char *);
+
+    if(!argptr || data->set.postfieldsize == -1)
+      result = Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr);
+    else {
+      /*
+       *  Check that requested length does not overflow the size_t type.
+       */
+
+      if((data->set.postfieldsize < 0) ||
+         ((sizeof(curl_off_t) != sizeof(size_t)) &&
+          (data->set.postfieldsize > (curl_off_t)((size_t)-1))))
+        result = CURLE_OUT_OF_MEMORY;
+      else {
+        /* Allocate even when size == 0. This satisfies the need of possible
+           later address compare to detect the COPYPOSTFIELDS mode, and to
+           mark that postfields is used rather than read function or form
+           data.
+        */
+        char *p = Curl_memdup0(argptr, (size_t)data->set.postfieldsize);
+        (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+        if(!p)
+          result = CURLE_OUT_OF_MEMORY;
+        else
+          data->set.str[STRING_COPYPOSTFIELDS] = p;
+      }
+    }
+
+    data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
+    data->set.method = HTTPREQ_POST;
+    break;
+
+  case CURLOPT_POSTFIELDS:
+    /*
+     * Like above, but use static data instead of copying it.
+     */
+    data->set.postfields = va_arg(param, void *);
+    /* Release old copied data. */
+    (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+    data->set.method = HTTPREQ_POST;
+    break;
+
+  case CURLOPT_POSTFIELDSIZE:
+    /*
+     * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+     * figure it out. Enables binary posts.
+     */
+    bigsize = va_arg(param, long);
+    if(bigsize < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+
+    if(data->set.postfieldsize < bigsize &&
+       data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+      /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+      (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+      data->set.postfields = NULL;
+    }
+
+    data->set.postfieldsize = bigsize;
+    break;
+
+  case CURLOPT_POSTFIELDSIZE_LARGE:
+    /*
+     * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+     * figure it out. Enables binary posts.
+     */
+    bigsize = va_arg(param, curl_off_t);
+    if(bigsize < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+
+    if(data->set.postfieldsize < bigsize &&
+       data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+      /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+      (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+      data->set.postfields = NULL;
+    }
+
+    data->set.postfieldsize = bigsize;
+    break;
+#endif
+#ifndef CURL_DISABLE_HTTP
+  case CURLOPT_AUTOREFERER:
+    /*
+     * Switch on automatic referer that gets set if curl follows locations.
+     */
+    data->set.http_auto_referer = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_ACCEPT_ENCODING:
+    /*
+     * String to use at the value of Accept-Encoding header.
+     *
+     * If the encoding is set to "" we use an Accept-Encoding header that
+     * encompasses all the encodings we support.
+     * If the encoding is set to NULL we don't send an Accept-Encoding header
+     * and ignore an received Content-Encoding header.
+     *
+     */
+    argptr = va_arg(param, char *);
+    if(argptr && !*argptr) {
+      char all[256];
+      Curl_all_content_encodings(all, sizeof(all));
+      result = Curl_setstropt(&data->set.str[STRING_ENCODING], all);
+    }
+    else
+      result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
+    break;
+
+  case CURLOPT_TRANSFER_ENCODING:
+    data->set.http_transfer_encoding = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_FOLLOWLOCATION:
+    /*
+     * Follow Location: header hints on an HTTP-server.
+     */
+    data->set.http_follow_location = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_UNRESTRICTED_AUTH:
+    /*
+     * Send authentication (user+password) when following locations, even when
+     * hostname changed.
+     */
+    data->set.allow_auth_to_other_hosts = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_MAXREDIRS:
+    /*
+     * The maximum amount of hops you allow curl to follow Location:
+     * headers. This should mostly be used to detect never-ending loops.
+     */
+    arg = va_arg(param, long);
+    if(arg < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.maxredirs = arg;
+    break;
+
+  case CURLOPT_POSTREDIR:
+    /*
+     * Set the behavior of POST when redirecting
+     * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
+     * CURL_REDIR_POST_301 - POST is kept as POST after 301
+     * CURL_REDIR_POST_302 - POST is kept as POST after 302
+     * CURL_REDIR_POST_303 - POST is kept as POST after 303
+     * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303
+     * other - POST is kept as POST after 301 and 302
+     */
+    arg = va_arg(param, long);
+    if(arg < CURL_REDIR_GET_ALL)
+      /* no return error on too high numbers since the bitmask could be
+         extended in a future */
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.keep_post = arg & CURL_REDIR_POST_ALL;
+    break;
+
+  case CURLOPT_POST:
+    /* Does this option serve a purpose anymore? Yes it does, when
+       CURLOPT_POSTFIELDS isn't used and the POST data is read off the
+       callback! */
+    if(va_arg(param, long)) {
+      data->set.method = HTTPREQ_POST;
+      data->set.opt_no_body = FALSE; /* this is implied */
+    }
+    else
+      data->set.method = HTTPREQ_GET;
+    break;
+
+#ifndef CURL_DISABLE_FORM_API
+  case CURLOPT_HTTPPOST:
+    /*
+     * Set to make us do HTTP POST. Legacy API-style.
+     */
+    data->set.httppost = va_arg(param, struct curl_httppost *);
+    data->set.method = HTTPREQ_POST_FORM;
+    data->set.opt_no_body = FALSE; /* this is implied */
+    Curl_mime_cleanpart(data->state.formp);
+    Curl_safefree(data->state.formp);
+    data->state.mimepost = NULL;
+    break;
+#endif
+
+#if !defined(CURL_DISABLE_AWS)
+  case CURLOPT_AWS_SIGV4:
+    /*
+     * String that is merged to some authentication
+     * parameters are used by the algorithm.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_AWS_SIGV4],
+                            va_arg(param, char *));
+    /*
+     * Basic been set by default it need to be unset here
+     */
+    if(data->set.str[STRING_AWS_SIGV4])
+      data->set.httpauth = CURLAUTH_AWS_SIGV4;
+    break;
+#endif
+
+  case CURLOPT_REFERER:
+    /*
+     * String to set in the HTTP Referer: field.
+     */
+    if(data->state.referer_alloc) {
+      Curl_safefree(data->state.referer);
+      data->state.referer_alloc = FALSE;
+    }
+    result = Curl_setstropt(&data->set.str[STRING_SET_REFERER],
+                            va_arg(param, char *));
+    data->state.referer = data->set.str[STRING_SET_REFERER];
+    break;
+
+  case CURLOPT_USERAGENT:
+    /*
+     * String to use in the HTTP User-Agent field
+     */
+    result = Curl_setstropt(&data->set.str[STRING_USERAGENT],
+                            va_arg(param, char *));
+    break;
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXYHEADER:
+    /*
+     * Set a list with proxy headers to use (or replace internals with)
+     *
+     * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a
+     * long time we remain doing it this way until CURLOPT_PROXYHEADER is
+     * used. As soon as this option has been used, if set to anything but
+     * NULL, custom headers for proxies are only picked from this list.
+     *
+     * Set this option to NULL to restore the previous behavior.
+     */
+    data->set.proxyheaders = va_arg(param, struct curl_slist *);
+    break;
+#endif
+  case CURLOPT_HEADEROPT:
+    /*
+     * Set header option.
+     */
+    arg = va_arg(param, long);
+    data->set.sep_headers = !!(arg & CURLHEADER_SEPARATE);
+    break;
+
+#if !defined(CURL_DISABLE_COOKIES)
+  case CURLOPT_COOKIE:
+    /*
+     * Cookie string to send to the remote server in the request.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_COOKIE],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_COOKIEFILE:
+    /*
+     * Set cookie file to read and parse. Can be used multiple times.
+     */
+    argptr = (char *)va_arg(param, void *);
+    if(argptr) {
+      struct curl_slist *cl;
+      /* general protection against mistakes and abuse */
+      if(strlen(argptr) > CURL_MAX_INPUT_LENGTH)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+      /* append the cookie file name to the list of file names, and deal with
+         them later */
+      cl = curl_slist_append(data->state.cookielist, argptr);
+      if(!cl) {
+        curl_slist_free_all(data->state.cookielist);
+        data->state.cookielist = NULL;
+        return CURLE_OUT_OF_MEMORY;
+      }
+      data->state.cookielist = cl; /* store the list for later use */
+    }
+    else {
+      /* clear the list of cookie files */
+      curl_slist_free_all(data->state.cookielist);
+      data->state.cookielist = NULL;
+
+      if(!data->share || !data->share->cookies) {
+        /* throw away all existing cookies if this isn't a shared cookie
+           container */
+        Curl_cookie_clearall(data->cookies);
+        Curl_cookie_cleanup(data->cookies);
+      }
+      /* disable the cookie engine */
+      data->cookies = NULL;
+    }
+    break;
+
+  case CURLOPT_COOKIEJAR:
+    /*
+     * Set cookie file name to dump all cookies to when we're done.
+     */
+  {
+    struct CookieInfo *newcookies;
+    result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR],
+                            va_arg(param, char *));
+
+    /*
+     * Activate the cookie parser. This may or may not already
+     * have been made.
+     */
+    newcookies = Curl_cookie_init(data, NULL, data->cookies,
+                                  data->set.cookiesession);
+    if(!newcookies)
+      result = CURLE_OUT_OF_MEMORY;
+    data->cookies = newcookies;
+  }
+  break;
+
+  case CURLOPT_COOKIESESSION:
+    /*
+     * Set this option to TRUE to start a new "cookie session". It will
+     * prevent the forthcoming read-cookies-from-file actions to accept
+     * cookies that are marked as being session cookies, as they belong to a
+     * previous session.
+     */
+    data->set.cookiesession = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_COOKIELIST:
+    argptr = va_arg(param, char *);
+
+    if(!argptr)
+      break;
+
+    if(strcasecompare(argptr, "ALL")) {
+      /* clear all cookies */
+      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+      Curl_cookie_clearall(data->cookies);
+      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+    }
+    else if(strcasecompare(argptr, "SESS")) {
+      /* clear session cookies */
+      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+      Curl_cookie_clearsess(data->cookies);
+      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+    }
+    else if(strcasecompare(argptr, "FLUSH")) {
+      /* flush cookies to file, takes care of the locking */
+      Curl_flush_cookies(data, FALSE);
+    }
+    else if(strcasecompare(argptr, "RELOAD")) {
+      /* reload cookies from file */
+      Curl_cookie_loadfiles(data);
+      break;
+    }
+    else {
+      if(!data->cookies)
+        /* if cookie engine was not running, activate it */
+        data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
+
+      /* general protection against mistakes and abuse */
+      if(strlen(argptr) > CURL_MAX_INPUT_LENGTH)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+      argptr = strdup(argptr);
+      if(!argptr || !data->cookies) {
+        result = CURLE_OUT_OF_MEMORY;
+        free(argptr);
+      }
+      else {
+        Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+
+        if(checkprefix("Set-Cookie:", argptr))
+          /* HTTP Header format line */
+          Curl_cookie_add(data, data->cookies, TRUE, FALSE, argptr + 11, NULL,
+                          NULL, TRUE);
+
+        else
+          /* Netscape format line */
+          Curl_cookie_add(data, data->cookies, FALSE, FALSE, argptr, NULL,
+                          NULL, TRUE);
+
+        Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+        free(argptr);
+      }
+    }
+
+    break;
+#endif /* !CURL_DISABLE_COOKIES */
+
+  case CURLOPT_HTTPGET:
+    /*
+     * Set to force us do HTTP GET
+     */
+    if(va_arg(param, long)) {
+      data->set.method = HTTPREQ_GET;
+      data->set.opt_no_body = FALSE; /* this is implied */
+    }
+    break;
+
+  case CURLOPT_HTTP_VERSION:
+    /*
+     * This sets a requested HTTP version to be used. The value is one of
+     * the listed enums in curl/curl.h.
+     */
+    arg = va_arg(param, long);
+    switch(arg) {
+    case CURL_HTTP_VERSION_NONE:
+#ifdef USE_HTTP2
+      /* TODO: this seems an undesirable quirk to force a behaviour on
+       * lower implementations that they should recognize independently? */
+      arg = CURL_HTTP_VERSION_2TLS;
+#endif
+      /* accepted */
+      break;
+    case CURL_HTTP_VERSION_1_0:
+    case CURL_HTTP_VERSION_1_1:
+      /* accepted */
+      break;
+#ifdef USE_HTTP2
+    case CURL_HTTP_VERSION_2_0:
+    case CURL_HTTP_VERSION_2TLS:
+    case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE:
+      /* accepted */
+      break;
+#endif
+#ifdef ENABLE_QUIC
+    case CURL_HTTP_VERSION_3:
+    case CURL_HTTP_VERSION_3ONLY:
+      /* accepted */
+      break;
+#endif
+    default:
+      /* not accepted */
+      if(arg < CURL_HTTP_VERSION_NONE)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+      return CURLE_UNSUPPORTED_PROTOCOL;
+    }
+    data->set.httpwant = (unsigned char)arg;
+    break;
+
+  case CURLOPT_EXPECT_100_TIMEOUT_MS:
+    /*
+     * Time to wait for a response to an HTTP request containing an
+     * Expect: 100-continue header before sending the data anyway.
+     */
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.expect_100_timeout = arg;
+    break;
+
+  case CURLOPT_HTTP09_ALLOWED:
+    arg = va_arg(param, unsigned long);
+    if(arg > 1L)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+#ifdef USE_HYPER
+    /* Hyper does not support HTTP/0.9 */
+    if(arg)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+#else
+    data->set.http09_allowed = !!arg;
+#endif
+    break;
+
+  case CURLOPT_HTTP200ALIASES:
+    /*
+     * Set a list of aliases for HTTP 200 in response header
+     */
+    data->set.http200aliases = va_arg(param, struct curl_slist *);
+    break;
+#endif   /* CURL_DISABLE_HTTP */
+
+#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) ||       \
+    !defined(CURL_DISABLE_IMAP)
+# if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MIME)
+  case CURLOPT_HTTPHEADER:
+    /*
+     * Set a list with HTTP headers to use (or replace internals with)
+     */
+    data->set.headers = va_arg(param, struct curl_slist *);
+    break;
+# endif
+
+# ifndef CURL_DISABLE_MIME
+  case CURLOPT_MIMEPOST:
+    /*
+     * Set to make us do MIME POST
+     */
+    result = Curl_mime_set_subparts(&data->set.mimepost,
+                                    va_arg(param, curl_mime *), FALSE);
+    if(!result) {
+      data->set.method = HTTPREQ_POST_MIME;
+      data->set.opt_no_body = FALSE; /* this is implied */
+#ifndef CURL_DISABLE_FORM_API
+      Curl_mime_cleanpart(data->state.formp);
+      Curl_safefree(data->state.formp);
+      data->state.mimepost = NULL;
+#endif
+    }
+    break;
+
+  case CURLOPT_MIME_OPTIONS:
+    arg = va_arg(param, long);
+    data->set.mime_formescape = !!(arg & CURLMIMEOPT_FORMESCAPE);
+  break;
+# endif
+#endif
+
+  case CURLOPT_HTTPAUTH:
+    /*
+     * Set HTTP Authentication type BITMASK.
+     */
+  {
+    int bitcheck;
+    bool authbits;
+    unsigned long auth = va_arg(param, unsigned long);
+
+    if(auth == CURLAUTH_NONE) {
+      data->set.httpauth = auth;
+      break;
+    }
+
+    /* the DIGEST_IE bit is only used to set a special marker, for all the
+       rest we need to handle it as normal DIGEST */
+    data->state.authhost.iestyle = !!(auth & CURLAUTH_DIGEST_IE);
+
+    if(auth & CURLAUTH_DIGEST_IE) {
+      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+    }
+
+    /* switch off bits we can't support */
+#ifndef USE_NTLM
+    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
+    auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#elif !defined(NTLM_WB_ENABLED)
+    auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#endif
+#ifndef USE_SPNEGO
+    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
+                                    GSS-API or SSPI */
+#endif
+
+    /* check if any auth bit lower than CURLAUTH_ONLY is still set */
+    bitcheck = 0;
+    authbits = FALSE;
+    while(bitcheck < 31) {
+      if(auth & (1UL << bitcheck++)) {
+        authbits = TRUE;
+        break;
+      }
+    }
+    if(!authbits)
+      return CURLE_NOT_BUILT_IN; /* no supported types left! */
+
+    data->set.httpauth = auth;
+  }
+  break;
+
+  case CURLOPT_CUSTOMREQUEST:
+    /*
+     * Set a custom string to use as request
+     */
+    result = Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST],
+                            va_arg(param, char *));
+
+    /* we don't set
+       data->set.method = HTTPREQ_CUSTOM;
+       here, we continue as if we were using the already set type
+       and this just changes the actual request keyword */
+    break;
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_HTTPPROXYTUNNEL:
+    /*
+     * Tunnel operations through the proxy instead of normal proxy use
+     */
+    data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_PROXYPORT:
+    /*
+     * Explicitly set HTTP proxy port number.
+     */
+    arg = va_arg(param, long);
+    if((arg < 0) || (arg > 65535))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.proxyport = (unsigned short)arg;
+    break;
+
+  case CURLOPT_PROXYAUTH:
+    /*
+     * Set HTTP Authentication type BITMASK.
+     */
+  {
+    int bitcheck;
+    bool authbits;
+    unsigned long auth = va_arg(param, unsigned long);
+
+    if(auth == CURLAUTH_NONE) {
+      data->set.proxyauth = auth;
+      break;
+    }
+
+    /* the DIGEST_IE bit is only used to set a special marker, for all the
+       rest we need to handle it as normal DIGEST */
+    data->state.authproxy.iestyle = !!(auth & CURLAUTH_DIGEST_IE);
+
+    if(auth & CURLAUTH_DIGEST_IE) {
+      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+    }
+    /* switch off bits we can't support */
+#ifndef USE_NTLM
+    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
+    auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#elif !defined(NTLM_WB_ENABLED)
+    auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#endif
+#ifndef USE_SPNEGO
+    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
+                                    GSS-API or SSPI */
+#endif
+
+    /* check if any auth bit lower than CURLAUTH_ONLY is still set */
+    bitcheck = 0;
+    authbits = FALSE;
+    while(bitcheck < 31) {
+      if(auth & (1UL << bitcheck++)) {
+        authbits = TRUE;
+        break;
+      }
+    }
+    if(!authbits)
+      return CURLE_NOT_BUILT_IN; /* no supported types left! */
+
+    data->set.proxyauth = auth;
+  }
+  break;
+
+  case CURLOPT_PROXY:
+    /*
+     * Set proxy server:port to use as proxy.
+     *
+     * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL)
+     * we explicitly say that we don't want to use a proxy
+     * (even though there might be environment variables saying so).
+     *
+     * Setting it to NULL, means no proxy but allows the environment variables
+     * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL).
+     */
+    result = Curl_setstropt(&data->set.str[STRING_PROXY],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_PRE_PROXY:
+    /*
+     * Set proxy server:port to use as SOCKS proxy.
+     *
+     * If the proxy is set to "" or NULL we explicitly say that we don't want
+     * to use the socks proxy.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_PRE_PROXY],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_PROXYTYPE:
+    /*
+     * Set proxy type.
+     */
+    arg = va_arg(param, long);
+    if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.proxytype = (unsigned char)(curl_proxytype)arg;
+    break;
+
+  case CURLOPT_PROXY_TRANSFER_MODE:
+    /*
+     * set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy
+     */
+    switch(va_arg(param, long)) {
+    case 0:
+      data->set.proxy_transfer_mode = FALSE;
+      break;
+    case 1:
+      data->set.proxy_transfer_mode = TRUE;
+      break;
+    default:
+      /* reserve other values for future use */
+      result = CURLE_BAD_FUNCTION_ARGUMENT;
+      break;
+    }
+    break;
+
+  case CURLOPT_SOCKS5_AUTH:
+    data->set.socks5auth = (unsigned char)va_arg(param, unsigned long);
+    if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
+      result = CURLE_NOT_BUILT_IN;
+    break;
+#endif   /* CURL_DISABLE_PROXY */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  case CURLOPT_SOCKS5_GSSAPI_NEC:
+    /*
+     * Set flag for NEC SOCK5 support
+     */
+    data->set.socks5_gssapi_nec = (0 != va_arg(param, long));
+    break;
+#endif
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_SOCKS5_GSSAPI_SERVICE:
+  case CURLOPT_PROXY_SERVICE_NAME:
+    /*
+     * Set proxy authentication service name for Kerberos 5 and SPNEGO
+     */
+    result = Curl_setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME],
+                            va_arg(param, char *));
+    break;
+#endif
+  case CURLOPT_SERVICE_NAME:
+    /*
+     * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SERVICE_NAME],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_HEADERDATA:
+    /*
+     * Custom pointer to pass the header write callback function
+     */
+    data->set.writeheader = (void *)va_arg(param, void *);
+    break;
+  case CURLOPT_ERRORBUFFER:
+    /*
+     * Error buffer provided by the caller to get the human readable
+     * error string in.
+     */
+    data->set.errorbuffer = va_arg(param, char *);
+    break;
+  case CURLOPT_WRITEDATA:
+    /*
+     * FILE pointer to write to. Or possibly
+     * used as argument to the write callback.
+     */
+    data->set.out = va_arg(param, void *);
+    break;
+
+#ifdef CURL_LIST_ONLY_PROTOCOL
+  case CURLOPT_DIRLISTONLY:
+    /*
+     * An option that changes the command to one that asks for a list only, no
+     * file info details. Used for FTP, POP3 and SFTP.
+     */
+    data->set.list_only = (0 != va_arg(param, long));
+    break;
+#endif
+  case CURLOPT_APPEND:
+    /*
+     * We want to upload and append to an existing file. Used for FTP and
+     * SFTP.
+     */
+    data->set.remote_append = (0 != va_arg(param, long));
+    break;
+
+#ifndef CURL_DISABLE_FTP
+  case CURLOPT_FTP_FILEMETHOD:
+    /*
+     * How do access files over FTP.
+     */
+    arg = va_arg(param, long);
+    if((arg < CURLFTPMETHOD_DEFAULT) || (arg >= CURLFTPMETHOD_LAST))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.ftp_filemethod = (unsigned char)arg;
+    break;
+  case CURLOPT_FTPPORT:
+    /*
+     * Use FTP PORT, this also specifies which IP address to use
+     */
+    result = Curl_setstropt(&data->set.str[STRING_FTPPORT],
+                            va_arg(param, char *));
+    data->set.ftp_use_port = !!(data->set.str[STRING_FTPPORT]);
+    break;
+
+  case CURLOPT_FTP_USE_EPRT:
+    data->set.ftp_use_eprt = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_FTP_USE_EPSV:
+    data->set.ftp_use_epsv = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_FTP_USE_PRET:
+    data->set.ftp_use_pret = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_FTP_SSL_CCC:
+    arg = va_arg(param, long);
+    if((arg < CURLFTPSSL_CCC_NONE) || (arg >= CURLFTPSSL_CCC_LAST))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.ftp_ccc = (unsigned char)arg;
+    break;
+
+  case CURLOPT_FTP_SKIP_PASV_IP:
+    /*
+     * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the
+     * bypass of the IP address in PASV responses.
+     */
+    data->set.ftp_skip_ip = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_FTP_ACCOUNT:
+    result = Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_FTP_ALTERNATIVE_TO_USER:
+    result = Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_FTPSSLAUTH:
+    /*
+     * Set a specific auth for FTP-SSL transfers.
+     */
+    arg = va_arg(param, long);
+    if((arg < CURLFTPAUTH_DEFAULT) || (arg >= CURLFTPAUTH_LAST))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.ftpsslauth = (unsigned char)(curl_ftpauth)arg;
+    break;
+  case CURLOPT_KRBLEVEL:
+    /*
+     * A string that defines the kerberos security level.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL],
+                            va_arg(param, char *));
+    data->set.krb = !!(data->set.str[STRING_KRB_LEVEL]);
+    break;
+#endif
+#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
+  case CURLOPT_FTP_CREATE_MISSING_DIRS:
+    /*
+     * An FTP/SFTP option that modifies an upload to create missing
+     * directories on the server.
+     */
+    arg = va_arg(param, long);
+    /* reserve other values for future use */
+    if((arg < CURLFTP_CREATE_DIR_NONE) ||
+       (arg > CURLFTP_CREATE_DIR_RETRY))
+      result = CURLE_BAD_FUNCTION_ARGUMENT;
+    else
+      data->set.ftp_create_missing_dirs = (unsigned char)arg;
+    break;
+
+  case CURLOPT_POSTQUOTE:
+    /*
+     * List of RAW FTP commands to use after a transfer
+     */
+    data->set.postquote = va_arg(param, struct curl_slist *);
+    break;
+  case CURLOPT_PREQUOTE:
+    /*
+     * List of RAW FTP commands to use prior to RETR (Wesley Laxton)
+     */
+    data->set.prequote = va_arg(param, struct curl_slist *);
+    break;
+  case CURLOPT_QUOTE:
+    /*
+     * List of RAW FTP commands to use before a transfer
+     */
+    data->set.quote = va_arg(param, struct curl_slist *);
+    break;
+#endif
+  case CURLOPT_READDATA:
+    /*
+     * FILE pointer to read the file to be uploaded from. Or possibly
+     * used as argument to the read callback.
+     */
+    data->set.in_set = va_arg(param, void *);
+    break;
+  case CURLOPT_INFILESIZE:
+    /*
+     * If known, this should inform curl about the file size of the
+     * to-be-uploaded file.
+     */
+    arg = va_arg(param, long);
+    if(arg < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.filesize = arg;
+    break;
+  case CURLOPT_INFILESIZE_LARGE:
+    /*
+     * If known, this should inform curl about the file size of the
+     * to-be-uploaded file.
+     */
+    bigsize = va_arg(param, curl_off_t);
+    if(bigsize < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.filesize = bigsize;
+    break;
+  case CURLOPT_LOW_SPEED_LIMIT:
+    /*
+     * The low speed limit that if transfers are below this for
+     * CURLOPT_LOW_SPEED_TIME, the transfer is aborted.
+     */
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.low_speed_limit = arg;
+    break;
+  case CURLOPT_MAX_SEND_SPEED_LARGE:
+    /*
+     * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE
+     * bytes per second the transfer is throttled..
+     */
+    bigsize = va_arg(param, curl_off_t);
+    if(bigsize < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.max_send_speed = bigsize;
+    break;
+  case CURLOPT_MAX_RECV_SPEED_LARGE:
+    /*
+     * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per
+     * second the transfer is throttled..
+     */
+    bigsize = va_arg(param, curl_off_t);
+    if(bigsize < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.max_recv_speed = bigsize;
+    break;
+  case CURLOPT_LOW_SPEED_TIME:
+    /*
+     * The low speed time that if transfers are below the set
+     * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted.
+     */
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.low_speed_time = arg;
+    break;
+  case CURLOPT_CURLU:
+    /*
+     * pass CURLU to set URL
+     */
+    data->set.uh = va_arg(param, CURLU *);
+    break;
+  case CURLOPT_URL:
+    /*
+     * The URL to fetch.
+     */
+    if(data->state.url_alloc) {
+      /* the already set URL is allocated, free it first! */
+      Curl_safefree(data->state.url);
+      data->state.url_alloc = FALSE;
+    }
+    result = Curl_setstropt(&data->set.str[STRING_SET_URL],
+                            va_arg(param, char *));
+    data->state.url = data->set.str[STRING_SET_URL];
+    break;
+  case CURLOPT_PORT:
+    /*
+     * The port number to use when getting the URL. 0 disables it.
+     */
+    arg = va_arg(param, long);
+    if((arg < 0) || (arg > 65535))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.use_port = (unsigned short)arg;
+    break;
+  case CURLOPT_TIMEOUT:
+    /*
+     * The maximum time you allow curl to use for a single transfer
+     * operation.
+     */
+    arg = va_arg(param, long);
+    if((arg >= 0) && (arg <= (INT_MAX/1000)))
+      data->set.timeout = (unsigned int)arg * 1000;
+    else
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+
+  case CURLOPT_TIMEOUT_MS:
+    uarg = va_arg(param, unsigned long);
+    if(uarg > UINT_MAX)
+      uarg = UINT_MAX;
+    data->set.timeout = (unsigned int)uarg;
+    break;
+
+  case CURLOPT_CONNECTTIMEOUT:
+    /*
+     * The maximum time you allow curl to use to connect.
+     */
+    arg = va_arg(param, long);
+    if((arg >= 0) && (arg <= (INT_MAX/1000)))
+      data->set.connecttimeout = (unsigned int)arg * 1000;
+    else
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+
+  case CURLOPT_CONNECTTIMEOUT_MS:
+    uarg = va_arg(param, unsigned long);
+    if(uarg > UINT_MAX)
+      uarg = UINT_MAX;
+    data->set.connecttimeout = (unsigned int)uarg;
+    break;
+
+#ifndef CURL_DISABLE_FTP
+  case CURLOPT_ACCEPTTIMEOUT_MS:
+    /*
+     * The maximum time for curl to wait for FTP server connect
+     */
+    uarg = va_arg(param, unsigned long);
+    if(uarg > UINT_MAX)
+      uarg = UINT_MAX;
+    data->set.accepttimeout = (unsigned int)uarg;
+    break;
+#endif
+
+  case CURLOPT_USERPWD:
+    /*
+     * user:password to use in the operation
+     */
+    result = setstropt_userpwd(va_arg(param, char *),
+                               &data->set.str[STRING_USERNAME],
+                               &data->set.str[STRING_PASSWORD]);
+    break;
+
+  case CURLOPT_USERNAME:
+    /*
+     * authentication user name to use in the operation
+     */
+    result = Curl_setstropt(&data->set.str[STRING_USERNAME],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_PASSWORD:
+    /*
+     * authentication password to use in the operation
+     */
+    result = Curl_setstropt(&data->set.str[STRING_PASSWORD],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_LOGIN_OPTIONS:
+    /*
+     * authentication options to use in the operation
+     */
+    result = Curl_setstropt(&data->set.str[STRING_OPTIONS],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_XOAUTH2_BEARER:
+    /*
+     * OAuth 2.0 bearer token to use in the operation
+     */
+    result = Curl_setstropt(&data->set.str[STRING_BEARER],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_RESOLVE:
+    /*
+     * List of HOST:PORT:[addresses] strings to populate the DNS cache with
+     * Entries added this way will remain in the cache until explicitly
+     * removed or the handle is cleaned up.
+     *
+     * Prefix the HOST with plus sign (+) to have the entry expire just like
+     * automatically added entries.
+     *
+     * Prefix the HOST with dash (-) to _remove_ the entry from the cache.
+     *
+     * This API can remove any entry from the DNS cache, but only entries
+     * that aren't actually in use right now will be pruned immediately.
+     */
+    data->set.resolve = va_arg(param, struct curl_slist *);
+    data->state.resolve = data->set.resolve;
+    break;
+  case CURLOPT_PROGRESSFUNCTION:
+    /*
+     * Progress callback function
+     */
+    data->set.fprogress = va_arg(param, curl_progress_callback);
+    if(data->set.fprogress)
+      data->progress.callback = TRUE; /* no longer internal */
+    else
+      data->progress.callback = FALSE; /* NULL enforces internal */
+    break;
+
+  case CURLOPT_XFERINFOFUNCTION:
+    /*
+     * Transfer info callback function
+     */
+    data->set.fxferinfo = va_arg(param, curl_xferinfo_callback);
+    if(data->set.fxferinfo)
+      data->progress.callback = TRUE; /* no longer internal */
+    else
+      data->progress.callback = FALSE; /* NULL enforces internal */
+
+    break;
+
+  case CURLOPT_PROGRESSDATA:
+    /*
+     * Custom client data to pass to the progress callback
+     */
+    data->set.progress_client = va_arg(param, void *);
+    break;
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXYUSERPWD:
+    /*
+     * user:password needed to use the proxy
+     */
+    result = setstropt_userpwd(va_arg(param, char *),
+                               &data->set.str[STRING_PROXYUSERNAME],
+                               &data->set.str[STRING_PROXYPASSWORD]);
+    break;
+  case CURLOPT_PROXYUSERNAME:
+    /*
+     * authentication user name to use in the operation
+     */
+    result = Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_PROXYPASSWORD:
+    /*
+     * authentication password to use in the operation
+     */
+    result = Curl_setstropt(&data->set.str[STRING_PROXYPASSWORD],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_NOPROXY:
+    /*
+     * proxy exception list
+     */
+    result = Curl_setstropt(&data->set.str[STRING_NOPROXY],
+                            va_arg(param, char *));
+    break;
+#endif
+
+  case CURLOPT_RANGE:
+    /*
+     * What range of the file you want to transfer
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SET_RANGE],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_RESUME_FROM:
+    /*
+     * Resume transfer at the given file position
+     */
+    arg = va_arg(param, long);
+    if(arg < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.set_resume_from = arg;
+    break;
+  case CURLOPT_RESUME_FROM_LARGE:
+    /*
+     * Resume transfer at the given file position
+     */
+    bigsize = va_arg(param, curl_off_t);
+    if(bigsize < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.set_resume_from = bigsize;
+    break;
+  case CURLOPT_DEBUGFUNCTION:
+    /*
+     * stderr write callback.
+     */
+    data->set.fdebug = va_arg(param, curl_debug_callback);
+    /*
+     * if the callback provided is NULL, it'll use the default callback
+     */
+    break;
+  case CURLOPT_DEBUGDATA:
+    /*
+     * Set to a void * that should receive all error writes. This
+     * defaults to CURLOPT_STDERR for normal operations.
+     */
+    data->set.debugdata = va_arg(param, void *);
+    break;
+  case CURLOPT_STDERR:
+    /*
+     * Set to a FILE * that should receive all error writes. This
+     * defaults to stderr for normal operations.
+     */
+    data->set.err = va_arg(param, FILE *);
+    if(!data->set.err)
+      data->set.err = stderr;
+    break;
+  case CURLOPT_HEADERFUNCTION:
+    /*
+     * Set header write callback
+     */
+    data->set.fwrite_header = va_arg(param, curl_write_callback);
+    break;
+  case CURLOPT_WRITEFUNCTION:
+    /*
+     * Set data write callback
+     */
+    data->set.fwrite_func = va_arg(param, curl_write_callback);
+    if(!data->set.fwrite_func)
+      /* When set to NULL, reset to our internal default function */
+      data->set.fwrite_func = (curl_write_callback)fwrite;
+    break;
+  case CURLOPT_READFUNCTION:
+    /*
+     * Read data callback
+     */
+    data->set.fread_func_set = va_arg(param, curl_read_callback);
+    if(!data->set.fread_func_set) {
+      data->set.is_fread_set = 0;
+      /* When set to NULL, reset to our internal default function */
+      data->set.fread_func_set = (curl_read_callback)fread;
+    }
+    else
+      data->set.is_fread_set = 1;
+    break;
+  case CURLOPT_SEEKFUNCTION:
+    /*
+     * Seek callback. Might be NULL.
+     */
+    data->set.seek_func = va_arg(param, curl_seek_callback);
+    break;
+  case CURLOPT_SEEKDATA:
+    /*
+     * Seek control callback. Might be NULL.
+     */
+    data->set.seek_client = va_arg(param, void *);
+    break;
+  case CURLOPT_IOCTLFUNCTION:
+    /*
+     * I/O control callback. Might be NULL.
+     */
+    data->set.ioctl_func = va_arg(param, curl_ioctl_callback);
+    break;
+  case CURLOPT_IOCTLDATA:
+    /*
+     * I/O control data pointer. Might be NULL.
+     */
+    data->set.ioctl_client = va_arg(param, void *);
+    break;
+  case CURLOPT_SSLCERT:
+    /*
+     * String that holds file name of the SSL certificate to use
+     */
+    result = Curl_setstropt(&data->set.str[STRING_CERT],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_SSLCERT_BLOB:
+    /*
+     * Blob that holds file content of the SSL certificate to use
+     */
+    result = Curl_setblobopt(&data->set.blobs[BLOB_CERT],
+                             va_arg(param, struct curl_blob *));
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSLCERT:
+    /*
+     * String that holds file name of the SSL certificate to use for proxy
+     */
+    result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_PROXY_SSLCERT_BLOB:
+    /*
+     * Blob that holds file content of the SSL certificate to use for proxy
+     */
+    result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY],
+                             va_arg(param, struct curl_blob *));
+    break;
+#endif
+  case CURLOPT_SSLCERTTYPE:
+    /*
+     * String that holds file type of the SSL certificate to use
+     */
+    result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE],
+                            va_arg(param, char *));
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSLCERTTYPE:
+    /*
+     * String that holds file type of the SSL certificate to use for proxy
+     */
+    result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY],
+                            va_arg(param, char *));
+    break;
+#endif
+  case CURLOPT_SSLKEY:
+    /*
+     * String that holds file name of the SSL key to use
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KEY],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_SSLKEY_BLOB:
+    /*
+     * Blob that holds file content of the SSL key to use
+     */
+    result = Curl_setblobopt(&data->set.blobs[BLOB_KEY],
+                             va_arg(param, struct curl_blob *));
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSLKEY:
+    /*
+     * String that holds file name of the SSL key to use for proxy
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_PROXY_SSLKEY_BLOB:
+    /*
+     * Blob that holds file content of the SSL key to use for proxy
+     */
+    result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY],
+                             va_arg(param, struct curl_blob *));
+    break;
+#endif
+  case CURLOPT_SSLKEYTYPE:
+    /*
+     * String that holds file type of the SSL key to use
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE],
+                            va_arg(param, char *));
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSLKEYTYPE:
+    /*
+     * String that holds file type of the SSL key to use for proxy
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_PROXY],
+                            va_arg(param, char *));
+    break;
+#endif
+  case CURLOPT_KEYPASSWD:
+    /*
+     * String that holds the SSL or SSH private key password.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD],
+                            va_arg(param, char *));
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_KEYPASSWD:
+    /*
+     * String that holds the SSL private key password for proxy.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY],
+                            va_arg(param, char *));
+    break;
+#endif
+  case CURLOPT_SSLENGINE:
+    /*
+     * String that holds the SSL crypto engine.
+     */
+    argptr = va_arg(param, char *);
+    if(argptr && argptr[0]) {
+      result = Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], argptr);
+      if(!result) {
+        result = Curl_ssl_set_engine(data, argptr);
+      }
+    }
+    break;
+
+  case CURLOPT_SSLENGINE_DEFAULT:
+    /*
+     * flag to set engine as default.
+     */
+    Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], NULL);
+    result = Curl_ssl_set_engine_default(data);
+    break;
+  case CURLOPT_CRLF:
+    /*
+     * Kludgy option to enable CRLF conversions. Subject for removal.
+     */
+    data->set.crlf = (0 != va_arg(param, long));
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_HAPROXYPROTOCOL:
+    /*
+     * Set to send the HAProxy Proxy Protocol header
+     */
+    data->set.haproxyprotocol = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_HAPROXY_CLIENT_IP:
+    /*
+     * Set the client IP to send through HAProxy PROXY protocol
+     */
+    result = Curl_setstropt(&data->set.str[STRING_HAPROXY_CLIENT_IP],
+                            va_arg(param, char *));
+    /* We enable implicitly the HAProxy protocol if we use this flag. */
+    data->set.haproxyprotocol = TRUE;
+    break;
+#endif
+  case CURLOPT_INTERFACE:
+    /*
+     * Set what interface or address/hostname to bind the socket to when
+     * performing an operation and thus what from-IP your connection will use.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_DEVICE],
+                            va_arg(param, char *));
+    break;
+#ifndef CURL_DISABLE_BINDLOCAL
+  case CURLOPT_LOCALPORT:
+    /*
+     * Set what local port to bind the socket to when performing an operation.
+     */
+    arg = va_arg(param, long);
+    if((arg < 0) || (arg > 65535))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.localport = curlx_sltous(arg);
+    break;
+  case CURLOPT_LOCALPORTRANGE:
+    /*
+     * Set number of local ports to try, starting with CURLOPT_LOCALPORT.
+     */
+    arg = va_arg(param, long);
+    if((arg < 0) || (arg > 65535))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.localportrange = curlx_sltous(arg);
+    break;
+#endif
+  case CURLOPT_GSSAPI_DELEGATION:
+    /*
+     * GSS-API credential delegation bitmask
+     */
+    uarg = va_arg(param, unsigned long);
+    data->set.gssapi_delegation = (unsigned char)uarg&
+      (CURLGSSAPI_DELEGATION_POLICY_FLAG|CURLGSSAPI_DELEGATION_FLAG);
+    break;
+  case CURLOPT_SSL_VERIFYPEER:
+    /*
+     * Enable peer SSL verifying.
+     */
+    data->set.ssl.primary.verifypeer = (0 != va_arg(param, long));
+
+    /* Update the current connection ssl_config. */
+    Curl_ssl_conn_config_update(data, FALSE);
+    break;
+#ifndef CURL_DISABLE_DOH
+  case CURLOPT_DOH_SSL_VERIFYPEER:
+    /*
+     * Enable peer SSL verifying for DoH.
+     */
+    data->set.doh_verifypeer = (0 != va_arg(param, long));
+    break;
+#endif
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSL_VERIFYPEER:
+    /*
+     * Enable peer SSL verifying for proxy.
+     */
+    data->set.proxy_ssl.primary.verifypeer =
+      (0 != va_arg(param, long))?TRUE:FALSE;
+
+    /* Update the current connection proxy_ssl_config. */
+    Curl_ssl_conn_config_update(data, TRUE);
+    break;
+#endif
+  case CURLOPT_SSL_VERIFYHOST:
+    /*
+     * Enable verification of the host name in the peer certificate
+     */
+    arg = va_arg(param, long);
+
+    /* Obviously people are not reading documentation and too many thought
+       this argument took a boolean when it wasn't and misused it.
+       Treat 1 and 2 the same */
+    data->set.ssl.primary.verifyhost = !!(arg & 3);
+
+    /* Update the current connection ssl_config. */
+    Curl_ssl_conn_config_update(data, FALSE);
+    break;
+#ifndef CURL_DISABLE_DOH
+  case CURLOPT_DOH_SSL_VERIFYHOST:
+    /*
+     * Enable verification of the host name in the peer certificate for DoH
+     */
+    arg = va_arg(param, long);
+
+    /* Treat both 1 and 2 as TRUE */
+    data->set.doh_verifyhost = !!(arg & 3);
+    break;
+#endif
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSL_VERIFYHOST:
+    /*
+     * Enable verification of the host name in the peer certificate for proxy
+     */
+    arg = va_arg(param, long);
+
+    /* Treat both 1 and 2 as TRUE */
+    data->set.proxy_ssl.primary.verifyhost = (bool)((arg & 3)?TRUE:FALSE);
+    /* Update the current connection proxy_ssl_config. */
+    Curl_ssl_conn_config_update(data, TRUE);
+    break;
+#endif
+  case CURLOPT_SSL_VERIFYSTATUS:
+    /*
+     * Enable certificate status verifying.
+     */
+    if(!Curl_ssl_cert_status_request()) {
+      result = CURLE_NOT_BUILT_IN;
+      break;
+    }
+
+    data->set.ssl.primary.verifystatus = (0 != va_arg(param, long));
+
+    /* Update the current connection ssl_config. */
+    Curl_ssl_conn_config_update(data, FALSE);
+    break;
+#ifndef CURL_DISABLE_DOH
+  case CURLOPT_DOH_SSL_VERIFYSTATUS:
+    /*
+     * Enable certificate status verifying for DoH.
+     */
+    if(!Curl_ssl_cert_status_request()) {
+      result = CURLE_NOT_BUILT_IN;
+      break;
+    }
+
+    data->set.doh_verifystatus = (0 != va_arg(param, long));
+    break;
+#endif
+  case CURLOPT_SSL_CTX_FUNCTION:
+    /*
+     * Set a SSL_CTX callback
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
+      data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+    break;
+  case CURLOPT_SSL_CTX_DATA:
+    /*
+     * Set a SSL_CTX callback parameter pointer
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
+      data->set.ssl.fsslctxp = va_arg(param, void *);
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+    break;
+  case CURLOPT_SSL_FALSESTART:
+    /*
+     * Enable TLS false start.
+     */
+    if(!Curl_ssl_false_start(data)) {
+      result = CURLE_NOT_BUILT_IN;
+      break;
+    }
+
+    data->set.ssl.falsestart = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_CERTINFO:
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_CERTINFO))
+      data->set.ssl.certinfo = (0 != va_arg(param, long));
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+    break;
+  case CURLOPT_PINNEDPUBLICKEY:
+    /*
+     * Set pinned public key for SSL connection.
+     * Specify file name of the public key in DER format.
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
+      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY],
+                              va_arg(param, char *));
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_PINNEDPUBLICKEY:
+    /*
+     * Set pinned public key for SSL connection.
+     * Specify file name of the public key in DER format.
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
+      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
+                              va_arg(param, char *));
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+    break;
+#endif
+  case CURLOPT_CAINFO:
+    /*
+     * Set CA info for SSL connection. Specify file name of the CA certificate
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_CAINFO_BLOB:
+    /*
+     * Blob that holds CA info for SSL connection.
+     * Specify entire PEM of the CA certificate
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) {
+      result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO],
+                               va_arg(param, struct curl_blob *));
+      break;
+    }
+    else
+#endif
+      return CURLE_NOT_BUILT_IN;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_CAINFO:
+    /*
+     * Set CA info SSL connection for proxy. Specify file name of the
+     * CA certificate
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_PROXY_CAINFO_BLOB:
+    /*
+     * Blob that holds CA info for SSL connection proxy.
+     * Specify entire PEM of the CA certificate
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) {
+      result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY],
+                               va_arg(param, struct curl_blob *));
+      break;
+    }
+    else
+#endif
+      return CURLE_NOT_BUILT_IN;
+#endif
+  case CURLOPT_CAPATH:
+    /*
+     * Set CA path info for SSL connection. Specify directory name of the CA
+     * certificates which have been prepared using openssl c_rehash utility.
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_CA_PATH))
+      /* This does not work on windows. */
+      result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH],
+                              va_arg(param, char *));
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_CAPATH:
+    /*
+     * Set CA path info for SSL connection proxy. Specify directory name of the
+     * CA certificates which have been prepared using openssl c_rehash utility.
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_CA_PATH))
+      /* This does not work on windows. */
+      result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY],
+                              va_arg(param, char *));
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+    break;
+#endif
+  case CURLOPT_CRLFILE:
+    /*
+     * Set CRL file info for SSL connection. Specify file name of the CRL
+     * to check certificates revocation
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE],
+                            va_arg(param, char *));
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_CRLFILE:
+    /*
+     * Set CRL file info for SSL connection for proxy. Specify file name of the
+     * CRL to check certificates revocation
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY],
+                            va_arg(param, char *));
+    break;
+#endif
+  case CURLOPT_ISSUERCERT:
+    /*
+     * Set Issuer certificate file
+     * to check certificates issuer
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_ISSUERCERT_BLOB:
+    /*
+     * Blob that holds Issuer certificate to check certificates issuer
+     */
+    result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT],
+                             va_arg(param, struct curl_blob *));
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_ISSUERCERT:
+    /*
+     * Set Issuer certificate file
+     * to check certificates issuer
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_PROXY],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_PROXY_ISSUERCERT_BLOB:
+    /*
+     * Blob that holds Issuer certificate to check certificates issuer
+     */
+    result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY],
+                             va_arg(param, struct curl_blob *));
+    break;
+#endif
+#ifndef CURL_DISABLE_TELNET
+  case CURLOPT_TELNETOPTIONS:
+    /*
+     * Set a linked list of telnet options
+     */
+    data->set.telnet_options = va_arg(param, struct curl_slist *);
+    break;
+#endif
+  case CURLOPT_BUFFERSIZE:
+    /*
+     * The application kindly asks for a differently sized receive buffer.
+     * If it seems reasonable, we'll use it.
+     */
+    arg = va_arg(param, long);
+
+    if(arg > READBUFFER_MAX)
+      arg = READBUFFER_MAX;
+    else if(arg < 1)
+      arg = READBUFFER_SIZE;
+    else if(arg < READBUFFER_MIN)
+      arg = READBUFFER_MIN;
+
+    data->set.buffer_size = (unsigned int)arg;
+    break;
+
+  case CURLOPT_UPLOAD_BUFFERSIZE:
+    /*
+     * The application kindly asks for a differently sized upload buffer.
+     * Cap it to sensible.
+     */
+    arg = va_arg(param, long);
+
+    if(arg > UPLOADBUFFER_MAX)
+      arg = UPLOADBUFFER_MAX;
+    else if(arg < UPLOADBUFFER_MIN)
+      arg = UPLOADBUFFER_MIN;
+
+    data->set.upload_buffer_size = (unsigned int)arg;
+    break;
+
+  case CURLOPT_NOSIGNAL:
+    /*
+     * The application asks not to set any signal() or alarm() handlers,
+     * even when using a timeout.
+     */
+    data->set.no_signal = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_SHARE:
+  {
+    struct Curl_share *set;
+    set = va_arg(param, struct Curl_share *);
+
+    /* disconnect from old share, if any */
+    if(data->share) {
+      Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+      if(data->dns.hostcachetype == HCACHE_SHARED) {
+        data->dns.hostcache = NULL;
+        data->dns.hostcachetype = HCACHE_NONE;
+      }
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+      if(data->share->cookies == data->cookies)
+        data->cookies = NULL;
+#endif
+
+#ifndef CURL_DISABLE_HSTS
+      if(data->share->hsts == data->hsts)
+        data->hsts = NULL;
+#endif
+#ifdef USE_SSL
+      if(data->share->sslsession == data->state.session)
+        data->state.session = NULL;
+#endif
+#ifdef USE_LIBPSL
+      if(data->psl == &data->share->psl)
+        data->psl = data->multi? &data->multi->psl: NULL;
+#endif
+
+      data->share->dirty--;
+
+      Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+      data->share = NULL;
+    }
+
+    if(GOOD_SHARE_HANDLE(set))
+      /* use new share if it set */
+      data->share = set;
+    if(data->share) {
+
+      Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+      data->share->dirty++;
+
+      if(data->share->specifier & (1<< CURL_LOCK_DATA_DNS)) {
+        /* use shared host cache */
+        data->dns.hostcache = &data->share->hostcache;
+        data->dns.hostcachetype = HCACHE_SHARED;
+      }
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+      if(data->share->cookies) {
+        /* use shared cookie list, first free own one if any */
+        Curl_cookie_cleanup(data->cookies);
+        /* enable cookies since we now use a share that uses cookies! */
+        data->cookies = data->share->cookies;
+      }
+#endif   /* CURL_DISABLE_HTTP */
+#ifndef CURL_DISABLE_HSTS
+      if(data->share->hsts) {
+        /* first free the private one if any */
+        Curl_hsts_cleanup(&data->hsts);
+        data->hsts = data->share->hsts;
+      }
+#endif   /* CURL_DISABLE_HTTP */
+#ifdef USE_SSL
+      if(data->share->sslsession) {
+        data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
+        data->state.session = data->share->sslsession;
+      }
+#endif
+#ifdef USE_LIBPSL
+      if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL))
+        data->psl = &data->share->psl;
+#endif
+
+      Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+    }
+    /* check for host cache not needed,
+     * it will be done by curl_easy_perform */
+  }
+  break;
+
+  case CURLOPT_PRIVATE:
+    /*
+     * Set private data pointer.
+     */
+    data->set.private_data = va_arg(param, void *);
+    break;
+
+  case CURLOPT_MAXFILESIZE:
+    /*
+     * Set the maximum size of a file to download.
+     */
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.max_filesize = arg;
+    break;
+
+#ifdef USE_SSL
+  case CURLOPT_USE_SSL:
+    /*
+     * Make transfers attempt to use SSL/TLS.
+     */
+    arg = va_arg(param, long);
+    if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.use_ssl = (unsigned char)arg;
+    break;
+
+  case CURLOPT_SSL_OPTIONS:
+    arg = va_arg(param, long);
+    data->set.ssl.primary.ssl_options = (unsigned char)(arg & 0xff);
+    data->set.ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST);
+    data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
+    data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
+    data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
+    data->set.ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
+    data->set.ssl.auto_client_cert = !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT);
+    /* If a setting is added here it should also be added in dohprobe()
+       which sets its own CURLOPT_SSL_OPTIONS based on these settings. */
+    break;
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSL_OPTIONS:
+    arg = va_arg(param, long);
+    data->set.proxy_ssl.primary.ssl_options = (unsigned char)(arg & 0xff);
+    data->set.proxy_ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST);
+    data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
+    data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
+    data->set.proxy_ssl.revoke_best_effort =
+      !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
+    data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
+    data->set.proxy_ssl.auto_client_cert =
+      !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT);
+    break;
+#endif
+
+  case CURLOPT_SSL_EC_CURVES:
+    /*
+     * Set accepted curves in SSL connection setup.
+     * Specify colon-delimited list of curve algorithm names.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES],
+                            va_arg(param, char *));
+    break;
+#endif
+  case CURLOPT_IPRESOLVE:
+    arg = va_arg(param, long);
+    if((arg < CURL_IPRESOLVE_WHATEVER) || (arg > CURL_IPRESOLVE_V6))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.ipver = (unsigned char) arg;
+    break;
+
+  case CURLOPT_MAXFILESIZE_LARGE:
+    /*
+     * Set the maximum size of a file to download.
+     */
+    bigsize = va_arg(param, curl_off_t);
+    if(bigsize < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.max_filesize = bigsize;
+    break;
+
+  case CURLOPT_TCP_NODELAY:
+    /*
+     * Enable or disable TCP_NODELAY, which will disable/enable the Nagle
+     * algorithm
+     */
+    data->set.tcp_nodelay = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_IGNORE_CONTENT_LENGTH:
+    data->set.ignorecl = (0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_CONNECT_ONLY:
+    /*
+     * No data transfer.
+     * (1) - only do connection
+     * (2) - do first get request but get no content
+     */
+    arg = va_arg(param, long);
+    if(arg > 2)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.connect_only = (unsigned char)arg;
+    break;
+
+  case CURLOPT_SOCKOPTFUNCTION:
+    /*
+     * socket callback function: called after socket() but before connect()
+     */
+    data->set.fsockopt = va_arg(param, curl_sockopt_callback);
+    break;
+
+  case CURLOPT_SOCKOPTDATA:
+    /*
+     * socket callback data pointer. Might be NULL.
+     */
+    data->set.sockopt_client = va_arg(param, void *);
+    break;
+
+  case CURLOPT_OPENSOCKETFUNCTION:
+    /*
+     * open/create socket callback function: called instead of socket(),
+     * before connect()
+     */
+    data->set.fopensocket = va_arg(param, curl_opensocket_callback);
+    break;
+
+  case CURLOPT_OPENSOCKETDATA:
+    /*
+     * socket callback data pointer. Might be NULL.
+     */
+    data->set.opensocket_client = va_arg(param, void *);
+    break;
+
+  case CURLOPT_CLOSESOCKETFUNCTION:
+    /*
+     * close socket callback function: called instead of close()
+     * when shutting down a connection
+     */
+    data->set.fclosesocket = va_arg(param, curl_closesocket_callback);
+    break;
+
+  case CURLOPT_RESOLVER_START_FUNCTION:
+    /*
+     * resolver start callback function: called before a new resolver request
+     * is started
+     */
+    data->set.resolver_start = va_arg(param, curl_resolver_start_callback);
+    break;
+
+  case CURLOPT_RESOLVER_START_DATA:
+    /*
+     * resolver start callback data pointer. Might be NULL.
+     */
+    data->set.resolver_start_client = va_arg(param, void *);
+    break;
+
+  case CURLOPT_CLOSESOCKETDATA:
+    /*
+     * socket callback data pointer. Might be NULL.
+     */
+    data->set.closesocket_client = va_arg(param, void *);
+    break;
+
+  case CURLOPT_SSL_SESSIONID_CACHE:
+    data->set.ssl.primary.sessionid = (0 != va_arg(param, long));
+#ifndef CURL_DISABLE_PROXY
+    data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid;
+#endif
+    break;
+
+#ifdef USE_SSH
+    /* we only include SSH options if explicitly built to support SSH */
+  case CURLOPT_SSH_AUTH_TYPES:
+    data->set.ssh_auth_types = (unsigned int)va_arg(param, long);
+    break;
+
+  case CURLOPT_SSH_PUBLIC_KEYFILE:
+    /*
+     * Use this file instead of the $HOME/.ssh/id_dsa.pub file
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_SSH_PRIVATE_KEYFILE:
+    /*
+     * Use this file instead of the $HOME/.ssh/id_dsa file
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
+    /*
+     * Option to allow for the MD5 of the host public key to be checked
+     * for validation purposes.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_SSH_KNOWNHOSTS:
+    /*
+     * Store the file name to read known hosts from.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
+                            va_arg(param, char *));
+    break;
+#ifdef USE_LIBSSH2
+  case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
+    /*
+     * Option to allow for the SHA256 of the host public key to be checked
+     * for validation purposes.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_SSH_HOSTKEYFUNCTION:
+    /* the callback to check the hostkey without the knownhost file */
+    data->set.ssh_hostkeyfunc = va_arg(param, curl_sshhostkeycallback);
+    break;
+
+  case CURLOPT_SSH_HOSTKEYDATA:
+    /*
+     * Custom client data to pass to the SSH keyfunc callback
+     */
+    data->set.ssh_hostkeyfunc_userp = va_arg(param, void *);
+    break;
+#endif
+
+  case CURLOPT_SSH_KEYFUNCTION:
+    /* setting to NULL is fine since the ssh.c functions themselves will
+       then revert to use the internal default */
+    data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback);
+    break;
+
+  case CURLOPT_SSH_KEYDATA:
+    /*
+     * Custom client data to pass to the SSH keyfunc callback
+     */
+    data->set.ssh_keyfunc_userp = va_arg(param, void *);
+    break;
+
+  case CURLOPT_SSH_COMPRESSION:
+    data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE;
+    break;
+#endif /* USE_SSH */
+
+  case CURLOPT_HTTP_TRANSFER_DECODING:
+    /*
+     * disable libcurl transfer encoding is used
+     */
+#ifndef USE_HYPER
+    data->set.http_te_skip = (0 == va_arg(param, long));
+    break;
+#else
+    return CURLE_NOT_BUILT_IN; /* hyper doesn't support */
+#endif
+
+  case CURLOPT_HTTP_CONTENT_DECODING:
+    /*
+     * raw data passed to the application when content encoding is used
+     */
+    data->set.http_ce_skip = (0 == va_arg(param, long));
+    break;
+
+#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
+  case CURLOPT_NEW_FILE_PERMS:
+    /*
+     * Uses these permissions instead of 0644
+     */
+    arg = va_arg(param, long);
+    if((arg < 0) || (arg > 0777))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.new_file_perms = (unsigned int)arg;
+    break;
+#endif
+#ifdef USE_SSH
+  case CURLOPT_NEW_DIRECTORY_PERMS:
+    /*
+     * Uses these permissions instead of 0755
+     */
+    arg = va_arg(param, long);
+    if((arg < 0) || (arg > 0777))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.new_directory_perms = (unsigned int)arg;
+    break;
+#endif
+
+#ifdef ENABLE_IPV6
+  case CURLOPT_ADDRESS_SCOPE:
+    /*
+     * Use this scope id when using IPv6
+     * We always get longs when passed plain numericals so we should check
+     * that the value fits into an unsigned 32 bit integer.
+     */
+    uarg = va_arg(param, unsigned long);
+#if SIZEOF_LONG > 4
+    if(uarg > UINT_MAX)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+#endif
+    data->set.scope_id = (unsigned int)uarg;
+    break;
+#endif
+
+  case CURLOPT_PROTOCOLS:
+    /* set the bitmask for the protocols that are allowed to be used for the
+       transfer, which thus helps the app which takes URLs from users or other
+       external inputs and want to restrict what protocol(s) to deal
+       with. Defaults to CURLPROTO_ALL. */
+    data->set.allowed_protocols = (curl_prot_t)va_arg(param, long);
+    break;
+
+  case CURLOPT_REDIR_PROTOCOLS:
+    /* set the bitmask for the protocols that libcurl is allowed to follow to,
+       as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+       to be set in both bitmasks to be allowed to get redirected to. */
+    data->set.redir_protocols = (curl_prot_t)va_arg(param, long);
+    break;
+
+  case CURLOPT_PROTOCOLS_STR: {
+    argptr = va_arg(param, char *);
+    result = protocol2num(argptr, &data->set.allowed_protocols);
+    if(result)
+      return result;
+    break;
+  }
+
+  case CURLOPT_REDIR_PROTOCOLS_STR: {
+    argptr = va_arg(param, char *);
+    result = protocol2num(argptr, &data->set.redir_protocols);
+    if(result)
+      return result;
+    break;
+  }
+
+  case CURLOPT_DEFAULT_PROTOCOL:
+    /* Set the protocol to use when the URL doesn't include any protocol */
+    result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
+                            va_arg(param, char *));
+    break;
+#ifndef CURL_DISABLE_SMTP
+  case CURLOPT_MAIL_FROM:
+    /* Set the SMTP mail originator */
+    result = Curl_setstropt(&data->set.str[STRING_MAIL_FROM],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_MAIL_AUTH:
+    /* Set the SMTP auth originator */
+    result = Curl_setstropt(&data->set.str[STRING_MAIL_AUTH],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_MAIL_RCPT:
+    /* Set the list of mail recipients */
+    data->set.mail_rcpt = va_arg(param, struct curl_slist *);
+    break;
+  case CURLOPT_MAIL_RCPT_ALLOWFAILS:
+    /* allow RCPT TO command to fail for some recipients */
+    data->set.mail_rcpt_allowfails = (0 != va_arg(param, long));
+    break;
+#endif
+
+  case CURLOPT_SASL_AUTHZID:
+    /* Authorization identity (identity to act as) */
+    result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_SASL_IR:
+    /* Enable/disable SASL initial response */
+    data->set.sasl_ir = (0 != va_arg(param, long));
+    break;
+#ifndef CURL_DISABLE_RTSP
+  case CURLOPT_RTSP_REQUEST:
+  {
+    /*
+     * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...)
+     * Would this be better if the RTSPREQ_* were just moved into here?
+     */
+    long in_rtspreq = va_arg(param, long);
+    Curl_RtspReq rtspreq = RTSPREQ_NONE;
+    switch(in_rtspreq) {
+    case CURL_RTSPREQ_OPTIONS:
+      rtspreq = RTSPREQ_OPTIONS;
+      break;
+
+    case CURL_RTSPREQ_DESCRIBE:
+      rtspreq = RTSPREQ_DESCRIBE;
+      break;
+
+    case CURL_RTSPREQ_ANNOUNCE:
+      rtspreq = RTSPREQ_ANNOUNCE;
+      break;
+
+    case CURL_RTSPREQ_SETUP:
+      rtspreq = RTSPREQ_SETUP;
+      break;
+
+    case CURL_RTSPREQ_PLAY:
+      rtspreq = RTSPREQ_PLAY;
+      break;
+
+    case CURL_RTSPREQ_PAUSE:
+      rtspreq = RTSPREQ_PAUSE;
+      break;
+
+    case CURL_RTSPREQ_TEARDOWN:
+      rtspreq = RTSPREQ_TEARDOWN;
+      break;
+
+    case CURL_RTSPREQ_GET_PARAMETER:
+      rtspreq = RTSPREQ_GET_PARAMETER;
+      break;
+
+    case CURL_RTSPREQ_SET_PARAMETER:
+      rtspreq = RTSPREQ_SET_PARAMETER;
+      break;
+
+    case CURL_RTSPREQ_RECORD:
+      rtspreq = RTSPREQ_RECORD;
+      break;
+
+    case CURL_RTSPREQ_RECEIVE:
+      rtspreq = RTSPREQ_RECEIVE;
+      break;
+    default:
+      rtspreq = RTSPREQ_NONE;
+    }
+
+    data->set.rtspreq = rtspreq;
+    break;
+  }
+
+
+  case CURLOPT_RTSP_SESSION_ID:
+    /*
+     * Set the RTSP Session ID manually. Useful if the application is
+     * resuming a previously established RTSP session
+     */
+    result = Curl_setstropt(&data->set.str[STRING_RTSP_SESSION_ID],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_RTSP_STREAM_URI:
+    /*
+     * Set the Stream URI for the RTSP request. Unless the request is
+     * for generic server options, the application will need to set this.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_RTSP_STREAM_URI],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_RTSP_TRANSPORT:
+    /*
+     * The content of the Transport: header for the RTSP request
+     */
+    result = Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_RTSP_CLIENT_CSEQ:
+    /*
+     * Set the CSEQ number to issue for the next RTSP request. Useful if the
+     * application is resuming a previously broken connection. The CSEQ
+     * will increment from this new number henceforth.
+     */
+    data->state.rtsp_next_client_CSeq = va_arg(param, long);
+    break;
+
+  case CURLOPT_RTSP_SERVER_CSEQ:
+    /* Same as the above, but for server-initiated requests */
+    data->state.rtsp_next_server_CSeq = va_arg(param, long);
+    break;
+
+  case CURLOPT_INTERLEAVEDATA:
+    data->set.rtp_out = va_arg(param, void *);
+    break;
+  case CURLOPT_INTERLEAVEFUNCTION:
+    /* Set the user defined RTP write function */
+    data->set.fwrite_rtp = va_arg(param, curl_write_callback);
+    break;
+#endif
+#ifndef CURL_DISABLE_FTP
+  case CURLOPT_WILDCARDMATCH:
+    data->set.wildcard_enabled = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_CHUNK_BGN_FUNCTION:
+    data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback);
+    break;
+  case CURLOPT_CHUNK_END_FUNCTION:
+    data->set.chunk_end = va_arg(param, curl_chunk_end_callback);
+    break;
+  case CURLOPT_FNMATCH_FUNCTION:
+    data->set.fnmatch = va_arg(param, curl_fnmatch_callback);
+    break;
+  case CURLOPT_CHUNK_DATA:
+    data->set.wildcardptr = va_arg(param, void *);
+    break;
+  case CURLOPT_FNMATCH_DATA:
+    data->set.fnmatch_data = va_arg(param, void *);
+    break;
+#endif
+#ifdef USE_TLS_SRP
+  case CURLOPT_TLSAUTH_USERNAME:
+    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME],
+                            va_arg(param, char *));
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_TLSAUTH_USERNAME:
+    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY],
+                            va_arg(param, char *));
+    break;
+#endif
+  case CURLOPT_TLSAUTH_PASSWORD:
+    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD],
+                            va_arg(param, char *));
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_TLSAUTH_PASSWORD:
+    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY],
+                            va_arg(param, char *));
+    break;
+#endif
+  case CURLOPT_TLSAUTH_TYPE:
+    argptr = va_arg(param, char *);
+    if(argptr && !strcasecompare(argptr, "SRP"))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_TLSAUTH_TYPE:
+    argptr = va_arg(param, char *);
+    if(argptr && !strcasecompare(argptr, "SRP"))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+#endif
+#endif
+#ifdef USE_ARES
+  case CURLOPT_DNS_SERVERS:
+    result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS],
+                            va_arg(param, char *));
+    if(result)
+      return result;
+    result = Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]);
+    break;
+  case CURLOPT_DNS_INTERFACE:
+    result = Curl_setstropt(&data->set.str[STRING_DNS_INTERFACE],
+                            va_arg(param, char *));
+    if(result)
+      return result;
+    result = Curl_set_dns_interface(data, data->set.str[STRING_DNS_INTERFACE]);
+    break;
+  case CURLOPT_DNS_LOCAL_IP4:
+    result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP4],
+                            va_arg(param, char *));
+    if(result)
+      return result;
+    result = Curl_set_dns_local_ip4(data, data->set.str[STRING_DNS_LOCAL_IP4]);
+    break;
+  case CURLOPT_DNS_LOCAL_IP6:
+    result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP6],
+                            va_arg(param, char *));
+    if(result)
+      return result;
+    result = Curl_set_dns_local_ip6(data, data->set.str[STRING_DNS_LOCAL_IP6]);
+    break;
+#endif
+  case CURLOPT_TCP_KEEPALIVE:
+    data->set.tcp_keepalive = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_TCP_KEEPIDLE:
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    else if(arg > INT_MAX)
+      arg = INT_MAX;
+    data->set.tcp_keepidle = (int)arg;
+    break;
+  case CURLOPT_TCP_KEEPINTVL:
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    else if(arg > INT_MAX)
+      arg = INT_MAX;
+    data->set.tcp_keepintvl = (int)arg;
+    break;
+  case CURLOPT_TCP_FASTOPEN:
+#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \
+   defined(TCP_FASTOPEN_CONNECT)
+    data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE;
+#else
+    result = CURLE_NOT_BUILT_IN;
+#endif
+    break;
+  case CURLOPT_SSL_ENABLE_NPN:
+    break;
+  case CURLOPT_SSL_ENABLE_ALPN:
+    data->set.ssl_enable_alpn = (0 != va_arg(param, long));
+    break;
+#ifdef USE_UNIX_SOCKETS
+  case CURLOPT_UNIX_SOCKET_PATH:
+    data->set.abstract_unix_socket = FALSE;
+    result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_ABSTRACT_UNIX_SOCKET:
+    data->set.abstract_unix_socket = TRUE;
+    result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
+                            va_arg(param, char *));
+    break;
+#endif
+
+  case CURLOPT_PATH_AS_IS:
+    data->set.path_as_is = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_PIPEWAIT:
+    data->set.pipewait = (0 != va_arg(param, long));
+    break;
+  case CURLOPT_STREAM_WEIGHT:
+#if defined(USE_HTTP2) || defined(USE_HTTP3)
+    arg = va_arg(param, long);
+    if((arg >= 1) && (arg <= 256))
+      data->set.priority.weight = (int)arg;
+    break;
+#else
+    return CURLE_NOT_BUILT_IN;
+#endif
+  case CURLOPT_STREAM_DEPENDS:
+  case CURLOPT_STREAM_DEPENDS_E:
+  {
+    struct Curl_easy *dep = va_arg(param, struct Curl_easy *);
+    if(!dep || GOOD_EASY_HANDLE(dep)) {
+      return Curl_data_priority_add_child(dep, data,
+                                          option == CURLOPT_STREAM_DEPENDS_E);
+    }
+    break;
+  }
+  case CURLOPT_CONNECT_TO:
+    data->set.connect_to = va_arg(param, struct curl_slist *);
+    break;
+  case CURLOPT_SUPPRESS_CONNECT_HEADERS:
+    data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE;
+    break;
+  case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS:
+    uarg = va_arg(param, unsigned long);
+    if(uarg > UINT_MAX)
+      uarg = UINT_MAX;
+    data->set.happy_eyeballs_timeout = (unsigned int)uarg;
+    break;
+#ifndef CURL_DISABLE_SHUFFLE_DNS
+  case CURLOPT_DNS_SHUFFLE_ADDRESSES:
+    data->set.dns_shuffle_addresses = (0 != va_arg(param, long));
+    break;
+#endif
+  case CURLOPT_DISALLOW_USERNAME_IN_URL:
+    data->set.disallow_username_in_url = (0 != va_arg(param, long));
+    break;
+#ifndef CURL_DISABLE_DOH
+  case CURLOPT_DOH_URL:
+    result = Curl_setstropt(&data->set.str[STRING_DOH],
+                            va_arg(param, char *));
+    data->set.doh = data->set.str[STRING_DOH]?TRUE:FALSE;
+    break;
+#endif
+  case CURLOPT_UPKEEP_INTERVAL_MS:
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.upkeep_interval_ms = arg;
+    break;
+  case CURLOPT_MAXAGE_CONN:
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.maxage_conn = arg;
+    break;
+  case CURLOPT_MAXLIFETIME_CONN:
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.maxlifetime_conn = arg;
+    break;
+  case CURLOPT_TRAILERFUNCTION:
+#ifndef CURL_DISABLE_HTTP
+    data->set.trailer_callback = va_arg(param, curl_trailer_callback);
+#endif
+    break;
+  case CURLOPT_TRAILERDATA:
+#ifndef CURL_DISABLE_HTTP
+    data->set.trailer_data = va_arg(param, void *);
+#endif
+    break;
+#ifndef CURL_DISABLE_HSTS
+  case CURLOPT_HSTSREADFUNCTION:
+    data->set.hsts_read = va_arg(param, curl_hstsread_callback);
+    break;
+  case CURLOPT_HSTSREADDATA:
+    data->set.hsts_read_userp = va_arg(param, void *);
+    break;
+  case CURLOPT_HSTSWRITEFUNCTION:
+    data->set.hsts_write = va_arg(param, curl_hstswrite_callback);
+    break;
+  case CURLOPT_HSTSWRITEDATA:
+    data->set.hsts_write_userp = va_arg(param, void *);
+    break;
+  case CURLOPT_HSTS: {
+    struct curl_slist *h;
+    if(!data->hsts) {
+      data->hsts = Curl_hsts_init();
+      if(!data->hsts)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    argptr = va_arg(param, char *);
+    if(argptr) {
+      result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
+      if(result)
+        return result;
+      /* this needs to build a list of file names to read from, so that it can
+         read them later, as we might get a shared HSTS handle to load them
+         into */
+      h = curl_slist_append(data->state.hstslist, argptr);
+      if(!h) {
+        curl_slist_free_all(data->state.hstslist);
+        data->state.hstslist = NULL;
+        return CURLE_OUT_OF_MEMORY;
+      }
+      data->state.hstslist = h; /* store the list for later use */
+    }
+    else {
+      /* clear the list of HSTS files */
+      curl_slist_free_all(data->state.hstslist);
+      data->state.hstslist = NULL;
+      if(!data->share || !data->share->hsts)
+        /* throw away the HSTS cache unless shared */
+        Curl_hsts_cleanup(&data->hsts);
+    }
+    break;
+  }
+  case CURLOPT_HSTS_CTRL:
+    arg = va_arg(param, long);
+    if(arg & CURLHSTS_ENABLE) {
+      if(!data->hsts) {
+        data->hsts = Curl_hsts_init();
+        if(!data->hsts)
+          return CURLE_OUT_OF_MEMORY;
+      }
+    }
+    else
+      Curl_hsts_cleanup(&data->hsts);
+    break;
+#endif
+#ifndef CURL_DISABLE_ALTSVC
+  case CURLOPT_ALTSVC:
+    if(!data->asi) {
+      data->asi = Curl_altsvc_init();
+      if(!data->asi)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    argptr = va_arg(param, char *);
+    result = Curl_setstropt(&data->set.str[STRING_ALTSVC], argptr);
+    if(result)
+      return result;
+    if(argptr)
+      (void)Curl_altsvc_load(data->asi, argptr);
+    break;
+  case CURLOPT_ALTSVC_CTRL:
+    if(!data->asi) {
+      data->asi = Curl_altsvc_init();
+      if(!data->asi)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    arg = va_arg(param, long);
+    if(!arg) {
+      DEBUGF(infof(data, "bad CURLOPT_ALTSVC_CTRL input"));
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+    result = Curl_altsvc_ctrl(data->asi, arg);
+    if(result)
+      return result;
+    break;
+#endif
+  case CURLOPT_PREREQFUNCTION:
+    data->set.fprereq = va_arg(param, curl_prereq_callback);
+    break;
+  case CURLOPT_PREREQDATA:
+    data->set.prereq_userp = va_arg(param, void *);
+    break;
+#ifdef USE_WEBSOCKETS
+  case CURLOPT_WS_OPTIONS: {
+    bool raw;
+    arg = va_arg(param, long);
+    raw = (arg & CURLWS_RAW_MODE);
+    data->set.ws_raw_mode = raw;
+    break;
+  }
+#endif
+  case CURLOPT_QUICK_EXIT:
+    data->set.quick_exit = (0 != va_arg(param, long)) ? 1L:0L;
+    break;
+  default:
+    /* unknown tag and its companion, just ignore: */
+    result = CURLE_UNKNOWN_OPTION;
+    break;
+  }
+
+  return result;
+}
+
+/*
+ * curl_easy_setopt() is the external interface for setting options on an
+ * easy handle.
+ *
+ * NOTE: This is one of few API functions that are allowed to be called from
+ * within a callback.
+ */
+
+#undef curl_easy_setopt
+CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
+{
+  va_list arg;
+  CURLcode result;
+
+  if(!data)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  va_start(arg, tag);
+
+  result = Curl_vsetopt(data, tag, arg);
+
+  va_end(arg);
+#ifdef DEBUGBUILD
+  if(result == CURLE_BAD_FUNCTION_ARGUMENT)
+    infof(data, "setopt arg 0x%x returned CURLE_BAD_FUNCTION_ARGUMENT", tag);
+#endif
+  return result;
+}
Index: trunk/src/libs/curl-8.7.1/lib/setopt.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/setopt.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/setopt.h	(revision 104083)
@@ -0,0 +1,32 @@
+#ifndef HEADER_CURL_SETOPT_H
+#define HEADER_CURL_SETOPT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+CURLcode Curl_setstropt(char **charp, const char *s);
+CURLcode Curl_setblobopt(struct curl_blob **blobp,
+                         const struct curl_blob *blob);
+CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list arg);
+
+#endif /* HEADER_CURL_SETOPT_H */
Index: trunk/src/libs/curl-8.7.1/lib/setup-os400.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/setup-os400.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/setup-os400.h	(revision 104083)
@@ -0,0 +1,144 @@
+#ifndef HEADER_CURL_SETUP_OS400_H
+#define HEADER_CURL_SETUP_OS400_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+
+/* OS/400 netdb.h does not define NI_MAXHOST. */
+#define NI_MAXHOST      1025
+
+/* OS/400 netdb.h does not define NI_MAXSERV. */
+#define NI_MAXSERV      32
+
+/* No OS/400 header file defines u_int32_t. */
+typedef unsigned long   u_int32_t;
+
+/* OS/400 has no idea of a tty! */
+#define isatty(fd)      0
+
+
+/* System API wrapper prototypes & definitions to support ASCII parameters. */
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <gskssl.h>
+#include <qsoasync.h>
+#include <gssapi.h>
+
+extern int Curl_getaddrinfo_a(const char *nodename,
+                              const char *servname,
+                              const struct addrinfo *hints,
+                              struct addrinfo **res);
+#define getaddrinfo             Curl_getaddrinfo_a
+
+/* Note socklen_t must be used as this is declared before curl_socklen_t */
+extern int Curl_getnameinfo_a(const struct sockaddr *sa,
+                              socklen_t salen,
+                              char *nodename, socklen_t nodenamelen,
+                              char *servname, socklen_t servnamelen,
+                              int flags);
+#define getnameinfo             Curl_getnameinfo_a
+
+/* GSSAPI wrappers. */
+
+extern OM_uint32 Curl_gss_import_name_a(OM_uint32 * minor_status,
+                                        gss_buffer_t in_name,
+                                        gss_OID in_name_type,
+                                        gss_name_t * out_name);
+#define gss_import_name         Curl_gss_import_name_a
+
+
+extern OM_uint32 Curl_gss_display_status_a(OM_uint32 * minor_status,
+                                           OM_uint32 status_value,
+                                           int status_type, gss_OID mech_type,
+                                           gss_msg_ctx_t * message_context,
+                                           gss_buffer_t status_string);
+#define gss_display_status      Curl_gss_display_status_a
+
+
+extern OM_uint32 Curl_gss_init_sec_context_a(OM_uint32 * minor_status,
+                                             gss_cred_id_t cred_handle,
+                                             gss_ctx_id_t * context_handle,
+                                             gss_name_t target_name,
+                                             gss_OID mech_type,
+                                             gss_flags_t req_flags,
+                                             OM_uint32 time_req,
+                                             gss_channel_bindings_t
+                                             input_chan_bindings,
+                                             gss_buffer_t input_token,
+                                             gss_OID * actual_mech_type,
+                                             gss_buffer_t output_token,
+                                             gss_flags_t * ret_flags,
+                                             OM_uint32 * time_rec);
+#define gss_init_sec_context    Curl_gss_init_sec_context_a
+
+
+extern OM_uint32 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status,
+                                               gss_ctx_id_t * context_handle,
+                                               gss_buffer_t output_token);
+#define gss_delete_sec_context  Curl_gss_delete_sec_context_a
+
+
+/* LDAP wrappers. */
+
+#define BerValue                struct berval
+
+#define ldap_url_parse          ldap_url_parse_utf8
+#define ldap_init               Curl_ldap_init_a
+#define ldap_simple_bind_s      Curl_ldap_simple_bind_s_a
+#define ldap_search_s           Curl_ldap_search_s_a
+#define ldap_get_values_len     Curl_ldap_get_values_len_a
+#define ldap_err2string         Curl_ldap_err2string_a
+#define ldap_get_dn             Curl_ldap_get_dn_a
+#define ldap_first_attribute    Curl_ldap_first_attribute_a
+#define ldap_next_attribute     Curl_ldap_next_attribute_a
+
+/* Some socket functions must be wrapped to process textual addresses
+   like AF_UNIX. */
+
+extern int Curl_os400_connect(int sd, struct sockaddr *destaddr, int addrlen);
+extern int Curl_os400_bind(int sd, struct sockaddr *localaddr, int addrlen);
+extern int Curl_os400_sendto(int sd, char *buffer, int buflen, int flags,
+                             const struct sockaddr *dstaddr, int addrlen);
+extern int Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags,
+                               struct sockaddr *fromaddr, int *addrlen);
+extern int Curl_os400_getpeername(int sd, struct sockaddr *addr, int *addrlen);
+extern int Curl_os400_getsockname(int sd, struct sockaddr *addr, int *addrlen);
+
+#define connect                 Curl_os400_connect
+#define bind                    Curl_os400_bind
+#define sendto                  Curl_os400_sendto
+#define recvfrom                Curl_os400_recvfrom
+#define getpeername             Curl_os400_getpeername
+#define getsockname             Curl_os400_getsockname
+
+#ifdef HAVE_LIBZ
+#define zlibVersion             Curl_os400_zlibVersion
+#define inflateInit_            Curl_os400_inflateInit_
+#define inflateInit2_           Curl_os400_inflateInit2_
+#define inflate                 Curl_os400_inflate
+#define inflateEnd              Curl_os400_inflateEnd
+#endif
+
+#endif /* HEADER_CURL_SETUP_OS400_H */
Index: trunk/src/libs/curl-8.7.1/lib/setup-vms.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/setup-vms.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/setup-vms.h	(revision 104083)
@@ -0,0 +1,444 @@
+#ifndef HEADER_CURL_SETUP_VMS_H
+#define HEADER_CURL_SETUP_VMS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*                                                                         */
+/* JEM, 12/30/12, VMS now generates config.h, so only define wrappers for  */
+/*                getenv(), getpwuid() and provide is_vms_shell()          */
+/*                Also need upper case symbols for system services, and    */
+/*                OpenSSL, and some Kerberos image                         */
+
+#ifdef __DECC
+#pragma message save
+#pragma message disable dollarid
+#endif
+
+/* Hide the stuff we are overriding */
+#define getenv decc_getenv
+#ifdef __DECC
+#   if __INITIAL_POINTER_SIZE != 64
+#       define getpwuid decc_getpwuid
+#   endif
+#endif
+#include <stdlib.h>
+char *decc$getenv(const char *__name);
+#include <pwd.h>
+
+#include <string.h>
+#include <unixlib.h>
+
+#undef getenv
+#undef getpwuid
+#define getenv vms_getenv
+#define getpwuid vms_getpwuid
+
+/* VAX needs these in upper case when compiling exact case */
+#define sys$assign SYS$ASSIGN
+#define sys$dassgn SYS$DASSGN
+#define sys$qiow SYS$QIOW
+
+#ifdef __DECC
+#   if __INITIAL_POINTER_SIZE
+#       pragma __pointer_size __save
+#   endif
+#endif
+
+#if __USE_LONG_GID_T
+#   define decc_getpwuid DECC$__LONG_GID_GETPWUID
+#else
+#   if __INITIAL_POINTER_SIZE
+#       define decc_getpwuid decc$__32_getpwuid
+#   else
+#       define decc_getpwuid decc$getpwuid
+#   endif
+#endif
+
+    struct passwd *decc_getpwuid(uid_t uid);
+
+#ifdef __DECC
+#   if __INITIAL_POINTER_SIZE == 32
+/* Translate the path, but only if the path is a VMS file specification */
+/* The translation is usually only needed for older versions of VMS */
+static char *vms_translate_path(const char *path)
+{
+  char *unix_path;
+  char *test_str;
+
+  /* See if the result is in VMS format, if not, we are done */
+  /* Assume that this is a PATH, not just some data */
+  test_str = strpbrk(path, ":[<^");
+  if(!test_str) {
+    return (char *)path;
+  }
+
+  unix_path = decc$translate_vms(path);
+
+  if((int)unix_path <= 0) {
+    /* We can not translate it, so return the original string */
+    return (char *)path;
+  }
+}
+#   else
+    /* VMS translate path is actually not needed on the current 64 bit */
+    /* VMS platforms, so instead of figuring out the pointer settings */
+    /* Change it to a noop */
+#   define vms_translate_path(__path) __path
+#   endif
+#endif
+
+#ifdef __DECC
+#   if __INITIAL_POINTER_SIZE
+#       pragma __pointer_size __restore
+#   endif
+#endif
+
+static char *vms_getenv(const char *envvar)
+{
+  char *result;
+  char *vms_path;
+
+  /* first use the DECC getenv() function */
+  result = decc$getenv(envvar);
+  if(!result) {
+    return result;
+  }
+
+  vms_path = result;
+  result = vms_translate_path(vms_path);
+
+  /* note that if you backport this to use VAX C RTL, that the VAX C RTL */
+  /* may do a malloc(2048) for each call to getenv(), so you will need   */
+  /* to add a free(vms_path) */
+  /* Do not do a free() for DEC C RTL builds, which should be used for */
+  /* VMS 5.5-2 and later, even if using GCC */
+
+  return result;
+}
+
+
+static struct passwd vms_passwd_cache;
+
+static struct passwd *vms_getpwuid(uid_t uid)
+{
+  struct passwd *my_passwd;
+
+/* Hack needed to support 64 bit builds, decc_getpwnam is 32 bit only */
+#ifdef __DECC
+#   if __INITIAL_POINTER_SIZE
+  __char_ptr32 unix_path;
+#   else
+  char *unix_path;
+#   endif
+#else
+  char *unix_path;
+#endif
+
+  my_passwd = decc_getpwuid(uid);
+  if(!my_passwd) {
+    return my_passwd;
+  }
+
+  unix_path = vms_translate_path(my_passwd->pw_dir);
+
+  if((long)unix_path <= 0) {
+    /* We can not translate it, so return the original string */
+    return my_passwd;
+  }
+
+  /* If no changes needed just return it */
+  if(unix_path == my_passwd->pw_dir) {
+    return my_passwd;
+  }
+
+  /* Need to copy the structure returned */
+  /* Since curl is only using pw_dir, no need to fix up */
+  /* the pw_shell when running under Bash */
+  vms_passwd_cache.pw_name = my_passwd->pw_name;
+  vms_passwd_cache.pw_uid = my_passwd->pw_uid;
+  vms_passwd_cache.pw_gid = my_passwd->pw_uid;
+  vms_passwd_cache.pw_dir = unix_path;
+  vms_passwd_cache.pw_shell = my_passwd->pw_shell;
+
+  return &vms_passwd_cache;
+}
+
+#ifdef __DECC
+#pragma message restore
+#endif
+
+/* Bug - VMS OpenSSL and Kerberos universal symbols are in uppercase only */
+/* VMS libraries should have universal symbols in exact and uppercase */
+
+#define ASN1_INTEGER_get ASN1_INTEGER_GET
+#define ASN1_STRING_data ASN1_STRING_DATA
+#define ASN1_STRING_length ASN1_STRING_LENGTH
+#define ASN1_STRING_print ASN1_STRING_PRINT
+#define ASN1_STRING_to_UTF8 ASN1_STRING_TO_UTF8
+#define ASN1_STRING_type ASN1_STRING_TYPE
+#define BIO_ctrl BIO_CTRL
+#define BIO_free BIO_FREE
+#define BIO_new BIO_NEW
+#define BIO_s_mem BIO_S_MEM
+#define BN_bn2bin BN_BN2BIN
+#define BN_num_bits BN_NUM_BITS
+#define CRYPTO_cleanup_all_ex_data CRYPTO_CLEANUP_ALL_EX_DATA
+#define CRYPTO_free CRYPTO_FREE
+#define CRYPTO_malloc CRYPTO_MALLOC
+#define CONF_modules_load_file CONF_MODULES_LOAD_FILE
+#ifdef __VAX
+#  ifdef VMS_OLD_SSL
+  /* Ancient OpenSSL on VAX/VMS missing this constant */
+#    define CONF_MFLAGS_IGNORE_MISSING_FILE 0x10
+#    undef CONF_modules_load_file
+     static int CONF_modules_load_file(const char *filename,
+                                       const char *appname,
+                                       unsigned long flags) {
+             return 1;
+     }
+#  endif
+#endif
+#define DES_ecb_encrypt DES_ECB_ENCRYPT
+#define DES_set_key DES_SET_KEY
+#define DES_set_odd_parity DES_SET_ODD_PARITY
+#define ENGINE_ctrl ENGINE_CTRL
+#define ENGINE_ctrl_cmd ENGINE_CTRL_CMD
+#define ENGINE_finish ENGINE_FINISH
+#define ENGINE_free ENGINE_FREE
+#define ENGINE_get_first ENGINE_GET_FIRST
+#define ENGINE_get_id ENGINE_GET_ID
+#define ENGINE_get_next ENGINE_GET_NEXT
+#define ENGINE_init ENGINE_INIT
+#define ENGINE_load_builtin_engines ENGINE_LOAD_BUILTIN_ENGINES
+#define ENGINE_load_private_key ENGINE_LOAD_PRIVATE_KEY
+#define ENGINE_set_default ENGINE_SET_DEFAULT
+#define ERR_clear_error ERR_CLEAR_ERROR
+#define ERR_error_string ERR_ERROR_STRING
+#define ERR_error_string_n ERR_ERROR_STRING_N
+#define ERR_free_strings ERR_FREE_STRINGS
+#define ERR_get_error ERR_GET_ERROR
+#define ERR_peek_error ERR_PEEK_ERROR
+#define ERR_remove_state ERR_REMOVE_STATE
+#define EVP_PKEY_copy_parameters EVP_PKEY_COPY_PARAMETERS
+#define EVP_PKEY_free EVP_PKEY_FREE
+#define EVP_cleanup EVP_CLEANUP
+#define GENERAL_NAMES_free GENERAL_NAMES_FREE
+#define i2d_X509_PUBKEY I2D_X509_PUBKEY
+#define MD4_Final MD4_FINAL
+#define MD4_Init MD4_INIT
+#define MD4_Update MD4_UPDATE
+#define MD5_Final MD5_FINAL
+#define MD5_Init MD5_INIT
+#define MD5_Update MD5_UPDATE
+#define OPENSSL_add_all_algo_noconf OPENSSL_ADD_ALL_ALGO_NOCONF
+#ifndef __VAX
+#define OPENSSL_load_builtin_modules OPENSSL_LOAD_BUILTIN_MODULES
+#endif
+#define PEM_read_X509 PEM_READ_X509
+#define PEM_write_bio_X509 PEM_WRITE_BIO_X509
+#define PKCS12_PBE_add PKCS12_PBE_ADD
+#define PKCS12_free PKCS12_FREE
+#define PKCS12_parse PKCS12_PARSE
+#define RAND_add RAND_ADD
+#define RAND_bytes RAND_BYTES
+#define RAND_file_name RAND_FILE_NAME
+#define RAND_load_file RAND_LOAD_FILE
+#define RAND_status RAND_STATUS
+#define SSL_CIPHER_get_name SSL_CIPHER_GET_NAME
+#define SSL_CTX_add_client_CA SSL_CTX_ADD_CLIENT_CA
+#define SSL_CTX_callback_ctrl SSL_CTX_CALLBACK_CTRL
+#define SSL_CTX_check_private_key SSL_CTX_CHECK_PRIVATE_KEY
+#define SSL_CTX_ctrl SSL_CTX_CTRL
+#define SSL_CTX_free SSL_CTX_FREE
+#define SSL_CTX_get_cert_store SSL_CTX_GET_CERT_STORE
+#define SSL_CTX_load_verify_locations SSL_CTX_LOAD_VERIFY_LOCATIONS
+#define SSL_CTX_new SSL_CTX_NEW
+#define SSL_CTX_set_cipher_list SSL_CTX_SET_CIPHER_LIST
+#define SSL_CTX_set_def_passwd_cb_ud SSL_CTX_SET_DEF_PASSWD_CB_UD
+#define SSL_CTX_set_default_passwd_cb SSL_CTX_SET_DEFAULT_PASSWD_CB
+#define SSL_CTX_set_msg_callback SSL_CTX_SET_MSG_CALLBACK
+#define SSL_CTX_set_verify SSL_CTX_SET_VERIFY
+#define SSL_CTX_use_PrivateKey SSL_CTX_USE_PRIVATEKEY
+#define SSL_CTX_use_PrivateKey_file SSL_CTX_USE_PRIVATEKEY_FILE
+#define SSL_CTX_use_cert_chain_file SSL_CTX_USE_CERT_CHAIN_FILE
+#define SSL_CTX_use_certificate SSL_CTX_USE_CERTIFICATE
+#define SSL_CTX_use_certificate_file SSL_CTX_USE_CERTIFICATE_FILE
+#define SSL_SESSION_free SSL_SESSION_FREE
+#define SSL_connect SSL_CONNECT
+#define SSL_free SSL_FREE
+#define SSL_get1_session SSL_GET1_SESSION
+#define SSL_get_certificate SSL_GET_CERTIFICATE
+#define SSL_get_current_cipher SSL_GET_CURRENT_CIPHER
+#define SSL_get_error SSL_GET_ERROR
+#define SSL_get_peer_cert_chain SSL_GET_PEER_CERT_CHAIN
+#define SSL_get_peer_certificate SSL_GET_PEER_CERTIFICATE
+#define SSL_get_privatekey SSL_GET_PRIVATEKEY
+#define SSL_get_session SSL_GET_SESSION
+#define SSL_get_shutdown SSL_GET_SHUTDOWN
+#define SSL_get_verify_result SSL_GET_VERIFY_RESULT
+#define SSL_library_init SSL_LIBRARY_INIT
+#define SSL_load_error_strings SSL_LOAD_ERROR_STRINGS
+#define SSL_new SSL_NEW
+#define SSL_peek SSL_PEEK
+#define SSL_pending SSL_PENDING
+#define SSL_read SSL_READ
+#define SSL_set_connect_state SSL_SET_CONNECT_STATE
+#define SSL_set_fd SSL_SET_FD
+#define SSL_set_session SSL_SET_SESSION
+#define SSL_shutdown SSL_SHUTDOWN
+#define SSL_version SSL_VERSION
+#define SSL_write SSL_WRITE
+#define SSLeay SSLEAY
+#define SSLv23_client_method SSLV23_CLIENT_METHOD
+#define SSLv3_client_method SSLV3_CLIENT_METHOD
+#define TLSv1_client_method TLSV1_CLIENT_METHOD
+#define UI_create_method UI_CREATE_METHOD
+#define UI_destroy_method UI_DESTROY_METHOD
+#define UI_get0_user_data UI_GET0_USER_DATA
+#define UI_get_input_flags UI_GET_INPUT_FLAGS
+#define UI_get_string_type UI_GET_STRING_TYPE
+#define UI_create_method UI_CREATE_METHOD
+#define UI_destroy_method UI_DESTROY_METHOD
+#define UI_method_get_closer UI_METHOD_GET_CLOSER
+#define UI_method_get_opener UI_METHOD_GET_OPENER
+#define UI_method_get_reader UI_METHOD_GET_READER
+#define UI_method_get_writer UI_METHOD_GET_WRITER
+#define UI_method_set_closer UI_METHOD_SET_CLOSER
+#define UI_method_set_opener UI_METHOD_SET_OPENER
+#define UI_method_set_reader UI_METHOD_SET_READER
+#define UI_method_set_writer UI_METHOD_SET_WRITER
+#define UI_OpenSSL UI_OPENSSL
+#define UI_set_result UI_SET_RESULT
+#define X509V3_EXT_print X509V3_EXT_PRINT
+#define X509_EXTENSION_get_critical X509_EXTENSION_GET_CRITICAL
+#define X509_EXTENSION_get_data X509_EXTENSION_GET_DATA
+#define X509_EXTENSION_get_object X509_EXTENSION_GET_OBJECT
+#define X509_LOOKUP_file X509_LOOKUP_FILE
+#define X509_NAME_ENTRY_get_data X509_NAME_ENTRY_GET_DATA
+#define X509_NAME_get_entry X509_NAME_GET_ENTRY
+#define X509_NAME_get_index_by_NID X509_NAME_GET_INDEX_BY_NID
+#define X509_NAME_print_ex X509_NAME_PRINT_EX
+#define X509_STORE_CTX_get_current_cert X509_STORE_CTX_GET_CURRENT_CERT
+#define X509_STORE_add_lookup X509_STORE_ADD_LOOKUP
+#define X509_STORE_set_flags X509_STORE_SET_FLAGS
+#define X509_check_issued X509_CHECK_ISSUED
+#define X509_free X509_FREE
+#define X509_get_ext_d2i X509_GET_EXT_D2I
+#define X509_get_issuer_name X509_GET_ISSUER_NAME
+#define X509_get_pubkey X509_GET_PUBKEY
+#define X509_get_serialNumber X509_GET_SERIALNUMBER
+#define X509_get_subject_name X509_GET_SUBJECT_NAME
+#define X509_load_crl_file X509_LOAD_CRL_FILE
+#define X509_verify_cert_error_string X509_VERIFY_CERT_ERROR_STRING
+#define d2i_PKCS12_fp D2I_PKCS12_FP
+#define i2t_ASN1_OBJECT I2T_ASN1_OBJECT
+#define sk_num SK_NUM
+#define sk_pop SK_POP
+#define sk_pop_free SK_POP_FREE
+#define sk_value SK_VALUE
+#ifdef __VAX
+#define OPENSSL_NO_SHA256
+#endif
+#define SHA256_Final SHA256_FINAL
+#define SHA256_Init SHA256_INIT
+#define SHA256_Update SHA256_UPDATE
+
+#define USE_UPPERCASE_GSSAPI 1
+#define gss_seal GSS_SEAL
+#define gss_unseal GSS_UNSEAL
+
+#define USE_UPPERCASE_KRBAPI 1
+
+/* AI_NUMERICHOST needed for IP V6 support in Curl */
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#ifndef AI_NUMERICHOST
+#ifdef ENABLE_IPV6
+#undef ENABLE_IPV6
+#endif
+#endif
+#endif
+
+/* VAX symbols are always in uppercase */
+#ifdef __VAX
+#define inflate INFLATE
+#define inflateEnd INFLATEEND
+#define inflateInit2_ INFLATEINIT2_
+#define inflateInit_ INFLATEINIT_
+#define zlibVersion ZLIBVERSION
+#endif
+
+/* Older VAX OpenSSL port defines these as Macros */
+/* Need to include the headers first and then redefine */
+/* that way a newer port will also work if some one has one */
+#ifdef __VAX
+
+#   if (OPENSSL_VERSION_NUMBER < 0x00907001L)
+#       define des_set_odd_parity DES_SET_ODD_PARITY
+#       define des_set_key DES_SET_KEY
+#       define des_ecb_encrypt DES_ECB_ENCRYPT
+
+#   endif
+#   include <openssl/evp.h>
+#   ifndef OpenSSL_add_all_algorithms
+#       define OpenSSL_add_all_algorithms OPENSSL_ADD_ALL_ALGORITHMS
+        void OPENSSL_ADD_ALL_ALGORITHMS(void);
+#   endif
+
+    /* Curl defines these to lower case and VAX needs them in upper case */
+    /* So we need static routines */
+#   if (OPENSSL_VERSION_NUMBER < 0x00907001L)
+
+#       undef des_set_odd_parity
+#       undef DES_set_odd_parity
+#       undef des_set_key
+#       undef DES_set_key
+#       undef des_ecb_encrypt
+#       undef DES_ecb_encrypt
+
+        static void des_set_odd_parity(des_cblock *key) {
+            DES_SET_ODD_PARITY(key);
+        }
+
+        static int des_set_key(const_des_cblock *key,
+                               des_key_schedule schedule) {
+            return DES_SET_KEY(key, schedule);
+        }
+
+        static void des_ecb_encrypt(const_des_cblock *input,
+                                    des_cblock *output,
+                                    des_key_schedule ks, int enc) {
+            DES_ECB_ENCRYPT(input, output, ks, enc);
+        }
+#endif
+/* Need this to stop a macro redefinition error */
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+#   ifdef X509_STORE_set_flags
+#       undef X509_STORE_set_flags
+#       define X509_STORE_set_flags(x,y) Curl_nop_stmt
+#   endif
+#endif
+#endif
+
+#endif /* HEADER_CURL_SETUP_VMS_H */
Index: trunk/src/libs/curl-8.7.1/lib/setup-win32.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/setup-win32.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/setup-win32.h	(revision 104083)
@@ -0,0 +1,138 @@
+#ifndef HEADER_CURL_SETUP_WIN32_H
+#define HEADER_CURL_SETUP_WIN32_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#undef USE_WINSOCK
+/* ---------------------------------------------------------------- */
+/*                     Watt-32 TCP/IP SPECIFIC                      */
+/* ---------------------------------------------------------------- */
+#ifdef USE_WATT32
+#  include <tcp.h>
+#  undef byte
+#  undef word
+#  define HAVE_SYS_IOCTL_H
+#  define HAVE_SYS_SOCKET_H
+#  define HAVE_NETINET_IN_H
+#  define HAVE_NETDB_H
+#  define HAVE_ARPA_INET_H
+#  define SOCKET int
+/* ---------------------------------------------------------------- */
+/*               BSD-style lwIP TCP/IP stack SPECIFIC               */
+/* ---------------------------------------------------------------- */
+#elif defined(USE_LWIPSOCK)
+  /* Define to use BSD-style lwIP TCP/IP stack. */
+  /* #define USE_LWIPSOCK 1 */
+#  undef HAVE_GETHOSTNAME
+#  undef LWIP_POSIX_SOCKETS_IO_NAMES
+#  undef RECV_TYPE_ARG1
+#  undef RECV_TYPE_ARG3
+#  undef SEND_TYPE_ARG1
+#  undef SEND_TYPE_ARG3
+#  define HAVE_GETHOSTBYNAME_R
+#  define HAVE_GETHOSTBYNAME_R_6
+#  define LWIP_POSIX_SOCKETS_IO_NAMES 0
+#  define RECV_TYPE_ARG1 int
+#  define RECV_TYPE_ARG3 size_t
+#  define SEND_TYPE_ARG1 int
+#  define SEND_TYPE_ARG3 size_t
+#elif defined(_WIN32)
+#  define USE_WINSOCK 2
+#endif
+
+/*
+ * Include header files for windows builds before redefining anything.
+ * Use this preprocessor block only to include or exclude windows.h,
+ * winsock2.h or ws2tcpip.h. Any other windows thing belongs
+ * to any other further and independent block.  Under Cygwin things work
+ * just as under linux (e.g. <sys/socket.h>) and the winsock headers should
+ * never be included when __CYGWIN__ is defined.
+ */
+
+#ifdef _WIN32
+#  if defined(UNICODE) && !defined(_UNICODE)
+#    error "UNICODE is defined but _UNICODE is not defined"
+#  endif
+#  if defined(_UNICODE) && !defined(UNICODE)
+#    error "_UNICODE is defined but UNICODE is not defined"
+#  endif
+/*
+ * Don't include unneeded stuff in Windows headers to avoid compiler
+ * warnings and macro clashes.
+ * Make sure to define this macro before including any Windows headers.
+ */
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN
+#  endif
+#  ifndef NOGDI
+#    define NOGDI
+#  endif
+#  include <winsock2.h>
+#  include <ws2tcpip.h>
+#  include <windows.h>
+#  include <winerror.h>
+#  include <tchar.h>
+#  ifdef UNICODE
+     typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str);
+#  endif
+#endif
+
+/*
+ * Define _WIN32_WINNT_[OS] symbols because not all Windows build systems have
+ * those symbols to compare against, and even those that do may be missing
+ * newer symbols.
+ */
+
+#ifndef _WIN32_WINNT_NT4
+#define _WIN32_WINNT_NT4            0x0400   /* Windows NT 4.0 */
+#endif
+#ifndef _WIN32_WINNT_WIN2K
+#define _WIN32_WINNT_WIN2K          0x0500   /* Windows 2000 */
+#endif
+#ifndef _WIN32_WINNT_WINXP
+#define _WIN32_WINNT_WINXP          0x0501   /* Windows XP */
+#endif
+#ifndef _WIN32_WINNT_WS03
+#define _WIN32_WINNT_WS03           0x0502   /* Windows Server 2003 */
+#endif
+#ifndef _WIN32_WINNT_VISTA
+#define _WIN32_WINNT_VISTA          0x0600   /* Windows Vista */
+#endif
+#ifndef _WIN32_WINNT_WS08
+#define _WIN32_WINNT_WS08           0x0600   /* Windows Server 2008 */
+#endif
+#ifndef _WIN32_WINNT_WIN7
+#define _WIN32_WINNT_WIN7           0x0601   /* Windows 7 */
+#endif
+#ifndef _WIN32_WINNT_WIN8
+#define _WIN32_WINNT_WIN8           0x0602   /* Windows 8 */
+#endif
+#ifndef _WIN32_WINNT_WINBLUE
+#define _WIN32_WINNT_WINBLUE        0x0603   /* Windows 8.1 */
+#endif
+#ifndef _WIN32_WINNT_WIN10
+#define _WIN32_WINNT_WIN10          0x0A00   /* Windows 10 */
+#endif
+
+#endif /* HEADER_CURL_SETUP_WIN32_H */
Index: trunk/src/libs/curl-8.7.1/lib/sha256.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/sha256.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/sha256.c	(revision 104083)
@@ -0,0 +1,545 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Florin Petriuc, <petriuc.florin@gmail.com>
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) \
+    || defined(USE_LIBSSH2)
+
+#include "warnless.h"
+#include "curl_sha256.h"
+#include "curl_hmac.h"
+
+#ifdef USE_WOLFSSL
+#include <wolfssl/options.h>
+#ifndef NO_SHA256
+#define USE_OPENSSL_SHA256
+#endif
+#endif
+
+#if defined(USE_OPENSSL)
+
+#include <openssl/opensslv.h>
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
+#define USE_OPENSSL_SHA256
+#endif
+
+#endif /* USE_OPENSSL */
+
+#ifdef USE_MBEDTLS
+#include <mbedtls/version.h>
+
+#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \
+   (MBEDTLS_VERSION_NUMBER < 0x03000000)
+  #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
+#endif
+#endif /* USE_MBEDTLS */
+
+#if defined(USE_OPENSSL_SHA256)
+
+/* When OpenSSL or wolfSSL is available we use their SHA256-functions. */
+#if defined(USE_OPENSSL)
+#include <openssl/evp.h>
+#elif defined(USE_WOLFSSL)
+#include <wolfssl/openssl/evp.h>
+#endif
+
+#elif defined(USE_GNUTLS)
+#include <nettle/sha.h>
+#elif defined(USE_MBEDTLS)
+#include <mbedtls/sha256.h>
+#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
+              (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
+      (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
+              (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
+#include <CommonCrypto/CommonDigest.h>
+#define AN_APPLE_OS
+#elif defined(USE_WIN32_CRYPTO)
+#include <wincrypt.h>
+#endif
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Please keep the SSL backend-specific #if branches in this order:
+ *
+ * 1. USE_OPENSSL
+ * 2. USE_GNUTLS
+ * 3. USE_MBEDTLS
+ * 4. USE_COMMON_CRYPTO
+ * 5. USE_WIN32_CRYPTO
+ *
+ * This ensures that the same SSL branch gets activated throughout this source
+ * file even if multiple backends are enabled at the same time.
+ */
+
+#if defined(USE_OPENSSL_SHA256)
+
+struct sha256_ctx {
+  EVP_MD_CTX *openssl_ctx;
+};
+typedef struct sha256_ctx my_sha256_ctx;
+
+static CURLcode my_sha256_init(my_sha256_ctx *ctx)
+{
+  ctx->openssl_ctx = EVP_MD_CTX_create();
+  if(!ctx->openssl_ctx)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(!EVP_DigestInit_ex(ctx->openssl_ctx, EVP_sha256(), NULL)) {
+    EVP_MD_CTX_destroy(ctx->openssl_ctx);
+    return CURLE_FAILED_INIT;
+  }
+  return CURLE_OK;
+}
+
+static void my_sha256_update(my_sha256_ctx *ctx,
+                             const unsigned char *data,
+                             unsigned int length)
+{
+  EVP_DigestUpdate(ctx->openssl_ctx, data, length);
+}
+
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
+{
+  EVP_DigestFinal_ex(ctx->openssl_ctx, digest, NULL);
+  EVP_MD_CTX_destroy(ctx->openssl_ctx);
+}
+
+#elif defined(USE_GNUTLS)
+
+typedef struct sha256_ctx my_sha256_ctx;
+
+static CURLcode my_sha256_init(my_sha256_ctx *ctx)
+{
+  sha256_init(ctx);
+  return CURLE_OK;
+}
+
+static void my_sha256_update(my_sha256_ctx *ctx,
+                             const unsigned char *data,
+                             unsigned int length)
+{
+  sha256_update(ctx, length, data);
+}
+
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
+{
+  sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
+}
+
+#elif defined(USE_MBEDTLS)
+
+typedef mbedtls_sha256_context my_sha256_ctx;
+
+static CURLcode my_sha256_init(my_sha256_ctx *ctx)
+{
+#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
+  (void) mbedtls_sha256_starts(ctx, 0);
+#else
+  (void) mbedtls_sha256_starts_ret(ctx, 0);
+#endif
+  return CURLE_OK;
+}
+
+static void my_sha256_update(my_sha256_ctx *ctx,
+                             const unsigned char *data,
+                             unsigned int length)
+{
+#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
+  (void) mbedtls_sha256_update(ctx, data, length);
+#else
+  (void) mbedtls_sha256_update_ret(ctx, data, length);
+#endif
+}
+
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
+{
+#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
+  (void) mbedtls_sha256_finish(ctx, digest);
+#else
+  (void) mbedtls_sha256_finish_ret(ctx, digest);
+#endif
+}
+
+#elif defined(AN_APPLE_OS)
+typedef CC_SHA256_CTX my_sha256_ctx;
+
+static CURLcode my_sha256_init(my_sha256_ctx *ctx)
+{
+  (void) CC_SHA256_Init(ctx);
+  return CURLE_OK;
+}
+
+static void my_sha256_update(my_sha256_ctx *ctx,
+                             const unsigned char *data,
+                             unsigned int length)
+{
+  (void) CC_SHA256_Update(ctx, data, length);
+}
+
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
+{
+  (void) CC_SHA256_Final(digest, ctx);
+}
+
+#elif defined(USE_WIN32_CRYPTO)
+
+struct sha256_ctx {
+  HCRYPTPROV hCryptProv;
+  HCRYPTHASH hHash;
+};
+typedef struct sha256_ctx my_sha256_ctx;
+
+#if !defined(CALG_SHA_256)
+#define CALG_SHA_256 0x0000800c
+#endif
+
+static CURLcode my_sha256_init(my_sha256_ctx *ctx)
+{
+  if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES,
+                         CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+    return CURLE_OUT_OF_MEMORY;
+
+  if(!CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash)) {
+    CryptReleaseContext(ctx->hCryptProv, 0);
+    ctx->hCryptProv = 0;
+    return CURLE_FAILED_INIT;
+  }
+
+  return CURLE_OK;
+}
+
+static void my_sha256_update(my_sha256_ctx *ctx,
+                             const unsigned char *data,
+                             unsigned int length)
+{
+  CryptHashData(ctx->hHash, (unsigned char *) data, length, 0);
+}
+
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
+{
+  unsigned long length = 0;
+
+  CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
+  if(length == SHA256_DIGEST_LENGTH)
+    CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
+
+  if(ctx->hHash)
+    CryptDestroyHash(ctx->hHash);
+
+  if(ctx->hCryptProv)
+    CryptReleaseContext(ctx->hCryptProv, 0);
+}
+
+#else
+
+/* When no other crypto library is available we use this code segment */
+
+/* This is based on SHA256 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+#define WPA_GET_BE32(a) ((((unsigned long)(a)[0]) << 24) | \
+                         (((unsigned long)(a)[1]) << 16) | \
+                         (((unsigned long)(a)[2]) <<  8) | \
+                          ((unsigned long)(a)[3]))
+#define WPA_PUT_BE32(a, val)                                        \
+do {                                                                \
+  (a)[0] = (unsigned char)((((unsigned long) (val)) >> 24) & 0xff); \
+  (a)[1] = (unsigned char)((((unsigned long) (val)) >> 16) & 0xff); \
+  (a)[2] = (unsigned char)((((unsigned long) (val)) >> 8) & 0xff);  \
+  (a)[3] = (unsigned char)(((unsigned long) (val)) & 0xff);         \
+} while(0)
+
+#ifdef HAVE_LONGLONG
+#define WPA_PUT_BE64(a, val)                                    \
+do {                                                            \
+  (a)[0] = (unsigned char)(((unsigned long long)(val)) >> 56);  \
+  (a)[1] = (unsigned char)(((unsigned long long)(val)) >> 48);  \
+  (a)[2] = (unsigned char)(((unsigned long long)(val)) >> 40);  \
+  (a)[3] = (unsigned char)(((unsigned long long)(val)) >> 32);  \
+  (a)[4] = (unsigned char)(((unsigned long long)(val)) >> 24);  \
+  (a)[5] = (unsigned char)(((unsigned long long)(val)) >> 16);  \
+  (a)[6] = (unsigned char)(((unsigned long long)(val)) >> 8);   \
+  (a)[7] = (unsigned char)(((unsigned long long)(val)) & 0xff); \
+} while(0)
+#else
+#define WPA_PUT_BE64(a, val)                                  \
+do {                                                          \
+  (a)[0] = (unsigned char)(((unsigned __int64)(val)) >> 56);  \
+  (a)[1] = (unsigned char)(((unsigned __int64)(val)) >> 48);  \
+  (a)[2] = (unsigned char)(((unsigned __int64)(val)) >> 40);  \
+  (a)[3] = (unsigned char)(((unsigned __int64)(val)) >> 32);  \
+  (a)[4] = (unsigned char)(((unsigned __int64)(val)) >> 24);  \
+  (a)[5] = (unsigned char)(((unsigned __int64)(val)) >> 16);  \
+  (a)[6] = (unsigned char)(((unsigned __int64)(val)) >> 8);   \
+  (a)[7] = (unsigned char)(((unsigned __int64)(val)) & 0xff); \
+} while(0)
+#endif
+
+struct sha256_state {
+#ifdef HAVE_LONGLONG
+  unsigned long long length;
+#else
+  unsigned __int64 length;
+#endif
+  unsigned long state[8], curlen;
+  unsigned char buf[64];
+};
+typedef struct sha256_state my_sha256_ctx;
+
+/* The K array */
+static const unsigned long K[64] = {
+  0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+  0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+  0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+  0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+  0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+  0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+  0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+  0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+  0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+  0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+  0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+  0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+  0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Various logical functions */
+#define RORc(x, y) \
+(((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \
+   ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define Ch(x,y,z)   (z ^ (x & (y ^ z)))
+#define Maj(x,y,z)  (((x | y) & z) | (x & y))
+#define S(x, n)     RORc((x), (n))
+#define R(x, n)     (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x)   (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x)   (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x)   (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x)   (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+
+/* Compress 512-bits */
+static int sha256_compress(struct sha256_state *md,
+                           unsigned char *buf)
+{
+  unsigned long S[8], W[64];
+  int i;
+
+  /* Copy state into S */
+  for(i = 0; i < 8; i++) {
+    S[i] = md->state[i];
+  }
+  /* copy the state into 512-bits into W[0..15] */
+  for(i = 0; i < 16; i++)
+    W[i] = WPA_GET_BE32(buf + (4 * i));
+  /* fill W[16..63] */
+  for(i = 16; i < 64; i++) {
+    W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
+      W[i - 16];
+  }
+
+  /* Compress */
+#define RND(a,b,c,d,e,f,g,h,i)                                          \
+  do {                                                                  \
+    unsigned long t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];       \
+    unsigned long t1 = Sigma0(a) + Maj(a, b, c);                        \
+    d += t0;                                                            \
+    h = t0 + t1;                                                        \
+  } while(0)
+
+  for(i = 0; i < 64; ++i) {
+    unsigned long t;
+    RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
+    t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
+    S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
+  }
+
+  /* Feedback */
+  for(i = 0; i < 8; i++) {
+    md->state[i] = md->state[i] + S[i];
+  }
+
+  return 0;
+}
+
+/* Initialize the hash state */
+static CURLcode my_sha256_init(struct sha256_state *md)
+{
+  md->curlen = 0;
+  md->length = 0;
+  md->state[0] = 0x6A09E667UL;
+  md->state[1] = 0xBB67AE85UL;
+  md->state[2] = 0x3C6EF372UL;
+  md->state[3] = 0xA54FF53AUL;
+  md->state[4] = 0x510E527FUL;
+  md->state[5] = 0x9B05688CUL;
+  md->state[6] = 0x1F83D9ABUL;
+  md->state[7] = 0x5BE0CD19UL;
+
+  return CURLE_OK;
+}
+
+/*
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return 0 if successful
+*/
+static int my_sha256_update(struct sha256_state *md,
+                            const unsigned char *in,
+                            unsigned long inlen)
+{
+  unsigned long n;
+
+#define block_size 64
+  if(md->curlen > sizeof(md->buf))
+    return -1;
+  while(inlen > 0) {
+    if(md->curlen == 0 && inlen >= block_size) {
+      if(sha256_compress(md, (unsigned char *)in) < 0)
+        return -1;
+      md->length += block_size * 8;
+      in += block_size;
+      inlen -= block_size;
+    }
+    else {
+      n = CURLMIN(inlen, (block_size - md->curlen));
+      memcpy(md->buf + md->curlen, in, n);
+      md->curlen += n;
+      in += n;
+      inlen -= n;
+      if(md->curlen == block_size) {
+        if(sha256_compress(md, md->buf) < 0)
+          return -1;
+        md->length += 8 * block_size;
+        md->curlen = 0;
+      }
+    }
+  }
+
+  return 0;
+}
+
+/*
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (32 bytes)
+   @return 0 if successful
+*/
+static int my_sha256_final(unsigned char *out,
+                           struct sha256_state *md)
+{
+  int i;
+
+  if(md->curlen >= sizeof(md->buf))
+    return -1;
+
+  /* Increase the length of the message */
+  md->length += md->curlen * 8;
+
+  /* Append the '1' bit */
+  md->buf[md->curlen++] = (unsigned char)0x80;
+
+  /* If the length is currently above 56 bytes we append zeros
+   * then compress.  Then we can fall back to padding zeros and length
+   * encoding like normal.
+   */
+  if(md->curlen > 56) {
+    while(md->curlen < 64) {
+      md->buf[md->curlen++] = (unsigned char)0;
+    }
+    sha256_compress(md, md->buf);
+    md->curlen = 0;
+  }
+
+  /* Pad up to 56 bytes of zeroes */
+  while(md->curlen < 56) {
+    md->buf[md->curlen++] = (unsigned char)0;
+  }
+
+  /* Store length */
+  WPA_PUT_BE64(md->buf + 56, md->length);
+  sha256_compress(md, md->buf);
+
+  /* Copy output */
+  for(i = 0; i < 8; i++)
+    WPA_PUT_BE32(out + (4 * i), md->state[i]);
+
+  return 0;
+}
+
+#endif /* CRYPTO LIBS */
+
+/*
+ * Curl_sha256it()
+ *
+ * Generates a SHA256 hash for the given input data.
+ *
+ * Parameters:
+ *
+ * output [in/out] - The output buffer.
+ * input  [in]     - The input data.
+ * length [in]     - The input length.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_sha256it(unsigned char *output, const unsigned char *input,
+                   const size_t length)
+{
+  CURLcode result;
+  my_sha256_ctx ctx;
+
+  result = my_sha256_init(&ctx);
+  if(!result) {
+    my_sha256_update(&ctx, input, curlx_uztoui(length));
+    my_sha256_final(output, &ctx);
+  }
+  return result;
+}
+
+
+const struct HMAC_params Curl_HMAC_SHA256[] = {
+  {
+    /* Hash initialization function. */
+    CURLX_FUNCTION_CAST(HMAC_hinit_func, my_sha256_init),
+    /* Hash update function. */
+    CURLX_FUNCTION_CAST(HMAC_hupdate_func, my_sha256_update),
+    /* Hash computation end function. */
+    CURLX_FUNCTION_CAST(HMAC_hfinal_func, my_sha256_final),
+    /* Size of hash context structure. */
+    sizeof(my_sha256_ctx),
+    /* Maximum key length. */
+    64,
+    /* Result size. */
+    32
+  }
+};
+
+
+#endif /* AWS, DIGEST, or libSSH2 */
Index: trunk/src/libs/curl-8.7.1/lib/share.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/share.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/share.c	(revision 104083)
@@ -0,0 +1,290 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "share.h"
+#include "psl.h"
+#include "vtls/vtls.h"
+#include "hsts.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+struct Curl_share *
+curl_share_init(void)
+{
+  struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
+  if(share) {
+    share->magic = CURL_GOOD_SHARE;
+    share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
+    Curl_init_dnscache(&share->hostcache, 23);
+  }
+
+  return share;
+}
+
+#undef curl_share_setopt
+CURLSHcode
+curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
+{
+  va_list param;
+  int type;
+  curl_lock_function lockfunc;
+  curl_unlock_function unlockfunc;
+  void *ptr;
+  CURLSHcode res = CURLSHE_OK;
+
+  if(!GOOD_SHARE_HANDLE(share))
+    return CURLSHE_INVALID;
+
+  if(share->dirty)
+    /* don't allow setting options while one or more handles are already
+       using this share */
+    return CURLSHE_IN_USE;
+
+  va_start(param, option);
+
+  switch(option) {
+  case CURLSHOPT_SHARE:
+    /* this is a type this share will share */
+    type = va_arg(param, int);
+
+    switch(type) {
+    case CURL_LOCK_DATA_DNS:
+      break;
+
+    case CURL_LOCK_DATA_COOKIE:
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+      if(!share->cookies) {
+        share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE);
+        if(!share->cookies)
+          res = CURLSHE_NOMEM;
+      }
+#else   /* CURL_DISABLE_HTTP */
+      res = CURLSHE_NOT_BUILT_IN;
+#endif
+      break;
+
+    case CURL_LOCK_DATA_HSTS:
+#ifndef CURL_DISABLE_HSTS
+      if(!share->hsts) {
+        share->hsts = Curl_hsts_init();
+        if(!share->hsts)
+          res = CURLSHE_NOMEM;
+      }
+#else   /* CURL_DISABLE_HSTS */
+      res = CURLSHE_NOT_BUILT_IN;
+#endif
+      break;
+
+    case CURL_LOCK_DATA_SSL_SESSION:
+#ifdef USE_SSL
+      if(!share->sslsession) {
+        share->max_ssl_sessions = 8;
+        share->sslsession = calloc(share->max_ssl_sessions,
+                                   sizeof(struct Curl_ssl_session));
+        share->sessionage = 0;
+        if(!share->sslsession)
+          res = CURLSHE_NOMEM;
+      }
+#else
+      res = CURLSHE_NOT_BUILT_IN;
+#endif
+      break;
+
+    case CURL_LOCK_DATA_CONNECT:
+      if(Curl_conncache_init(&share->conn_cache, 103))
+        res = CURLSHE_NOMEM;
+      break;
+
+    case CURL_LOCK_DATA_PSL:
+#ifndef USE_LIBPSL
+      res = CURLSHE_NOT_BUILT_IN;
+#endif
+      break;
+
+    default:
+      res = CURLSHE_BAD_OPTION;
+    }
+    if(!res)
+      share->specifier |= (unsigned int)(1<<type);
+    break;
+
+  case CURLSHOPT_UNSHARE:
+    /* this is a type this share will no longer share */
+    type = va_arg(param, int);
+    share->specifier &= ~(unsigned int)(1<<type);
+    switch(type) {
+    case CURL_LOCK_DATA_DNS:
+      break;
+
+    case CURL_LOCK_DATA_COOKIE:
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+      if(share->cookies) {
+        Curl_cookie_cleanup(share->cookies);
+        share->cookies = NULL;
+      }
+#else   /* CURL_DISABLE_HTTP */
+      res = CURLSHE_NOT_BUILT_IN;
+#endif
+      break;
+
+    case CURL_LOCK_DATA_HSTS:
+#ifndef CURL_DISABLE_HSTS
+      if(share->hsts) {
+        Curl_hsts_cleanup(&share->hsts);
+      }
+#else   /* CURL_DISABLE_HSTS */
+      res = CURLSHE_NOT_BUILT_IN;
+#endif
+      break;
+
+    case CURL_LOCK_DATA_SSL_SESSION:
+#ifdef USE_SSL
+      Curl_safefree(share->sslsession);
+#else
+      res = CURLSHE_NOT_BUILT_IN;
+#endif
+      break;
+
+    case CURL_LOCK_DATA_CONNECT:
+      break;
+
+    default:
+      res = CURLSHE_BAD_OPTION;
+      break;
+    }
+    break;
+
+  case CURLSHOPT_LOCKFUNC:
+    lockfunc = va_arg(param, curl_lock_function);
+    share->lockfunc = lockfunc;
+    break;
+
+  case CURLSHOPT_UNLOCKFUNC:
+    unlockfunc = va_arg(param, curl_unlock_function);
+    share->unlockfunc = unlockfunc;
+    break;
+
+  case CURLSHOPT_USERDATA:
+    ptr = va_arg(param, void *);
+    share->clientdata = ptr;
+    break;
+
+  default:
+    res = CURLSHE_BAD_OPTION;
+    break;
+  }
+
+  va_end(param);
+
+  return res;
+}
+
+CURLSHcode
+curl_share_cleanup(struct Curl_share *share)
+{
+  if(!GOOD_SHARE_HANDLE(share))
+    return CURLSHE_INVALID;
+
+  if(share->lockfunc)
+    share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
+                    share->clientdata);
+
+  if(share->dirty) {
+    if(share->unlockfunc)
+      share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
+    return CURLSHE_IN_USE;
+  }
+
+  Curl_conncache_close_all_connections(&share->conn_cache);
+  Curl_conncache_destroy(&share->conn_cache);
+  Curl_hash_destroy(&share->hostcache);
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+  Curl_cookie_cleanup(share->cookies);
+#endif
+
+#ifndef CURL_DISABLE_HSTS
+  Curl_hsts_cleanup(&share->hsts);
+#endif
+
+#ifdef USE_SSL
+  if(share->sslsession) {
+    size_t i;
+    for(i = 0; i < share->max_ssl_sessions; i++)
+      Curl_ssl_kill_session(&(share->sslsession[i]));
+    free(share->sslsession);
+  }
+#endif
+
+  Curl_psl_destroy(&share->psl);
+
+  if(share->unlockfunc)
+    share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
+  share->magic = 0;
+  free(share);
+
+  return CURLSHE_OK;
+}
+
+
+CURLSHcode
+Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
+                curl_lock_access accesstype)
+{
+  struct Curl_share *share = data->share;
+
+  if(!share)
+    return CURLSHE_INVALID;
+
+  if(share->specifier & (unsigned int)(1<<type)) {
+    if(share->lockfunc) /* only call this if set! */
+      share->lockfunc(data, type, accesstype, share->clientdata);
+  }
+  /* else if we don't share this, pretend successful lock */
+
+  return CURLSHE_OK;
+}
+
+CURLSHcode
+Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
+{
+  struct Curl_share *share = data->share;
+
+  if(!share)
+    return CURLSHE_INVALID;
+
+  if(share->specifier & (unsigned int)(1<<type)) {
+    if(share->unlockfunc) /* only call this if set! */
+      share->unlockfunc (data, type, share->clientdata);
+  }
+
+  return CURLSHE_OK;
+}
Index: trunk/src/libs/curl-8.7.1/lib/share.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/share.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/share.h	(revision 104083)
@@ -0,0 +1,68 @@
+#ifndef HEADER_CURL_SHARE_H
+#define HEADER_CURL_SHARE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include <curl/curl.h>
+#include "cookie.h"
+#include "psl.h"
+#include "urldata.h"
+#include "conncache.h"
+
+#define CURL_GOOD_SHARE 0x7e117a1e
+#define GOOD_SHARE_HANDLE(x) ((x) && (x)->magic == CURL_GOOD_SHARE)
+
+/* this struct is libcurl-private, don't export details */
+struct Curl_share {
+  unsigned int magic; /* CURL_GOOD_SHARE */
+  unsigned int specifier;
+  volatile unsigned int dirty;
+
+  curl_lock_function lockfunc;
+  curl_unlock_function unlockfunc;
+  void *clientdata;
+  struct conncache conn_cache;
+  struct Curl_hash hostcache;
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+  struct CookieInfo *cookies;
+#endif
+#ifdef USE_LIBPSL
+  struct PslCache psl;
+#endif
+#ifndef CURL_DISABLE_HSTS
+  struct hsts *hsts;
+#endif
+#ifdef USE_SSL
+  struct Curl_ssl_session *sslsession;
+  size_t max_ssl_sessions;
+  long sessionage;
+#endif
+};
+
+CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data,
+                           curl_lock_access);
+CURLSHcode Curl_share_unlock(struct Curl_easy *, curl_lock_data);
+
+#endif /* HEADER_CURL_SHARE_H */
Index: trunk/src/libs/curl-8.7.1/lib/sigpipe.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/sigpipe.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/sigpipe.h	(revision 104083)
@@ -0,0 +1,80 @@
+#ifndef HEADER_CURL_SIGPIPE_H
+#define HEADER_CURL_SIGPIPE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(HAVE_SIGACTION) &&        \
+  (defined(USE_OPENSSL) || defined(USE_MBEDTLS) || defined(USE_WOLFSSL))
+#include <signal.h>
+
+struct sigpipe_ignore {
+  struct sigaction old_pipe_act;
+  bool no_signal;
+};
+
+#define SIGPIPE_VARIABLE(x) struct sigpipe_ignore x
+
+/*
+ * sigpipe_ignore() makes sure we ignore SIGPIPE while running libcurl
+ * internals, and then sigpipe_restore() will restore the situation when we
+ * return from libcurl again.
+ */
+static void sigpipe_ignore(struct Curl_easy *data,
+                           struct sigpipe_ignore *ig)
+{
+  /* get a local copy of no_signal because the Curl_easy might not be
+     around when we restore */
+  ig->no_signal = data->set.no_signal;
+  if(!data->set.no_signal) {
+    struct sigaction action;
+    /* first, extract the existing situation */
+    sigaction(SIGPIPE, NULL, &ig->old_pipe_act);
+    action = ig->old_pipe_act;
+    /* ignore this signal */
+    action.sa_handler = SIG_IGN;
+    sigaction(SIGPIPE, &action, NULL);
+  }
+}
+
+/*
+ * sigpipe_restore() puts back the outside world's opinion of signal handler
+ * and SIGPIPE handling. It MUST only be called after a corresponding
+ * sigpipe_ignore() was used.
+ */
+static void sigpipe_restore(struct sigpipe_ignore *ig)
+{
+  if(!ig->no_signal)
+    /* restore the outside state */
+    sigaction(SIGPIPE, &ig->old_pipe_act, NULL);
+}
+
+#else
+/* for systems without sigaction */
+#define sigpipe_ignore(x,y) Curl_nop_stmt
+#define sigpipe_restore(x)  Curl_nop_stmt
+#define SIGPIPE_VARIABLE(x)
+#endif
+
+#endif /* HEADER_CURL_SIGPIPE_H */
Index: trunk/src/libs/curl-8.7.1/lib/slist.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/slist.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/slist.c	(revision 104083)
@@ -0,0 +1,146 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "slist.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* returns last node in linked list */
+static struct curl_slist *slist_get_last(struct curl_slist *list)
+{
+  struct curl_slist     *item;
+
+  /* if caller passed us a NULL, return now */
+  if(!list)
+    return NULL;
+
+  /* loop through to find the last item */
+  item = list;
+  while(item->next) {
+    item = item->next;
+  }
+  return item;
+}
+
+/*
+ * Curl_slist_append_nodup() appends a string to the linked list. Rather than
+ * copying the string in dynamic storage, it takes its ownership. The string
+ * should have been malloc()ated. Curl_slist_append_nodup always returns
+ * the address of the first record, so that you can use this function as an
+ * initialization function as well as an append function.
+ * If an error occurs, NULL is returned and the string argument is NOT
+ * released.
+ */
+struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, char *data)
+{
+  struct curl_slist     *last;
+  struct curl_slist     *new_item;
+
+  DEBUGASSERT(data);
+
+  new_item = malloc(sizeof(struct curl_slist));
+  if(!new_item)
+    return NULL;
+
+  new_item->next = NULL;
+  new_item->data = data;
+
+  /* if this is the first item, then new_item *is* the list */
+  if(!list)
+    return new_item;
+
+  last = slist_get_last(list);
+  last->next = new_item;
+  return list;
+}
+
+/*
+ * curl_slist_append() appends a string to the linked list. It always returns
+ * the address of the first record, so that you can use this function as an
+ * initialization function as well as an append function. If you find this
+ * bothersome, then simply create a separate _init function and call it
+ * appropriately from within the program.
+ */
+struct curl_slist *curl_slist_append(struct curl_slist *list,
+                                     const char *data)
+{
+  char *dupdata = strdup(data);
+
+  if(!dupdata)
+    return NULL;
+
+  list = Curl_slist_append_nodup(list, dupdata);
+  if(!list)
+    free(dupdata);
+
+  return list;
+}
+
+/*
+ * Curl_slist_duplicate() duplicates a linked list. It always returns the
+ * address of the first record of the cloned list or NULL in case of an
+ * error (or if the input list was NULL).
+ */
+struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist)
+{
+  struct curl_slist *outlist = NULL;
+  struct curl_slist *tmp;
+
+  while(inlist) {
+    tmp = curl_slist_append(outlist, inlist->data);
+
+    if(!tmp) {
+      curl_slist_free_all(outlist);
+      return NULL;
+    }
+
+    outlist = tmp;
+    inlist = inlist->next;
+  }
+  return outlist;
+}
+
+/* be nice and clean up resources */
+void curl_slist_free_all(struct curl_slist *list)
+{
+  struct curl_slist     *next;
+  struct curl_slist     *item;
+
+  if(!list)
+    return;
+
+  item = list;
+  do {
+    next = item->next;
+    Curl_safefree(item->data);
+    free(item);
+    item = next;
+  } while(next);
+}
Index: trunk/src/libs/curl-8.7.1/lib/slist.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/slist.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/slist.h	(revision 104083)
@@ -0,0 +1,41 @@
+#ifndef HEADER_CURL_SLIST_H
+#define HEADER_CURL_SLIST_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Curl_slist_duplicate() duplicates a linked list. It always returns the
+ * address of the first record of the cloned list or NULL in case of an
+ * error (or if the input list was NULL).
+ */
+struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist);
+
+/*
+ * Curl_slist_append_nodup() takes ownership of the given string and appends
+ * it to the list.
+ */
+struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list,
+                                           char *data);
+
+#endif /* HEADER_CURL_SLIST_H */
Index: trunk/src/libs/curl-8.7.1/lib/smb.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/smb.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/smb.c	(revision 104083)
@@ -0,0 +1,1204 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Bill Nagel <wnagel@tycoint.com>, Exacq Technologies
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE)
+
+#ifdef _WIN32
+#define getpid GetCurrentProcessId
+#endif
+
+#include "smb.h"
+#include "urldata.h"
+#include "sendf.h"
+#include "multiif.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "progress.h"
+#include "transfer.h"
+#include "vtls/vtls.h"
+#include "curl_ntlm_core.h"
+#include "escape.h"
+#include "curl_endian.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Definitions for SMB protocol data structures
+ */
+#if defined(_MSC_VER) || defined(__ILEC400__)
+#  define PACK
+#  pragma pack(push)
+#  pragma pack(1)
+#elif defined(__GNUC__)
+#  define PACK __attribute__((packed))
+#else
+#  define PACK
+#endif
+
+#define SMB_COM_CLOSE                 0x04
+#define SMB_COM_READ_ANDX             0x2e
+#define SMB_COM_WRITE_ANDX            0x2f
+#define SMB_COM_TREE_DISCONNECT       0x71
+#define SMB_COM_NEGOTIATE             0x72
+#define SMB_COM_SETUP_ANDX            0x73
+#define SMB_COM_TREE_CONNECT_ANDX     0x75
+#define SMB_COM_NT_CREATE_ANDX        0xa2
+#define SMB_COM_NO_ANDX_COMMAND       0xff
+
+#define SMB_WC_CLOSE                  0x03
+#define SMB_WC_READ_ANDX              0x0c
+#define SMB_WC_WRITE_ANDX             0x0e
+#define SMB_WC_SETUP_ANDX             0x0d
+#define SMB_WC_TREE_CONNECT_ANDX      0x04
+#define SMB_WC_NT_CREATE_ANDX         0x18
+
+#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10
+#define SMB_FLAGS_CASELESS_PATHNAMES  0x08
+#define SMB_FLAGS2_UNICODE_STRINGS    0x8000
+#define SMB_FLAGS2_IS_LONG_NAME       0x0040
+#define SMB_FLAGS2_KNOWS_LONG_NAME    0x0001
+
+#define SMB_CAP_LARGE_FILES           0x08
+#define SMB_GENERIC_WRITE             0x40000000
+#define SMB_GENERIC_READ              0x80000000
+#define SMB_FILE_SHARE_ALL            0x07
+#define SMB_FILE_OPEN                 0x01
+#define SMB_FILE_OVERWRITE_IF         0x05
+
+#define SMB_ERR_NOACCESS              0x00050001
+
+struct smb_header {
+  unsigned char nbt_type;
+  unsigned char nbt_flags;
+  unsigned short nbt_length;
+  unsigned char magic[4];
+  unsigned char command;
+  unsigned int status;
+  unsigned char flags;
+  unsigned short flags2;
+  unsigned short pid_high;
+  unsigned char signature[8];
+  unsigned short pad;
+  unsigned short tid;
+  unsigned short pid;
+  unsigned short uid;
+  unsigned short mid;
+} PACK;
+
+struct smb_negotiate_response {
+  struct smb_header h;
+  unsigned char word_count;
+  unsigned short dialect_index;
+  unsigned char security_mode;
+  unsigned short max_mpx_count;
+  unsigned short max_number_vcs;
+  unsigned int max_buffer_size;
+  unsigned int max_raw_size;
+  unsigned int session_key;
+  unsigned int capabilities;
+  unsigned int system_time_low;
+  unsigned int system_time_high;
+  unsigned short server_time_zone;
+  unsigned char encryption_key_length;
+  unsigned short byte_count;
+  char bytes[1];
+} PACK;
+
+struct andx {
+  unsigned char command;
+  unsigned char pad;
+  unsigned short offset;
+} PACK;
+
+struct smb_setup {
+  unsigned char word_count;
+  struct andx andx;
+  unsigned short max_buffer_size;
+  unsigned short max_mpx_count;
+  unsigned short vc_number;
+  unsigned int session_key;
+  unsigned short lengths[2];
+  unsigned int pad;
+  unsigned int capabilities;
+  unsigned short byte_count;
+  char bytes[1024];
+} PACK;
+
+struct smb_tree_connect {
+  unsigned char word_count;
+  struct andx andx;
+  unsigned short flags;
+  unsigned short pw_len;
+  unsigned short byte_count;
+  char bytes[1024];
+} PACK;
+
+struct smb_nt_create {
+  unsigned char word_count;
+  struct andx andx;
+  unsigned char pad;
+  unsigned short name_length;
+  unsigned int flags;
+  unsigned int root_fid;
+  unsigned int access;
+  curl_off_t allocation_size;
+  unsigned int ext_file_attributes;
+  unsigned int share_access;
+  unsigned int create_disposition;
+  unsigned int create_options;
+  unsigned int impersonation_level;
+  unsigned char security_flags;
+  unsigned short byte_count;
+  char bytes[1024];
+} PACK;
+
+struct smb_nt_create_response {
+  struct smb_header h;
+  unsigned char word_count;
+  struct andx andx;
+  unsigned char op_lock_level;
+  unsigned short fid;
+  unsigned int create_disposition;
+
+  curl_off_t create_time;
+  curl_off_t last_access_time;
+  curl_off_t last_write_time;
+  curl_off_t last_change_time;
+  unsigned int ext_file_attributes;
+  curl_off_t allocation_size;
+  curl_off_t end_of_file;
+} PACK;
+
+struct smb_read {
+  unsigned char word_count;
+  struct andx andx;
+  unsigned short fid;
+  unsigned int offset;
+  unsigned short max_bytes;
+  unsigned short min_bytes;
+  unsigned int timeout;
+  unsigned short remaining;
+  unsigned int offset_high;
+  unsigned short byte_count;
+} PACK;
+
+struct smb_write {
+  struct smb_header h;
+  unsigned char word_count;
+  struct andx andx;
+  unsigned short fid;
+  unsigned int offset;
+  unsigned int timeout;
+  unsigned short write_mode;
+  unsigned short remaining;
+  unsigned short pad;
+  unsigned short data_length;
+  unsigned short data_offset;
+  unsigned int offset_high;
+  unsigned short byte_count;
+  unsigned char pad2;
+} PACK;
+
+struct smb_close {
+  unsigned char word_count;
+  unsigned short fid;
+  unsigned int last_mtime;
+  unsigned short byte_count;
+} PACK;
+
+struct smb_tree_disconnect {
+  unsigned char word_count;
+  unsigned short byte_count;
+} PACK;
+
+#if defined(_MSC_VER) || defined(__ILEC400__)
+#  pragma pack(pop)
+#endif
+
+/* Local API functions */
+static CURLcode smb_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn);
+static CURLcode smb_connect(struct Curl_easy *data, bool *done);
+static CURLcode smb_connection_state(struct Curl_easy *data, bool *done);
+static CURLcode smb_do(struct Curl_easy *data, bool *done);
+static CURLcode smb_request_state(struct Curl_easy *data, bool *done);
+static CURLcode smb_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn, bool dead);
+static int smb_getsock(struct Curl_easy *data, struct connectdata *conn,
+                       curl_socket_t *socks);
+static CURLcode smb_parse_url_path(struct Curl_easy *data,
+                                   struct connectdata *conn);
+
+/*
+ * SMB handler interface
+ */
+const struct Curl_handler Curl_handler_smb = {
+  "SMB",                                /* scheme */
+  smb_setup_connection,                 /* setup_connection */
+  smb_do,                               /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  smb_connect,                          /* connect_it */
+  smb_connection_state,                 /* connecting */
+  smb_request_state,                    /* doing */
+  smb_getsock,                          /* proto_getsock */
+  smb_getsock,                          /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  smb_disconnect,                       /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_SMB,                             /* defport */
+  CURLPROTO_SMB,                        /* protocol */
+  CURLPROTO_SMB,                        /* family */
+  PROTOPT_NONE                          /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * SMBS handler interface
+ */
+const struct Curl_handler Curl_handler_smbs = {
+  "SMBS",                               /* scheme */
+  smb_setup_connection,                 /* setup_connection */
+  smb_do,                               /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  smb_connect,                          /* connect_it */
+  smb_connection_state,                 /* connecting */
+  smb_request_state,                    /* doing */
+  smb_getsock,                          /* proto_getsock */
+  smb_getsock,                          /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  smb_disconnect,                       /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_SMBS,                            /* defport */
+  CURLPROTO_SMBS,                       /* protocol */
+  CURLPROTO_SMB,                        /* family */
+  PROTOPT_SSL                           /* flags */
+};
+#endif
+
+#define MAX_PAYLOAD_SIZE  0x8000
+#define MAX_MESSAGE_SIZE  (MAX_PAYLOAD_SIZE + 0x1000)
+#define CLIENTNAME        "curl"
+#define SERVICENAME       "?????"
+
+/* Append a string to an SMB message */
+#define MSGCAT(str)                             \
+  do {                                          \
+    strcpy(p, (str));                           \
+    p += strlen(str);                           \
+  } while(0)
+
+/* Append a null-terminated string to an SMB message */
+#define MSGCATNULL(str)                         \
+  do {                                          \
+    strcpy(p, (str));                           \
+    p += strlen(str) + 1;                       \
+  } while(0)
+
+/* SMB is mostly little endian */
+#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
+  defined(__OS400__)
+static unsigned short smb_swap16(unsigned short x)
+{
+  return (unsigned short) ((x << 8) | ((x >> 8) & 0xff));
+}
+
+static unsigned int smb_swap32(unsigned int x)
+{
+  return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) |
+    ((x >> 24) & 0xff);
+}
+
+static curl_off_t smb_swap64(curl_off_t x)
+{
+  return ((curl_off_t) smb_swap32((unsigned int) x) << 32) |
+    smb_swap32((unsigned int) (x >> 32));
+}
+
+#else
+#  define smb_swap16(x) (x)
+#  define smb_swap32(x) (x)
+#  define smb_swap64(x) (x)
+#endif
+
+/* SMB request state */
+enum smb_req_state {
+  SMB_REQUESTING,
+  SMB_TREE_CONNECT,
+  SMB_OPEN,
+  SMB_DOWNLOAD,
+  SMB_UPLOAD,
+  SMB_CLOSE,
+  SMB_TREE_DISCONNECT,
+  SMB_DONE
+};
+
+/* SMB request data */
+struct smb_request {
+  enum smb_req_state state;
+  char *path;
+  unsigned short tid; /* Even if we connect to the same tree as another */
+  unsigned short fid; /* request, the tid will be different */
+  CURLcode result;
+};
+
+static void conn_state(struct Curl_easy *data, enum smb_conn_state newstate)
+{
+  struct smb_conn *smbc = &data->conn->proto.smbc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* For debug purposes */
+  static const char * const names[] = {
+    "SMB_NOT_CONNECTED",
+    "SMB_CONNECTING",
+    "SMB_NEGOTIATE",
+    "SMB_SETUP",
+    "SMB_CONNECTED",
+    /* LAST */
+  };
+
+  if(smbc->state != newstate)
+    infof(data, "SMB conn %p state change from %s to %s",
+          (void *)smbc, names[smbc->state], names[newstate]);
+#endif
+
+  smbc->state = newstate;
+}
+
+static void request_state(struct Curl_easy *data,
+                          enum smb_req_state newstate)
+{
+  struct smb_request *req = data->req.p.smb;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* For debug purposes */
+  static const char * const names[] = {
+    "SMB_REQUESTING",
+    "SMB_TREE_CONNECT",
+    "SMB_OPEN",
+    "SMB_DOWNLOAD",
+    "SMB_UPLOAD",
+    "SMB_CLOSE",
+    "SMB_TREE_DISCONNECT",
+    "SMB_DONE",
+    /* LAST */
+  };
+
+  if(req->state != newstate)
+    infof(data, "SMB request %p state change from %s to %s",
+          (void *)req, names[req->state], names[newstate]);
+#endif
+
+  req->state = newstate;
+}
+
+/* this should setup things in the connection, not in the easy
+   handle */
+static CURLcode smb_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn)
+{
+  struct smb_request *req;
+
+  /* Initialize the request state */
+  data->req.p.smb = req = calloc(1, sizeof(struct smb_request));
+  if(!req)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Parse the URL path */
+  return smb_parse_url_path(data, conn);
+}
+
+static CURLcode smb_connect(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct smb_conn *smbc = &conn->proto.smbc;
+  char *slash;
+
+  (void) done;
+
+  /* Check we have a username and password to authenticate with */
+  if(!data->state.aptr.user)
+    return CURLE_LOGIN_DENIED;
+
+  /* Initialize the connection state */
+  smbc->state = SMB_CONNECTING;
+  smbc->recv_buf = malloc(MAX_MESSAGE_SIZE);
+  if(!smbc->recv_buf)
+    return CURLE_OUT_OF_MEMORY;
+  smbc->send_buf = malloc(MAX_MESSAGE_SIZE);
+  if(!smbc->send_buf)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Multiple requests are allowed with this connection */
+  connkeep(conn, "SMB default");
+
+  /* Parse the username, domain, and password */
+  slash = strchr(conn->user, '/');
+  if(!slash)
+    slash = strchr(conn->user, '\\');
+
+  if(slash) {
+    smbc->user = slash + 1;
+    smbc->domain = strdup(conn->user);
+    if(!smbc->domain)
+      return CURLE_OUT_OF_MEMORY;
+    smbc->domain[slash - conn->user] = 0;
+  }
+  else {
+    smbc->user = conn->user;
+    smbc->domain = strdup(conn->host.name);
+    if(!smbc->domain)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode smb_recv_message(struct Curl_easy *data, void **msg)
+{
+  struct connectdata *conn = data->conn;
+  struct smb_conn *smbc = &conn->proto.smbc;
+  char *buf = smbc->recv_buf;
+  ssize_t bytes_read;
+  size_t nbt_size;
+  size_t msg_size;
+  size_t len = MAX_MESSAGE_SIZE - smbc->got;
+  CURLcode result;
+
+  result = Curl_xfer_recv(data, buf + smbc->got, len, &bytes_read);
+  if(result)
+    return result;
+
+  if(!bytes_read)
+    return CURLE_OK;
+
+  smbc->got += bytes_read;
+
+  /* Check for a 32-bit nbt header */
+  if(smbc->got < sizeof(unsigned int))
+    return CURLE_OK;
+
+  nbt_size = Curl_read16_be((const unsigned char *)
+                            (buf + sizeof(unsigned short))) +
+    sizeof(unsigned int);
+  if(smbc->got < nbt_size)
+    return CURLE_OK;
+
+  msg_size = sizeof(struct smb_header);
+  if(nbt_size >= msg_size + 1) {
+    /* Add the word count */
+    msg_size += 1 + ((unsigned char) buf[msg_size]) * sizeof(unsigned short);
+    if(nbt_size >= msg_size + sizeof(unsigned short)) {
+      /* Add the byte count */
+      msg_size += sizeof(unsigned short) +
+        Curl_read16_le((const unsigned char *)&buf[msg_size]);
+      if(nbt_size < msg_size)
+        return CURLE_READ_ERROR;
+    }
+  }
+
+  *msg = buf;
+
+  return CURLE_OK;
+}
+
+static void smb_pop_message(struct connectdata *conn)
+{
+  struct smb_conn *smbc = &conn->proto.smbc;
+
+  smbc->got = 0;
+}
+
+static void smb_format_message(struct Curl_easy *data, struct smb_header *h,
+                               unsigned char cmd, size_t len)
+{
+  struct connectdata *conn = data->conn;
+  struct smb_conn *smbc = &conn->proto.smbc;
+  struct smb_request *req = data->req.p.smb;
+  unsigned int pid;
+
+  memset(h, 0, sizeof(*h));
+  h->nbt_length = htons((unsigned short) (sizeof(*h) - sizeof(unsigned int) +
+                                          len));
+  memcpy((char *)h->magic, "\xffSMB", 4);
+  h->command = cmd;
+  h->flags = SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES;
+  h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME);
+  h->uid = smb_swap16(smbc->uid);
+  h->tid = smb_swap16(req->tid);
+  pid = getpid();
+  h->pid_high = smb_swap16((unsigned short)(pid >> 16));
+  h->pid = smb_swap16((unsigned short) pid);
+}
+
+static CURLcode smb_send(struct Curl_easy *data, size_t len,
+                         size_t upload_size)
+{
+  struct connectdata *conn = data->conn;
+  struct smb_conn *smbc = &conn->proto.smbc;
+  size_t bytes_written;
+  CURLcode result;
+
+  result = Curl_xfer_send(data, smbc->send_buf, len, &bytes_written);
+  if(result)
+    return result;
+
+  if(bytes_written != len) {
+    smbc->send_size = len;
+    smbc->sent = bytes_written;
+  }
+
+  smbc->upload_size = upload_size;
+
+  return CURLE_OK;
+}
+
+static CURLcode smb_flush(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+  struct smb_conn *smbc = &conn->proto.smbc;
+  size_t bytes_written;
+  size_t len = smbc->send_size - smbc->sent;
+  CURLcode result;
+
+  if(!smbc->send_size)
+    return CURLE_OK;
+
+  result = Curl_xfer_send(data, smbc->send_buf + smbc->sent, len,
+                          &bytes_written);
+  if(result)
+    return result;
+
+  if(bytes_written != len)
+    smbc->sent += bytes_written;
+  else
+    smbc->send_size = 0;
+
+  return CURLE_OK;
+}
+
+static CURLcode smb_send_message(struct Curl_easy *data, unsigned char cmd,
+                                 const void *msg, size_t msg_len)
+{
+  struct connectdata *conn = data->conn;
+  struct smb_conn *smbc = &conn->proto.smbc;
+
+  smb_format_message(data, (struct smb_header *)smbc->send_buf,
+                     cmd, msg_len);
+  DEBUGASSERT((sizeof(struct smb_header) + msg_len) <= MAX_MESSAGE_SIZE);
+  memcpy(smbc->send_buf + sizeof(struct smb_header), msg, msg_len);
+
+  return smb_send(data, sizeof(struct smb_header) + msg_len, 0);
+}
+
+static CURLcode smb_send_negotiate(struct Curl_easy *data)
+{
+  const char *msg = "\x00\x0c\x00\x02NT LM 0.12";
+
+  return smb_send_message(data, SMB_COM_NEGOTIATE, msg, 15);
+}
+
+static CURLcode smb_send_setup(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+  struct smb_conn *smbc = &conn->proto.smbc;
+  struct smb_setup msg;
+  char *p = msg.bytes;
+  unsigned char lm_hash[21];
+  unsigned char lm[24];
+  unsigned char nt_hash[21];
+  unsigned char nt[24];
+
+  size_t byte_count = sizeof(lm) + sizeof(nt);
+  byte_count += strlen(smbc->user) + strlen(smbc->domain);
+  byte_count += strlen(OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */
+  if(byte_count > sizeof(msg.bytes))
+    return CURLE_FILESIZE_EXCEEDED;
+
+  Curl_ntlm_core_mk_lm_hash(conn->passwd, lm_hash);
+  Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm);
+  Curl_ntlm_core_mk_nt_hash(conn->passwd, nt_hash);
+  Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt);
+
+  memset(&msg, 0, sizeof(msg));
+  msg.word_count = SMB_WC_SETUP_ANDX;
+  msg.andx.command = SMB_COM_NO_ANDX_COMMAND;
+  msg.max_buffer_size = smb_swap16(MAX_MESSAGE_SIZE);
+  msg.max_mpx_count = smb_swap16(1);
+  msg.vc_number = smb_swap16(1);
+  msg.session_key = smb_swap32(smbc->session_key);
+  msg.capabilities = smb_swap32(SMB_CAP_LARGE_FILES);
+  msg.lengths[0] = smb_swap16(sizeof(lm));
+  msg.lengths[1] = smb_swap16(sizeof(nt));
+  memcpy(p, lm, sizeof(lm));
+  p += sizeof(lm);
+  memcpy(p, nt, sizeof(nt));
+  p += sizeof(nt);
+  MSGCATNULL(smbc->user);
+  MSGCATNULL(smbc->domain);
+  MSGCATNULL(OS);
+  MSGCATNULL(CLIENTNAME);
+  byte_count = p - msg.bytes;
+  msg.byte_count = smb_swap16((unsigned short)byte_count);
+
+  return smb_send_message(data, SMB_COM_SETUP_ANDX, &msg,
+                          sizeof(msg) - sizeof(msg.bytes) + byte_count);
+}
+
+static CURLcode smb_send_tree_connect(struct Curl_easy *data)
+{
+  struct smb_tree_connect msg;
+  struct connectdata *conn = data->conn;
+  struct smb_conn *smbc = &conn->proto.smbc;
+  char *p = msg.bytes;
+
+  size_t byte_count = strlen(conn->host.name) + strlen(smbc->share);
+  byte_count += strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */
+  if(byte_count > sizeof(msg.bytes))
+    return CURLE_FILESIZE_EXCEEDED;
+
+  memset(&msg, 0, sizeof(msg));
+  msg.word_count = SMB_WC_TREE_CONNECT_ANDX;
+  msg.andx.command = SMB_COM_NO_ANDX_COMMAND;
+  msg.pw_len = 0;
+  MSGCAT("\\\\");
+  MSGCAT(conn->host.name);
+  MSGCAT("\\");
+  MSGCATNULL(smbc->share);
+  MSGCATNULL(SERVICENAME); /* Match any type of service */
+  byte_count = p - msg.bytes;
+  msg.byte_count = smb_swap16((unsigned short)byte_count);
+
+  return smb_send_message(data, SMB_COM_TREE_CONNECT_ANDX, &msg,
+                          sizeof(msg) - sizeof(msg.bytes) + byte_count);
+}
+
+static CURLcode smb_send_open(struct Curl_easy *data)
+{
+  struct smb_request *req = data->req.p.smb;
+  struct smb_nt_create msg;
+  size_t byte_count;
+
+  if((strlen(req->path) + 1) > sizeof(msg.bytes))
+    return CURLE_FILESIZE_EXCEEDED;
+
+  memset(&msg, 0, sizeof(msg));
+  msg.word_count = SMB_WC_NT_CREATE_ANDX;
+  msg.andx.command = SMB_COM_NO_ANDX_COMMAND;
+  byte_count = strlen(req->path);
+  msg.name_length = smb_swap16((unsigned short)byte_count);
+  msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL);
+  if(data->state.upload) {
+    msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE);
+    msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF);
+  }
+  else {
+    msg.access = smb_swap32(SMB_GENERIC_READ);
+    msg.create_disposition = smb_swap32(SMB_FILE_OPEN);
+  }
+  msg.byte_count = smb_swap16((unsigned short) ++byte_count);
+  strcpy(msg.bytes, req->path);
+
+  return smb_send_message(data, SMB_COM_NT_CREATE_ANDX, &msg,
+                          sizeof(msg) - sizeof(msg.bytes) + byte_count);
+}
+
+static CURLcode smb_send_close(struct Curl_easy *data)
+{
+  struct smb_request *req = data->req.p.smb;
+  struct smb_close msg;
+
+  memset(&msg, 0, sizeof(msg));
+  msg.word_count = SMB_WC_CLOSE;
+  msg.fid = smb_swap16(req->fid);
+
+  return smb_send_message(data, SMB_COM_CLOSE, &msg, sizeof(msg));
+}
+
+static CURLcode smb_send_tree_disconnect(struct Curl_easy *data)
+{
+  struct smb_tree_disconnect msg;
+
+  memset(&msg, 0, sizeof(msg));
+
+  return smb_send_message(data, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg));
+}
+
+static CURLcode smb_send_read(struct Curl_easy *data)
+{
+  struct smb_request *req = data->req.p.smb;
+  curl_off_t offset = data->req.offset;
+  struct smb_read msg;
+
+  memset(&msg, 0, sizeof(msg));
+  msg.word_count = SMB_WC_READ_ANDX;
+  msg.andx.command = SMB_COM_NO_ANDX_COMMAND;
+  msg.fid = smb_swap16(req->fid);
+  msg.offset = smb_swap32((unsigned int) offset);
+  msg.offset_high = smb_swap32((unsigned int) (offset >> 32));
+  msg.min_bytes = smb_swap16(MAX_PAYLOAD_SIZE);
+  msg.max_bytes = smb_swap16(MAX_PAYLOAD_SIZE);
+
+  return smb_send_message(data, SMB_COM_READ_ANDX, &msg, sizeof(msg));
+}
+
+static CURLcode smb_send_write(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+  struct smb_conn *smbc = &conn->proto.smbc;
+  struct smb_write *msg;
+  struct smb_request *req = data->req.p.smb;
+  curl_off_t offset = data->req.offset;
+  curl_off_t upload_size = data->req.size - data->req.bytecount;
+
+  msg = (struct smb_write *)smbc->send_buf;
+  if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */
+    upload_size = MAX_PAYLOAD_SIZE - 1;
+
+  memset(msg, 0, sizeof(*msg));
+  msg->word_count = SMB_WC_WRITE_ANDX;
+  msg->andx.command = SMB_COM_NO_ANDX_COMMAND;
+  msg->fid = smb_swap16(req->fid);
+  msg->offset = smb_swap32((unsigned int) offset);
+  msg->offset_high = smb_swap32((unsigned int) (offset >> 32));
+  msg->data_length = smb_swap16((unsigned short) upload_size);
+  msg->data_offset = smb_swap16(sizeof(*msg) - sizeof(unsigned int));
+  msg->byte_count = smb_swap16((unsigned short) (upload_size + 1));
+
+  smb_format_message(data, &msg->h, SMB_COM_WRITE_ANDX,
+                     sizeof(*msg) - sizeof(msg->h) + (size_t) upload_size);
+
+  return smb_send(data, sizeof(*msg), (size_t) upload_size);
+}
+
+static CURLcode smb_send_and_recv(struct Curl_easy *data, void **msg)
+{
+  struct connectdata *conn = data->conn;
+  struct smb_conn *smbc = &conn->proto.smbc;
+  CURLcode result;
+  *msg = NULL; /* if it returns early */
+
+  /* Check if there is data in the transfer buffer */
+  if(!smbc->send_size && smbc->upload_size) {
+    size_t nread = smbc->upload_size > (size_t)MAX_MESSAGE_SIZE ?
+      (size_t)MAX_MESSAGE_SIZE : smbc->upload_size;
+    bool eos;
+
+    result = Curl_client_read(data, smbc->send_buf, nread, &nread, &eos);
+    if(result && result != CURLE_AGAIN)
+      return result;
+    if(!nread)
+      return CURLE_OK;
+
+    smbc->upload_size -= nread;
+    smbc->send_size = nread;
+    smbc->sent = 0;
+  }
+
+  /* Check if there is data to send */
+  if(smbc->send_size) {
+    result = smb_flush(data);
+    if(result)
+      return result;
+  }
+
+  /* Check if there is still data to be sent */
+  if(smbc->send_size || smbc->upload_size)
+    return CURLE_AGAIN;
+
+  return smb_recv_message(data, msg);
+}
+
+static CURLcode smb_connection_state(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct smb_conn *smbc = &conn->proto.smbc;
+  struct smb_negotiate_response *nrsp;
+  struct smb_header *h;
+  CURLcode result;
+  void *msg = NULL;
+
+  if(smbc->state == SMB_CONNECTING) {
+#ifdef USE_SSL
+    if((conn->handler->flags & PROTOPT_SSL)) {
+      bool ssl_done = FALSE;
+      result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssl_done);
+      if(result && result != CURLE_AGAIN)
+        return result;
+      if(!ssl_done)
+        return CURLE_OK;
+    }
+#endif
+
+    result = smb_send_negotiate(data);
+    if(result) {
+      connclose(conn, "SMB: failed to send negotiate message");
+      return result;
+    }
+
+    conn_state(data, SMB_NEGOTIATE);
+  }
+
+  /* Send the previous message and check for a response */
+  result = smb_send_and_recv(data, &msg);
+  if(result && result != CURLE_AGAIN) {
+    connclose(conn, "SMB: failed to communicate");
+    return result;
+  }
+
+  if(!msg)
+    return CURLE_OK;
+
+  h = msg;
+
+  switch(smbc->state) {
+  case SMB_NEGOTIATE:
+    if((smbc->got < sizeof(*nrsp) + sizeof(smbc->challenge) - 1) ||
+       h->status) {
+      connclose(conn, "SMB: negotiation failed");
+      return CURLE_COULDNT_CONNECT;
+    }
+    nrsp = msg;
+    memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge));
+    smbc->session_key = smb_swap32(nrsp->session_key);
+    result = smb_send_setup(data);
+    if(result) {
+      connclose(conn, "SMB: failed to send setup message");
+      return result;
+    }
+    conn_state(data, SMB_SETUP);
+    break;
+
+  case SMB_SETUP:
+    if(h->status) {
+      connclose(conn, "SMB: authentication failed");
+      return CURLE_LOGIN_DENIED;
+    }
+    smbc->uid = smb_swap16(h->uid);
+    conn_state(data, SMB_CONNECTED);
+    *done = true;
+    break;
+
+  default:
+    smb_pop_message(conn);
+    return CURLE_OK; /* ignore */
+  }
+
+  smb_pop_message(conn);
+
+  return CURLE_OK;
+}
+
+/*
+ * Convert a timestamp from the Windows world (100 nsec units from 1 Jan 1601)
+ * to Posix time. Cap the output to fit within a time_t.
+ */
+static void get_posix_time(time_t *out, curl_off_t timestamp)
+{
+  timestamp -= 116444736000000000;
+  timestamp /= 10000000;
+#if SIZEOF_TIME_T < SIZEOF_CURL_OFF_T
+  if(timestamp > TIME_T_MAX)
+    *out = TIME_T_MAX;
+  else if(timestamp < TIME_T_MIN)
+    *out = TIME_T_MIN;
+  else
+#endif
+    *out = (time_t) timestamp;
+}
+
+static CURLcode smb_request_state(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct smb_request *req = data->req.p.smb;
+  struct smb_header *h;
+  struct smb_conn *smbc = &conn->proto.smbc;
+  enum smb_req_state next_state = SMB_DONE;
+  unsigned short len;
+  unsigned short off;
+  CURLcode result;
+  void *msg = NULL;
+  const struct smb_nt_create_response *smb_m;
+
+  if(data->state.upload && (data->state.infilesize < 0)) {
+    failf(data, "SMB upload needs to know the size up front");
+    return CURLE_SEND_ERROR;
+  }
+
+  /* Start the request */
+  if(req->state == SMB_REQUESTING) {
+    result = smb_send_tree_connect(data);
+    if(result) {
+      connclose(conn, "SMB: failed to send tree connect message");
+      return result;
+    }
+
+    request_state(data, SMB_TREE_CONNECT);
+  }
+
+  /* Send the previous message and check for a response */
+  result = smb_send_and_recv(data, &msg);
+  if(result && result != CURLE_AGAIN) {
+    connclose(conn, "SMB: failed to communicate");
+    return result;
+  }
+
+  if(!msg)
+    return CURLE_OK;
+
+  h = msg;
+
+  switch(req->state) {
+  case SMB_TREE_CONNECT:
+    if(h->status) {
+      req->result = CURLE_REMOTE_FILE_NOT_FOUND;
+      if(h->status == smb_swap32(SMB_ERR_NOACCESS))
+        req->result = CURLE_REMOTE_ACCESS_DENIED;
+      break;
+    }
+    req->tid = smb_swap16(h->tid);
+    next_state = SMB_OPEN;
+    break;
+
+  case SMB_OPEN:
+    if(h->status || smbc->got < sizeof(struct smb_nt_create_response)) {
+      req->result = CURLE_REMOTE_FILE_NOT_FOUND;
+      if(h->status == smb_swap32(SMB_ERR_NOACCESS))
+        req->result = CURLE_REMOTE_ACCESS_DENIED;
+      next_state = SMB_TREE_DISCONNECT;
+      break;
+    }
+    smb_m = (const struct smb_nt_create_response*) msg;
+    req->fid = smb_swap16(smb_m->fid);
+    data->req.offset = 0;
+    if(data->state.upload) {
+      data->req.size = data->state.infilesize;
+      Curl_pgrsSetUploadSize(data, data->req.size);
+      next_state = SMB_UPLOAD;
+    }
+    else {
+      data->req.size = smb_swap64(smb_m->end_of_file);
+      if(data->req.size < 0) {
+        req->result = CURLE_WEIRD_SERVER_REPLY;
+        next_state = SMB_CLOSE;
+      }
+      else {
+        Curl_pgrsSetDownloadSize(data, data->req.size);
+        if(data->set.get_filetime)
+          get_posix_time(&data->info.filetime, smb_m->last_change_time);
+        next_state = SMB_DOWNLOAD;
+      }
+    }
+    break;
+
+  case SMB_DOWNLOAD:
+    if(h->status || smbc->got < sizeof(struct smb_header) + 14) {
+      req->result = CURLE_RECV_ERROR;
+      next_state = SMB_CLOSE;
+      break;
+    }
+    len = Curl_read16_le(((const unsigned char *) msg) +
+                         sizeof(struct smb_header) + 11);
+    off = Curl_read16_le(((const unsigned char *) msg) +
+                         sizeof(struct smb_header) + 13);
+    if(len > 0) {
+      if(off + sizeof(unsigned int) + len > smbc->got) {
+        failf(data, "Invalid input packet");
+        result = CURLE_RECV_ERROR;
+      }
+      else
+        result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                   (char *)msg + off + sizeof(unsigned int),
+                                   len);
+      if(result) {
+        req->result = result;
+        next_state = SMB_CLOSE;
+        break;
+      }
+    }
+    data->req.offset += len;
+    next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD;
+    break;
+
+  case SMB_UPLOAD:
+    if(h->status || smbc->got < sizeof(struct smb_header) + 6) {
+      req->result = CURLE_UPLOAD_FAILED;
+      next_state = SMB_CLOSE;
+      break;
+    }
+    len = Curl_read16_le(((const unsigned char *) msg) +
+                         sizeof(struct smb_header) + 5);
+    data->req.bytecount += len;
+    data->req.offset += len;
+    Curl_pgrsSetUploadCounter(data, data->req.bytecount);
+    if(data->req.bytecount >= data->req.size)
+      next_state = SMB_CLOSE;
+    else
+      next_state = SMB_UPLOAD;
+    break;
+
+  case SMB_CLOSE:
+    /* We don't care if the close failed, proceed to tree disconnect anyway */
+    next_state = SMB_TREE_DISCONNECT;
+    break;
+
+  case SMB_TREE_DISCONNECT:
+    next_state = SMB_DONE;
+    break;
+
+  default:
+    smb_pop_message(conn);
+    return CURLE_OK; /* ignore */
+  }
+
+  smb_pop_message(conn);
+
+  switch(next_state) {
+  case SMB_OPEN:
+    result = smb_send_open(data);
+    break;
+
+  case SMB_DOWNLOAD:
+    result = smb_send_read(data);
+    break;
+
+  case SMB_UPLOAD:
+    result = smb_send_write(data);
+    break;
+
+  case SMB_CLOSE:
+    result = smb_send_close(data);
+    break;
+
+  case SMB_TREE_DISCONNECT:
+    result = smb_send_tree_disconnect(data);
+    break;
+
+  case SMB_DONE:
+    result = req->result;
+    *done = true;
+    break;
+
+  default:
+    break;
+  }
+
+  if(result) {
+    connclose(conn, "SMB: failed to send message");
+    return result;
+  }
+
+  request_state(data, next_state);
+
+  return CURLE_OK;
+}
+
+static CURLcode smb_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn, bool dead)
+{
+  struct smb_conn *smbc = &conn->proto.smbc;
+  (void) dead;
+  (void) data;
+  Curl_safefree(smbc->share);
+  Curl_safefree(smbc->domain);
+  Curl_safefree(smbc->recv_buf);
+  Curl_safefree(smbc->send_buf);
+  return CURLE_OK;
+}
+
+static int smb_getsock(struct Curl_easy *data,
+                       struct connectdata *conn, curl_socket_t *socks)
+{
+  (void)data;
+  socks[0] = conn->sock[FIRSTSOCKET];
+  return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0);
+}
+
+static CURLcode smb_do(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct smb_conn *smbc = &conn->proto.smbc;
+
+  *done = FALSE;
+  if(smbc->share) {
+    return CURLE_OK;
+  }
+  return CURLE_URL_MALFORMAT;
+}
+
+static CURLcode smb_parse_url_path(struct Curl_easy *data,
+                                   struct connectdata *conn)
+{
+  struct smb_request *req = data->req.p.smb;
+  struct smb_conn *smbc = &conn->proto.smbc;
+  char *path;
+  char *slash;
+
+  /* URL decode the path */
+  CURLcode result = Curl_urldecode(data->state.up.path, 0, &path, NULL,
+                                   REJECT_CTRL);
+  if(result)
+    return result;
+
+  /* Parse the path for the share */
+  smbc->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path);
+  free(path);
+  if(!smbc->share)
+    return CURLE_OUT_OF_MEMORY;
+
+  slash = strchr(smbc->share, '/');
+  if(!slash)
+    slash = strchr(smbc->share, '\\');
+
+  /* The share must be present */
+  if(!slash) {
+    Curl_safefree(smbc->share);
+    failf(data, "missing share in URL path for SMB");
+    return CURLE_URL_MALFORMAT;
+  }
+
+  /* Parse the path for the file path converting any forward slashes into
+     backslashes */
+  *slash++ = 0;
+  req->path = slash;
+
+  for(; *slash; slash++) {
+    if(*slash == '/')
+      *slash = '\\';
+  }
+  return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE &&
+          SIZEOF_CURL_OFF_T > 4 */
Index: trunk/src/libs/curl-8.7.1/lib/smb.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/smb.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/smb.h	(revision 104083)
@@ -0,0 +1,61 @@
+#ifndef HEADER_CURL_SMB_H
+#define HEADER_CURL_SMB_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Bill Nagel <wnagel@tycoint.com>, Exacq Technologies
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+enum smb_conn_state {
+  SMB_NOT_CONNECTED = 0,
+  SMB_CONNECTING,
+  SMB_NEGOTIATE,
+  SMB_SETUP,
+  SMB_CONNECTED
+};
+
+struct smb_conn {
+  enum smb_conn_state state;
+  char *user;
+  char *domain;
+  char *share;
+  unsigned char challenge[8];
+  unsigned int session_key;
+  unsigned short uid;
+  char *recv_buf;
+  char *send_buf;
+  size_t upload_size;
+  size_t send_size;
+  size_t sent;
+  size_t got;
+};
+
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
+    (SIZEOF_CURL_OFF_T > 4)
+
+extern const struct Curl_handler Curl_handler_smb;
+extern const struct Curl_handler Curl_handler_smbs;
+
+#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE &&
+          SIZEOF_CURL_OFF_T > 4 */
+
+#endif /* HEADER_CURL_SMB_H */
Index: trunk/src/libs/curl-8.7.1/lib/smtp.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/smtp.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/smtp.c	(revision 104083)
@@ -0,0 +1,1945 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC1870 SMTP Service Extension for Message Size
+ * RFC2195 CRAM-MD5 authentication
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC3207 SMTP over TLS
+ * RFC4422 Simple Authentication and Security Layer (SASL)
+ * RFC4616 PLAIN authentication
+ * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
+ * RFC4954 SMTP Authentication
+ * RFC5321 SMTP protocol
+ * RFC5890 Internationalized Domain Names for Applications (IDNA)
+ * RFC6531 SMTP Extension for Internationalized Email
+ * RFC6532 Internationalized Email Headers
+ * RFC6749 OAuth 2.0 Authorization Framework
+ * RFC8314 Use of TLS for Email Submission and Access
+ * Draft   SMTP URL Interface   <draft-earhart-url-smtp-00.txt>
+ * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_SMTP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "mime.h"
+#include "socks.h"
+#include "smtp.h"
+#include "strtoofft.h"
+#include "strcase.h"
+#include "vtls/vtls.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "select.h"
+#include "multiif.h"
+#include "url.h"
+#include "curl_gethostname.h"
+#include "bufref.h"
+#include "curl_sasl.h"
+#include "warnless.h"
+#include "idn.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Local API functions */
+static CURLcode smtp_regular_transfer(struct Curl_easy *data, bool *done);
+static CURLcode smtp_do(struct Curl_easy *data, bool *done);
+static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
+                          bool premature);
+static CURLcode smtp_connect(struct Curl_easy *data, bool *done);
+static CURLcode smtp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
+static CURLcode smtp_multi_statemach(struct Curl_easy *data, bool *done);
+static int smtp_getsock(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks);
+static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done);
+static CURLcode smtp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static CURLcode smtp_parse_url_options(struct connectdata *conn);
+static CURLcode smtp_parse_url_path(struct Curl_easy *data);
+static CURLcode smtp_parse_custom_request(struct Curl_easy *data);
+static CURLcode smtp_parse_address(const char *fqma,
+                                   char **address, struct hostname *host);
+static CURLcode smtp_perform_auth(struct Curl_easy *data, const char *mech,
+                                  const struct bufref *initresp);
+static CURLcode smtp_continue_auth(struct Curl_easy *data, const char *mech,
+                                   const struct bufref *resp);
+static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech);
+static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out);
+static CURLcode cr_eob_add(struct Curl_easy *data);
+
+/*
+ * SMTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_smtp = {
+  "SMTP",                           /* scheme */
+  smtp_setup_connection,            /* setup_connection */
+  smtp_do,                          /* do_it */
+  smtp_done,                        /* done */
+  ZERO_NULL,                        /* do_more */
+  smtp_connect,                     /* connect_it */
+  smtp_multi_statemach,             /* connecting */
+  smtp_doing,                       /* doing */
+  smtp_getsock,                     /* proto_getsock */
+  smtp_getsock,                     /* doing_getsock */
+  ZERO_NULL,                        /* domore_getsock */
+  ZERO_NULL,                        /* perform_getsock */
+  smtp_disconnect,                  /* disconnect */
+  ZERO_NULL,                        /* write_resp */
+  ZERO_NULL,                        /* connection_check */
+  ZERO_NULL,                        /* attach connection */
+  PORT_SMTP,                        /* defport */
+  CURLPROTO_SMTP,                   /* protocol */
+  CURLPROTO_SMTP,                   /* family */
+  PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
+  PROTOPT_URLOPTIONS
+};
+
+#ifdef USE_SSL
+/*
+ * SMTPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_smtps = {
+  "SMTPS",                          /* scheme */
+  smtp_setup_connection,            /* setup_connection */
+  smtp_do,                          /* do_it */
+  smtp_done,                        /* done */
+  ZERO_NULL,                        /* do_more */
+  smtp_connect,                     /* connect_it */
+  smtp_multi_statemach,             /* connecting */
+  smtp_doing,                       /* doing */
+  smtp_getsock,                     /* proto_getsock */
+  smtp_getsock,                     /* doing_getsock */
+  ZERO_NULL,                        /* domore_getsock */
+  ZERO_NULL,                        /* perform_getsock */
+  smtp_disconnect,                  /* disconnect */
+  ZERO_NULL,                        /* write_resp */
+  ZERO_NULL,                        /* connection_check */
+  ZERO_NULL,                        /* attach connection */
+  PORT_SMTPS,                       /* defport */
+  CURLPROTO_SMTPS,                  /* protocol */
+  CURLPROTO_SMTP,                   /* family */
+  PROTOPT_CLOSEACTION | PROTOPT_SSL
+  | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
+};
+#endif
+
+/* SASL parameters for the smtp protocol */
+static const struct SASLproto saslsmtp = {
+  "smtp",               /* The service name */
+  smtp_perform_auth,    /* Send authentication command */
+  smtp_continue_auth,   /* Send authentication continuation */
+  smtp_cancel_auth,     /* Cancel authentication */
+  smtp_get_message,     /* Get SASL response message */
+  512 - 8,              /* Max line len - strlen("AUTH ") - 1 space - crlf */
+  334,                  /* Code received when continuation is expected */
+  235,                  /* Code to receive upon authentication success */
+  SASL_AUTH_DEFAULT,    /* Default mechanisms */
+  SASL_FLAG_BASE64      /* Configuration flags */
+};
+
+#ifdef USE_SSL
+static void smtp_to_smtps(struct connectdata *conn)
+{
+  /* Change the connection handler */
+  conn->handler = &Curl_handler_smtps;
+
+  /* Set the connection's upgraded to TLS flag */
+  conn->bits.tls_upgraded = TRUE;
+}
+#else
+#define smtp_to_smtps(x) Curl_nop_stmt
+#endif
+
+/***********************************************************************
+ *
+ * smtp_endofresp()
+ *
+ * Checks for an ending SMTP status code at the start of the given string, but
+ * also detects various capabilities from the EHLO response including the
+ * supported authentication mechanisms.
+ */
+static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
+                           char *line, size_t len, int *resp)
+{
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  bool result = FALSE;
+  (void)data;
+
+  /* Nothing for us */
+  if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
+    return FALSE;
+
+  /* Do we have a command response? This should be the response code followed
+     by a space and optionally some text as per RFC-5321 and as outlined in
+     Section 4. Examples of RFC-4954 but some email servers ignore this and
+     only send the response code instead as per Section 4.2. */
+  if(line[3] == ' ' || len == 5) {
+    char tmpline[6];
+
+    result = TRUE;
+    memset(tmpline, '\0', sizeof(tmpline));
+    memcpy(tmpline, line, (len == 5 ? 5 : 3));
+    *resp = curlx_sltosi(strtol(tmpline, NULL, 10));
+
+    /* Make sure real server never sends internal value */
+    if(*resp == 1)
+      *resp = 0;
+  }
+  /* Do we have a multiline (continuation) response? */
+  else if(line[3] == '-' &&
+          (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) {
+    result = TRUE;
+    *resp = 1;  /* Internal response code */
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_get_message()
+ *
+ * Gets the authentication message from the response buffer.
+ */
+static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out)
+{
+  char *message = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf);
+  size_t len = data->conn->proto.smtpc.pp.nfinal;
+
+  if(len > 4) {
+    /* Find the start of the message */
+    len -= 4;
+    for(message += 4; *message == ' ' || *message == '\t'; message++, len--)
+      ;
+
+    /* Find the end of the message */
+    while(len--)
+      if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
+         message[len] != '\t')
+        break;
+
+    /* Terminate the message */
+    message[++len] = '\0';
+    Curl_bufref_set(out, message, len, NULL);
+  }
+  else
+    /* junk input => zero length output */
+    Curl_bufref_set(out, "", 0, NULL);
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * smtp_state()
+ *
+ * This is the ONLY way to change SMTP state!
+ */
+static void smtp_state(struct Curl_easy *data, smtpstate newstate)
+{
+  struct smtp_conn *smtpc = &data->conn->proto.smtpc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[] = {
+    "STOP",
+    "SERVERGREET",
+    "EHLO",
+    "HELO",
+    "STARTTLS",
+    "UPGRADETLS",
+    "AUTH",
+    "COMMAND",
+    "MAIL",
+    "RCPT",
+    "DATA",
+    "POSTDATA",
+    "QUIT",
+    /* LAST */
+  };
+
+  if(smtpc->state != newstate)
+    infof(data, "SMTP %p state change from %s to %s",
+          (void *)smtpc, names[smtpc->state], names[newstate]);
+#endif
+
+  smtpc->state = newstate;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_ehlo()
+ *
+ * Sends the EHLO command to not only initialise communication with the ESMTP
+ * server but to also obtain a list of server side supported capabilities.
+ */
+static CURLcode smtp_perform_ehlo(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+  smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */
+  smtpc->sasl.authused = SASL_AUTH_NONE;  /* Clear the authentication mechanism
+                                             used for esmtp connections */
+  smtpc->tls_supported = FALSE;           /* Clear the TLS capability */
+  smtpc->auth_supported = FALSE;          /* Clear the AUTH capability */
+
+  /* Send the EHLO command */
+  result = Curl_pp_sendf(data, &smtpc->pp, "EHLO %s", smtpc->domain);
+
+  if(!result)
+    smtp_state(data, SMTP_EHLO);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_helo()
+ *
+ * Sends the HELO command to initialise communication with the SMTP server.
+ */
+static CURLcode smtp_perform_helo(struct Curl_easy *data,
+                                  struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+  smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used
+                                            in smtp connections */
+
+  /* Send the HELO command */
+  result = Curl_pp_sendf(data, &smtpc->pp, "HELO %s", smtpc->domain);
+
+  if(!result)
+    smtp_state(data, SMTP_HELO);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_starttls()
+ *
+ * Sends the STLS command to start the upgrade to TLS.
+ */
+static CURLcode smtp_perform_starttls(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  /* Send the STARTTLS command */
+  CURLcode result = Curl_pp_sendf(data, &conn->proto.smtpc.pp,
+                                  "%s", "STARTTLS");
+
+  if(!result)
+    smtp_state(data, SMTP_STARTTLS);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_upgrade_tls()
+ *
+ * Performs the upgrade to TLS.
+ */
+static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data)
+{
+  /* Start the SSL connection */
+  struct connectdata *conn = data->conn;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  CURLcode result;
+  bool ssldone = FALSE;
+
+  if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
+    result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
+    if(result)
+      goto out;
+  }
+
+  result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
+  if(!result) {
+    smtpc->ssldone = ssldone;
+    if(smtpc->state != SMTP_UPGRADETLS)
+      smtp_state(data, SMTP_UPGRADETLS);
+
+    if(smtpc->ssldone) {
+      smtp_to_smtps(conn);
+      result = smtp_perform_ehlo(data);
+    }
+  }
+out:
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_auth()
+ *
+ * Sends an AUTH command allowing the client to login with the given SASL
+ * authentication mechanism.
+ */
+static CURLcode smtp_perform_auth(struct Curl_easy *data,
+                                  const char *mech,
+                                  const struct bufref *initresp)
+{
+  CURLcode result = CURLE_OK;
+  struct smtp_conn *smtpc = &data->conn->proto.smtpc;
+  const char *ir = (const char *) Curl_bufref_ptr(initresp);
+
+  if(ir) {                                  /* AUTH <mech> ...<crlf> */
+    /* Send the AUTH command with the initial response */
+    result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s %s", mech, ir);
+  }
+  else {
+    /* Send the AUTH command */
+    result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s", mech);
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_continue_auth()
+ *
+ * Sends SASL continuation data.
+ */
+static CURLcode smtp_continue_auth(struct Curl_easy *data,
+                                   const char *mech,
+                                   const struct bufref *resp)
+{
+  struct smtp_conn *smtpc = &data->conn->proto.smtpc;
+
+  (void)mech;
+
+  return Curl_pp_sendf(data, &smtpc->pp,
+                       "%s", (const char *) Curl_bufref_ptr(resp));
+}
+
+/***********************************************************************
+ *
+ * smtp_cancel_auth()
+ *
+ * Sends SASL cancellation.
+ */
+static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech)
+{
+  struct smtp_conn *smtpc = &data->conn->proto.smtpc;
+
+  (void)mech;
+
+  return Curl_pp_sendf(data, &smtpc->pp, "*");
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_authentication()
+ *
+ * Initiates the authentication sequence, with the appropriate SASL
+ * authentication mechanism.
+ */
+static CURLcode smtp_perform_authentication(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  saslprogress progress;
+
+  /* Check we have enough data to authenticate with, and the
+     server supports authentication, and end the connect phase if not */
+  if(!smtpc->auth_supported ||
+     !Curl_sasl_can_authenticate(&smtpc->sasl, data)) {
+    smtp_state(data, SMTP_STOP);
+    return result;
+  }
+
+  /* Calculate the SASL login details */
+  result = Curl_sasl_start(&smtpc->sasl, data, FALSE, &progress);
+
+  if(!result) {
+    if(progress == SASL_INPROGRESS)
+      smtp_state(data, SMTP_AUTH);
+    else {
+      /* Other mechanisms not supported */
+      infof(data, "No known authentication mechanisms supported");
+      result = CURLE_LOGIN_DENIED;
+    }
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_command()
+ *
+ * Sends a SMTP based command.
+ */
+static CURLcode smtp_perform_command(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct SMTP *smtp = data->req.p.smtp;
+
+  if(smtp->rcpt) {
+    /* We notify the server we are sending UTF-8 data if a) it supports the
+       SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
+       either the local address or host name parts. This is regardless of
+       whether the host name is encoded using IDN ACE */
+    bool utf8 = FALSE;
+
+    if((!smtp->custom) || (!smtp->custom[0])) {
+      char *address = NULL;
+      struct hostname host = { NULL, NULL, NULL, NULL };
+
+      /* Parse the mailbox to verify into the local address and host name
+         parts, converting the host name to an IDN A-label if necessary */
+      result = smtp_parse_address(smtp->rcpt->data,
+                                  &address, &host);
+      if(result)
+        return result;
+
+      /* Establish whether we should report SMTPUTF8 to the server for this
+         mailbox as per RFC-6531 sect. 3.1 point 6 */
+      utf8 = (conn->proto.smtpc.utf8_supported) &&
+             ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
+              (!Curl_is_ASCII_name(host.name)));
+
+      /* Send the VRFY command (Note: The host name part may be absent when the
+         host is a local system) */
+      result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "VRFY %s%s%s%s",
+                             address,
+                             host.name ? "@" : "",
+                             host.name ? host.name : "",
+                             utf8 ? " SMTPUTF8" : "");
+
+      Curl_free_idnconverted_hostname(&host);
+      free(address);
+    }
+    else {
+      /* Establish whether we should report that we support SMTPUTF8 for EXPN
+         commands to the server as per RFC-6531 sect. 3.1 point 6 */
+      utf8 = (conn->proto.smtpc.utf8_supported) &&
+             (!strcmp(smtp->custom, "EXPN"));
+
+      /* Send the custom recipient based command such as the EXPN command */
+      result = Curl_pp_sendf(data, &conn->proto.smtpc.pp,
+                             "%s %s%s", smtp->custom,
+                             smtp->rcpt->data,
+                             utf8 ? " SMTPUTF8" : "");
+    }
+  }
+  else
+    /* Send the non-recipient based command such as HELP */
+    result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s",
+                           smtp->custom && smtp->custom[0] != '\0' ?
+                           smtp->custom : "HELP");
+
+  if(!result)
+    smtp_state(data, SMTP_COMMAND);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_mail()
+ *
+ * Sends an MAIL command to initiate the upload of a message.
+ */
+static CURLcode smtp_perform_mail(struct Curl_easy *data)
+{
+  char *from = NULL;
+  char *auth = NULL;
+  char *size = NULL;
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+
+  /* We notify the server we are sending UTF-8 data if a) it supports the
+     SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
+     either the local address or host name parts. This is regardless of
+     whether the host name is encoded using IDN ACE */
+  bool utf8 = FALSE;
+
+  /* Calculate the FROM parameter */
+  if(data->set.str[STRING_MAIL_FROM]) {
+    char *address = NULL;
+    struct hostname host = { NULL, NULL, NULL, NULL };
+
+    /* Parse the FROM mailbox into the local address and host name parts,
+       converting the host name to an IDN A-label if necessary */
+    result = smtp_parse_address(data->set.str[STRING_MAIL_FROM],
+                                &address, &host);
+    if(result)
+      goto out;
+
+    /* Establish whether we should report SMTPUTF8 to the server for this
+       mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
+    utf8 = (conn->proto.smtpc.utf8_supported) &&
+           ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
+            (!Curl_is_ASCII_name(host.name)));
+
+    if(host.name) {
+      from = aprintf("<%s@%s>", address, host.name);
+
+      Curl_free_idnconverted_hostname(&host);
+    }
+    else
+      /* An invalid mailbox was provided but we'll simply let the server worry
+         about that and reply with a 501 error */
+      from = aprintf("<%s>", address);
+
+    free(address);
+  }
+  else
+    /* Null reverse-path, RFC-5321, sect. 3.6.3 */
+    from = strdup("<>");
+
+  if(!from) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+
+  /* Calculate the optional AUTH parameter */
+  if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
+    if(data->set.str[STRING_MAIL_AUTH][0] != '\0') {
+      char *address = NULL;
+      struct hostname host = { NULL, NULL, NULL, NULL };
+
+      /* Parse the AUTH mailbox into the local address and host name parts,
+         converting the host name to an IDN A-label if necessary */
+      result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH],
+                                  &address, &host);
+      if(result)
+        goto out;
+
+      /* Establish whether we should report SMTPUTF8 to the server for this
+         mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
+      if((!utf8) && (conn->proto.smtpc.utf8_supported) &&
+         ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
+          (!Curl_is_ASCII_name(host.name))))
+        utf8 = TRUE;
+
+      if(host.name) {
+        auth = aprintf("<%s@%s>", address, host.name);
+
+        Curl_free_idnconverted_hostname(&host);
+      }
+      else
+        /* An invalid mailbox was provided but we'll simply let the server
+           worry about it */
+        auth = aprintf("<%s>", address);
+      free(address);
+    }
+    else
+      /* Empty AUTH, RFC-2554, sect. 5 */
+      auth = strdup("<>");
+
+    if(!auth) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
+  }
+
+#ifndef CURL_DISABLE_MIME
+  /* Prepare the mime data if some. */
+  if(data->set.mimepost.kind != MIMEKIND_NONE) {
+    /* Use the whole structure as data. */
+    data->set.mimepost.flags &= ~MIME_BODY_ONLY;
+
+    /* Add external headers and mime version. */
+    curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
+    result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL,
+                                       NULL, MIMESTRATEGY_MAIL);
+
+    if(!result)
+      if(!Curl_checkheaders(data, STRCONST("Mime-Version")))
+        result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
+                                      "Mime-Version: 1.0");
+
+    if(!result)
+      result = Curl_creader_set_mime(data, &data->set.mimepost);
+    if(result)
+      goto out;
+    data->state.infilesize = Curl_creader_total_length(data);
+  }
+  else
+#endif
+  {
+    result = Curl_creader_set_fread(data, data->state.infilesize);
+    if(result)
+      goto out;
+  }
+
+  /* Calculate the optional SIZE parameter */
+  if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) {
+    size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
+
+    if(!size) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
+  }
+
+  /* If the mailboxes in the FROM and AUTH parameters don't include a UTF-8
+     based address then quickly scan through the recipient list and check if
+     any there do, as we need to correctly identify our support for SMTPUTF8
+     in the envelope, as per RFC-6531 sect. 3.4 */
+  if(conn->proto.smtpc.utf8_supported && !utf8) {
+    struct SMTP *smtp = data->req.p.smtp;
+    struct curl_slist *rcpt = smtp->rcpt;
+
+    while(rcpt && !utf8) {
+      /* Does the host name contain non-ASCII characters? */
+      if(!Curl_is_ASCII_name(rcpt->data))
+        utf8 = TRUE;
+
+      rcpt = rcpt->next;
+    }
+  }
+
+  /* Add the client reader doing STMP EOB escaping */
+  result = cr_eob_add(data);
+  if(result)
+    goto out;
+
+  /* Send the MAIL command */
+  result = Curl_pp_sendf(data, &conn->proto.smtpc.pp,
+                         "MAIL FROM:%s%s%s%s%s%s",
+                         from,                 /* Mandatory                 */
+                         auth ? " AUTH=" : "", /* Optional on AUTH support  */
+                         auth ? auth : "",     /*                           */
+                         size ? " SIZE=" : "", /* Optional on SIZE support  */
+                         size ? size : "",     /*                           */
+                         utf8 ? " SMTPUTF8"    /* Internationalised mailbox */
+                               : "");          /* included in our envelope  */
+
+out:
+  free(from);
+  free(auth);
+  free(size);
+
+  if(!result)
+    smtp_state(data, SMTP_MAIL);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_rcpt_to()
+ *
+ * Sends a RCPT TO command for a given recipient as part of the message upload
+ * process.
+ */
+static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct SMTP *smtp = data->req.p.smtp;
+  char *address = NULL;
+  struct hostname host = { NULL, NULL, NULL, NULL };
+
+  /* Parse the recipient mailbox into the local address and host name parts,
+     converting the host name to an IDN A-label if necessary */
+  result = smtp_parse_address(smtp->rcpt->data,
+                              &address, &host);
+  if(result)
+    return result;
+
+  /* Send the RCPT TO command */
+  if(host.name)
+    result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s@%s>",
+                           address, host.name);
+  else
+    /* An invalid mailbox was provided but we'll simply let the server worry
+       about that and reply with a 501 error */
+    result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s>",
+                           address);
+
+  Curl_free_idnconverted_hostname(&host);
+  free(address);
+
+  if(!result)
+    smtp_state(data, SMTP_RCPT);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_quit()
+ *
+ * Performs the quit action prior to sclose() being called.
+ */
+static CURLcode smtp_perform_quit(struct Curl_easy *data,
+                                  struct connectdata *conn)
+{
+  /* Send the QUIT command */
+  CURLcode result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s", "QUIT");
+
+  if(!result)
+    smtp_state(data, SMTP_QUIT);
+
+  return result;
+}
+
+/* For the initial server greeting */
+static CURLcode smtp_state_servergreet_resp(struct Curl_easy *data,
+                                            int smtpcode,
+                                            smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode/100 != 2) {
+    failf(data, "Got unexpected smtp-server response: %d", smtpcode);
+    result = CURLE_WEIRD_SERVER_REPLY;
+  }
+  else
+    result = smtp_perform_ehlo(data);
+
+  return result;
+}
+
+/* For STARTTLS responses */
+static CURLcode smtp_state_starttls_resp(struct Curl_easy *data,
+                                         int smtpcode,
+                                         smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  (void)instate; /* no use for this yet */
+
+  /* Pipelining in response is forbidden. */
+  if(data->conn->proto.smtpc.pp.overflow)
+    return CURLE_WEIRD_SERVER_REPLY;
+
+  if(smtpcode != 220) {
+    if(data->set.use_ssl != CURLUSESSL_TRY) {
+      failf(data, "STARTTLS denied, code %d", smtpcode);
+      result = CURLE_USE_SSL_FAILED;
+    }
+    else
+      result = smtp_perform_authentication(data);
+  }
+  else
+    result = smtp_perform_upgrade_tls(data);
+
+  return result;
+}
+
+/* For EHLO responses */
+static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data,
+                                     struct connectdata *conn, int smtpcode,
+                                     smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  const char *line = Curl_dyn_ptr(&smtpc->pp.recvbuf);
+  size_t len = smtpc->pp.nfinal;
+
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode/100 != 2 && smtpcode != 1) {
+    if(data->set.use_ssl <= CURLUSESSL_TRY
+       || Curl_conn_is_ssl(conn, FIRSTSOCKET))
+      result = smtp_perform_helo(data, conn);
+    else {
+      failf(data, "Remote access denied: %d", smtpcode);
+      result = CURLE_REMOTE_ACCESS_DENIED;
+    }
+  }
+  else if(len >= 4) {
+    line += 4;
+    len -= 4;
+
+    /* Does the server support the STARTTLS capability? */
+    if(len >= 8 && !memcmp(line, "STARTTLS", 8))
+      smtpc->tls_supported = TRUE;
+
+    /* Does the server support the SIZE capability? */
+    else if(len >= 4 && !memcmp(line, "SIZE", 4))
+      smtpc->size_supported = TRUE;
+
+    /* Does the server support the UTF-8 capability? */
+    else if(len >= 8 && !memcmp(line, "SMTPUTF8", 8))
+      smtpc->utf8_supported = TRUE;
+
+    /* Does the server support authentication? */
+    else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
+      smtpc->auth_supported = TRUE;
+
+      /* Advance past the AUTH keyword */
+      line += 5;
+      len -= 5;
+
+      /* Loop through the data line */
+      for(;;) {
+        size_t llen;
+        size_t wordlen;
+        unsigned short mechbit;
+
+        while(len &&
+              (*line == ' ' || *line == '\t' ||
+               *line == '\r' || *line == '\n')) {
+
+          line++;
+          len--;
+        }
+
+        if(!len)
+          break;
+
+        /* Extract the word */
+        for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
+              line[wordlen] != '\t' && line[wordlen] != '\r' &&
+              line[wordlen] != '\n';)
+          wordlen++;
+
+        /* Test the word for a matching authentication mechanism */
+        mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
+        if(mechbit && llen == wordlen)
+          smtpc->sasl.authmechs |= mechbit;
+
+        line += wordlen;
+        len -= wordlen;
+      }
+    }
+
+    if(smtpcode != 1) {
+      if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
+        /* We don't have a SSL/TLS connection yet, but SSL is requested */
+        if(smtpc->tls_supported)
+          /* Switch to TLS connection now */
+          result = smtp_perform_starttls(data, conn);
+        else if(data->set.use_ssl == CURLUSESSL_TRY)
+          /* Fallback and carry on with authentication */
+          result = smtp_perform_authentication(data);
+        else {
+          failf(data, "STARTTLS not supported.");
+          result = CURLE_USE_SSL_FAILED;
+        }
+      }
+      else
+        result = smtp_perform_authentication(data);
+    }
+  }
+  else {
+    failf(data, "Unexpectedly short EHLO response");
+    result = CURLE_WEIRD_SERVER_REPLY;
+  }
+
+  return result;
+}
+
+/* For HELO responses */
+static CURLcode smtp_state_helo_resp(struct Curl_easy *data, int smtpcode,
+                                     smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode/100 != 2) {
+    failf(data, "Remote access denied: %d", smtpcode);
+    result = CURLE_REMOTE_ACCESS_DENIED;
+  }
+  else
+    /* End of connect phase */
+    smtp_state(data, SMTP_STOP);
+
+  return result;
+}
+
+/* For SASL authentication responses */
+static CURLcode smtp_state_auth_resp(struct Curl_easy *data,
+                                     int smtpcode,
+                                     smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  saslprogress progress;
+
+  (void)instate; /* no use for this yet */
+
+  result = Curl_sasl_continue(&smtpc->sasl, data, smtpcode, &progress);
+  if(!result)
+    switch(progress) {
+    case SASL_DONE:
+      smtp_state(data, SMTP_STOP);  /* Authenticated */
+      break;
+    case SASL_IDLE:            /* No mechanism left after cancellation */
+      failf(data, "Authentication cancelled");
+      result = CURLE_LOGIN_DENIED;
+      break;
+    default:
+      break;
+    }
+
+  return result;
+}
+
+/* For command responses */
+static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode,
+                                        smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SMTP *smtp = data->req.p.smtp;
+  char *line = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf);
+  size_t len = data->conn->proto.smtpc.pp.nfinal;
+
+  (void)instate; /* no use for this yet */
+
+  if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) ||
+     (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) {
+    failf(data, "Command failed: %d", smtpcode);
+    result = CURLE_WEIRD_SERVER_REPLY;
+  }
+  else {
+    if(!data->req.no_body)
+      result = Curl_client_write(data, CLIENTWRITE_BODY, line, len);
+
+    if(smtpcode != 1) {
+      if(smtp->rcpt) {
+        smtp->rcpt = smtp->rcpt->next;
+
+        if(smtp->rcpt) {
+          /* Send the next command */
+          result = smtp_perform_command(data);
+        }
+        else
+          /* End of DO phase */
+          smtp_state(data, SMTP_STOP);
+      }
+      else
+        /* End of DO phase */
+        smtp_state(data, SMTP_STOP);
+    }
+  }
+
+  return result;
+}
+
+/* For MAIL responses */
+static CURLcode smtp_state_mail_resp(struct Curl_easy *data, int smtpcode,
+                                     smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode/100 != 2) {
+    failf(data, "MAIL failed: %d", smtpcode);
+    result = CURLE_SEND_ERROR;
+  }
+  else
+    /* Start the RCPT TO command */
+    result = smtp_perform_rcpt_to(data);
+
+  return result;
+}
+
+/* For RCPT responses */
+static CURLcode smtp_state_rcpt_resp(struct Curl_easy *data,
+                                     struct connectdata *conn, int smtpcode,
+                                     smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SMTP *smtp = data->req.p.smtp;
+  bool is_smtp_err = FALSE;
+  bool is_smtp_blocking_err = FALSE;
+
+  (void)instate; /* no use for this yet */
+
+  is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE;
+
+  /* If there's multiple RCPT TO to be issued, it's possible to ignore errors
+     and proceed with only the valid addresses. */
+  is_smtp_blocking_err =
+    (is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE;
+
+  if(is_smtp_err) {
+    /* Remembering the last failure which we can report if all "RCPT TO" have
+       failed and we cannot proceed. */
+    smtp->rcpt_last_error = smtpcode;
+
+    if(is_smtp_blocking_err) {
+      failf(data, "RCPT failed: %d", smtpcode);
+      result = CURLE_SEND_ERROR;
+    }
+  }
+  else {
+    /* Some RCPT TO commands have succeeded. */
+    smtp->rcpt_had_ok = TRUE;
+  }
+
+  if(!is_smtp_blocking_err) {
+    smtp->rcpt = smtp->rcpt->next;
+
+    if(smtp->rcpt)
+      /* Send the next RCPT TO command */
+      result = smtp_perform_rcpt_to(data);
+    else {
+      /* We weren't able to issue a successful RCPT TO command while going
+         over recipients (potentially multiple). Sending back last error. */
+      if(!smtp->rcpt_had_ok) {
+        failf(data, "RCPT failed: %d (last error)", smtp->rcpt_last_error);
+        result = CURLE_SEND_ERROR;
+      }
+      else {
+        /* Send the DATA command */
+        result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s", "DATA");
+
+        if(!result)
+          smtp_state(data, SMTP_DATA);
+      }
+    }
+  }
+
+  return result;
+}
+
+/* For DATA response */
+static CURLcode smtp_state_data_resp(struct Curl_easy *data, int smtpcode,
+                                     smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode != 354) {
+    failf(data, "DATA failed: %d", smtpcode);
+    result = CURLE_SEND_ERROR;
+  }
+  else {
+    /* Set the progress upload size */
+    Curl_pgrsSetUploadSize(data, data->state.infilesize);
+
+    /* SMTP upload */
+    Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
+
+    /* End of DO phase */
+    smtp_state(data, SMTP_STOP);
+  }
+
+  return result;
+}
+
+/* For POSTDATA responses, which are received after the entire DATA
+   part has been sent to the server */
+static CURLcode smtp_state_postdata_resp(struct Curl_easy *data,
+                                         int smtpcode,
+                                         smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode != 250)
+    result = CURLE_WEIRD_SERVER_REPLY;
+
+  /* End of DONE phase */
+  smtp_state(data, SMTP_STOP);
+
+  return result;
+}
+
+static CURLcode smtp_statemachine(struct Curl_easy *data,
+                                  struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  int smtpcode;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  struct pingpong *pp = &smtpc->pp;
+  size_t nread = 0;
+
+  /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
+  if(smtpc->state == SMTP_UPGRADETLS)
+    return smtp_perform_upgrade_tls(data);
+
+  /* Flush any data that needs to be sent */
+  if(pp->sendleft)
+    return Curl_pp_flushsend(data, pp);
+
+  do {
+    /* Read the response from the server */
+    result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &smtpcode, &nread);
+    if(result)
+      return result;
+
+    /* Store the latest response for later retrieval if necessary */
+    if(smtpc->state != SMTP_QUIT && smtpcode != 1)
+      data->info.httpcode = smtpcode;
+
+    if(!smtpcode)
+      break;
+
+    /* We have now received a full SMTP server response */
+    switch(smtpc->state) {
+    case SMTP_SERVERGREET:
+      result = smtp_state_servergreet_resp(data, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_EHLO:
+      result = smtp_state_ehlo_resp(data, conn, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_HELO:
+      result = smtp_state_helo_resp(data, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_STARTTLS:
+      result = smtp_state_starttls_resp(data, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_AUTH:
+      result = smtp_state_auth_resp(data, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_COMMAND:
+      result = smtp_state_command_resp(data, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_MAIL:
+      result = smtp_state_mail_resp(data, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_RCPT:
+      result = smtp_state_rcpt_resp(data, conn, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_DATA:
+      result = smtp_state_data_resp(data, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_POSTDATA:
+      result = smtp_state_postdata_resp(data, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_QUIT:
+    default:
+      /* internal error */
+      smtp_state(data, SMTP_STOP);
+      break;
+    }
+  } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp));
+
+  return result;
+}
+
+/* Called repeatedly until done from multi.c */
+static CURLcode smtp_multi_statemach(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+  if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
+    bool ssldone = FALSE;
+    result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
+    smtpc->ssldone = ssldone;
+    if(result || !smtpc->ssldone)
+      return result;
+  }
+
+  result = Curl_pp_statemach(data, &smtpc->pp, FALSE, FALSE);
+  *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
+
+  return result;
+}
+
+static CURLcode smtp_block_statemach(struct Curl_easy *data,
+                                     struct connectdata *conn,
+                                     bool disconnecting)
+{
+  CURLcode result = CURLE_OK;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+  while(smtpc->state != SMTP_STOP && !result)
+    result = Curl_pp_statemach(data, &smtpc->pp, TRUE, disconnecting);
+
+  return result;
+}
+
+/* Allocate and initialize the SMTP struct for the current Curl_easy if
+   required */
+static CURLcode smtp_init(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct SMTP *smtp;
+
+  smtp = data->req.p.smtp = calloc(1, sizeof(struct SMTP));
+  if(!smtp)
+    result = CURLE_OUT_OF_MEMORY;
+
+  return result;
+}
+
+/* For the SMTP "protocol connect" and "doing" phases only */
+static int smtp_getsock(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks)
+{
+  return Curl_pp_getsock(data, &conn->proto.smtpc.pp, socks);
+}
+
+/***********************************************************************
+ *
+ * smtp_connect()
+ *
+ * This function should do everything that is to be considered a part of
+ * the connection phase.
+ *
+ * The variable pointed to by 'done' will be TRUE if the protocol-layer
+ * connect phase is done when this function returns, or FALSE if not.
+ */
+static CURLcode smtp_connect(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  struct pingpong *pp = &smtpc->pp;
+
+  *done = FALSE; /* default to not done yet */
+
+  /* We always support persistent connections in SMTP */
+  connkeep(conn, "SMTP default");
+
+  PINGPONG_SETUP(pp, smtp_statemachine, smtp_endofresp);
+
+  /* Initialize the SASL storage */
+  Curl_sasl_init(&smtpc->sasl, data, &saslsmtp);
+
+  /* Initialise the pingpong layer */
+  Curl_pp_init(pp);
+
+  /* Parse the URL options */
+  result = smtp_parse_url_options(conn);
+  if(result)
+    return result;
+
+  /* Parse the URL path */
+  result = smtp_parse_url_path(data);
+  if(result)
+    return result;
+
+  /* Start off waiting for the server greeting response */
+  smtp_state(data, SMTP_SERVERGREET);
+
+  result = smtp_multi_statemach(data, done);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
+                          bool premature)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct SMTP *smtp = data->req.p.smtp;
+
+  (void)premature;
+
+  if(!smtp)
+    return CURLE_OK;
+
+  /* Cleanup our per-request based variables */
+  Curl_safefree(smtp->custom);
+
+  if(status) {
+    connclose(conn, "SMTP done with bad status"); /* marked for closure */
+    result = status;         /* use the already set error code */
+  }
+  else if(!data->set.connect_only && data->set.mail_rcpt &&
+          (data->state.upload || IS_MIME_POST(data))) {
+
+    smtp_state(data, SMTP_POSTDATA);
+
+    /* Run the state-machine */
+    result = smtp_block_statemach(data, conn, FALSE);
+  }
+
+  /* Clear the transfer mode for the next request */
+  smtp->transfer = PPTRANSFER_BODY;
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform()
+ *
+ * This is the actual DO function for SMTP. Transfer a mail, send a command
+ * or get some data according to the options previously setup.
+ */
+static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
+                             bool *dophase_done)
+{
+  /* This is SMTP and no proxy */
+  CURLcode result = CURLE_OK;
+  struct SMTP *smtp = data->req.p.smtp;
+
+  DEBUGF(infof(data, "DO phase starts"));
+
+  if(data->req.no_body) {
+    /* Requested no body means no transfer */
+    smtp->transfer = PPTRANSFER_INFO;
+  }
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* Store the first recipient (or NULL if not specified) */
+  smtp->rcpt = data->set.mail_rcpt;
+
+  /* Track of whether we've successfully sent at least one RCPT TO command */
+  smtp->rcpt_had_ok = FALSE;
+
+  /* Track of the last error we've received by sending RCPT TO command */
+  smtp->rcpt_last_error = 0;
+
+  /* Initial data character is the first character in line: it is implicitly
+     preceded by a virtual CRLF. */
+  smtp->trailing_crlf = TRUE;
+  smtp->eob = 2;
+
+  /* Start the first command in the DO phase */
+  if((data->state.upload || IS_MIME_POST(data)) && data->set.mail_rcpt)
+    /* MAIL transfer */
+    result = smtp_perform_mail(data);
+  else
+    /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */
+    result = smtp_perform_command(data);
+
+  if(result)
+    return result;
+
+  /* Run the state-machine */
+  result = smtp_multi_statemach(data, dophase_done);
+
+  *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
+
+  if(*dophase_done)
+    DEBUGF(infof(data, "DO phase is complete"));
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (smtp_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode smtp_do(struct Curl_easy *data, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  *done = FALSE; /* default to false */
+
+  /* Parse the custom request */
+  result = smtp_parse_custom_request(data);
+  if(result)
+    return result;
+
+  result = smtp_regular_transfer(data, done);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_disconnect()
+ *
+ * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode smtp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                bool dead_connection)
+{
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  (void)data;
+
+  /* We cannot send quit unconditionally. If this connection is stale or
+     bad in any way, sending quit and waiting around here will make the
+     disconnect wait in vain and cause more problems than we need to. */
+
+  if(!dead_connection && conn->bits.protoconnstart) {
+    if(!smtp_perform_quit(data, conn))
+      (void)smtp_block_statemach(data, conn, TRUE); /* ignore errors on QUIT */
+  }
+
+  /* Disconnect from the server */
+  Curl_pp_disconnect(&smtpc->pp);
+
+  /* Cleanup the SASL module */
+  Curl_sasl_cleanup(conn, smtpc->sasl.authused);
+
+  /* Cleanup our connection based variables */
+  Curl_safefree(smtpc->domain);
+
+  return CURLE_OK;
+}
+
+/* Call this when the DO phase has completed */
+static CURLcode smtp_dophase_done(struct Curl_easy *data, bool connected)
+{
+  struct SMTP *smtp = data->req.p.smtp;
+
+  (void)connected;
+
+  if(smtp->transfer != PPTRANSFER_BODY)
+    /* no data to transfer */
+    Curl_xfer_setup(data, -1, -1, FALSE, -1);
+
+  return CURLE_OK;
+}
+
+/* Called from multi.c while DOing */
+static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done)
+{
+  CURLcode result = smtp_multi_statemach(data, dophase_done);
+
+  if(result)
+    DEBUGF(infof(data, "DO phase failed"));
+  else if(*dophase_done) {
+    result = smtp_dophase_done(data, FALSE /* not connected */);
+
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ */
+static CURLcode smtp_regular_transfer(struct Curl_easy *data,
+                                      bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+  bool connected = FALSE;
+
+  /* Make sure size is unknown at this point */
+  data->req.size = -1;
+
+  /* Set the progress data */
+  Curl_pgrsSetUploadCounter(data, 0);
+  Curl_pgrsSetDownloadCounter(data, 0);
+  Curl_pgrsSetUploadSize(data, -1);
+  Curl_pgrsSetDownloadSize(data, -1);
+
+  /* Carry out the perform */
+  result = smtp_perform(data, &connected, dophase_done);
+
+  /* Perform post DO phase operations if necessary */
+  if(!result && *dophase_done)
+    result = smtp_dophase_done(data, connected);
+
+  return result;
+}
+
+static CURLcode smtp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  CURLcode result;
+
+  /* Clear the TLS upgraded flag */
+  conn->bits.tls_upgraded = FALSE;
+
+  /* Initialise the SMTP layer */
+  result = smtp_init(data);
+  if(result)
+    return result;
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * smtp_parse_url_options()
+ *
+ * Parse the URL login options.
+ */
+static CURLcode smtp_parse_url_options(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  const char *ptr = conn->options;
+
+  while(!result && ptr && *ptr) {
+    const char *key = ptr;
+    const char *value;
+
+    while(*ptr && *ptr != '=')
+      ptr++;
+
+    value = ptr + 1;
+
+    while(*ptr && *ptr != ';')
+      ptr++;
+
+    if(strncasecompare(key, "AUTH=", 5))
+      result = Curl_sasl_parse_url_auth_option(&smtpc->sasl,
+                                               value, ptr - value);
+    else
+      result = CURLE_URL_MALFORMAT;
+
+    if(*ptr == ';')
+      ptr++;
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ */
+static CURLcode smtp_parse_url_path(struct Curl_easy *data)
+{
+  /* The SMTP struct is already initialised in smtp_connect() */
+  struct connectdata *conn = data->conn;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  const char *path = &data->state.up.path[1]; /* skip leading path */
+  char localhost[HOSTNAME_MAX + 1];
+
+  /* Calculate the path if necessary */
+  if(!*path) {
+    if(!Curl_gethostname(localhost, sizeof(localhost)))
+      path = localhost;
+    else
+      path = "localhost";
+  }
+
+  /* URL decode the path and use it as the domain in our EHLO */
+  return Curl_urldecode(path, 0, &smtpc->domain, NULL, REJECT_CTRL);
+}
+
+/***********************************************************************
+ *
+ * smtp_parse_custom_request()
+ *
+ * Parse the custom request.
+ */
+static CURLcode smtp_parse_custom_request(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct SMTP *smtp = data->req.p.smtp;
+  const char *custom = data->set.str[STRING_CUSTOMREQUEST];
+
+  /* URL decode the custom request */
+  if(custom)
+    result = Curl_urldecode(custom, 0, &smtp->custom, NULL, REJECT_CTRL);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_parse_address()
+ *
+ * Parse the fully qualified mailbox address into a local address part and the
+ * host name, converting the host name to an IDN A-label, as per RFC-5890, if
+ * necessary.
+ *
+ * Parameters:
+ *
+ * conn  [in]              - The connection handle.
+ * fqma  [in]              - The fully qualified mailbox address (which may or
+ *                           may not contain UTF-8 characters).
+ * address        [in/out] - A new allocated buffer which holds the local
+ *                           address part of the mailbox. This buffer must be
+ *                           free'ed by the caller.
+ * host           [in/out] - The host name structure that holds the original,
+ *                           and optionally encoded, host name.
+ *                           Curl_free_idnconverted_hostname() must be called
+ *                           once the caller has finished with the structure.
+ *
+ * Returns CURLE_OK on success.
+ *
+ * Notes:
+ *
+ * Should a UTF-8 host name require conversion to IDN ACE and we cannot honor
+ * that conversion then we shall return success. This allow the caller to send
+ * the data to the server as a U-label (as per RFC-6531 sect. 3.2).
+ *
+ * If an mailbox '@' separator cannot be located then the mailbox is considered
+ * to be either a local mailbox or an invalid mailbox (depending on what the
+ * calling function deems it to be) then the input will simply be returned in
+ * the address part with the host name being NULL.
+ */
+static CURLcode smtp_parse_address(const char *fqma, char **address,
+                                   struct hostname *host)
+{
+  CURLcode result = CURLE_OK;
+  size_t length;
+
+  /* Duplicate the fully qualified email address so we can manipulate it,
+     ensuring it doesn't contain the delimiters if specified */
+  char *dup = strdup(fqma[0] == '<' ? fqma + 1  : fqma);
+  if(!dup)
+    return CURLE_OUT_OF_MEMORY;
+
+  length = strlen(dup);
+  if(length) {
+    if(dup[length - 1] == '>')
+      dup[length - 1] = '\0';
+  }
+
+  /* Extract the host name from the address (if we can) */
+  host->name = strpbrk(dup, "@");
+  if(host->name) {
+    *host->name = '\0';
+    host->name = host->name + 1;
+
+    /* Attempt to convert the host name to IDN ACE */
+    (void) Curl_idnconvert_hostname(host);
+
+    /* If Curl_idnconvert_hostname() fails then we shall attempt to continue
+       and send the host name using UTF-8 rather than as 7-bit ACE (which is
+       our preference) */
+  }
+
+  /* Extract the local address from the mailbox */
+  *address = dup;
+
+  return result;
+}
+
+struct cr_eob_ctx {
+  struct Curl_creader super;
+  struct bufq buf;
+  size_t n_eob; /* how many EOB bytes we matched so far */
+  size_t eob;       /* Number of bytes of the EOB (End Of Body) that
+                       have been received so far */
+  BIT(read_eos);  /* we read an EOS from the next reader */
+  BIT(eos);       /* we have returned an EOS */
+};
+
+static CURLcode cr_eob_init(struct Curl_easy *data,
+                            struct Curl_creader *reader)
+{
+  struct cr_eob_ctx *ctx = reader->ctx;
+  (void)data;
+  /* The first char we read is the first on a line, as if we had
+   * read CRLF just before */
+  ctx->n_eob = 2;
+  Curl_bufq_init2(&ctx->buf, (16 * 1024), 1, BUFQ_OPT_SOFT_LIMIT);
+  return CURLE_OK;
+}
+
+static void cr_eob_close(struct Curl_easy *data, struct Curl_creader *reader)
+{
+  struct cr_eob_ctx *ctx = reader->ctx;
+  (void)data;
+  Curl_bufq_free(&ctx->buf);
+}
+
+/* this is the 5-bytes End-Of-Body marker for SMTP */
+#define SMTP_EOB "\r\n.\r\n"
+#define SMTP_EOB_FIND_LEN 3
+
+/* client reader doing SMTP End-Of-Body escaping. */
+static CURLcode cr_eob_read(struct Curl_easy *data,
+                            struct Curl_creader *reader,
+                            char *buf, size_t blen,
+                            size_t *pnread, bool *peos)
+{
+  struct cr_eob_ctx *ctx = reader->ctx;
+  CURLcode result = CURLE_OK;
+  size_t nread, i, start, n;
+  bool eos;
+
+  if(!ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
+    /* Get more and convert it when needed */
+    result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);
+    if(result)
+      return result;
+
+    ctx->read_eos = eos;
+    if(nread) {
+      if(!ctx->n_eob && !memchr(buf, SMTP_EOB[0], nread)) {
+        /* not in the middle of a match, no EOB start found, just pass */
+        *pnread = nread;
+        *peos = FALSE;
+        return CURLE_OK;
+      }
+      /* scan for EOB (continuation) and convert */
+      for(i = start = 0; i < nread; ++i) {
+        if(ctx->n_eob >= SMTP_EOB_FIND_LEN) {
+          /* matched the EOB prefix and seeing additional char, add '.' */
+          result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
+          if(result)
+            return result;
+          result = Curl_bufq_cwrite(&ctx->buf, ".", 1, &n);
+          if(result)
+            return result;
+          ctx->n_eob = 0;
+          start = i;
+          if(data->state.infilesize > 0)
+            data->state.infilesize++;
+        }
+
+        if(buf[i] != SMTP_EOB[ctx->n_eob])
+          ctx->n_eob = 0;
+
+        if(buf[i] == SMTP_EOB[ctx->n_eob]) {
+          /* matching another char of the EOB */
+          ++ctx->n_eob;
+        }
+      }
+
+      /* add any remainder to buf */
+      if(start < nread) {
+        result = Curl_bufq_cwrite(&ctx->buf, buf + start, nread - start, &n);
+        if(result)
+          return result;
+      }
+    }
+
+    if(ctx->read_eos) {
+      /* if we last matched a CRLF or if the data was empty, add ".\r\n"
+       * to end the body. If we sent something and it did not end with "\r\n",
+       * add "\r\n.\r\n" to end the body */
+      const char *eob = SMTP_EOB;
+      switch(ctx->n_eob) {
+        case 2:
+          /* seen a CRLF at the end, just add the remainder */
+          eob = &SMTP_EOB[2];
+          break;
+        case 3:
+          /* ended with '\r\n.', we should escpe the last '.' */
+          eob = "." SMTP_EOB;
+          break;
+        default:
+          break;
+      }
+      result = Curl_bufq_cwrite(&ctx->buf, eob, strlen(eob), &n);
+      if(result)
+        return result;
+    }
+  }
+
+  *peos = FALSE;
+  if(!Curl_bufq_is_empty(&ctx->buf)) {
+    result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
+  }
+  else
+    *pnread = 0;
+
+  if(ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
+    /* no more data, read all, done. */
+    ctx->eos = TRUE;
+  }
+  *peos = ctx->eos;
+  DEBUGF(infof(data, "cr_eob_read(%zu) -> %d, %zd, %d",
+         blen, result, *pnread, *peos));
+  return CURLE_OK;
+}
+
+static curl_off_t cr_eob_total_length(struct Curl_easy *data,
+                                      struct Curl_creader *reader)
+{
+  /* this reader changes length depending on input */
+  (void)data;
+  (void)reader;
+  return -1;
+}
+
+static const struct Curl_crtype cr_eob = {
+  "cr-smtp-eob",
+  cr_eob_init,
+  cr_eob_read,
+  cr_eob_close,
+  Curl_creader_def_needs_rewind,
+  cr_eob_total_length,
+  Curl_creader_def_resume_from,
+  Curl_creader_def_rewind,
+  Curl_creader_def_unpause,
+  Curl_creader_def_done,
+  sizeof(struct cr_eob_ctx)
+};
+
+static CURLcode cr_eob_add(struct Curl_easy *data)
+{
+  struct Curl_creader *reader = NULL;
+  CURLcode result;
+
+  result = Curl_creader_create(&reader, data, &cr_eob,
+                               CURL_CR_CONTENT_ENCODE);
+  if(!result)
+    result = Curl_creader_add(data, reader);
+
+  if(result && reader)
+    Curl_creader_free(data, reader);
+  return result;
+}
+
+#endif /* CURL_DISABLE_SMTP */
Index: trunk/src/libs/curl-8.7.1/lib/smtp.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/smtp.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/smtp.h	(revision 104083)
@@ -0,0 +1,87 @@
+#ifndef HEADER_CURL_SMTP_H
+#define HEADER_CURL_SMTP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "pingpong.h"
+#include "curl_sasl.h"
+
+/****************************************************************************
+ * SMTP unique setup
+ ***************************************************************************/
+typedef enum {
+  SMTP_STOP,        /* do nothing state, stops the state machine */
+  SMTP_SERVERGREET, /* waiting for the initial greeting immediately after
+                       a connect */
+  SMTP_EHLO,
+  SMTP_HELO,
+  SMTP_STARTTLS,
+  SMTP_UPGRADETLS,  /* asynchronously upgrade the connection to SSL/TLS
+                       (multi mode only) */
+  SMTP_AUTH,
+  SMTP_COMMAND,     /* VRFY, EXPN, NOOP, RSET and HELP */
+  SMTP_MAIL,        /* MAIL FROM */
+  SMTP_RCPT,        /* RCPT TO */
+  SMTP_DATA,
+  SMTP_POSTDATA,
+  SMTP_QUIT,
+  SMTP_LAST         /* never used */
+} smtpstate;
+
+/* This SMTP struct is used in the Curl_easy. All SMTP data that is
+   connection-oriented must be in smtp_conn to properly deal with the fact that
+   perhaps the Curl_easy is changed between the times the connection is
+   used. */
+struct SMTP {
+  curl_pp_transfer transfer;
+  char *custom;            /* Custom Request */
+  struct curl_slist *rcpt; /* Recipient list */
+  int rcpt_last_error;     /* The last error received for RCPT TO command */
+  size_t eob;              /* Number of bytes of the EOB (End Of Body) that
+                              have been received so far */
+  BIT(rcpt_had_ok);        /* Whether any of RCPT TO commands (depends on
+                              total number of recipients) succeeded so far */
+  BIT(trailing_crlf);      /* Specifies if the trailing CRLF is present */
+};
+
+/* smtp_conn is used for struct connection-oriented data in the connectdata
+   struct */
+struct smtp_conn {
+  struct pingpong pp;
+  struct SASL sasl;        /* SASL-related storage */
+  smtpstate state;         /* Always use smtp.c:state() to change state! */
+  char *domain;            /* Client address/name to send in the EHLO */
+  BIT(ssldone);            /* Is connect() over SSL done? */
+  BIT(tls_supported);      /* StartTLS capability supported by server */
+  BIT(size_supported);     /* If server supports SIZE extension according to
+                              RFC 1870 */
+  BIT(utf8_supported);     /* If server supports SMTPUTF8 extension according
+                              to RFC 6531 */
+  BIT(auth_supported);     /* AUTH capability supported by server */
+};
+
+extern const struct Curl_handler Curl_handler_smtp;
+extern const struct Curl_handler Curl_handler_smtps;
+
+#endif /* HEADER_CURL_SMTP_H */
Index: trunk/src/libs/curl-8.7.1/lib/sockaddr.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/sockaddr.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/sockaddr.h	(revision 104083)
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_SOCKADDR_H
+#define HEADER_CURL_SOCKADDR_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+struct Curl_sockaddr_storage {
+  union {
+    struct sockaddr sa;
+    struct sockaddr_in sa_in;
+#ifdef ENABLE_IPV6
+    struct sockaddr_in6 sa_in6;
+#endif
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+    struct sockaddr_storage sa_stor;
+#else
+    char cbuf[256];   /* this should be big enough to fit a lot */
+#endif
+  } buffer;
+};
+
+#endif /* HEADER_CURL_SOCKADDR_H */
Index: trunk/src/libs/curl-8.7.1/lib/socketpair.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/socketpair.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/socketpair.c	(revision 104083)
@@ -0,0 +1,190 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "socketpair.h"
+#include "urldata.h"
+#include "rand.h"
+
+#if !defined(HAVE_SOCKETPAIR) && !defined(CURL_DISABLE_SOCKETPAIR)
+#ifdef _WIN32
+/*
+ * This is a socketpair() implementation for Windows.
+ */
+#include <string.h>
+#include <io.h>
+#else
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h> /* IPPROTO_TCP */
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001
+#endif /* !INADDR_LOOPBACK */
+#endif /* !_WIN32 */
+
+#include "nonblock.h" /* for curlx_nonblock */
+#include "timeval.h"  /* needed before select.h */
+#include "select.h"   /* for Curl_poll */
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+int Curl_socketpair(int domain, int type, int protocol,
+                    curl_socket_t socks[2])
+{
+  union {
+    struct sockaddr_in inaddr;
+    struct sockaddr addr;
+  } a;
+  curl_socket_t listener;
+  curl_socklen_t addrlen = sizeof(a.inaddr);
+  int reuse = 1;
+  struct pollfd pfd[1];
+  (void)domain;
+  (void)type;
+  (void)protocol;
+
+  listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if(listener == CURL_SOCKET_BAD)
+    return -1;
+
+  memset(&a, 0, sizeof(a));
+  a.inaddr.sin_family = AF_INET;
+  a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  a.inaddr.sin_port = 0;
+
+  socks[0] = socks[1] = CURL_SOCKET_BAD;
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+  /* don't set SO_REUSEADDR on Windows */
+  (void)reuse;
+#ifdef SO_EXCLUSIVEADDRUSE
+  {
+    int exclusive = 1;
+    if(setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
+                  (char *)&exclusive, (curl_socklen_t)sizeof(exclusive)) == -1)
+      goto error;
+  }
+#endif
+#else
+  if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR,
+                (char *)&reuse, (curl_socklen_t)sizeof(reuse)) == -1)
+    goto error;
+#endif
+  if(bind(listener, &a.addr, sizeof(a.inaddr)) == -1)
+    goto error;
+  if(getsockname(listener, &a.addr, &addrlen) == -1 ||
+     addrlen < (int)sizeof(a.inaddr))
+    goto error;
+  if(listen(listener, 1) == -1)
+    goto error;
+  socks[0] = socket(AF_INET, SOCK_STREAM, 0);
+  if(socks[0] == CURL_SOCKET_BAD)
+    goto error;
+  if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1)
+    goto error;
+
+  /* use non-blocking accept to make sure we don't block forever */
+  if(curlx_nonblock(listener, TRUE) < 0)
+    goto error;
+  pfd[0].fd = listener;
+  pfd[0].events = POLLIN;
+  pfd[0].revents = 0;
+  (void)Curl_poll(pfd, 1, 1000); /* one second */
+  socks[1] = accept(listener, NULL, NULL);
+  if(socks[1] == CURL_SOCKET_BAD)
+    goto error;
+  else {
+    struct curltime start = Curl_now();
+    char rnd[9];
+    char check[sizeof(rnd)];
+    char *p = &check[0];
+    size_t s = sizeof(check);
+
+    if(Curl_rand(NULL, (unsigned char *)rnd, sizeof(rnd)))
+      goto error;
+
+    /* write data to the socket */
+    swrite(socks[0], rnd, sizeof(rnd));
+    /* verify that we read the correct data */
+    do {
+      ssize_t nread;
+
+      pfd[0].fd = socks[1];
+      pfd[0].events = POLLIN;
+      pfd[0].revents = 0;
+      (void)Curl_poll(pfd, 1, 1000); /* one second */
+
+      nread = sread(socks[1], p, s);
+      if(nread == -1) {
+        int sockerr = SOCKERRNO;
+        /* Don't block forever */
+        if(Curl_timediff(Curl_now(), start) > (60 * 1000))
+          goto error;
+        if(
+#ifdef WSAEWOULDBLOCK
+          /* This is how Windows does it */
+          (WSAEWOULDBLOCK == sockerr)
+#else
+          /* errno may be EWOULDBLOCK or on some systems EAGAIN when it
+             returned due to its inability to send off data without
+             blocking. We therefore treat both error codes the same here */
+          (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) ||
+          (EINTR == sockerr) || (EINPROGRESS == sockerr)
+#endif
+          ) {
+          continue;
+        }
+        goto error;
+      }
+      s -= nread;
+      if(s) {
+        p += nread;
+        continue;
+      }
+      if(memcmp(rnd, check, sizeof(check)))
+        goto error;
+      break;
+    } while(1);
+  }
+
+  sclose(listener);
+  return 0;
+
+error:
+  sclose(listener);
+  sclose(socks[0]);
+  sclose(socks[1]);
+  return -1;
+}
+
+#endif /* ! HAVE_SOCKETPAIR */
Index: trunk/src/libs/curl-8.7.1/lib/socketpair.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/socketpair.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/socketpair.h	(revision 104083)
@@ -0,0 +1,54 @@
+#ifndef HEADER_CURL_SOCKETPAIR_H
+#define HEADER_CURL_SOCKETPAIR_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_PIPE
+
+#define wakeup_write  write
+#define wakeup_read   read
+#define wakeup_close  close
+#define wakeup_create pipe
+
+#else /* HAVE_PIPE */
+
+#define wakeup_write     swrite
+#define wakeup_read      sread
+#define wakeup_close     sclose
+#define wakeup_create(p) Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, p)
+
+#endif /* HAVE_PIPE */
+
+#ifndef HAVE_SOCKETPAIR
+#include <curl/curl.h>
+
+int Curl_socketpair(int domain, int type, int protocol,
+                    curl_socket_t socks[2]);
+#else
+#define Curl_socketpair(a,b,c,d) socketpair(a,b,c,d)
+#endif
+
+#endif /* HEADER_CURL_SOCKETPAIR_H */
Index: trunk/src/libs/curl-8.7.1/lib/socks.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/socks.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/socks.c	(revision 104083)
@@ -0,0 +1,1276 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_PROXY)
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "select.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "timeval.h"
+#include "socks.h"
+#include "multiif.h" /* for getsock macros */
+#include "inet_pton.h"
+#include "url.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* for the (SOCKS) connect state machine */
+enum connect_t {
+  CONNECT_INIT,
+  CONNECT_SOCKS_INIT, /* 1 */
+  CONNECT_SOCKS_SEND, /* 2 waiting to send more first data */
+  CONNECT_SOCKS_READ_INIT, /* 3 set up read */
+  CONNECT_SOCKS_READ, /* 4 read server response */
+  CONNECT_GSSAPI_INIT, /* 5 */
+  CONNECT_AUTH_INIT, /* 6 setup outgoing auth buffer */
+  CONNECT_AUTH_SEND, /* 7 send auth */
+  CONNECT_AUTH_READ, /* 8 read auth response */
+  CONNECT_REQ_INIT,  /* 9 init SOCKS "request" */
+  CONNECT_RESOLVING, /* 10 */
+  CONNECT_RESOLVED,  /* 11 */
+  CONNECT_RESOLVE_REMOTE, /* 12 */
+  CONNECT_REQ_SEND,  /* 13 */
+  CONNECT_REQ_SENDING, /* 14 */
+  CONNECT_REQ_READ,  /* 15 */
+  CONNECT_REQ_READ_MORE, /* 16 */
+  CONNECT_DONE /* 17 connected fine to the remote or the SOCKS proxy */
+};
+
+#define CURL_SOCKS_BUF_SIZE 600
+
+/* make sure we configure it not too low */
+#if CURL_SOCKS_BUF_SIZE < 600
+#error CURL_SOCKS_BUF_SIZE must be at least 600
+#endif
+
+
+struct socks_state {
+  enum connect_t state;
+  ssize_t outstanding;  /* send this many bytes more */
+  unsigned char buffer[CURL_SOCKS_BUF_SIZE];
+  unsigned char *outp; /* send from this pointer */
+
+  const char *hostname;
+  int remote_port;
+  const char *proxy_user;
+  const char *proxy_password;
+};
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+/*
+ * Helper read-from-socket functions. Does the same as Curl_read() but it
+ * blocks until all bytes amount of buffersize will be read. No more, no less.
+ *
+ * This is STUPID BLOCKING behavior. Only used by the SOCKS GSSAPI functions.
+ */
+int Curl_blockread_all(struct Curl_cfilter *cf,
+                       struct Curl_easy *data,   /* transfer */
+                       char *buf,                /* store read data here */
+                       ssize_t buffersize,       /* max amount to read */
+                       ssize_t *n)               /* amount bytes read */
+{
+  ssize_t nread = 0;
+  ssize_t allread = 0;
+  int result;
+  CURLcode err = CURLE_OK;
+
+  *n = 0;
+  for(;;) {
+    timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+    if(timeout_ms < 0) {
+      /* we already got the timeout */
+      result = CURLE_OPERATION_TIMEDOUT;
+      break;
+    }
+    if(!timeout_ms)
+      timeout_ms = TIMEDIFF_T_MAX;
+    if(SOCKET_READABLE(cf->conn->sock[cf->sockindex], timeout_ms) <= 0) {
+      result = ~CURLE_OK;
+      break;
+    }
+    nread = Curl_conn_cf_recv(cf->next, data, buf, buffersize, &err);
+    if(nread <= 0) {
+      result = err;
+      if(CURLE_AGAIN == err)
+        continue;
+      if(err) {
+        break;
+      }
+    }
+
+    if(buffersize == nread) {
+      allread += nread;
+      *n = allread;
+      result = CURLE_OK;
+      break;
+    }
+    if(!nread) {
+      result = ~CURLE_OK;
+      break;
+    }
+
+    buffersize -= nread;
+    buf += nread;
+    allread += nread;
+  }
+  return result;
+}
+#endif
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+#define DEBUG_AND_VERBOSE
+#define sxstate(x,d,y) socksstate(x,d,y, __LINE__)
+#else
+#define sxstate(x,d,y) socksstate(x,d,y)
+#endif
+
+/* always use this function to change state, to make debugging easier */
+static void socksstate(struct socks_state *sx, struct Curl_easy *data,
+                       enum connect_t state
+#ifdef DEBUG_AND_VERBOSE
+                       , int lineno
+#endif
+)
+{
+  enum connect_t oldstate = sx->state;
+#ifdef DEBUG_AND_VERBOSE
+  /* synced with the state list in urldata.h */
+  static const char * const socks_statename[] = {
+    "INIT",
+    "SOCKS_INIT",
+    "SOCKS_SEND",
+    "SOCKS_READ_INIT",
+    "SOCKS_READ",
+    "GSSAPI_INIT",
+    "AUTH_INIT",
+    "AUTH_SEND",
+    "AUTH_READ",
+    "REQ_INIT",
+    "RESOLVING",
+    "RESOLVED",
+    "RESOLVE_REMOTE",
+    "REQ_SEND",
+    "REQ_SENDING",
+    "REQ_READ",
+    "REQ_READ_MORE",
+    "DONE"
+  };
+#endif
+
+  (void)data;
+  if(oldstate == state)
+    /* don't bother when the new state is the same as the old state */
+    return;
+
+  sx->state = state;
+
+#ifdef DEBUG_AND_VERBOSE
+  infof(data,
+        "SXSTATE: %s => %s; line %d",
+        socks_statename[oldstate], socks_statename[sx->state],
+        lineno);
+#endif
+}
+
+static CURLproxycode socks_state_send(struct Curl_cfilter *cf,
+                                      struct socks_state *sx,
+                                      struct Curl_easy *data,
+                                      CURLproxycode failcode,
+                                      const char *description)
+{
+  ssize_t nwritten;
+  CURLcode result;
+
+  nwritten = Curl_conn_cf_send(cf->next, data, (char *)sx->outp,
+                               sx->outstanding, &result);
+  if(nwritten <= 0) {
+    if(CURLE_AGAIN == result) {
+      return CURLPX_OK;
+    }
+    else if(CURLE_OK == result) {
+      /* connection closed */
+      failf(data, "connection to proxy closed");
+      return CURLPX_CLOSED;
+    }
+    failf(data, "Failed to send %s: %s", description,
+          curl_easy_strerror(result));
+    return failcode;
+  }
+  DEBUGASSERT(sx->outstanding >= nwritten);
+  /* not done, remain in state */
+  sx->outstanding -= nwritten;
+  sx->outp += nwritten;
+  return CURLPX_OK;
+}
+
+static CURLproxycode socks_state_recv(struct Curl_cfilter *cf,
+                                      struct socks_state *sx,
+                                      struct Curl_easy *data,
+                                      CURLproxycode failcode,
+                                      const char *description)
+{
+  ssize_t nread;
+  CURLcode result;
+
+  nread = Curl_conn_cf_recv(cf->next, data, (char *)sx->outp,
+                            sx->outstanding, &result);
+  if(nread <= 0) {
+    if(CURLE_AGAIN == result) {
+      return CURLPX_OK;
+    }
+    else if(CURLE_OK == result) {
+      /* connection closed */
+      failf(data, "connection to proxy closed");
+      return CURLPX_CLOSED;
+    }
+    failf(data, "SOCKS: Failed receiving %s: %s", description,
+          curl_easy_strerror(result));
+    return failcode;
+  }
+  /* remain in reading state */
+  DEBUGASSERT(sx->outstanding >= nread);
+  sx->outstanding -= nread;
+  sx->outp += nread;
+  return CURLPX_OK;
+}
+
+/*
+* This function logs in to a SOCKS4 proxy and sends the specifics to the final
+* destination server.
+*
+* Reference :
+*   https://www.openssh.com/txt/socks4.protocol
+*
+* Note :
+*   Set protocol4a=true for  "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
+*   Nonsupport "Identification Protocol (RFC1413)"
+*/
+static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
+                               struct socks_state *sx,
+                               struct Curl_easy *data)
+{
+  struct connectdata *conn = cf->conn;
+  const bool protocol4a =
+    (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
+  unsigned char *socksreq = sx->buffer;
+  CURLcode result;
+  CURLproxycode presult;
+  struct Curl_dns_entry *dns = NULL;
+
+  switch(sx->state) {
+  case CONNECT_SOCKS_INIT:
+    /* SOCKS4 can only do IPv4, insist! */
+    conn->ip_version = CURL_IPRESOLVE_V4;
+    if(conn->bits.httpproxy)
+      infof(data, "SOCKS4%s: connecting to HTTP proxy %s port %d",
+            protocol4a ? "a" : "", sx->hostname, sx->remote_port);
+
+    infof(data, "SOCKS4 communication to %s:%d",
+          sx->hostname, sx->remote_port);
+
+    /*
+     * Compose socks4 request
+     *
+     * Request format
+     *
+     *     +----+----+----+----+----+----+----+----+----+----+....+----+
+     *     | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
+     *     +----+----+----+----+----+----+----+----+----+----+....+----+
+     * # of bytes:  1    1      2              4           variable       1
+     */
+
+    socksreq[0] = 4; /* version (SOCKS4) */
+    socksreq[1] = 1; /* connect */
+    socksreq[2] = (unsigned char)((sx->remote_port >> 8) & 0xff); /* MSB */
+    socksreq[3] = (unsigned char)(sx->remote_port & 0xff);        /* LSB */
+
+    /* DNS resolve only for SOCKS4, not SOCKS4a */
+    if(!protocol4a) {
+      enum resolve_t rc =
+        Curl_resolv(data, sx->hostname, sx->remote_port, TRUE, &dns);
+
+      if(rc == CURLRESOLV_ERROR)
+        return CURLPX_RESOLVE_HOST;
+      else if(rc == CURLRESOLV_PENDING) {
+        sxstate(sx, data, CONNECT_RESOLVING);
+        infof(data, "SOCKS4 non-blocking resolve of %s", sx->hostname);
+        return CURLPX_OK;
+      }
+      sxstate(sx, data, CONNECT_RESOLVED);
+      goto CONNECT_RESOLVED;
+    }
+
+    /* socks4a doesn't resolve anything locally */
+    sxstate(sx, data, CONNECT_REQ_INIT);
+    goto CONNECT_REQ_INIT;
+
+  case CONNECT_RESOLVING:
+    /* check if we have the name resolved by now */
+    dns = Curl_fetch_addr(data, sx->hostname, conn->primary.remote_port);
+
+    if(dns) {
+#ifdef CURLRES_ASYNCH
+      data->state.async.dns = dns;
+      data->state.async.done = TRUE;
+#endif
+      infof(data, "Hostname '%s' was found", sx->hostname);
+      sxstate(sx, data, CONNECT_RESOLVED);
+    }
+    else {
+      result = Curl_resolv_check(data, &dns);
+      if(!dns) {
+        if(result)
+          return CURLPX_RESOLVE_HOST;
+        return CURLPX_OK;
+      }
+    }
+    FALLTHROUGH();
+  case CONNECT_RESOLVED:
+CONNECT_RESOLVED:
+  {
+    struct Curl_addrinfo *hp = NULL;
+    /*
+     * We cannot use 'hostent' as a struct that Curl_resolv() returns.  It
+     * returns a Curl_addrinfo pointer that may not always look the same.
+     */
+    if(dns) {
+      hp = dns->addr;
+
+      /* scan for the first IPv4 address */
+      while(hp && (hp->ai_family != AF_INET))
+        hp = hp->ai_next;
+
+      if(hp) {
+        struct sockaddr_in *saddr_in;
+        char buf[64];
+        Curl_printable_address(hp, buf, sizeof(buf));
+
+        saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
+        socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0];
+        socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1];
+        socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2];
+        socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3];
+
+        infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)", buf);
+
+        Curl_resolv_unlock(data, dns); /* not used anymore from now on */
+      }
+      else
+        failf(data, "SOCKS4 connection to %s not supported", sx->hostname);
+    }
+    else
+      failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
+            sx->hostname);
+
+    if(!hp)
+      return CURLPX_RESOLVE_HOST;
+  }
+    FALLTHROUGH();
+  case CONNECT_REQ_INIT:
+CONNECT_REQ_INIT:
+    /*
+     * This is currently not supporting "Identification Protocol (RFC1413)".
+     */
+    socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
+    if(sx->proxy_user) {
+      size_t plen = strlen(sx->proxy_user);
+      if(plen > 255) {
+        /* there is no real size limit to this field in the protocol, but
+           SOCKS5 limits the proxy user field to 255 bytes and it seems likely
+           that a longer field is either a mistake or malicious input */
+        failf(data, "Too long SOCKS proxy user name");
+        return CURLPX_LONG_USER;
+      }
+      /* copy the proxy name WITH trailing zero */
+      memcpy(socksreq + 8, sx->proxy_user, plen + 1);
+    }
+
+    /*
+     * Make connection
+     */
+    {
+      size_t packetsize = 9 +
+        strlen((char *)socksreq + 8); /* size including NUL */
+
+      /* If SOCKS4a, set special invalid IP address 0.0.0.x */
+      if(protocol4a) {
+        size_t hostnamelen = 0;
+        socksreq[4] = 0;
+        socksreq[5] = 0;
+        socksreq[6] = 0;
+        socksreq[7] = 1;
+        /* append hostname */
+        hostnamelen = strlen(sx->hostname) + 1; /* length including NUL */
+        if((hostnamelen <= 255) &&
+           (packetsize + hostnamelen < sizeof(sx->buffer)))
+          strcpy((char *)socksreq + packetsize, sx->hostname);
+        else {
+          failf(data, "SOCKS4: too long host name");
+          return CURLPX_LONG_HOSTNAME;
+        }
+        packetsize += hostnamelen;
+      }
+      sx->outp = socksreq;
+      DEBUGASSERT(packetsize <= sizeof(sx->buffer));
+      sx->outstanding = packetsize;
+      sxstate(sx, data, CONNECT_REQ_SENDING);
+    }
+    FALLTHROUGH();
+  case CONNECT_REQ_SENDING:
+    /* Send request */
+    presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT,
+                               "SOCKS4 connect request");
+    if(CURLPX_OK != presult)
+      return presult;
+    else if(sx->outstanding) {
+      /* remain in sending state */
+      return CURLPX_OK;
+    }
+    /* done sending! */
+    sx->outstanding = 8; /* receive data size */
+    sx->outp = socksreq;
+    sxstate(sx, data, CONNECT_SOCKS_READ);
+
+    FALLTHROUGH();
+  case CONNECT_SOCKS_READ:
+    /* Receive response */
+    presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT,
+                               "connect request ack");
+    if(CURLPX_OK != presult)
+      return presult;
+    else if(sx->outstanding) {
+      /* remain in reading state */
+      return CURLPX_OK;
+    }
+    sxstate(sx, data, CONNECT_DONE);
+    break;
+  default: /* lots of unused states in SOCKS4 */
+    break;
+  }
+
+  /*
+   * Response format
+   *
+   *     +----+----+----+----+----+----+----+----+
+   *     | VN | CD | DSTPORT |      DSTIP        |
+   *     +----+----+----+----+----+----+----+----+
+   * # of bytes:  1    1      2              4
+   *
+   * VN is the version of the reply code and should be 0. CD is the result
+   * code with one of the following values:
+   *
+   * 90: request granted
+   * 91: request rejected or failed
+   * 92: request rejected because SOCKS server cannot connect to
+   *     identd on the client
+   * 93: request rejected because the client program and identd
+   *     report different user-ids
+   */
+
+  /* wrong version ? */
+  if(socksreq[0]) {
+    failf(data,
+          "SOCKS4 reply has wrong version, version should be 0.");
+    return CURLPX_BAD_VERSION;
+  }
+
+  /* Result */
+  switch(socksreq[1]) {
+  case 90:
+    infof(data, "SOCKS4%s request granted.", protocol4a?"a":"");
+    break;
+  case 91:
+    failf(data,
+          "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+          ", request rejected or failed.",
+          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
+          (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
+          (unsigned char)socksreq[1]);
+    return CURLPX_REQUEST_FAILED;
+  case 92:
+    failf(data,
+          "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+          ", request rejected because SOCKS server cannot connect to "
+          "identd on the client.",
+          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
+          (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
+          (unsigned char)socksreq[1]);
+    return CURLPX_IDENTD;
+  case 93:
+    failf(data,
+          "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+          ", request rejected because the client program and identd "
+          "report different user-ids.",
+          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
+          (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
+          (unsigned char)socksreq[1]);
+    return CURLPX_IDENTD_DIFFER;
+  default:
+    failf(data,
+          "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+          ", Unknown.",
+          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
+          (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
+          (unsigned char)socksreq[1]);
+    return CURLPX_UNKNOWN_FAIL;
+  }
+
+  return CURLPX_OK; /* Proxy was successful! */
+}
+
+/*
+ * This function logs in to a SOCKS5 proxy and sends the specifics to the final
+ * destination server.
+ */
+static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
+                               struct socks_state *sx,
+                               struct Curl_easy *data)
+{
+  /*
+    According to the RFC1928, section "6.  Replies". This is what a SOCK5
+    replies:
+
+        +----+-----+-------+------+----------+----------+
+        |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
+        +----+-----+-------+------+----------+----------+
+        | 1  |  1  | X'00' |  1   | Variable |    2     |
+        +----+-----+-------+------+----------+----------+
+
+    Where:
+
+    o  VER    protocol version: X'05'
+    o  REP    Reply field:
+    o  X'00' succeeded
+  */
+  struct connectdata *conn = cf->conn;
+  unsigned char *socksreq = sx->buffer;
+  size_t idx;
+  CURLcode result;
+  CURLproxycode presult;
+  bool socks5_resolve_local =
+    (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
+  const size_t hostname_len = strlen(sx->hostname);
+  size_t len = 0;
+  const unsigned char auth = data->set.socks5auth;
+  bool allow_gssapi = FALSE;
+  struct Curl_dns_entry *dns = NULL;
+
+  DEBUGASSERT(auth & (CURLAUTH_BASIC | CURLAUTH_GSSAPI));
+  switch(sx->state) {
+  case CONNECT_SOCKS_INIT:
+    if(conn->bits.httpproxy)
+      infof(data, "SOCKS5: connecting to HTTP proxy %s port %d",
+            sx->hostname, sx->remote_port);
+
+    /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
+    if(!socks5_resolve_local && hostname_len > 255) {
+      failf(data, "SOCKS5: the destination hostname is too long to be "
+            "resolved remotely by the proxy.");
+      return CURLPX_LONG_HOSTNAME;
+    }
+
+    if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
+      infof(data,
+            "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %u",
+            auth);
+    if(!(auth & CURLAUTH_BASIC))
+      /* disable username/password auth */
+      sx->proxy_user = NULL;
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+    if(auth & CURLAUTH_GSSAPI)
+      allow_gssapi = TRUE;
+#endif
+
+    idx = 0;
+    socksreq[idx++] = 5;   /* version */
+    idx++;                 /* number of authentication methods */
+    socksreq[idx++] = 0;   /* no authentication */
+    if(allow_gssapi)
+      socksreq[idx++] = 1; /* GSS-API */
+    if(sx->proxy_user)
+      socksreq[idx++] = 2; /* username/password */
+    /* write the number of authentication methods */
+    socksreq[1] = (unsigned char) (idx - 2);
+
+    sx->outp = socksreq;
+    DEBUGASSERT(idx <= sizeof(sx->buffer));
+    sx->outstanding = idx;
+    presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT,
+                               "initial SOCKS5 request");
+    if(CURLPX_OK != presult)
+      return presult;
+    else if(sx->outstanding) {
+      /* remain in sending state */
+      return CURLPX_OK;
+    }
+    sxstate(sx, data, CONNECT_SOCKS_READ);
+    goto CONNECT_SOCKS_READ_INIT;
+  case CONNECT_SOCKS_SEND:
+    presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT,
+                               "initial SOCKS5 request");
+    if(CURLPX_OK != presult)
+      return presult;
+    else if(sx->outstanding) {
+      /* remain in sending state */
+      return CURLPX_OK;
+    }
+    FALLTHROUGH();
+  case CONNECT_SOCKS_READ_INIT:
+CONNECT_SOCKS_READ_INIT:
+    sx->outstanding = 2; /* expect two bytes */
+    sx->outp = socksreq; /* store it here */
+    FALLTHROUGH();
+  case CONNECT_SOCKS_READ:
+    presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT,
+                               "initial SOCKS5 response");
+    if(CURLPX_OK != presult)
+      return presult;
+    else if(sx->outstanding) {
+      /* remain in reading state */
+      return CURLPX_OK;
+    }
+    else if(socksreq[0] != 5) {
+      failf(data, "Received invalid version in initial SOCKS5 response.");
+      return CURLPX_BAD_VERSION;
+    }
+    else if(socksreq[1] == 0) {
+      /* DONE! No authentication needed. Send request. */
+      sxstate(sx, data, CONNECT_REQ_INIT);
+      goto CONNECT_REQ_INIT;
+    }
+    else if(socksreq[1] == 2) {
+      /* regular name + password authentication */
+      sxstate(sx, data, CONNECT_AUTH_INIT);
+      goto CONNECT_AUTH_INIT;
+    }
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+    else if(allow_gssapi && (socksreq[1] == 1)) {
+      sxstate(sx, data, CONNECT_GSSAPI_INIT);
+      result = Curl_SOCKS5_gssapi_negotiate(cf, data);
+      if(result) {
+        failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
+        return CURLPX_GSSAPI;
+      }
+    }
+#endif
+    else {
+      /* error */
+      if(!allow_gssapi && (socksreq[1] == 1)) {
+        failf(data,
+              "SOCKS5 GSSAPI per-message authentication is not supported.");
+        return CURLPX_GSSAPI_PERMSG;
+      }
+      else if(socksreq[1] == 255) {
+        failf(data, "No authentication method was acceptable.");
+        return CURLPX_NO_AUTH;
+      }
+    }
+    failf(data,
+          "Undocumented SOCKS5 mode attempted to be used by server.");
+    return CURLPX_UNKNOWN_MODE;
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  case CONNECT_GSSAPI_INIT:
+    /* GSSAPI stuff done non-blocking */
+    break;
+#endif
+
+  default: /* do nothing! */
+    break;
+
+CONNECT_AUTH_INIT:
+  case CONNECT_AUTH_INIT: {
+    /* Needs user name and password */
+    size_t proxy_user_len, proxy_password_len;
+    if(sx->proxy_user && sx->proxy_password) {
+      proxy_user_len = strlen(sx->proxy_user);
+      proxy_password_len = strlen(sx->proxy_password);
+    }
+    else {
+      proxy_user_len = 0;
+      proxy_password_len = 0;
+    }
+
+    /*   username/password request looks like
+     * +----+------+----------+------+----------+
+     * |VER | ULEN |  UNAME   | PLEN |  PASSWD  |
+     * +----+------+----------+------+----------+
+     * | 1  |  1   | 1 to 255 |  1   | 1 to 255 |
+     * +----+------+----------+------+----------+
+     */
+    len = 0;
+    socksreq[len++] = 1;    /* username/pw subnegotiation version */
+    socksreq[len++] = (unsigned char) proxy_user_len;
+    if(sx->proxy_user && proxy_user_len) {
+      /* the length must fit in a single byte */
+      if(proxy_user_len > 255) {
+        failf(data, "Excessive user name length for proxy auth");
+        return CURLPX_LONG_USER;
+      }
+      memcpy(socksreq + len, sx->proxy_user, proxy_user_len);
+    }
+    len += proxy_user_len;
+    socksreq[len++] = (unsigned char) proxy_password_len;
+    if(sx->proxy_password && proxy_password_len) {
+      /* the length must fit in a single byte */
+      if(proxy_password_len > 255) {
+        failf(data, "Excessive password length for proxy auth");
+        return CURLPX_LONG_PASSWD;
+      }
+      memcpy(socksreq + len, sx->proxy_password, proxy_password_len);
+    }
+    len += proxy_password_len;
+    sxstate(sx, data, CONNECT_AUTH_SEND);
+    DEBUGASSERT(len <= sizeof(sx->buffer));
+    sx->outstanding = len;
+    sx->outp = socksreq;
+  }
+    FALLTHROUGH();
+  case CONNECT_AUTH_SEND:
+    presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH,
+                               "SOCKS5 sub-negotiation request");
+    if(CURLPX_OK != presult)
+      return presult;
+    else if(sx->outstanding) {
+      /* remain in sending state */
+      return CURLPX_OK;
+    }
+    sx->outp = socksreq;
+    sx->outstanding = 2;
+    sxstate(sx, data, CONNECT_AUTH_READ);
+    FALLTHROUGH();
+  case CONNECT_AUTH_READ:
+    presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH,
+                               "SOCKS5 sub-negotiation response");
+    if(CURLPX_OK != presult)
+      return presult;
+    else if(sx->outstanding) {
+      /* remain in reading state */
+      return CURLPX_OK;
+    }
+    /* ignore the first (VER) byte */
+    else if(socksreq[1]) { /* status */
+      failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+            socksreq[0], socksreq[1]);
+      return CURLPX_USER_REJECTED;
+    }
+
+    /* Everything is good so far, user was authenticated! */
+    sxstate(sx, data, CONNECT_REQ_INIT);
+    FALLTHROUGH();
+  case CONNECT_REQ_INIT:
+CONNECT_REQ_INIT:
+    if(socks5_resolve_local) {
+      enum resolve_t rc = Curl_resolv(data, sx->hostname, sx->remote_port,
+                                      TRUE, &dns);
+
+      if(rc == CURLRESOLV_ERROR)
+        return CURLPX_RESOLVE_HOST;
+
+      if(rc == CURLRESOLV_PENDING) {
+        sxstate(sx, data, CONNECT_RESOLVING);
+        return CURLPX_OK;
+      }
+      sxstate(sx, data, CONNECT_RESOLVED);
+      goto CONNECT_RESOLVED;
+    }
+    goto CONNECT_RESOLVE_REMOTE;
+
+  case CONNECT_RESOLVING:
+    /* check if we have the name resolved by now */
+    dns = Curl_fetch_addr(data, sx->hostname, sx->remote_port);
+
+    if(dns) {
+#ifdef CURLRES_ASYNCH
+      data->state.async.dns = dns;
+      data->state.async.done = TRUE;
+#endif
+      infof(data, "SOCKS5: hostname '%s' found", sx->hostname);
+    }
+
+    if(!dns) {
+      result = Curl_resolv_check(data, &dns);
+      if(!dns) {
+        if(result)
+          return CURLPX_RESOLVE_HOST;
+        return CURLPX_OK;
+      }
+    }
+    FALLTHROUGH();
+  case CONNECT_RESOLVED:
+CONNECT_RESOLVED:
+  {
+    char dest[MAX_IPADR_LEN];  /* printable address */
+    struct Curl_addrinfo *hp = NULL;
+    if(dns)
+      hp = dns->addr;
+#ifdef ENABLE_IPV6
+    if(data->set.ipver != CURL_IPRESOLVE_WHATEVER) {
+      int wanted_family = data->set.ipver == CURL_IPRESOLVE_V4 ?
+        AF_INET : AF_INET6;
+      /* scan for the first proper address */
+      while(hp && (hp->ai_family != wanted_family))
+        hp = hp->ai_next;
+    }
+#endif
+    if(!hp) {
+      failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
+            sx->hostname);
+      return CURLPX_RESOLVE_HOST;
+    }
+
+    Curl_printable_address(hp, dest, sizeof(dest));
+
+    len = 0;
+    socksreq[len++] = 5; /* version (SOCKS5) */
+    socksreq[len++] = 1; /* connect */
+    socksreq[len++] = 0; /* must be zero */
+    if(hp->ai_family == AF_INET) {
+      int i;
+      struct sockaddr_in *saddr_in;
+      socksreq[len++] = 1; /* ATYP: IPv4 = 1 */
+
+      saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
+      for(i = 0; i < 4; i++) {
+        socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i];
+      }
+
+      infof(data, "SOCKS5 connect to %s:%d (locally resolved)", dest,
+            sx->remote_port);
+    }
+#ifdef ENABLE_IPV6
+    else if(hp->ai_family == AF_INET6) {
+      int i;
+      struct sockaddr_in6 *saddr_in6;
+      socksreq[len++] = 4; /* ATYP: IPv6 = 4 */
+
+      saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr;
+      for(i = 0; i < 16; i++) {
+        socksreq[len++] =
+          ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i];
+      }
+
+      infof(data, "SOCKS5 connect to [%s]:%d (locally resolved)", dest,
+            sx->remote_port);
+    }
+#endif
+    else {
+      hp = NULL; /* fail! */
+      failf(data, "SOCKS5 connection to %s not supported", dest);
+    }
+
+    Curl_resolv_unlock(data, dns); /* not used anymore from now on */
+    goto CONNECT_REQ_SEND;
+  }
+CONNECT_RESOLVE_REMOTE:
+  case CONNECT_RESOLVE_REMOTE:
+    /* Authentication is complete, now specify destination to the proxy */
+    len = 0;
+    socksreq[len++] = 5; /* version (SOCKS5) */
+    socksreq[len++] = 1; /* connect */
+    socksreq[len++] = 0; /* must be zero */
+
+    if(!socks5_resolve_local) {
+      /* ATYP: domain name = 3,
+         IPv6 == 4,
+         IPv4 == 1 */
+      unsigned char ip4[4];
+#ifdef ENABLE_IPV6
+      if(conn->bits.ipv6_ip) {
+        char ip6[16];
+        if(1 != Curl_inet_pton(AF_INET6, sx->hostname, ip6))
+          return CURLPX_BAD_ADDRESS_TYPE;
+        socksreq[len++] = 4;
+        memcpy(&socksreq[len], ip6, sizeof(ip6));
+        len += sizeof(ip6);
+      }
+      else
+#endif
+      if(1 == Curl_inet_pton(AF_INET, sx->hostname, ip4)) {
+        socksreq[len++] = 1;
+        memcpy(&socksreq[len], ip4, sizeof(ip4));
+        len += sizeof(ip4);
+      }
+      else {
+        socksreq[len++] = 3;
+        socksreq[len++] = (unsigned char) hostname_len; /* one byte length */
+        memcpy(&socksreq[len], sx->hostname, hostname_len); /* w/o NULL */
+        len += hostname_len;
+      }
+      infof(data, "SOCKS5 connect to %s:%d (remotely resolved)",
+            sx->hostname, sx->remote_port);
+    }
+    FALLTHROUGH();
+
+  case CONNECT_REQ_SEND:
+CONNECT_REQ_SEND:
+    /* PORT MSB */
+    socksreq[len++] = (unsigned char)((sx->remote_port >> 8) & 0xff);
+    /* PORT LSB */
+    socksreq[len++] = (unsigned char)(sx->remote_port & 0xff);
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+    if(conn->socks5_gssapi_enctype) {
+      failf(data, "SOCKS5 GSS-API protection not yet implemented.");
+      return CURLPX_GSSAPI_PROTECTION;
+    }
+#endif
+    sx->outp = socksreq;
+    DEBUGASSERT(len <= sizeof(sx->buffer));
+    sx->outstanding = len;
+    sxstate(sx, data, CONNECT_REQ_SENDING);
+    FALLTHROUGH();
+  case CONNECT_REQ_SENDING:
+    presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST,
+                               "SOCKS5 connect request");
+    if(CURLPX_OK != presult)
+      return presult;
+    else if(sx->outstanding) {
+      /* remain in send state */
+      return CURLPX_OK;
+    }
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+    if(conn->socks5_gssapi_enctype) {
+      failf(data, "SOCKS5 GSS-API protection not yet implemented.");
+      return CURLPX_GSSAPI_PROTECTION;
+    }
+#endif
+    sx->outstanding = 10; /* minimum packet size is 10 */
+    sx->outp = socksreq;
+    sxstate(sx, data, CONNECT_REQ_READ);
+    FALLTHROUGH();
+  case CONNECT_REQ_READ:
+    presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK,
+                               "SOCKS5 connect request ack");
+    if(CURLPX_OK != presult)
+      return presult;
+    else if(sx->outstanding) {
+      /* remain in reading state */
+      return CURLPX_OK;
+    }
+    else if(socksreq[0] != 5) { /* version */
+      failf(data,
+            "SOCKS5 reply has wrong version, version should be 5.");
+      return CURLPX_BAD_VERSION;
+    }
+    else if(socksreq[1]) { /* Anything besides 0 is an error */
+      CURLproxycode rc = CURLPX_REPLY_UNASSIGNED;
+      int code = socksreq[1];
+      failf(data, "Can't complete SOCKS5 connection to %s. (%d)",
+            sx->hostname, (unsigned char)socksreq[1]);
+      if(code < 9) {
+        /* RFC 1928 section 6 lists: */
+        static const CURLproxycode lookup[] = {
+          CURLPX_OK,
+          CURLPX_REPLY_GENERAL_SERVER_FAILURE,
+          CURLPX_REPLY_NOT_ALLOWED,
+          CURLPX_REPLY_NETWORK_UNREACHABLE,
+          CURLPX_REPLY_HOST_UNREACHABLE,
+          CURLPX_REPLY_CONNECTION_REFUSED,
+          CURLPX_REPLY_TTL_EXPIRED,
+          CURLPX_REPLY_COMMAND_NOT_SUPPORTED,
+          CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED,
+        };
+        rc = lookup[code];
+      }
+      return rc;
+    }
+
+    /* Fix: in general, returned BND.ADDR is variable length parameter by RFC
+       1928, so the reply packet should be read until the end to avoid errors
+       at subsequent protocol level.
+
+       +----+-----+-------+------+----------+----------+
+       |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
+       +----+-----+-------+------+----------+----------+
+       | 1  |  1  | X'00' |  1   | Variable |    2     |
+       +----+-----+-------+------+----------+----------+
+
+       ATYP:
+       o  IP v4 address: X'01', BND.ADDR = 4 byte
+       o  domain name:  X'03', BND.ADDR = [ 1 byte length, string ]
+       o  IP v6 address: X'04', BND.ADDR = 16 byte
+    */
+
+    /* Calculate real packet size */
+    if(socksreq[3] == 3) {
+      /* domain name */
+      int addrlen = (int) socksreq[4];
+      len = 5 + addrlen + 2;
+    }
+    else if(socksreq[3] == 4) {
+      /* IPv6 */
+      len = 4 + 16 + 2;
+    }
+    else if(socksreq[3] == 1) {
+      len = 4 + 4 + 2;
+    }
+    else {
+      failf(data, "SOCKS5 reply has wrong address type.");
+      return CURLPX_BAD_ADDRESS_TYPE;
+    }
+
+    /* At this point we already read first 10 bytes */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+    if(!conn->socks5_gssapi_enctype) {
+      /* decrypt_gssapi_blockread already read the whole packet */
+#endif
+      if(len > 10) {
+        DEBUGASSERT(len <= sizeof(sx->buffer));
+        sx->outstanding = len - 10; /* get the rest */
+        sx->outp = &socksreq[10];
+        sxstate(sx, data, CONNECT_REQ_READ_MORE);
+      }
+      else {
+        sxstate(sx, data, CONNECT_DONE);
+        break;
+      }
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+    }
+#endif
+    FALLTHROUGH();
+  case CONNECT_REQ_READ_MORE:
+    presult = socks_state_recv(cf, sx, data, CURLPX_RECV_ADDRESS,
+                               "SOCKS5 connect request address");
+    if(CURLPX_OK != presult)
+      return presult;
+    else if(sx->outstanding) {
+      /* remain in reading state */
+      return CURLPX_OK;
+    }
+    sxstate(sx, data, CONNECT_DONE);
+  }
+  infof(data, "SOCKS5 request granted.");
+
+  return CURLPX_OK; /* Proxy was successful! */
+}
+
+static CURLcode connect_SOCKS(struct Curl_cfilter *cf,
+                              struct socks_state *sxstate,
+                              struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  CURLproxycode pxresult = CURLPX_OK;
+  struct connectdata *conn = cf->conn;
+
+  switch(conn->socks_proxy.proxytype) {
+  case CURLPROXY_SOCKS5:
+  case CURLPROXY_SOCKS5_HOSTNAME:
+    pxresult = do_SOCKS5(cf, sxstate, data);
+    break;
+
+  case CURLPROXY_SOCKS4:
+  case CURLPROXY_SOCKS4A:
+    pxresult = do_SOCKS4(cf, sxstate, data);
+    break;
+
+  default:
+    failf(data, "unknown proxytype option given");
+    result = CURLE_COULDNT_CONNECT;
+  } /* switch proxytype */
+  if(pxresult) {
+    result = CURLE_PROXY;
+    data->info.pxcode = pxresult;
+  }
+
+  return result;
+}
+
+static void socks_proxy_cf_free(struct Curl_cfilter *cf)
+{
+  struct socks_state *sxstate = cf->ctx;
+  if(sxstate) {
+    free(sxstate);
+    cf->ctx = NULL;
+  }
+}
+
+/* After a TCP connection to the proxy has been verified, this function does
+   the next magic steps. If 'done' isn't set TRUE, it is not done yet and
+   must be called again.
+
+   Note: this function's sub-functions call failf()
+
+*/
+static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
+                                       struct Curl_easy *data,
+                                       bool blocking, bool *done)
+{
+  CURLcode result;
+  struct connectdata *conn = cf->conn;
+  int sockindex = cf->sockindex;
+  struct socks_state *sx = cf->ctx;
+
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+  if(result || !*done)
+    return result;
+
+  if(!sx) {
+    sx = calloc(1, sizeof(*sx));
+    if(!sx)
+      return CURLE_OUT_OF_MEMORY;
+    cf->ctx = sx;
+  }
+
+  if(sx->state == CONNECT_INIT) {
+    /* for the secondary socket (FTP), use the "connect to host"
+     * but ignore the "connect to port" (use the secondary port)
+     */
+    sxstate(sx, data, CONNECT_SOCKS_INIT);
+    sx->hostname =
+      conn->bits.httpproxy ?
+      conn->http_proxy.host.name :
+      conn->bits.conn_to_host ?
+      conn->conn_to_host.name :
+      sockindex == SECONDARYSOCKET ?
+      conn->secondaryhostname : conn->host.name;
+    sx->remote_port =
+      conn->bits.httpproxy ? (int)conn->http_proxy.port :
+      sockindex == SECONDARYSOCKET ? conn->secondary_port :
+      conn->bits.conn_to_port ? conn->conn_to_port :
+      conn->remote_port;
+    sx->proxy_user = conn->socks_proxy.user;
+    sx->proxy_password = conn->socks_proxy.passwd;
+  }
+
+  result = connect_SOCKS(cf, sx, data);
+  if(!result && sx->state == CONNECT_DONE) {
+    cf->connected = TRUE;
+    Curl_verboseconnect(data, conn, cf->sockindex);
+    socks_proxy_cf_free(cf);
+  }
+
+  *done = cf->connected;
+  return result;
+}
+
+static void socks_cf_adjust_pollset(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data,
+                                     struct easy_pollset *ps)
+{
+  struct socks_state *sx = cf->ctx;
+
+  if(!cf->connected && sx) {
+    /* If we are not connected, the filter below is and has nothing
+     * to wait on, we determine what to wait for. */
+    curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
+    switch(sx->state) {
+    case CONNECT_RESOLVING:
+    case CONNECT_SOCKS_READ:
+    case CONNECT_AUTH_READ:
+    case CONNECT_REQ_READ:
+    case CONNECT_REQ_READ_MORE:
+      Curl_pollset_set_in_only(data, ps, sock);
+      break;
+    default:
+      Curl_pollset_set_out_only(data, ps, sock);
+      break;
+    }
+  }
+}
+
+static void socks_proxy_cf_close(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data)
+{
+
+  DEBUGASSERT(cf->next);
+  cf->connected = FALSE;
+  socks_proxy_cf_free(cf);
+  cf->next->cft->do_close(cf->next, data);
+}
+
+static void socks_proxy_cf_destroy(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data)
+{
+  (void)data;
+  socks_proxy_cf_free(cf);
+}
+
+static void socks_cf_get_host(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              const char **phost,
+                              const char **pdisplay_host,
+                              int *pport)
+{
+  (void)data;
+  if(!cf->connected) {
+    *phost = cf->conn->socks_proxy.host.name;
+    *pdisplay_host = cf->conn->http_proxy.host.dispname;
+    *pport = (int)cf->conn->socks_proxy.port;
+  }
+  else {
+    cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
+  }
+}
+
+struct Curl_cftype Curl_cft_socks_proxy = {
+  "SOCKS-PROXYY",
+  CF_TYPE_IP_CONNECT,
+  0,
+  socks_proxy_cf_destroy,
+  socks_proxy_cf_connect,
+  socks_proxy_cf_close,
+  socks_cf_get_host,
+  socks_cf_adjust_pollset,
+  Curl_cf_def_data_pending,
+  Curl_cf_def_send,
+  Curl_cf_def_recv,
+  Curl_cf_def_cntrl,
+  Curl_cf_def_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  Curl_cf_def_query,
+};
+
+CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
+                                          struct Curl_easy *data)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result;
+
+  (void)data;
+  result = Curl_cf_create(&cf, &Curl_cft_socks_proxy, NULL);
+  if(!result)
+    Curl_conn_cf_insert_after(cf_at, cf);
+  return result;
+}
+
+#endif /* CURL_DISABLE_PROXY */
Index: trunk/src/libs/curl-8.7.1/lib/socks.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/socks.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/socks.h	(revision 104083)
@@ -0,0 +1,61 @@
+#ifndef HEADER_CURL_SOCKS_H
+#define HEADER_CURL_SOCKS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef CURL_DISABLE_PROXY
+#define Curl_SOCKS4(a,b,c,d,e) CURLE_NOT_BUILT_IN
+#define Curl_SOCKS5(a,b,c,d,e,f) CURLE_NOT_BUILT_IN
+#define Curl_SOCKS_getsock(x,y,z) 0
+#else
+/*
+ * Helper read-from-socket functions. Does the same as Curl_read() but it
+ * blocks until all bytes amount of buffersize will be read. No more, no less.
+ *
+ * This is STUPID BLOCKING behavior
+ */
+int Curl_blockread_all(struct Curl_cfilter *cf,
+                       struct Curl_easy *data,
+                       char *buf,
+                       ssize_t buffersize,
+                       ssize_t *n);
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+/*
+ * This function handles the SOCKS5 GSS-API negotiation and initialization
+ */
+CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data);
+#endif
+
+CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
+                                          struct Curl_easy *data);
+
+extern struct Curl_cftype Curl_cft_socks_proxy;
+
+#endif /* CURL_DISABLE_PROXY */
+
+#endif  /* HEADER_CURL_SOCKS_H */
Index: trunk/src/libs/curl-8.7.1/lib/socks_gssapi.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/socks_gssapi.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/socks_gssapi.c	(revision 104083)
@@ -0,0 +1,535 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Markus Moeller, <markus_moeller@compuserve.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_PROXY)
+
+#include "curl_gssapi.h"
+#include "urldata.h"
+#include "sendf.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "timeval.h"
+#include "socks.h"
+#include "warnless.h"
+#include "strdup.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
+
+/*
+ * Helper GSS-API error functions.
+ */
+static int check_gss_err(struct Curl_easy *data,
+                         OM_uint32 major_status,
+                         OM_uint32 minor_status,
+                         const char *function)
+{
+  if(GSS_ERROR(major_status)) {
+    OM_uint32 maj_stat, min_stat;
+    OM_uint32 msg_ctx = 0;
+    gss_buffer_desc status_string = GSS_C_EMPTY_BUFFER;
+    char buf[1024];
+    size_t len;
+
+    len = 0;
+    msg_ctx = 0;
+    while(!msg_ctx) {
+      /* convert major status code (GSS-API error) to text */
+      maj_stat = gss_display_status(&min_stat, major_status,
+                                    GSS_C_GSS_CODE,
+                                    GSS_C_NULL_OID,
+                                    &msg_ctx, &status_string);
+      if(maj_stat == GSS_S_COMPLETE) {
+        if(sizeof(buf) > len + status_string.length + 1) {
+          strcpy(buf + len, (char *) status_string.value);
+          len += status_string.length;
+        }
+        gss_release_buffer(&min_stat, &status_string);
+        break;
+      }
+      gss_release_buffer(&min_stat, &status_string);
+    }
+    if(sizeof(buf) > len + 3) {
+      strcpy(buf + len, ".\n");
+      len += 2;
+    }
+    msg_ctx = 0;
+    while(!msg_ctx) {
+      /* convert minor status code (underlying routine error) to text */
+      maj_stat = gss_display_status(&min_stat, minor_status,
+                                    GSS_C_MECH_CODE,
+                                    GSS_C_NULL_OID,
+                                    &msg_ctx, &status_string);
+      if(maj_stat == GSS_S_COMPLETE) {
+        if(sizeof(buf) > len + status_string.length)
+          strcpy(buf + len, (char *) status_string.value);
+        gss_release_buffer(&min_stat, &status_string);
+        break;
+      }
+      gss_release_buffer(&min_stat, &status_string);
+    }
+    failf(data, "GSS-API error: %s failed: %s", function, buf);
+    return 1;
+  }
+
+  return 0;
+}
+
+CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data)
+{
+  struct connectdata *conn = cf->conn;
+  curl_socket_t sock = conn->sock[cf->sockindex];
+  CURLcode code;
+  ssize_t actualread;
+  ssize_t nwritten;
+  int result;
+  OM_uint32 gss_major_status, gss_minor_status, gss_status;
+  OM_uint32 gss_ret_flags;
+  int gss_conf_state, gss_enc;
+  gss_buffer_desc  service = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc  gss_send_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc  gss_recv_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc  gss_w_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc *gss_token = GSS_C_NO_BUFFER;
+  gss_name_t       server = GSS_C_NO_NAME;
+  gss_name_t       gss_client_name = GSS_C_NO_NAME;
+  unsigned short   us_length;
+  char             *user = NULL;
+  unsigned char socksreq[4]; /* room for GSS-API exchange header only */
+  const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ?
+                           data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd";
+  const size_t serviceptr_length = strlen(serviceptr);
+
+  /*   GSS-API request looks like
+   * +----+------+-----+----------------+
+   * |VER | MTYP | LEN |     TOKEN      |
+   * +----+------+----------------------+
+   * | 1  |  1   |  2  | up to 2^16 - 1 |
+   * +----+------+-----+----------------+
+   */
+
+  /* prepare service name */
+  if(strchr(serviceptr, '/')) {
+    service.length = serviceptr_length;
+    service.value = Curl_memdup(serviceptr, service.length);
+    if(!service.value)
+      return CURLE_OUT_OF_MEMORY;
+
+    gss_major_status = gss_import_name(&gss_minor_status, &service,
+                                       (gss_OID) GSS_C_NULL_OID, &server);
+  }
+  else {
+    service.value = malloc(serviceptr_length +
+                           strlen(conn->socks_proxy.host.name) + 2);
+    if(!service.value)
+      return CURLE_OUT_OF_MEMORY;
+    service.length = serviceptr_length +
+      strlen(conn->socks_proxy.host.name) + 1;
+    msnprintf(service.value, service.length + 1, "%s@%s",
+              serviceptr, conn->socks_proxy.host.name);
+
+    gss_major_status = gss_import_name(&gss_minor_status, &service,
+                                       GSS_C_NT_HOSTBASED_SERVICE, &server);
+  }
+
+  gss_release_buffer(&gss_status, &service); /* clear allocated memory */
+
+  if(check_gss_err(data, gss_major_status,
+                   gss_minor_status, "gss_import_name()")) {
+    failf(data, "Failed to create service name.");
+    gss_release_name(&gss_status, &server);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  (void)curlx_nonblock(sock, FALSE);
+
+  /* As long as we need to keep sending some context info, and there's no  */
+  /* errors, keep sending it...                                            */
+  for(;;) {
+    gss_major_status = Curl_gss_init_sec_context(data,
+                                                 &gss_minor_status,
+                                                 &gss_context,
+                                                 server,
+                                                 &Curl_krb5_mech_oid,
+                                                 NULL,
+                                                 gss_token,
+                                                 &gss_send_token,
+                                                 TRUE,
+                                                 &gss_ret_flags);
+
+    if(gss_token != GSS_C_NO_BUFFER)
+      gss_release_buffer(&gss_status, &gss_recv_token);
+    if(check_gss_err(data, gss_major_status,
+                     gss_minor_status, "gss_init_sec_context")) {
+      gss_release_name(&gss_status, &server);
+      gss_release_buffer(&gss_status, &gss_recv_token);
+      gss_release_buffer(&gss_status, &gss_send_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      failf(data, "Failed to initial GSS-API token.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    if(gss_send_token.length) {
+      socksreq[0] = 1;    /* GSS-API subnegotiation version */
+      socksreq[1] = 1;    /* authentication message type */
+      us_length = htons((short)gss_send_token.length);
+      memcpy(socksreq + 2, &us_length, sizeof(short));
+
+      nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
+      if(code || (4 != nwritten)) {
+        failf(data, "Failed to send GSS-API authentication request.");
+        gss_release_name(&gss_status, &server);
+        gss_release_buffer(&gss_status, &gss_recv_token);
+        gss_release_buffer(&gss_status, &gss_send_token);
+        gss_delete_sec_context(&gss_status, &gss_context, NULL);
+        return CURLE_COULDNT_CONNECT;
+      }
+
+      nwritten = Curl_conn_cf_send(cf->next, data,
+                                   (char *)gss_send_token.value,
+                                   gss_send_token.length, &code);
+      if(code || ((ssize_t)gss_send_token.length != nwritten)) {
+        failf(data, "Failed to send GSS-API authentication token.");
+        gss_release_name(&gss_status, &server);
+        gss_release_buffer(&gss_status, &gss_recv_token);
+        gss_release_buffer(&gss_status, &gss_send_token);
+        gss_delete_sec_context(&gss_status, &gss_context, NULL);
+        return CURLE_COULDNT_CONNECT;
+      }
+
+    }
+
+    gss_release_buffer(&gss_status, &gss_send_token);
+    gss_release_buffer(&gss_status, &gss_recv_token);
+    if(gss_major_status != GSS_S_CONTINUE_NEEDED)
+      break;
+
+    /* analyse response */
+
+    /*   GSS-API response looks like
+     * +----+------+-----+----------------+
+     * |VER | MTYP | LEN |     TOKEN      |
+     * +----+------+----------------------+
+     * | 1  |  1   |  2  | up to 2^16 - 1 |
+     * +----+------+-----+----------------+
+     */
+
+    result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
+    if(result || (actualread != 4)) {
+      failf(data, "Failed to receive GSS-API authentication response.");
+      gss_release_name(&gss_status, &server);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    /* ignore the first (VER) byte */
+    if(socksreq[1] == 255) { /* status / message type */
+      failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+            socksreq[0], socksreq[1]);
+      gss_release_name(&gss_status, &server);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    if(socksreq[1] != 1) { /* status / message type */
+      failf(data, "Invalid GSS-API authentication response type (%d %d).",
+            socksreq[0], socksreq[1]);
+      gss_release_name(&gss_status, &server);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    memcpy(&us_length, socksreq + 2, sizeof(short));
+    us_length = ntohs(us_length);
+
+    gss_recv_token.length = us_length;
+    gss_recv_token.value = malloc(us_length);
+    if(!gss_recv_token.value) {
+      failf(data,
+            "Could not allocate memory for GSS-API authentication "
+            "response token.");
+      gss_release_name(&gss_status, &server);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    result = Curl_blockread_all(cf, data, (char *)gss_recv_token.value,
+                                gss_recv_token.length, &actualread);
+
+    if(result || (actualread != us_length)) {
+      failf(data, "Failed to receive GSS-API authentication token.");
+      gss_release_name(&gss_status, &server);
+      gss_release_buffer(&gss_status, &gss_recv_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    gss_token = &gss_recv_token;
+  }
+
+  gss_release_name(&gss_status, &server);
+
+  /* Everything is good so far, user was authenticated! */
+  gss_major_status = gss_inquire_context(&gss_minor_status, gss_context,
+                                         &gss_client_name, NULL, NULL, NULL,
+                                         NULL, NULL, NULL);
+  if(check_gss_err(data, gss_major_status,
+                   gss_minor_status, "gss_inquire_context")) {
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    gss_release_name(&gss_status, &gss_client_name);
+    failf(data, "Failed to determine user name.");
+    return CURLE_COULDNT_CONNECT;
+  }
+  gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
+                                      &gss_send_token, NULL);
+  if(check_gss_err(data, gss_major_status,
+                   gss_minor_status, "gss_display_name")) {
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    gss_release_name(&gss_status, &gss_client_name);
+    gss_release_buffer(&gss_status, &gss_send_token);
+    failf(data, "Failed to determine user name.");
+    return CURLE_COULDNT_CONNECT;
+  }
+  user = malloc(gss_send_token.length + 1);
+  if(!user) {
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    gss_release_name(&gss_status, &gss_client_name);
+    gss_release_buffer(&gss_status, &gss_send_token);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  memcpy(user, gss_send_token.value, gss_send_token.length);
+  user[gss_send_token.length] = '\0';
+  gss_release_name(&gss_status, &gss_client_name);
+  gss_release_buffer(&gss_status, &gss_send_token);
+  infof(data, "SOCKS5 server authenticated user %s with GSS-API.",user);
+  free(user);
+  user = NULL;
+
+  /* Do encryption */
+  socksreq[0] = 1;    /* GSS-API subnegotiation version */
+  socksreq[1] = 2;    /* encryption message type */
+
+  gss_enc = 0; /* no data protection */
+  /* do confidentiality protection if supported */
+  if(gss_ret_flags & GSS_C_CONF_FLAG)
+    gss_enc = 2;
+  /* else do integrity protection */
+  else if(gss_ret_flags & GSS_C_INTEG_FLAG)
+    gss_enc = 1;
+
+  infof(data, "SOCKS5 server supports GSS-API %s data protection.",
+        (gss_enc == 0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
+  /* force for the moment to no data protection */
+  gss_enc = 0;
+  /*
+   * Sending the encryption type in clear seems wrong. It should be
+   * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
+   * The NEC reference implementations on which this is based is
+   * therefore at fault
+   *
+   *  +------+------+------+.......................+
+   *  + ver  | mtyp | len  |   token               |
+   *  +------+------+------+.......................+
+   *  + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
+   *  +------+------+------+.......................+
+   *
+   *   Where:
+   *
+   *  - "ver" is the protocol version number, here 1 to represent the
+   *    first version of the SOCKS/GSS-API protocol
+   *
+   *  - "mtyp" is the message type, here 2 to represent a protection
+   *    -level negotiation message
+   *
+   *  - "len" is the length of the "token" field in octets
+   *
+   *  - "token" is the GSS-API encapsulated protection level
+   *
+   * The token is produced by encapsulating an octet containing the
+   * required protection level using gss_seal()/gss_wrap() with conf_req
+   * set to FALSE.  The token is verified using gss_unseal()/
+   * gss_unwrap().
+   *
+   */
+  if(data->set.socks5_gssapi_nec) {
+    us_length = htons((short)1);
+    memcpy(socksreq + 2, &us_length, sizeof(short));
+  }
+  else {
+    gss_send_token.length = 1;
+    gss_send_token.value = Curl_memdup(&gss_enc, 1);
+    if(!gss_send_token.value) {
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0,
+                                GSS_C_QOP_DEFAULT, &gss_send_token,
+                                &gss_conf_state, &gss_w_token);
+
+    if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_wrap")) {
+      gss_release_buffer(&gss_status, &gss_send_token);
+      gss_release_buffer(&gss_status, &gss_w_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      failf(data, "Failed to wrap GSS-API encryption value into token.");
+      return CURLE_COULDNT_CONNECT;
+    }
+    gss_release_buffer(&gss_status, &gss_send_token);
+
+    us_length = htons((short)gss_w_token.length);
+    memcpy(socksreq + 2, &us_length, sizeof(short));
+  }
+
+  nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
+  if(code  || (4 != nwritten)) {
+    failf(data, "Failed to send GSS-API encryption request.");
+    gss_release_buffer(&gss_status, &gss_w_token);
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if(data->set.socks5_gssapi_nec) {
+    memcpy(socksreq, &gss_enc, 1);
+    nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, &code);
+    if(code || ( 1 != nwritten)) {
+      failf(data, "Failed to send GSS-API encryption type.");
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+  }
+  else {
+    nwritten = Curl_conn_cf_send(cf->next, data,
+                                 (char *)gss_w_token.value,
+                                 gss_w_token.length, &code);
+    if(code || ((ssize_t)gss_w_token.length != nwritten)) {
+      failf(data, "Failed to send GSS-API encryption type.");
+      gss_release_buffer(&gss_status, &gss_w_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+    gss_release_buffer(&gss_status, &gss_w_token);
+  }
+
+  result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
+  if(result || (actualread != 4)) {
+    failf(data, "Failed to receive GSS-API encryption response.");
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  /* ignore the first (VER) byte */
+  if(socksreq[1] == 255) { /* status / message type */
+    failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+          socksreq[0], socksreq[1]);
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if(socksreq[1] != 2) { /* status / message type */
+    failf(data, "Invalid GSS-API encryption response type (%d %d).",
+          socksreq[0], socksreq[1]);
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  memcpy(&us_length, socksreq + 2, sizeof(short));
+  us_length = ntohs(us_length);
+
+  gss_recv_token.length = us_length;
+  gss_recv_token.value = malloc(gss_recv_token.length);
+  if(!gss_recv_token.value) {
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  result = Curl_blockread_all(cf, data, (char *)gss_recv_token.value,
+                              gss_recv_token.length, &actualread);
+
+  if(result || (actualread != us_length)) {
+    failf(data, "Failed to receive GSS-API encryption type.");
+    gss_release_buffer(&gss_status, &gss_recv_token);
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if(!data->set.socks5_gssapi_nec) {
+    gss_major_status = gss_unwrap(&gss_minor_status, gss_context,
+                                  &gss_recv_token, &gss_w_token,
+                                  0, GSS_C_QOP_DEFAULT);
+
+    if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_unwrap")) {
+      gss_release_buffer(&gss_status, &gss_recv_token);
+      gss_release_buffer(&gss_status, &gss_w_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      failf(data, "Failed to unwrap GSS-API encryption value into token.");
+      return CURLE_COULDNT_CONNECT;
+    }
+    gss_release_buffer(&gss_status, &gss_recv_token);
+
+    if(gss_w_token.length != 1) {
+      failf(data, "Invalid GSS-API encryption response length (%zu).",
+            gss_w_token.length);
+      gss_release_buffer(&gss_status, &gss_w_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    memcpy(socksreq, gss_w_token.value, gss_w_token.length);
+    gss_release_buffer(&gss_status, &gss_w_token);
+  }
+  else {
+    if(gss_recv_token.length != 1) {
+      failf(data, "Invalid GSS-API encryption response length (%zu).",
+            gss_recv_token.length);
+      gss_release_buffer(&gss_status, &gss_recv_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    memcpy(socksreq, gss_recv_token.value, gss_recv_token.length);
+    gss_release_buffer(&gss_status, &gss_recv_token);
+  }
+
+  (void)curlx_nonblock(sock, TRUE);
+
+  infof(data, "SOCKS5 access with%s protection granted.",
+        (socksreq[0] == 0)?"out GSS-API data":
+        ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
+
+  conn->socks5_gssapi_enctype = socksreq[0];
+  if(socksreq[0] == 0)
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+
+  return CURLE_OK;
+}
+
+#endif /* HAVE_GSSAPI && !CURL_DISABLE_PROXY */
Index: trunk/src/libs/curl-8.7.1/lib/socks_sspi.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/socks_sspi.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/socks_sspi.c	(revision 104083)
@@ -0,0 +1,620 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Markus Moeller, <markus_moeller@compuserve.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_PROXY)
+
+#include "urldata.h"
+#include "sendf.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "strerror.h"
+#include "timeval.h"
+#include "socks.h"
+#include "curl_sspi.h"
+#include "curl_multibyte.h"
+#include "warnless.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Helper sspi error functions.
+ */
+static int check_sspi_err(struct Curl_easy *data,
+                          SECURITY_STATUS status,
+                          const char *function)
+{
+  if(status != SEC_E_OK &&
+     status != SEC_I_COMPLETE_AND_CONTINUE &&
+     status != SEC_I_COMPLETE_NEEDED &&
+     status != SEC_I_CONTINUE_NEEDED) {
+    char buffer[STRERROR_LEN];
+    failf(data, "SSPI error: %s failed: %s", function,
+          Curl_sspi_strerror(status, buffer, sizeof(buffer)));
+    return 1;
+  }
+  return 0;
+}
+
+/* This is the SSPI-using version of this function */
+CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data)
+{
+  struct connectdata *conn = cf->conn;
+  curl_socket_t sock = conn->sock[cf->sockindex];
+  CURLcode code;
+  ssize_t actualread;
+  ssize_t written;
+  int result;
+  /* Needs GSS-API authentication */
+  SECURITY_STATUS status;
+  unsigned long sspi_ret_flags = 0;
+  unsigned char gss_enc;
+  SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3];
+  SecBufferDesc input_desc, output_desc, wrap_desc;
+  SecPkgContext_Sizes sspi_sizes;
+  CredHandle cred_handle;
+  CtxtHandle sspi_context;
+  PCtxtHandle context_handle = NULL;
+  SecPkgCredentials_Names names;
+  TimeStamp expiry;
+  char *service_name = NULL;
+  unsigned short us_length;
+  unsigned long qop;
+  unsigned char socksreq[4]; /* room for GSS-API exchange header only */
+  const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
+    data->set.str[STRING_PROXY_SERVICE_NAME]  : "rcmd";
+  const size_t service_length = strlen(service);
+
+  /*   GSS-API request looks like
+   * +----+------+-----+----------------+
+   * |VER | MTYP | LEN |     TOKEN      |
+   * +----+------+----------------------+
+   * | 1  |  1   |  2  | up to 2^16 - 1 |
+   * +----+------+-----+----------------+
+   */
+
+  /* prepare service name */
+  if(strchr(service, '/')) {
+    service_name = strdup(service);
+    if(!service_name)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  else {
+    service_name = malloc(service_length +
+                          strlen(conn->socks_proxy.host.name) + 2);
+    if(!service_name)
+      return CURLE_OUT_OF_MEMORY;
+    msnprintf(service_name, service_length +
+              strlen(conn->socks_proxy.host.name) + 2, "%s/%s",
+              service, conn->socks_proxy.host.name);
+  }
+
+  input_desc.cBuffers = 1;
+  input_desc.pBuffers = &sspi_recv_token;
+  input_desc.ulVersion = SECBUFFER_VERSION;
+
+  sspi_recv_token.BufferType = SECBUFFER_TOKEN;
+  sspi_recv_token.cbBuffer = 0;
+  sspi_recv_token.pvBuffer = NULL;
+
+  output_desc.cBuffers = 1;
+  output_desc.pBuffers = &sspi_send_token;
+  output_desc.ulVersion = SECBUFFER_VERSION;
+
+  sspi_send_token.BufferType = SECBUFFER_TOKEN;
+  sspi_send_token.cbBuffer = 0;
+  sspi_send_token.pvBuffer = NULL;
+
+  wrap_desc.cBuffers = 3;
+  wrap_desc.pBuffers = sspi_w_token;
+  wrap_desc.ulVersion = SECBUFFER_VERSION;
+
+  cred_handle.dwLower = 0;
+  cred_handle.dwUpper = 0;
+
+  status = s_pSecFn->AcquireCredentialsHandle(NULL,
+                                              (TCHAR *) TEXT("Kerberos"),
+                                              SECPKG_CRED_OUTBOUND,
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              &cred_handle,
+                                              &expiry);
+
+  if(check_sspi_err(data, status, "AcquireCredentialsHandle")) {
+    failf(data, "Failed to acquire credentials.");
+    free(service_name);
+    s_pSecFn->FreeCredentialsHandle(&cred_handle);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  (void)curlx_nonblock(sock, FALSE);
+
+  /* As long as we need to keep sending some context info, and there's no  */
+  /* errors, keep sending it...                                            */
+  for(;;) {
+    TCHAR *sname;
+
+    sname = curlx_convert_UTF8_to_tchar(service_name);
+    if(!sname)
+      return CURLE_OUT_OF_MEMORY;
+
+    status = s_pSecFn->InitializeSecurityContext(&cred_handle,
+                                                 context_handle,
+                                                 sname,
+                                                 ISC_REQ_MUTUAL_AUTH |
+                                                 ISC_REQ_ALLOCATE_MEMORY |
+                                                 ISC_REQ_CONFIDENTIALITY |
+                                                 ISC_REQ_REPLAY_DETECT,
+                                                 0,
+                                                 SECURITY_NATIVE_DREP,
+                                                 &input_desc,
+                                                 0,
+                                                 &sspi_context,
+                                                 &output_desc,
+                                                 &sspi_ret_flags,
+                                                 &expiry);
+
+    curlx_unicodefree(sname);
+
+    if(sspi_recv_token.pvBuffer) {
+      s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+      sspi_recv_token.pvBuffer = NULL;
+      sspi_recv_token.cbBuffer = 0;
+    }
+
+    if(check_sspi_err(data, status, "InitializeSecurityContext")) {
+      free(service_name);
+      s_pSecFn->FreeCredentialsHandle(&cred_handle);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      if(sspi_recv_token.pvBuffer)
+        s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+      failf(data, "Failed to initialise security context.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    if(sspi_send_token.cbBuffer) {
+      socksreq[0] = 1;    /* GSS-API subnegotiation version */
+      socksreq[1] = 1;    /* authentication message type */
+      us_length = htons((short)sspi_send_token.cbBuffer);
+      memcpy(socksreq + 2, &us_length, sizeof(short));
+
+      written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
+      if(code || (4 != written)) {
+        failf(data, "Failed to send SSPI authentication request.");
+        free(service_name);
+        if(sspi_send_token.pvBuffer)
+          s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+        if(sspi_recv_token.pvBuffer)
+          s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+        s_pSecFn->FreeCredentialsHandle(&cred_handle);
+        s_pSecFn->DeleteSecurityContext(&sspi_context);
+        return CURLE_COULDNT_CONNECT;
+      }
+
+      written = Curl_conn_cf_send(cf->next, data,
+                                  (char *)sspi_send_token.pvBuffer,
+                                  sspi_send_token.cbBuffer, &code);
+      if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
+        failf(data, "Failed to send SSPI authentication token.");
+        free(service_name);
+        if(sspi_send_token.pvBuffer)
+          s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+        if(sspi_recv_token.pvBuffer)
+          s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+        s_pSecFn->FreeCredentialsHandle(&cred_handle);
+        s_pSecFn->DeleteSecurityContext(&sspi_context);
+        return CURLE_COULDNT_CONNECT;
+      }
+
+    }
+
+    if(sspi_send_token.pvBuffer) {
+      s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+      sspi_send_token.pvBuffer = NULL;
+    }
+    sspi_send_token.cbBuffer = 0;
+
+    if(sspi_recv_token.pvBuffer) {
+      s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+      sspi_recv_token.pvBuffer = NULL;
+    }
+    sspi_recv_token.cbBuffer = 0;
+
+    if(status != SEC_I_CONTINUE_NEEDED)
+      break;
+
+    /* analyse response */
+
+    /*   GSS-API response looks like
+     * +----+------+-----+----------------+
+     * |VER | MTYP | LEN |     TOKEN      |
+     * +----+------+----------------------+
+     * | 1  |  1   |  2  | up to 2^16 - 1 |
+     * +----+------+-----+----------------+
+     */
+
+    result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
+    if(result || (actualread != 4)) {
+      failf(data, "Failed to receive SSPI authentication response.");
+      free(service_name);
+      s_pSecFn->FreeCredentialsHandle(&cred_handle);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    /* ignore the first (VER) byte */
+    if(socksreq[1] == 255) { /* status / message type */
+      failf(data, "User was rejected by the SOCKS5 server (%u %u).",
+            (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
+      free(service_name);
+      s_pSecFn->FreeCredentialsHandle(&cred_handle);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    if(socksreq[1] != 1) { /* status / message type */
+      failf(data, "Invalid SSPI authentication response type (%u %u).",
+            (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
+      free(service_name);
+      s_pSecFn->FreeCredentialsHandle(&cred_handle);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    memcpy(&us_length, socksreq + 2, sizeof(short));
+    us_length = ntohs(us_length);
+
+    sspi_recv_token.cbBuffer = us_length;
+    sspi_recv_token.pvBuffer = malloc(us_length);
+
+    if(!sspi_recv_token.pvBuffer) {
+      free(service_name);
+      s_pSecFn->FreeCredentialsHandle(&cred_handle);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer,
+                                sspi_recv_token.cbBuffer, &actualread);
+
+    if(result || (actualread != us_length)) {
+      failf(data, "Failed to receive SSPI authentication token.");
+      free(service_name);
+      if(sspi_recv_token.pvBuffer)
+        s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+      s_pSecFn->FreeCredentialsHandle(&cred_handle);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    context_handle = &sspi_context;
+  }
+
+  free(service_name);
+
+  /* Everything is good so far, user was authenticated! */
+  status = s_pSecFn->QueryCredentialsAttributes(&cred_handle,
+                                                SECPKG_CRED_ATTR_NAMES,
+                                                &names);
+  s_pSecFn->FreeCredentialsHandle(&cred_handle);
+  if(check_sspi_err(data, status, "QueryCredentialAttributes")) {
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    s_pSecFn->FreeContextBuffer(names.sUserName);
+    failf(data, "Failed to determine user name.");
+    return CURLE_COULDNT_CONNECT;
+  }
+  else {
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+    char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName);
+    infof(data, "SOCKS5 server authenticated user %s with GSS-API.",
+          (user_utf8 ? user_utf8 : "(unknown)"));
+    curlx_unicodefree(user_utf8);
+#endif
+    s_pSecFn->FreeContextBuffer(names.sUserName);
+  }
+
+  /* Do encryption */
+  socksreq[0] = 1;    /* GSS-API subnegotiation version */
+  socksreq[1] = 2;    /* encryption message type */
+
+  gss_enc = 0; /* no data protection */
+  /* do confidentiality protection if supported */
+  if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY)
+    gss_enc = 2;
+  /* else do integrity protection */
+  else if(sspi_ret_flags & ISC_REQ_INTEGRITY)
+    gss_enc = 1;
+
+  infof(data, "SOCKS5 server supports GSS-API %s data protection.",
+        (gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") );
+  /* force to no data protection, avoid encryption/decryption for now */
+  gss_enc = 0;
+  /*
+   * Sending the encryption type in clear seems wrong. It should be
+   * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
+   * The NEC reference implementations on which this is based is
+   * therefore at fault
+   *
+   *  +------+------+------+.......................+
+   *  + ver  | mtyp | len  |   token               |
+   *  +------+------+------+.......................+
+   *  + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
+   *  +------+------+------+.......................+
+   *
+   *   Where:
+   *
+   *  - "ver" is the protocol version number, here 1 to represent the
+   *    first version of the SOCKS/GSS-API protocol
+   *
+   *  - "mtyp" is the message type, here 2 to represent a protection
+   *    -level negotiation message
+   *
+   *  - "len" is the length of the "token" field in octets
+   *
+   *  - "token" is the GSS-API encapsulated protection level
+   *
+   * The token is produced by encapsulating an octet containing the
+   * required protection level using gss_seal()/gss_wrap() with conf_req
+   * set to FALSE.  The token is verified using gss_unseal()/
+   * gss_unwrap().
+   *
+   */
+
+  if(data->set.socks5_gssapi_nec) {
+    us_length = htons((short)1);
+    memcpy(socksreq + 2, &us_length, sizeof(short));
+  }
+  else {
+    status = s_pSecFn->QueryContextAttributes(&sspi_context,
+                                              SECPKG_ATTR_SIZES,
+                                              &sspi_sizes);
+    if(check_sspi_err(data, status, "QueryContextAttributes")) {
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      failf(data, "Failed to query security context attributes.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer;
+    sspi_w_token[0].BufferType = SECBUFFER_TOKEN;
+    sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer);
+
+    if(!sspi_w_token[0].pvBuffer) {
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    sspi_w_token[1].cbBuffer = 1;
+    sspi_w_token[1].pvBuffer = malloc(1);
+    if(!sspi_w_token[1].pvBuffer) {
+      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1);
+    sspi_w_token[2].BufferType = SECBUFFER_PADDING;
+    sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize;
+    sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize);
+    if(!sspi_w_token[2].pvBuffer) {
+      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    status = s_pSecFn->EncryptMessage(&sspi_context,
+                                      KERB_WRAP_NO_ENCRYPT,
+                                      &wrap_desc,
+                                      0);
+    if(check_sspi_err(data, status, "EncryptMessage")) {
+      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      failf(data, "Failed to query security context attributes.");
+      return CURLE_COULDNT_CONNECT;
+    }
+    sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer
+      + sspi_w_token[1].cbBuffer
+      + sspi_w_token[2].cbBuffer;
+    sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer);
+    if(!sspi_send_token.pvBuffer) {
+      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer,
+           sspi_w_token[0].cbBuffer);
+    memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer,
+           sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
+    memcpy((PUCHAR) sspi_send_token.pvBuffer
+           + sspi_w_token[0].cbBuffer
+           + sspi_w_token[1].cbBuffer,
+           sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer);
+
+    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+    sspi_w_token[0].pvBuffer = NULL;
+    sspi_w_token[0].cbBuffer = 0;
+    s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+    sspi_w_token[1].pvBuffer = NULL;
+    sspi_w_token[1].cbBuffer = 0;
+    s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+    sspi_w_token[2].pvBuffer = NULL;
+    sspi_w_token[2].cbBuffer = 0;
+
+    us_length = htons((short)sspi_send_token.cbBuffer);
+    memcpy(socksreq + 2, &us_length, sizeof(short));
+  }
+
+  written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
+  if(code || (4 != written)) {
+    failf(data, "Failed to send SSPI encryption request.");
+    if(sspi_send_token.pvBuffer)
+      s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if(data->set.socks5_gssapi_nec) {
+    memcpy(socksreq, &gss_enc, 1);
+    written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, &code);
+    if(code || (1 != written)) {
+      failf(data, "Failed to send SSPI encryption type.");
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+  }
+  else {
+    written = Curl_conn_cf_send(cf->next, data,
+                                (char *)sspi_send_token.pvBuffer,
+                                sspi_send_token.cbBuffer, &code);
+    if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
+      failf(data, "Failed to send SSPI encryption type.");
+      if(sspi_send_token.pvBuffer)
+        s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+    if(sspi_send_token.pvBuffer)
+      s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+  }
+
+  result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
+  if(result || (actualread != 4)) {
+    failf(data, "Failed to receive SSPI encryption response.");
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  /* ignore the first (VER) byte */
+  if(socksreq[1] == 255) { /* status / message type */
+    failf(data, "User was rejected by the SOCKS5 server (%u %u).",
+          (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if(socksreq[1] != 2) { /* status / message type */
+    failf(data, "Invalid SSPI encryption response type (%u %u).",
+          (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  memcpy(&us_length, socksreq + 2, sizeof(short));
+  us_length = ntohs(us_length);
+
+  sspi_w_token[0].cbBuffer = us_length;
+  sspi_w_token[0].pvBuffer = malloc(us_length);
+  if(!sspi_w_token[0].pvBuffer) {
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer,
+                              sspi_w_token[0].cbBuffer, &actualread);
+
+  if(result || (actualread != us_length)) {
+    failf(data, "Failed to receive SSPI encryption type.");
+    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+
+  if(!data->set.socks5_gssapi_nec) {
+    wrap_desc.cBuffers = 2;
+    sspi_w_token[0].BufferType = SECBUFFER_STREAM;
+    sspi_w_token[1].BufferType = SECBUFFER_DATA;
+    sspi_w_token[1].cbBuffer = 0;
+    sspi_w_token[1].pvBuffer = NULL;
+
+    status = s_pSecFn->DecryptMessage(&sspi_context,
+                                      &wrap_desc,
+                                      0,
+                                      &qop);
+
+    if(check_sspi_err(data, status, "DecryptMessage")) {
+      if(sspi_w_token[0].pvBuffer)
+        s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      if(sspi_w_token[1].pvBuffer)
+        s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      failf(data, "Failed to query security context attributes.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    if(sspi_w_token[1].cbBuffer != 1) {
+      failf(data, "Invalid SSPI encryption response length (%lu).",
+            (unsigned long)sspi_w_token[1].cbBuffer);
+      if(sspi_w_token[0].pvBuffer)
+        s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      if(sspi_w_token[1].pvBuffer)
+        s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
+    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+    s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+  }
+  else {
+    if(sspi_w_token[0].cbBuffer != 1) {
+      failf(data, "Invalid SSPI encryption response length (%lu).",
+            (unsigned long)sspi_w_token[0].cbBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+    memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer);
+    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+  }
+  (void)curlx_nonblock(sock, TRUE);
+
+  infof(data, "SOCKS5 access with%s protection granted.",
+        (socksreq[0] == 0)?"out GSS-API data":
+        ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
+
+  /* For later use if encryption is required
+     conn->socks5_gssapi_enctype = socksreq[0];
+     if(socksreq[0] != 0)
+       conn->socks5_sspi_context = sspi_context;
+     else {
+       s_pSecFn->DeleteSecurityContext(&sspi_context);
+       conn->socks5_sspi_context = sspi_context;
+     }
+  */
+  return CURLE_OK;
+}
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/speedcheck.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/speedcheck.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/speedcheck.c	(revision 104083)
@@ -0,0 +1,79 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "multiif.h"
+#include "speedcheck.h"
+
+void Curl_speedinit(struct Curl_easy *data)
+{
+  memset(&data->state.keeps_speed, 0, sizeof(struct curltime));
+}
+
+/*
+ * @unittest: 1606
+ */
+CURLcode Curl_speedcheck(struct Curl_easy *data,
+                         struct curltime now)
+{
+  if(data->req.keepon & KEEP_RECV_PAUSE)
+    /* A paused transfer is not qualified for speed checks */
+    return CURLE_OK;
+
+  if((data->progress.current_speed >= 0) && data->set.low_speed_time) {
+    if(data->progress.current_speed < data->set.low_speed_limit) {
+      if(!data->state.keeps_speed.tv_sec)
+        /* under the limit at this very moment */
+        data->state.keeps_speed = now;
+      else {
+        /* how long has it been under the limit */
+        timediff_t howlong = Curl_timediff(now, data->state.keeps_speed);
+
+        if(howlong >= data->set.low_speed_time * 1000) {
+          /* too long */
+          failf(data,
+                "Operation too slow. "
+                "Less than %ld bytes/sec transferred the last %ld seconds",
+                data->set.low_speed_limit,
+                data->set.low_speed_time);
+          return CURLE_OPERATION_TIMEDOUT;
+        }
+      }
+    }
+    else
+      /* faster right now */
+      data->state.keeps_speed.tv_sec = 0;
+  }
+
+  if(data->set.low_speed_limit)
+    /* if low speed limit is enabled, set the expire timer to make this
+       connection's speed get checked again in a second */
+    Curl_expire(data, 1000, EXPIRE_SPEEDCHECK);
+
+  return CURLE_OK;
+}
Index: trunk/src/libs/curl-8.7.1/lib/speedcheck.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/speedcheck.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/speedcheck.h	(revision 104083)
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_SPEEDCHECK_H
+#define HEADER_CURL_SPEEDCHECK_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "timeval.h"
+
+void Curl_speedinit(struct Curl_easy *data);
+CURLcode Curl_speedcheck(struct Curl_easy *data,
+                         struct curltime now);
+
+#endif /* HEADER_CURL_SPEEDCHECK_H */
Index: trunk/src/libs/curl-8.7.1/lib/splay.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/splay.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/splay.c	(revision 104083)
@@ -0,0 +1,278 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "splay.h"
+
+/*
+ * This macro compares two node keys i and j and returns:
+ *
+ *  negative value: when i is smaller than j
+ *  zero          : when i is equal   to   j
+ *  positive when : when i is larger  than j
+ */
+#define compare(i,j) Curl_splaycomparekeys((i),(j))
+
+/*
+ * Splay using the key i (which may or may not be in the tree.) The starting
+ * root is t.
+ */
+struct Curl_tree *Curl_splay(struct curltime i,
+                             struct Curl_tree *t)
+{
+  struct Curl_tree N, *l, *r, *y;
+
+  if(!t)
+    return t;
+  N.smaller = N.larger = NULL;
+  l = r = &N;
+
+  for(;;) {
+    long comp = compare(i, t->key);
+    if(comp < 0) {
+      if(!t->smaller)
+        break;
+      if(compare(i, t->smaller->key) < 0) {
+        y = t->smaller;                           /* rotate smaller */
+        t->smaller = y->larger;
+        y->larger = t;
+        t = y;
+        if(!t->smaller)
+          break;
+      }
+      r->smaller = t;                               /* link smaller */
+      r = t;
+      t = t->smaller;
+    }
+    else if(comp > 0) {
+      if(!t->larger)
+        break;
+      if(compare(i, t->larger->key) > 0) {
+        y = t->larger;                          /* rotate larger */
+        t->larger = y->smaller;
+        y->smaller = t;
+        t = y;
+        if(!t->larger)
+          break;
+      }
+      l->larger = t;                              /* link larger */
+      l = t;
+      t = t->larger;
+    }
+    else
+      break;
+  }
+
+  l->larger = t->smaller;                                /* assemble */
+  r->smaller = t->larger;
+  t->smaller = N.larger;
+  t->larger = N.smaller;
+
+  return t;
+}
+
+/* Insert key i into the tree t.  Return a pointer to the resulting tree or
+ * NULL if something went wrong.
+ *
+ * @unittest: 1309
+ */
+struct Curl_tree *Curl_splayinsert(struct curltime i,
+                                   struct Curl_tree *t,
+                                   struct Curl_tree *node)
+{
+  static const struct curltime KEY_NOTUSED = {
+    ~0, -1
+  }; /* will *NEVER* appear */
+
+  if(!node)
+    return t;
+
+  if(t) {
+    t = Curl_splay(i, t);
+    if(compare(i, t->key) == 0) {
+      /* There already exists a node in the tree with the very same key. Build
+         a doubly-linked circular list of nodes. We add the new 'node' struct
+         to the end of this list. */
+
+      node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED
+                                  to quickly identify this node as a subnode */
+      node->samen = t;
+      node->samep = t->samep;
+      t->samep->samen = node;
+      t->samep = node;
+
+      return t; /* the root node always stays the same */
+    }
+  }
+
+  if(!t) {
+    node->smaller = node->larger = NULL;
+  }
+  else if(compare(i, t->key) < 0) {
+    node->smaller = t->smaller;
+    node->larger = t;
+    t->smaller = NULL;
+
+  }
+  else {
+    node->larger = t->larger;
+    node->smaller = t;
+    t->larger = NULL;
+  }
+  node->key = i;
+
+  /* no identical nodes (yet), we are the only one in the list of nodes */
+  node->samen = node;
+  node->samep = node;
+  return node;
+}
+
+/* Finds and deletes the best-fit node from the tree. Return a pointer to the
+   resulting tree.  best-fit means the smallest node if it is not larger than
+   the key */
+struct Curl_tree *Curl_splaygetbest(struct curltime i,
+                                    struct Curl_tree *t,
+                                    struct Curl_tree **removed)
+{
+  static const struct curltime tv_zero = {0, 0};
+  struct Curl_tree *x;
+
+  if(!t) {
+    *removed = NULL; /* none removed since there was no root */
+    return NULL;
+  }
+
+  /* find smallest */
+  t = Curl_splay(tv_zero, t);
+  if(compare(i, t->key) < 0) {
+    /* even the smallest is too big */
+    *removed = NULL;
+    return t;
+  }
+
+  /* FIRST! Check if there is a list with identical keys */
+  x = t->samen;
+  if(x != t) {
+    /* there is, pick one from the list */
+
+    /* 'x' is the new root node */
+
+    x->key = t->key;
+    x->larger = t->larger;
+    x->smaller = t->smaller;
+    x->samep = t->samep;
+    t->samep->samen = x;
+
+    *removed = t;
+    return x; /* new root */
+  }
+
+  /* we splayed the tree to the smallest element, there is no smaller */
+  x = t->larger;
+  *removed = t;
+
+  return x;
+}
+
+
+/* Deletes the very node we point out from the tree if it's there. Stores a
+ * pointer to the new resulting tree in 'newroot'.
+ *
+ * Returns zero on success and non-zero on errors!
+ * When returning error, it does not touch the 'newroot' pointer.
+ *
+ * NOTE: when the last node of the tree is removed, there's no tree left so
+ * 'newroot' will be made to point to NULL.
+ *
+ * @unittest: 1309
+ */
+int Curl_splayremove(struct Curl_tree *t,
+                     struct Curl_tree *removenode,
+                     struct Curl_tree **newroot)
+{
+  static const struct curltime KEY_NOTUSED = {
+    ~0, -1
+  }; /* will *NEVER* appear */
+  struct Curl_tree *x;
+
+  if(!t || !removenode)
+    return 1;
+
+  if(compare(KEY_NOTUSED, removenode->key) == 0) {
+    /* Key set to NOTUSED means it is a subnode within a 'same' linked list
+       and thus we can unlink it easily. */
+    if(removenode->samen == removenode)
+      /* A non-subnode should never be set to KEY_NOTUSED */
+      return 3;
+
+    removenode->samep->samen = removenode->samen;
+    removenode->samen->samep = removenode->samep;
+
+    /* Ensures that double-remove gets caught. */
+    removenode->samen = removenode;
+
+    *newroot = t; /* return the same root */
+    return 0;
+  }
+
+  t = Curl_splay(removenode->key, t);
+
+  /* First make sure that we got the same root node as the one we want
+     to remove, as otherwise we might be trying to remove a node that
+     isn't actually in the tree.
+
+     We cannot just compare the keys here as a double remove in quick
+     succession of a node with key != KEY_NOTUSED && same != NULL
+     could return the same key but a different node. */
+  if(t != removenode)
+    return 2;
+
+  /* Check if there is a list with identical sizes, as then we're trying to
+     remove the root node of a list of nodes with identical keys. */
+  x = t->samen;
+  if(x != t) {
+    /* 'x' is the new root node, we just make it use the root node's
+       smaller/larger links */
+
+    x->key = t->key;
+    x->larger = t->larger;
+    x->smaller = t->smaller;
+    x->samep = t->samep;
+    t->samep->samen = x;
+  }
+  else {
+    /* Remove the root node */
+    if(!t->smaller)
+      x = t->larger;
+    else {
+      x = Curl_splay(removenode->key, t->smaller);
+      x->larger = t->larger;
+    }
+  }
+
+  *newroot = x; /* store new root pointer */
+
+  return 0;
+}
Index: trunk/src/libs/curl-8.7.1/lib/splay.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/splay.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/splay.h	(revision 104083)
@@ -0,0 +1,58 @@
+#ifndef HEADER_CURL_SPLAY_H
+#define HEADER_CURL_SPLAY_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+#include "timeval.h"
+
+struct Curl_tree {
+  struct Curl_tree *smaller; /* smaller node */
+  struct Curl_tree *larger;  /* larger node */
+  struct Curl_tree *samen;   /* points to the next node with identical key */
+  struct Curl_tree *samep;   /* points to the prev node with identical key */
+  struct curltime key;        /* this node's "sort" key */
+  void *payload;             /* data the splay code doesn't care about */
+};
+
+struct Curl_tree *Curl_splay(struct curltime i,
+                             struct Curl_tree *t);
+
+struct Curl_tree *Curl_splayinsert(struct curltime key,
+                                   struct Curl_tree *t,
+                                   struct Curl_tree *newnode);
+
+struct Curl_tree *Curl_splaygetbest(struct curltime key,
+                                    struct Curl_tree *t,
+                                    struct Curl_tree **removed);
+
+int Curl_splayremove(struct Curl_tree *t,
+                     struct Curl_tree *removenode,
+                     struct Curl_tree **newroot);
+
+#define Curl_splaycomparekeys(i,j) ( ((i.tv_sec)  < (j.tv_sec)) ? -1 : \
+                                   ( ((i.tv_sec)  > (j.tv_sec)) ?  1 : \
+                                   ( ((i.tv_usec) < (j.tv_usec)) ? -1 : \
+                                   ( ((i.tv_usec) > (j.tv_usec)) ?  1 : 0))))
+
+#endif /* HEADER_CURL_SPLAY_H */
Index: trunk/src/libs/curl-8.7.1/lib/strcase.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/strcase.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/strcase.c	(revision 104083)
@@ -0,0 +1,204 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "strcase.h"
+
+/* Mapping table to go from lowercase to uppercase for plain ASCII.*/
+static const unsigned char touppermap[256] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 65,
+66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
+134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
+166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
+182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
+198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213,
+214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
+230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
+246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+};
+
+/* Mapping table to go from uppercase to lowercase for plain ASCII.*/
+static const unsigned char tolowermap[256] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95,
+96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+};
+
+
+/* Portable, consistent toupper. Do not use toupper() because its behavior is
+   altered by the current locale. */
+char Curl_raw_toupper(char in)
+{
+  return touppermap[(unsigned char) in];
+}
+
+
+/* Portable, consistent tolower. Do not use tolower() because its behavior is
+   altered by the current locale. */
+char Curl_raw_tolower(char in)
+{
+  return tolowermap[(unsigned char) in];
+}
+
+/*
+ * curl_strequal() is for doing "raw" case insensitive strings. This is meant
+ * to be locale independent and only compare strings we know are safe for
+ * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
+ * further explanations as to why this function is necessary.
+ */
+
+static int casecompare(const char *first, const char *second)
+{
+  while(*first && *second) {
+    if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
+      /* get out of the loop as soon as they don't match */
+      return 0;
+    first++;
+    second++;
+  }
+  /* If we're here either the strings are the same or the length is different.
+     We can just test if the "current" character is non-zero for one and zero
+     for the other. Note that the characters may not be exactly the same even
+     if they match, we only want to compare zero-ness. */
+  return !*first == !*second;
+}
+
+/* --- public function --- */
+int curl_strequal(const char *first, const char *second)
+{
+  if(first && second)
+    /* both pointers point to something then compare them */
+    return casecompare(first, second);
+
+  /* if both pointers are NULL then treat them as equal */
+  return (NULL == first && NULL == second);
+}
+
+static int ncasecompare(const char *first, const char *second, size_t max)
+{
+  while(*first && *second && max) {
+    if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
+      return 0;
+    max--;
+    first++;
+    second++;
+  }
+  if(0 == max)
+    return 1; /* they are equal this far */
+
+  return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
+}
+
+/* --- public function --- */
+int curl_strnequal(const char *first, const char *second, size_t max)
+{
+  if(first && second)
+    /* both pointers point to something then compare them */
+    return ncasecompare(first, second, max);
+
+  /* if both pointers are NULL then treat them as equal if max is non-zero */
+  return (NULL == first && NULL == second && max);
+}
+/* Copy an upper case version of the string from src to dest.  The
+ * strings may overlap.  No more than n characters of the string are copied
+ * (including any NUL) and the destination string will NOT be
+ * NUL-terminated if that limit is reached.
+ */
+void Curl_strntoupper(char *dest, const char *src, size_t n)
+{
+  if(n < 1)
+    return;
+
+  do {
+    *dest++ = Curl_raw_toupper(*src);
+  } while(*src++ && --n);
+}
+
+/* Copy a lower case version of the string from src to dest.  The
+ * strings may overlap.  No more than n characters of the string are copied
+ * (including any NUL) and the destination string will NOT be
+ * NUL-terminated if that limit is reached.
+ */
+void Curl_strntolower(char *dest, const char *src, size_t n)
+{
+  if(n < 1)
+    return;
+
+  do {
+    *dest++ = Curl_raw_tolower(*src);
+  } while(*src++ && --n);
+}
+
+/* Compare case-sensitive NUL-terminated strings, taking care of possible
+ * null pointers. Return true if arguments match.
+ */
+bool Curl_safecmp(char *a, char *b)
+{
+  if(a && b)
+    return !strcmp(a, b);
+  return !a && !b;
+}
+
+/*
+ * Curl_timestrcmp() returns 0 if the two strings are identical. The time this
+ * function spends is a function of the shortest string, not of the contents.
+ */
+int Curl_timestrcmp(const char *a, const char *b)
+{
+  int match = 0;
+  int i = 0;
+
+  if(a && b) {
+    while(1) {
+      match |= a[i]^b[i];
+      if(!a[i] || !b[i])
+        break;
+      i++;
+    }
+  }
+  else
+    return a || b;
+  return match;
+}
Index: trunk/src/libs/curl-8.7.1/lib/strcase.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/strcase.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/strcase.h	(revision 104083)
@@ -0,0 +1,54 @@
+#ifndef HEADER_CURL_STRCASE_H
+#define HEADER_CURL_STRCASE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+/*
+ * Only "raw" case insensitive strings. This is meant to be locale independent
+ * and only compare strings we know are safe for this.
+ *
+ * The function is capable of comparing a-z case insensitively.
+ *
+ * Result is 1 if text matches and 0 if not.
+ */
+
+#define strcasecompare(a,b) curl_strequal(a,b)
+#define strncasecompare(a,b,c) curl_strnequal(a,b,c)
+
+char Curl_raw_toupper(char in);
+char Curl_raw_tolower(char in);
+
+/* checkprefix() is a shorter version of the above, used when the first
+   argument is the string literal */
+#define checkprefix(a,b)    curl_strnequal(b, STRCONST(a))
+
+void Curl_strntoupper(char *dest, const char *src, size_t n);
+void Curl_strntolower(char *dest, const char *src, size_t n);
+
+bool Curl_safecmp(char *a, char *b);
+int Curl_timestrcmp(const char *first, const char *second);
+
+#endif /* HEADER_CURL_STRCASE_H */
Index: trunk/src/libs/curl-8.7.1/lib/strdup.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/strdup.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/strdup.c	(revision 104083)
@@ -0,0 +1,143 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#ifdef _WIN32
+#include <wchar.h>
+#endif
+
+#include "strdup.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef HAVE_STRDUP
+char *Curl_strdup(const char *str)
+{
+  size_t len;
+  char *newstr;
+
+  if(!str)
+    return (char *)NULL;
+
+  len = strlen(str) + 1;
+
+  newstr = malloc(len);
+  if(!newstr)
+    return (char *)NULL;
+
+  memcpy(newstr, str, len);
+  return newstr;
+}
+#endif
+
+#ifdef _WIN32
+/***************************************************************************
+ *
+ * Curl_wcsdup(source)
+ *
+ * Copies the 'source' wchar string to a newly allocated buffer (that is
+ * returned).
+ *
+ * Returns the new pointer or NULL on failure.
+ *
+ ***************************************************************************/
+wchar_t *Curl_wcsdup(const wchar_t *src)
+{
+  size_t length = wcslen(src);
+
+  if(length > (SIZE_T_MAX / sizeof(wchar_t)) - 1)
+    return (wchar_t *)NULL; /* integer overflow */
+
+  return (wchar_t *)Curl_memdup(src, (length + 1) * sizeof(wchar_t));
+}
+#endif
+
+/***************************************************************************
+ *
+ * Curl_memdup(source, length)
+ *
+ * Copies the 'source' data to a newly allocated buffer (that is
+ * returned). Copies 'length' bytes.
+ *
+ * Returns the new pointer or NULL on failure.
+ *
+ ***************************************************************************/
+void *Curl_memdup(const void *src, size_t length)
+{
+  void *buffer = malloc(length);
+  if(!buffer)
+    return NULL; /* fail */
+
+  memcpy(buffer, src, length);
+
+  return buffer;
+}
+
+/***************************************************************************
+ *
+ * Curl_memdup0(source, length)
+ *
+ * Copies the 'source' string to a newly allocated buffer (that is returned).
+ * Copies 'length' bytes then adds a null terminator.
+ *
+ * Returns the new pointer or NULL on failure.
+ *
+ ***************************************************************************/
+void *Curl_memdup0(const char *src, size_t length)
+{
+  char *buf = malloc(length + 1);
+  if(!buf)
+    return NULL;
+  memcpy(buf, src, length);
+  buf[length] = 0;
+  return buf;
+}
+
+/***************************************************************************
+ *
+ * Curl_saferealloc(ptr, size)
+ *
+ * Does a normal realloc(), but will free the data pointer if the realloc
+ * fails. If 'size' is non-zero, it will free the data and return a failure.
+ *
+ * This convenience function is provided and used to help us avoid a common
+ * mistake pattern when we could pass in a zero, catch the NULL return and end
+ * up free'ing the memory twice.
+ *
+ * Returns the new pointer or NULL on failure.
+ *
+ ***************************************************************************/
+void *Curl_saferealloc(void *ptr, size_t size)
+{
+  void *datap = realloc(ptr, size);
+  if(size && !datap)
+    /* only free 'ptr' if size was non-zero */
+    free(ptr);
+  return datap;
+}
Index: trunk/src/libs/curl-8.7.1/lib/strdup.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/strdup.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/strdup.h	(revision 104083)
@@ -0,0 +1,38 @@
+#ifndef HEADER_CURL_STRDUP_H
+#define HEADER_CURL_STRDUP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifndef HAVE_STRDUP
+char *Curl_strdup(const char *str);
+#endif
+#ifdef _WIN32
+wchar_t* Curl_wcsdup(const wchar_t* src);
+#endif
+void *Curl_memdup(const void *src, size_t buffer_length);
+void *Curl_saferealloc(void *ptr, size_t size);
+void *Curl_memdup0(const char *src, size_t length);
+
+#endif /* HEADER_CURL_STRDUP_H */
Index: trunk/src/libs/curl-8.7.1/lib/strerror.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/strerror.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/strerror.c	(revision 104083)
@@ -0,0 +1,1114 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_STRERROR_R
+#  if (!defined(HAVE_POSIX_STRERROR_R) && \
+       !defined(HAVE_GLIBC_STRERROR_R)) || \
+      (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R))
+#    error "strerror_r MUST be either POSIX, glibc style"
+#  endif
+#endif
+
+#include <curl/curl.h>
+
+#ifdef USE_LIBIDN2
+#include <idn2.h>
+#endif
+
+#ifdef USE_WINDOWS_SSPI
+#include "curl_sspi.h"
+#endif
+
+#include "strerror.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if defined(_WIN32) || defined(_WIN32_WCE)
+#define PRESERVE_WINDOWS_ERROR_CODE
+#endif
+
+const char *
+curl_easy_strerror(CURLcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  switch(error) {
+  case CURLE_OK:
+    return "No error";
+
+  case CURLE_UNSUPPORTED_PROTOCOL:
+    return "Unsupported protocol";
+
+  case CURLE_FAILED_INIT:
+    return "Failed initialization";
+
+  case CURLE_URL_MALFORMAT:
+    return "URL using bad/illegal format or missing URL";
+
+  case CURLE_NOT_BUILT_IN:
+    return "A requested feature, protocol or option was not found built-in in"
+      " this libcurl due to a build-time decision.";
+
+  case CURLE_COULDNT_RESOLVE_PROXY:
+    return "Couldn't resolve proxy name";
+
+  case CURLE_COULDNT_RESOLVE_HOST:
+    return "Couldn't resolve host name";
+
+  case CURLE_COULDNT_CONNECT:
+    return "Couldn't connect to server";
+
+  case CURLE_WEIRD_SERVER_REPLY:
+    return "Weird server reply";
+
+  case CURLE_REMOTE_ACCESS_DENIED:
+    return "Access denied to remote resource";
+
+  case CURLE_FTP_ACCEPT_FAILED:
+    return "FTP: The server failed to connect to data port";
+
+  case CURLE_FTP_ACCEPT_TIMEOUT:
+    return "FTP: Accepting server connect has timed out";
+
+  case CURLE_FTP_PRET_FAILED:
+    return "FTP: The server did not accept the PRET command.";
+
+  case CURLE_FTP_WEIRD_PASS_REPLY:
+    return "FTP: unknown PASS reply";
+
+  case CURLE_FTP_WEIRD_PASV_REPLY:
+    return "FTP: unknown PASV reply";
+
+  case CURLE_FTP_WEIRD_227_FORMAT:
+    return "FTP: unknown 227 response format";
+
+  case CURLE_FTP_CANT_GET_HOST:
+    return "FTP: can't figure out the host in the PASV response";
+
+  case CURLE_HTTP2:
+    return "Error in the HTTP2 framing layer";
+
+  case CURLE_FTP_COULDNT_SET_TYPE:
+    return "FTP: couldn't set file type";
+
+  case CURLE_PARTIAL_FILE:
+    return "Transferred a partial file";
+
+  case CURLE_FTP_COULDNT_RETR_FILE:
+    return "FTP: couldn't retrieve (RETR failed) the specified file";
+
+  case CURLE_QUOTE_ERROR:
+    return "Quote command returned error";
+
+  case CURLE_HTTP_RETURNED_ERROR:
+    return "HTTP response code said error";
+
+  case CURLE_WRITE_ERROR:
+    return "Failed writing received data to disk/application";
+
+  case CURLE_UPLOAD_FAILED:
+    return "Upload failed (at start/before it took off)";
+
+  case CURLE_READ_ERROR:
+    return "Failed to open/read local data from file/application";
+
+  case CURLE_OUT_OF_MEMORY:
+    return "Out of memory";
+
+  case CURLE_OPERATION_TIMEDOUT:
+    return "Timeout was reached";
+
+  case CURLE_FTP_PORT_FAILED:
+    return "FTP: command PORT failed";
+
+  case CURLE_FTP_COULDNT_USE_REST:
+    return "FTP: command REST failed";
+
+  case CURLE_RANGE_ERROR:
+    return "Requested range was not delivered by the server";
+
+  case CURLE_HTTP_POST_ERROR:
+    return "Internal problem setting up the POST";
+
+  case CURLE_SSL_CONNECT_ERROR:
+    return "SSL connect error";
+
+  case CURLE_BAD_DOWNLOAD_RESUME:
+    return "Couldn't resume download";
+
+  case CURLE_FILE_COULDNT_READ_FILE:
+    return "Couldn't read a file:// file";
+
+  case CURLE_LDAP_CANNOT_BIND:
+    return "LDAP: cannot bind";
+
+  case CURLE_LDAP_SEARCH_FAILED:
+    return "LDAP: search failed";
+
+  case CURLE_FUNCTION_NOT_FOUND:
+    return "A required function in the library was not found";
+
+  case CURLE_ABORTED_BY_CALLBACK:
+    return "Operation was aborted by an application callback";
+
+  case CURLE_BAD_FUNCTION_ARGUMENT:
+    return "A libcurl function was given a bad argument";
+
+  case CURLE_INTERFACE_FAILED:
+    return "Failed binding local connection end";
+
+  case CURLE_TOO_MANY_REDIRECTS:
+    return "Number of redirects hit maximum amount";
+
+  case CURLE_UNKNOWN_OPTION:
+    return "An unknown option was passed in to libcurl";
+
+  case CURLE_SETOPT_OPTION_SYNTAX:
+    return "Malformed option provided in a setopt";
+
+  case CURLE_GOT_NOTHING:
+    return "Server returned nothing (no headers, no data)";
+
+  case CURLE_SSL_ENGINE_NOTFOUND:
+    return "SSL crypto engine not found";
+
+  case CURLE_SSL_ENGINE_SETFAILED:
+    return "Can not set SSL crypto engine as default";
+
+  case CURLE_SSL_ENGINE_INITFAILED:
+    return "Failed to initialise SSL crypto engine";
+
+  case CURLE_SEND_ERROR:
+    return "Failed sending data to the peer";
+
+  case CURLE_RECV_ERROR:
+    return "Failure when receiving data from the peer";
+
+  case CURLE_SSL_CERTPROBLEM:
+    return "Problem with the local SSL certificate";
+
+  case CURLE_SSL_CIPHER:
+    return "Couldn't use specified SSL cipher";
+
+  case CURLE_PEER_FAILED_VERIFICATION:
+    return "SSL peer certificate or SSH remote key was not OK";
+
+  case CURLE_SSL_CACERT_BADFILE:
+    return "Problem with the SSL CA cert (path? access rights?)";
+
+  case CURLE_BAD_CONTENT_ENCODING:
+    return "Unrecognized or bad HTTP Content or Transfer-Encoding";
+
+  case CURLE_FILESIZE_EXCEEDED:
+    return "Maximum file size exceeded";
+
+  case CURLE_USE_SSL_FAILED:
+    return "Requested SSL level failed";
+
+  case CURLE_SSL_SHUTDOWN_FAILED:
+    return "Failed to shut down the SSL connection";
+
+  case CURLE_SSL_CRL_BADFILE:
+    return "Failed to load CRL file (path? access rights?, format?)";
+
+  case CURLE_SSL_ISSUER_ERROR:
+    return "Issuer check against peer certificate failed";
+
+  case CURLE_SEND_FAIL_REWIND:
+    return "Send failed since rewinding of the data stream failed";
+
+  case CURLE_LOGIN_DENIED:
+    return "Login denied";
+
+  case CURLE_TFTP_NOTFOUND:
+    return "TFTP: File Not Found";
+
+  case CURLE_TFTP_PERM:
+    return "TFTP: Access Violation";
+
+  case CURLE_REMOTE_DISK_FULL:
+    return "Disk full or allocation exceeded";
+
+  case CURLE_TFTP_ILLEGAL:
+    return "TFTP: Illegal operation";
+
+  case CURLE_TFTP_UNKNOWNID:
+    return "TFTP: Unknown transfer ID";
+
+  case CURLE_REMOTE_FILE_EXISTS:
+    return "Remote file already exists";
+
+  case CURLE_TFTP_NOSUCHUSER:
+    return "TFTP: No such user";
+
+  case CURLE_REMOTE_FILE_NOT_FOUND:
+    return "Remote file not found";
+
+  case CURLE_SSH:
+    return "Error in the SSH layer";
+
+  case CURLE_AGAIN:
+    return "Socket not ready for send/recv";
+
+  case CURLE_RTSP_CSEQ_ERROR:
+    return "RTSP CSeq mismatch or invalid CSeq";
+
+  case CURLE_RTSP_SESSION_ERROR:
+    return "RTSP session error";
+
+  case CURLE_FTP_BAD_FILE_LIST:
+    return "Unable to parse FTP file list";
+
+  case CURLE_CHUNK_FAILED:
+    return "Chunk callback failed";
+
+  case CURLE_NO_CONNECTION_AVAILABLE:
+    return "The max connection limit is reached";
+
+  case CURLE_SSL_PINNEDPUBKEYNOTMATCH:
+    return "SSL public key does not match pinned public key";
+
+  case CURLE_SSL_INVALIDCERTSTATUS:
+    return "SSL server certificate status verification FAILED";
+
+  case CURLE_HTTP2_STREAM:
+    return "Stream error in the HTTP/2 framing layer";
+
+  case CURLE_RECURSIVE_API_CALL:
+    return "API function called from within callback";
+
+  case CURLE_AUTH_ERROR:
+    return "An authentication function returned an error";
+
+  case CURLE_HTTP3:
+    return "HTTP/3 error";
+
+  case CURLE_QUIC_CONNECT_ERROR:
+    return "QUIC connection error";
+
+  case CURLE_PROXY:
+    return "proxy handshake error";
+
+  case CURLE_SSL_CLIENTCERT:
+    return "SSL Client Certificate required";
+
+  case CURLE_UNRECOVERABLE_POLL:
+    return "Unrecoverable error in select/poll";
+
+  case CURLE_TOO_LARGE:
+    return "A value or data field grew larger than allowed";
+
+    /* error codes not used by current libcurl */
+  case CURLE_OBSOLETE20:
+  case CURLE_OBSOLETE24:
+  case CURLE_OBSOLETE29:
+  case CURLE_OBSOLETE32:
+  case CURLE_OBSOLETE40:
+  case CURLE_OBSOLETE44:
+  case CURLE_OBSOLETE46:
+  case CURLE_OBSOLETE50:
+  case CURLE_OBSOLETE51:
+  case CURLE_OBSOLETE57:
+  case CURLE_OBSOLETE62:
+  case CURLE_OBSOLETE75:
+  case CURLE_OBSOLETE76:
+  case CURL_LAST:
+    break;
+  }
+  /*
+   * By using a switch, gcc -Wall will complain about enum values
+   * which do not appear, helping keep this function up-to-date.
+   * By using gcc -Wall -Werror, you can't forget.
+   *
+   * A table would not have the same benefit.  Most compilers will
+   * generate code very similar to a table in any case, so there
+   * is little performance gain from a table.  And something is broken
+   * for the user's application, anyways, so does it matter how fast
+   * it _doesn't_ work?
+   *
+   * The line number for the error will be near this comment, which
+   * is why it is here, and not at the start of the switch.
+   */
+  return "Unknown error";
+#else
+  if(!error)
+    return "No error";
+  else
+    return "Error";
+#endif
+}
+
+const char *
+curl_multi_strerror(CURLMcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  switch(error) {
+  case CURLM_CALL_MULTI_PERFORM:
+    return "Please call curl_multi_perform() soon";
+
+  case CURLM_OK:
+    return "No error";
+
+  case CURLM_BAD_HANDLE:
+    return "Invalid multi handle";
+
+  case CURLM_BAD_EASY_HANDLE:
+    return "Invalid easy handle";
+
+  case CURLM_OUT_OF_MEMORY:
+    return "Out of memory";
+
+  case CURLM_INTERNAL_ERROR:
+    return "Internal error";
+
+  case CURLM_BAD_SOCKET:
+    return "Invalid socket argument";
+
+  case CURLM_UNKNOWN_OPTION:
+    return "Unknown option";
+
+  case CURLM_ADDED_ALREADY:
+    return "The easy handle is already added to a multi handle";
+
+  case CURLM_RECURSIVE_API_CALL:
+    return "API function called from within callback";
+
+  case CURLM_WAKEUP_FAILURE:
+    return "Wakeup is unavailable or failed";
+
+  case CURLM_BAD_FUNCTION_ARGUMENT:
+    return "A libcurl function was given a bad argument";
+
+  case CURLM_ABORTED_BY_CALLBACK:
+    return "Operation was aborted by an application callback";
+
+  case CURLM_UNRECOVERABLE_POLL:
+    return "Unrecoverable error in select/poll";
+
+  case CURLM_LAST:
+    break;
+  }
+
+  return "Unknown error";
+#else
+  if(error == CURLM_OK)
+    return "No error";
+  else
+    return "Error";
+#endif
+}
+
+const char *
+curl_share_strerror(CURLSHcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  switch(error) {
+  case CURLSHE_OK:
+    return "No error";
+
+  case CURLSHE_BAD_OPTION:
+    return "Unknown share option";
+
+  case CURLSHE_IN_USE:
+    return "Share currently in use";
+
+  case CURLSHE_INVALID:
+    return "Invalid share handle";
+
+  case CURLSHE_NOMEM:
+    return "Out of memory";
+
+  case CURLSHE_NOT_BUILT_IN:
+    return "Feature not enabled in this library";
+
+  case CURLSHE_LAST:
+    break;
+  }
+
+  return "CURLSHcode unknown";
+#else
+  if(error == CURLSHE_OK)
+    return "No error";
+  else
+    return "Error";
+#endif
+}
+
+const char *
+curl_url_strerror(CURLUcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  switch(error) {
+  case CURLUE_OK:
+    return "No error";
+
+  case CURLUE_BAD_HANDLE:
+    return "An invalid CURLU pointer was passed as argument";
+
+  case CURLUE_BAD_PARTPOINTER:
+    return "An invalid 'part' argument was passed as argument";
+
+  case CURLUE_MALFORMED_INPUT:
+    return "Malformed input to a URL function";
+
+  case CURLUE_BAD_PORT_NUMBER:
+    return "Port number was not a decimal number between 0 and 65535";
+
+  case CURLUE_UNSUPPORTED_SCHEME:
+    return "Unsupported URL scheme";
+
+  case CURLUE_URLDECODE:
+    return "URL decode error, most likely because of rubbish in the input";
+
+  case CURLUE_OUT_OF_MEMORY:
+    return "A memory function failed";
+
+  case CURLUE_USER_NOT_ALLOWED:
+    return "Credentials was passed in the URL when prohibited";
+
+  case CURLUE_UNKNOWN_PART:
+    return "An unknown part ID was passed to a URL API function";
+
+  case CURLUE_NO_SCHEME:
+    return "No scheme part in the URL";
+
+  case CURLUE_NO_USER:
+    return "No user part in the URL";
+
+  case CURLUE_NO_PASSWORD:
+    return "No password part in the URL";
+
+  case CURLUE_NO_OPTIONS:
+    return "No options part in the URL";
+
+  case CURLUE_NO_HOST:
+    return "No host part in the URL";
+
+  case CURLUE_NO_PORT:
+    return "No port part in the URL";
+
+  case CURLUE_NO_QUERY:
+    return "No query part in the URL";
+
+  case CURLUE_NO_FRAGMENT:
+    return "No fragment part in the URL";
+
+  case CURLUE_NO_ZONEID:
+    return "No zoneid part in the URL";
+
+  case CURLUE_BAD_LOGIN:
+    return "Bad login part";
+
+  case CURLUE_BAD_IPV6:
+    return "Bad IPv6 address";
+
+  case CURLUE_BAD_HOSTNAME:
+    return "Bad hostname";
+
+  case CURLUE_BAD_FILE_URL:
+    return "Bad file:// URL";
+
+  case CURLUE_BAD_SLASHES:
+    return "Unsupported number of slashes following scheme";
+
+  case CURLUE_BAD_SCHEME:
+    return "Bad scheme";
+
+  case CURLUE_BAD_PATH:
+    return "Bad path";
+
+  case CURLUE_BAD_FRAGMENT:
+    return "Bad fragment";
+
+  case CURLUE_BAD_QUERY:
+    return "Bad query";
+
+  case CURLUE_BAD_PASSWORD:
+    return "Bad password";
+
+  case CURLUE_BAD_USER:
+    return "Bad user";
+
+  case CURLUE_LACKS_IDN:
+    return "libcurl lacks IDN support";
+
+  case CURLUE_TOO_LARGE:
+    return "A value or data field is larger than allowed";
+
+  case CURLUE_LAST:
+    break;
+  }
+
+  return "CURLUcode unknown";
+#else
+  if(error == CURLUE_OK)
+    return "No error";
+  else
+    return "Error";
+#endif
+}
+
+#ifdef USE_WINSOCK
+/* This is a helper function for Curl_strerror that converts Winsock error
+ * codes (WSAGetLastError) to error messages.
+ * Returns NULL if no error message was found for error code.
+ */
+static const char *
+get_winsock_error(int err, char *buf, size_t len)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  const char *p;
+  size_t alen;
+#endif
+
+  if(!len)
+    return NULL;
+
+  *buf = '\0';
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)err;
+  return NULL;
+#else
+  switch(err) {
+  case WSAEINTR:
+    p = "Call interrupted";
+    break;
+  case WSAEBADF:
+    p = "Bad file";
+    break;
+  case WSAEACCES:
+    p = "Bad access";
+    break;
+  case WSAEFAULT:
+    p = "Bad argument";
+    break;
+  case WSAEINVAL:
+    p = "Invalid arguments";
+    break;
+  case WSAEMFILE:
+    p = "Out of file descriptors";
+    break;
+  case WSAEWOULDBLOCK:
+    p = "Call would block";
+    break;
+  case WSAEINPROGRESS:
+  case WSAEALREADY:
+    p = "Blocking call in progress";
+    break;
+  case WSAENOTSOCK:
+    p = "Descriptor is not a socket";
+    break;
+  case WSAEDESTADDRREQ:
+    p = "Need destination address";
+    break;
+  case WSAEMSGSIZE:
+    p = "Bad message size";
+    break;
+  case WSAEPROTOTYPE:
+    p = "Bad protocol";
+    break;
+  case WSAENOPROTOOPT:
+    p = "Protocol option is unsupported";
+    break;
+  case WSAEPROTONOSUPPORT:
+    p = "Protocol is unsupported";
+    break;
+  case WSAESOCKTNOSUPPORT:
+    p = "Socket is unsupported";
+    break;
+  case WSAEOPNOTSUPP:
+    p = "Operation not supported";
+    break;
+  case WSAEAFNOSUPPORT:
+    p = "Address family not supported";
+    break;
+  case WSAEPFNOSUPPORT:
+    p = "Protocol family not supported";
+    break;
+  case WSAEADDRINUSE:
+    p = "Address already in use";
+    break;
+  case WSAEADDRNOTAVAIL:
+    p = "Address not available";
+    break;
+  case WSAENETDOWN:
+    p = "Network down";
+    break;
+  case WSAENETUNREACH:
+    p = "Network unreachable";
+    break;
+  case WSAENETRESET:
+    p = "Network has been reset";
+    break;
+  case WSAECONNABORTED:
+    p = "Connection was aborted";
+    break;
+  case WSAECONNRESET:
+    p = "Connection was reset";
+    break;
+  case WSAENOBUFS:
+    p = "No buffer space";
+    break;
+  case WSAEISCONN:
+    p = "Socket is already connected";
+    break;
+  case WSAENOTCONN:
+    p = "Socket is not connected";
+    break;
+  case WSAESHUTDOWN:
+    p = "Socket has been shut down";
+    break;
+  case WSAETOOMANYREFS:
+    p = "Too many references";
+    break;
+  case WSAETIMEDOUT:
+    p = "Timed out";
+    break;
+  case WSAECONNREFUSED:
+    p = "Connection refused";
+    break;
+  case WSAELOOP:
+    p = "Loop??";
+    break;
+  case WSAENAMETOOLONG:
+    p = "Name too long";
+    break;
+  case WSAEHOSTDOWN:
+    p = "Host down";
+    break;
+  case WSAEHOSTUNREACH:
+    p = "Host unreachable";
+    break;
+  case WSAENOTEMPTY:
+    p = "Not empty";
+    break;
+  case WSAEPROCLIM:
+    p = "Process limit reached";
+    break;
+  case WSAEUSERS:
+    p = "Too many users";
+    break;
+  case WSAEDQUOT:
+    p = "Bad quota";
+    break;
+  case WSAESTALE:
+    p = "Something is stale";
+    break;
+  case WSAEREMOTE:
+    p = "Remote error";
+    break;
+#ifdef WSAEDISCON  /* missing in SalfordC! */
+  case WSAEDISCON:
+    p = "Disconnected";
+    break;
+#endif
+    /* Extended Winsock errors */
+  case WSASYSNOTREADY:
+    p = "Winsock library is not ready";
+    break;
+  case WSANOTINITIALISED:
+    p = "Winsock library not initialised";
+    break;
+  case WSAVERNOTSUPPORTED:
+    p = "Winsock version not supported";
+    break;
+
+    /* getXbyY() errors (already handled in herrmsg):
+     * Authoritative Answer: Host not found */
+  case WSAHOST_NOT_FOUND:
+    p = "Host not found";
+    break;
+
+    /* Non-Authoritative: Host not found, or SERVERFAIL */
+  case WSATRY_AGAIN:
+    p = "Host not found, try again";
+    break;
+
+    /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+  case WSANO_RECOVERY:
+    p = "Unrecoverable error in call to nameserver";
+    break;
+
+    /* Valid name, no data record of requested type */
+  case WSANO_DATA:
+    p = "No data record of requested type";
+    break;
+
+  default:
+    return NULL;
+  }
+  alen = strlen(p);
+  if(alen < len)
+    strcpy(buf, p);
+  return buf;
+#endif
+}
+#endif   /* USE_WINSOCK */
+
+#if defined(_WIN32) || defined(_WIN32_WCE)
+/* This is a helper function for Curl_strerror that converts Windows API error
+ * codes (GetLastError) to error messages.
+ * Returns NULL if no error message was found for error code.
+ */
+static const char *
+get_winapi_error(int err, char *buf, size_t buflen)
+{
+  char *p;
+  wchar_t wbuf[256];
+
+  if(!buflen)
+    return NULL;
+
+  *buf = '\0';
+  *wbuf = L'\0';
+
+  /* We return the local codepage version of the error string because if it is
+     output to the user's terminal it will likely be with functions which
+     expect the local codepage (eg fprintf, failf, infof).
+     FormatMessageW -> wcstombs is used for Windows CE compatibility. */
+  if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM |
+                     FORMAT_MESSAGE_IGNORE_INSERTS), NULL, err,
+                    LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) {
+    size_t written = wcstombs(buf, wbuf, buflen - 1);
+    if(written != (size_t)-1)
+      buf[written] = '\0';
+    else
+      *buf = '\0';
+  }
+
+  /* Truncate multiple lines */
+  p = strchr(buf, '\n');
+  if(p) {
+    if(p > buf && *(p-1) == '\r')
+      *(p-1) = '\0';
+    else
+      *p = '\0';
+  }
+
+  return (*buf ? buf : NULL);
+}
+#endif /* _WIN32 || _WIN32_WCE */
+
+/*
+ * Our thread-safe and smart strerror() replacement.
+ *
+ * The 'err' argument passed in to this function MUST be a true errno number
+ * as reported on this system. We do no range checking on the number before
+ * we pass it to the "number-to-message" conversion function and there might
+ * be systems that don't do proper range checking in there themselves.
+ *
+ * We don't do range checking (on systems other than Windows) since there is
+ * no good reliable and portable way to do it.
+ *
+ * On Windows different types of error codes overlap. This function has an
+ * order of preference when trying to match error codes:
+ * CRT (errno), Winsock (WSAGetLastError), Windows API (GetLastError).
+ *
+ * It may be more correct to call one of the variant functions instead:
+ * Call Curl_sspi_strerror if the error code is definitely Windows SSPI.
+ * Call Curl_winapi_strerror if the error code is definitely Windows API.
+ */
+const char *Curl_strerror(int err, char *buf, size_t buflen)
+{
+#ifdef PRESERVE_WINDOWS_ERROR_CODE
+  DWORD old_win_err = GetLastError();
+#endif
+  int old_errno = errno;
+  char *p;
+
+  if(!buflen)
+    return NULL;
+
+#ifndef _WIN32
+  DEBUGASSERT(err >= 0);
+#endif
+
+  *buf = '\0';
+
+#if defined(_WIN32) || defined(_WIN32_WCE)
+#if defined(_WIN32)
+  /* 'sys_nerr' is the maximum errno number, it is not widely portable */
+  if(err >= 0 && err < sys_nerr)
+    msnprintf(buf, buflen, "%s", sys_errlist[err]);
+  else
+#endif
+  {
+    if(
+#ifdef USE_WINSOCK
+       !get_winsock_error(err, buf, buflen) &&
+#endif
+       !get_winapi_error((DWORD)err, buf, buflen))
+      msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err);
+  }
+#else /* not Windows coming up */
+
+#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R)
+ /*
+  * The POSIX-style strerror_r() may set errno to ERANGE if insufficient
+  * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated
+  * message string, or EINVAL if 'errnum' is not a valid error number.
+  */
+  if(0 != strerror_r(err, buf, buflen)) {
+    if('\0' == buf[0])
+      msnprintf(buf, buflen, "Unknown error %d", err);
+  }
+#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)
+ /*
+  * The glibc-style strerror_r() only *might* use the buffer we pass to
+  * the function, but it always returns the error message as a pointer,
+  * so we must copy that string unconditionally (if non-NULL).
+  */
+  {
+    char buffer[256];
+    char *msg = strerror_r(err, buffer, sizeof(buffer));
+    if(msg)
+      msnprintf(buf, buflen, "%s", msg);
+    else
+      msnprintf(buf, buflen, "Unknown error %d", err);
+  }
+#else
+  {
+    /* !checksrc! disable STRERROR 1 */
+    const char *msg = strerror(err);
+    if(msg)
+      msnprintf(buf, buflen, "%s", msg);
+    else
+      msnprintf(buf, buflen, "Unknown error %d", err);
+  }
+#endif
+
+#endif /* end of not Windows */
+
+  /* strip trailing '\r\n' or '\n'. */
+  p = strrchr(buf, '\n');
+  if(p && (p - buf) >= 2)
+    *p = '\0';
+  p = strrchr(buf, '\r');
+  if(p && (p - buf) >= 1)
+    *p = '\0';
+
+  if(errno != old_errno)
+    errno = old_errno;
+
+#ifdef PRESERVE_WINDOWS_ERROR_CODE
+  if(old_win_err != GetLastError())
+    SetLastError(old_win_err);
+#endif
+
+  return buf;
+}
+
+/*
+ * Curl_winapi_strerror:
+ * Variant of Curl_strerror if the error code is definitely Windows API.
+ */
+#if defined(_WIN32) || defined(_WIN32_WCE)
+const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen)
+{
+#ifdef PRESERVE_WINDOWS_ERROR_CODE
+  DWORD old_win_err = GetLastError();
+#endif
+  int old_errno = errno;
+
+  if(!buflen)
+    return NULL;
+
+  *buf = '\0';
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  if(!get_winapi_error(err, buf, buflen)) {
+    msnprintf(buf, buflen, "Unknown error %lu (0x%08lX)", err, err);
+  }
+#else
+  {
+    const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error";
+    if(strlen(txt) < buflen)
+      strcpy(buf, txt);
+  }
+#endif
+
+  if(errno != old_errno)
+    errno = old_errno;
+
+#ifdef PRESERVE_WINDOWS_ERROR_CODE
+  if(old_win_err != GetLastError())
+    SetLastError(old_win_err);
+#endif
+
+  return buf;
+}
+#endif /* _WIN32 || _WIN32_WCE */
+
+#ifdef USE_WINDOWS_SSPI
+/*
+ * Curl_sspi_strerror:
+ * Variant of Curl_strerror if the error code is definitely Windows SSPI.
+ */
+const char *Curl_sspi_strerror(int err, char *buf, size_t buflen)
+{
+#ifdef PRESERVE_WINDOWS_ERROR_CODE
+  DWORD old_win_err = GetLastError();
+#endif
+  int old_errno = errno;
+  const char *txt;
+
+  if(!buflen)
+    return NULL;
+
+  *buf = '\0';
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+
+  switch(err) {
+    case SEC_E_OK:
+      txt = "No error";
+      break;
+#define SEC2TXT(sec) case sec: txt = #sec; break
+    SEC2TXT(CRYPT_E_REVOKED);
+    SEC2TXT(CRYPT_E_NO_REVOCATION_DLL);
+    SEC2TXT(CRYPT_E_NO_REVOCATION_CHECK);
+    SEC2TXT(CRYPT_E_REVOCATION_OFFLINE);
+    SEC2TXT(CRYPT_E_NOT_IN_REVOCATION_DATABASE);
+    SEC2TXT(SEC_E_ALGORITHM_MISMATCH);
+    SEC2TXT(SEC_E_BAD_BINDINGS);
+    SEC2TXT(SEC_E_BAD_PKGID);
+    SEC2TXT(SEC_E_BUFFER_TOO_SMALL);
+    SEC2TXT(SEC_E_CANNOT_INSTALL);
+    SEC2TXT(SEC_E_CANNOT_PACK);
+    SEC2TXT(SEC_E_CERT_EXPIRED);
+    SEC2TXT(SEC_E_CERT_UNKNOWN);
+    SEC2TXT(SEC_E_CERT_WRONG_USAGE);
+    SEC2TXT(SEC_E_CONTEXT_EXPIRED);
+    SEC2TXT(SEC_E_CROSSREALM_DELEGATION_FAILURE);
+    SEC2TXT(SEC_E_CRYPTO_SYSTEM_INVALID);
+    SEC2TXT(SEC_E_DECRYPT_FAILURE);
+    SEC2TXT(SEC_E_DELEGATION_POLICY);
+    SEC2TXT(SEC_E_DELEGATION_REQUIRED);
+    SEC2TXT(SEC_E_DOWNGRADE_DETECTED);
+    SEC2TXT(SEC_E_ENCRYPT_FAILURE);
+    SEC2TXT(SEC_E_ILLEGAL_MESSAGE);
+    SEC2TXT(SEC_E_INCOMPLETE_CREDENTIALS);
+    SEC2TXT(SEC_E_INCOMPLETE_MESSAGE);
+    SEC2TXT(SEC_E_INSUFFICIENT_MEMORY);
+    SEC2TXT(SEC_E_INTERNAL_ERROR);
+    SEC2TXT(SEC_E_INVALID_HANDLE);
+    SEC2TXT(SEC_E_INVALID_PARAMETER);
+    SEC2TXT(SEC_E_INVALID_TOKEN);
+    SEC2TXT(SEC_E_ISSUING_CA_UNTRUSTED);
+    SEC2TXT(SEC_E_ISSUING_CA_UNTRUSTED_KDC);
+    SEC2TXT(SEC_E_KDC_CERT_EXPIRED);
+    SEC2TXT(SEC_E_KDC_CERT_REVOKED);
+    SEC2TXT(SEC_E_KDC_INVALID_REQUEST);
+    SEC2TXT(SEC_E_KDC_UNABLE_TO_REFER);
+    SEC2TXT(SEC_E_KDC_UNKNOWN_ETYPE);
+    SEC2TXT(SEC_E_LOGON_DENIED);
+    SEC2TXT(SEC_E_MAX_REFERRALS_EXCEEDED);
+    SEC2TXT(SEC_E_MESSAGE_ALTERED);
+    SEC2TXT(SEC_E_MULTIPLE_ACCOUNTS);
+    SEC2TXT(SEC_E_MUST_BE_KDC);
+    SEC2TXT(SEC_E_NOT_OWNER);
+    SEC2TXT(SEC_E_NO_AUTHENTICATING_AUTHORITY);
+    SEC2TXT(SEC_E_NO_CREDENTIALS);
+    SEC2TXT(SEC_E_NO_IMPERSONATION);
+    SEC2TXT(SEC_E_NO_IP_ADDRESSES);
+    SEC2TXT(SEC_E_NO_KERB_KEY);
+    SEC2TXT(SEC_E_NO_PA_DATA);
+    SEC2TXT(SEC_E_NO_S4U_PROT_SUPPORT);
+    SEC2TXT(SEC_E_NO_TGT_REPLY);
+    SEC2TXT(SEC_E_OUT_OF_SEQUENCE);
+    SEC2TXT(SEC_E_PKINIT_CLIENT_FAILURE);
+    SEC2TXT(SEC_E_PKINIT_NAME_MISMATCH);
+    SEC2TXT(SEC_E_POLICY_NLTM_ONLY);
+    SEC2TXT(SEC_E_QOP_NOT_SUPPORTED);
+    SEC2TXT(SEC_E_REVOCATION_OFFLINE_C);
+    SEC2TXT(SEC_E_REVOCATION_OFFLINE_KDC);
+    SEC2TXT(SEC_E_SECPKG_NOT_FOUND);
+    SEC2TXT(SEC_E_SECURITY_QOS_FAILED);
+    SEC2TXT(SEC_E_SHUTDOWN_IN_PROGRESS);
+    SEC2TXT(SEC_E_SMARTCARD_CERT_EXPIRED);
+    SEC2TXT(SEC_E_SMARTCARD_CERT_REVOKED);
+    SEC2TXT(SEC_E_SMARTCARD_LOGON_REQUIRED);
+    SEC2TXT(SEC_E_STRONG_CRYPTO_NOT_SUPPORTED);
+    SEC2TXT(SEC_E_TARGET_UNKNOWN);
+    SEC2TXT(SEC_E_TIME_SKEW);
+    SEC2TXT(SEC_E_TOO_MANY_PRINCIPALS);
+    SEC2TXT(SEC_E_UNFINISHED_CONTEXT_DELETED);
+    SEC2TXT(SEC_E_UNKNOWN_CREDENTIALS);
+    SEC2TXT(SEC_E_UNSUPPORTED_FUNCTION);
+    SEC2TXT(SEC_E_UNSUPPORTED_PREAUTH);
+    SEC2TXT(SEC_E_UNTRUSTED_ROOT);
+    SEC2TXT(SEC_E_WRONG_CREDENTIAL_HANDLE);
+    SEC2TXT(SEC_E_WRONG_PRINCIPAL);
+    SEC2TXT(SEC_I_COMPLETE_AND_CONTINUE);
+    SEC2TXT(SEC_I_COMPLETE_NEEDED);
+    SEC2TXT(SEC_I_CONTEXT_EXPIRED);
+    SEC2TXT(SEC_I_CONTINUE_NEEDED);
+    SEC2TXT(SEC_I_INCOMPLETE_CREDENTIALS);
+    SEC2TXT(SEC_I_LOCAL_LOGON);
+    SEC2TXT(SEC_I_NO_LSA_CONTEXT);
+    SEC2TXT(SEC_I_RENEGOTIATE);
+    SEC2TXT(SEC_I_SIGNATURE_NEEDED);
+    default:
+      txt = "Unknown error";
+  }
+
+  if(err == SEC_E_ILLEGAL_MESSAGE) {
+    msnprintf(buf, buflen,
+              "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs "
+              "when a fatal SSL/TLS alert is received (e.g. handshake failed)."
+              " More detail may be available in the Windows System event log.",
+              err);
+  }
+  else {
+    char msgbuf[256];
+    if(get_winapi_error(err, msgbuf, sizeof(msgbuf)))
+      msnprintf(buf, buflen, "%s (0x%08X) - %s", txt, err, msgbuf);
+    else
+      msnprintf(buf, buflen, "%s (0x%08X)", txt, err);
+  }
+
+#else
+  if(err == SEC_E_OK)
+    txt = "No error";
+  else
+    txt = "Error";
+  if(buflen > strlen(txt))
+    strcpy(buf, txt);
+#endif
+
+  if(errno != old_errno)
+    errno = old_errno;
+
+#ifdef PRESERVE_WINDOWS_ERROR_CODE
+  if(old_win_err != GetLastError())
+    SetLastError(old_win_err);
+#endif
+
+  return buf;
+}
+#endif /* USE_WINDOWS_SSPI */
Index: trunk/src/libs/curl-8.7.1/lib/strerror.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/strerror.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/strerror.h	(revision 104083)
@@ -0,0 +1,39 @@
+#ifndef HEADER_CURL_STRERROR_H
+#define HEADER_CURL_STRERROR_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "urldata.h"
+
+#define STRERROR_LEN 256 /* a suitable length */
+
+const char *Curl_strerror(int err, char *buf, size_t buflen);
+#if defined(_WIN32) || defined(_WIN32_WCE)
+const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen);
+#endif
+#ifdef USE_WINDOWS_SSPI
+const char *Curl_sspi_strerror(int err, char *buf, size_t buflen);
+#endif
+
+#endif /* HEADER_CURL_STRERROR_H */
Index: trunk/src/libs/curl-8.7.1/lib/strtok.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/strtok.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/strtok.c	(revision 104083)
@@ -0,0 +1,68 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef HAVE_STRTOK_R
+#include <stddef.h>
+
+#include "strtok.h"
+
+char *
+Curl_strtok_r(char *ptr, const char *sep, char **end)
+{
+  if(!ptr)
+    /* we got NULL input so then we get our last position instead */
+    ptr = *end;
+
+  /* pass all letters that are including in the separator string */
+  while(*ptr && strchr(sep, *ptr))
+    ++ptr;
+
+  if(*ptr) {
+    /* so this is where the next piece of string starts */
+    char *start = ptr;
+
+    /* set the end pointer to the first byte after the start */
+    *end = start + 1;
+
+    /* scan through the string to find where it ends, it ends on a
+       null byte or a character that exists in the separator string */
+    while(**end && !strchr(sep, **end))
+      ++*end;
+
+    if(**end) {
+      /* the end is not a null byte */
+      **end = '\0';  /* null-terminate it! */
+      ++*end;        /* advance the last pointer to beyond the null byte */
+    }
+
+    return start; /* return the position where the string starts */
+  }
+
+  /* we ended up on a null byte, there are no more strings to find! */
+  return NULL;
+}
+
+#endif /* this was only compiled if strtok_r wasn't present */
Index: trunk/src/libs/curl-8.7.1/lib/strtok.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/strtok.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/strtok.h	(revision 104083)
@@ -0,0 +1,36 @@
+#ifndef HEADER_CURL_STRTOK_H
+#define HEADER_CURL_STRTOK_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+#include <stddef.h>
+
+#ifndef HAVE_STRTOK_R
+char *Curl_strtok_r(char *s, const char *delim, char **last);
+#define strtok_r Curl_strtok_r
+#else
+#include <string.h>
+#endif
+
+#endif /* HEADER_CURL_STRTOK_H */
Index: trunk/src/libs/curl-8.7.1/lib/strtoofft.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/strtoofft.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/strtoofft.c	(revision 104083)
@@ -0,0 +1,240 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <errno.h>
+#include "curl_setup.h"
+
+#include "strtoofft.h"
+
+/*
+ * NOTE:
+ *
+ * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we
+ * could use in case strtoll() doesn't exist...  See
+ * https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
+ */
+
+#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
+#  ifdef HAVE_STRTOLL
+#    define strtooff strtoll
+#  else
+#    if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64)
+#      if defined(_SAL_VERSION)
+         _Check_return_ _CRTIMP __int64 __cdecl _strtoi64(
+             _In_z_ const char *_String,
+             _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix);
+#      else
+         _CRTIMP __int64 __cdecl _strtoi64(const char *_String,
+                                           char **_EndPtr, int _Radix);
+#      endif
+#      define strtooff _strtoi64
+#    else
+#      define PRIVATE_STRTOOFF 1
+#    endif
+#  endif
+#else
+#  define strtooff strtol
+#endif
+
+#ifdef PRIVATE_STRTOOFF
+
+/* Range tests can be used for alphanum decoding if characters are consecutive,
+   like in ASCII. Else an array is scanned. Determine this condition now. */
+
+#if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25
+
+#define NO_RANGE_TEST
+
+static const char valchars[] =
+            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+#endif
+
+static int get_char(char c, int base);
+
+/**
+ * Custom version of the strtooff function.  This extracts a curl_off_t
+ * value from the given input string and returns it.
+ */
+static curl_off_t strtooff(const char *nptr, char **endptr, int base)
+{
+  char *end;
+  bool is_negative = FALSE;
+  bool overflow = FALSE;
+  int i;
+  curl_off_t value = 0;
+
+  /* Skip leading whitespace. */
+  end = (char *)nptr;
+  while(ISBLANK(end[0])) {
+    end++;
+  }
+
+  /* Handle the sign, if any. */
+  if(end[0] == '-') {
+    is_negative = TRUE;
+    end++;
+  }
+  else if(end[0] == '+') {
+    end++;
+  }
+  else if(end[0] == '\0') {
+    /* We had nothing but perhaps some whitespace -- there was no number. */
+    if(endptr) {
+      *endptr = end;
+    }
+    return 0;
+  }
+
+  /* Handle special beginnings, if present and allowed. */
+  if(end[0] == '0' && end[1] == 'x') {
+    if(base == 16 || base == 0) {
+      end += 2;
+      base = 16;
+    }
+  }
+  else if(end[0] == '0') {
+    if(base == 8 || base == 0) {
+      end++;
+      base = 8;
+    }
+  }
+
+  /* Matching strtol, if the base is 0 and it doesn't look like
+   * the number is octal or hex, we assume it's base 10.
+   */
+  if(base == 0) {
+    base = 10;
+  }
+
+  /* Loop handling digits. */
+  for(i = get_char(end[0], base);
+      i != -1;
+      end++, i = get_char(end[0], base)) {
+
+    if(value > (CURL_OFF_T_MAX - i) / base) {
+      overflow = TRUE;
+      break;
+    }
+    value = base * value + i;
+  }
+
+  if(!overflow) {
+    if(is_negative) {
+      /* Fix the sign. */
+      value *= -1;
+    }
+  }
+  else {
+    if(is_negative)
+      value = CURL_OFF_T_MIN;
+    else
+      value = CURL_OFF_T_MAX;
+
+    errno = ERANGE;
+  }
+
+  if(endptr)
+    *endptr = end;
+
+  return value;
+}
+
+/**
+ * Returns the value of c in the given base, or -1 if c cannot
+ * be interpreted properly in that base (i.e., is out of range,
+ * is a null, etc.).
+ *
+ * @param c     the character to interpret according to base
+ * @param base  the base in which to interpret c
+ *
+ * @return  the value of c in base, or -1 if c isn't in range
+ */
+static int get_char(char c, int base)
+{
+#ifndef NO_RANGE_TEST
+  int value = -1;
+  if(c <= '9' && c >= '0') {
+    value = c - '0';
+  }
+  else if(c <= 'Z' && c >= 'A') {
+    value = c - 'A' + 10;
+  }
+  else if(c <= 'z' && c >= 'a') {
+    value = c - 'a' + 10;
+  }
+#else
+  const char *cp;
+  int value;
+
+  cp = memchr(valchars, c, 10 + 26 + 26);
+
+  if(!cp)
+    return -1;
+
+  value = cp - valchars;
+
+  if(value >= 10 + 26)
+    value -= 26;                /* Lowercase. */
+#endif
+
+  if(value >= base) {
+    value = -1;
+  }
+
+  return value;
+}
+#endif  /* Only present if we need strtoll, but don't have it. */
+
+/*
+ * Parse a *positive* up to 64 bit number written in ascii.
+ */
+CURLofft curlx_strtoofft(const char *str, char **endp, int base,
+                         curl_off_t *num)
+{
+  char *end = NULL;
+  curl_off_t number;
+  errno = 0;
+  *num = 0; /* clear by default */
+  DEBUGASSERT(base); /* starting now, avoid base zero */
+
+  while(*str && ISBLANK(*str))
+    str++;
+  if(('-' == *str) || (ISSPACE(*str))) {
+    if(endp)
+      *endp = (char *)str; /* didn't actually move */
+    return CURL_OFFT_INVAL; /* nothing parsed */
+  }
+  number = strtooff(str, &end, base);
+  if(endp)
+    *endp = end;
+  if(errno == ERANGE)
+    /* overflow/underflow */
+    return CURL_OFFT_FLOW;
+  else if(str == end)
+    /* nothing parsed */
+    return CURL_OFFT_INVAL;
+
+  *num = number;
+  return CURL_OFFT_OK;
+}
Index: trunk/src/libs/curl-8.7.1/lib/strtoofft.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/strtoofft.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/strtoofft.h	(revision 104083)
@@ -0,0 +1,54 @@
+#ifndef HEADER_CURL_STRTOOFFT_H
+#define HEADER_CURL_STRTOOFFT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+/*
+ * Determine which string to integral data type conversion function we use
+ * to implement string conversion to our curl_off_t integral data type.
+ *
+ * Notice that curl_off_t might be 64 or 32 bit wide, and that it might use
+ * an underlying data type which might be 'long', 'int64_t', 'long long' or
+ * '__int64' and more remotely other data types.
+ *
+ * On systems where the size of curl_off_t is greater than the size of 'long'
+ * the conversion function to use is strtoll() if it is available, otherwise,
+ * we emulate its functionality with our own clone.
+ *
+ * On systems where the size of curl_off_t is smaller or equal than the size
+ * of 'long' the conversion function to use is strtol().
+ */
+
+typedef enum {
+  CURL_OFFT_OK,    /* parsed fine */
+  CURL_OFFT_FLOW,  /* over or underflow */
+  CURL_OFFT_INVAL  /* nothing was parsed */
+} CURLofft;
+
+CURLofft curlx_strtoofft(const char *str, char **endp, int base,
+                         curl_off_t *num);
+
+#endif /* HEADER_CURL_STRTOOFFT_H */
Index: trunk/src/libs/curl-8.7.1/lib/system_win32.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/system_win32.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/system_win32.c	(revision 104083)
@@ -0,0 +1,270 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(_WIN32)
+
+#include <curl/curl.h>
+#include "system_win32.h"
+#include "version_win32.h"
+#include "curl_sspi.h"
+#include "warnless.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+LARGE_INTEGER Curl_freq;
+bool Curl_isVistaOrGreater;
+bool Curl_isWindows8OrGreater;
+
+/* Handle of iphlpapp.dll */
+static HMODULE s_hIpHlpApiDll = NULL;
+
+/* Function pointers */
+IF_NAMETOINDEX_FN Curl_if_nametoindex = NULL;
+FREEADDRINFOEXW_FN Curl_FreeAddrInfoExW = NULL;
+GETADDRINFOEXCANCEL_FN Curl_GetAddrInfoExCancel = NULL;
+GETADDRINFOEXW_FN Curl_GetAddrInfoExW = NULL;
+
+/* Curl_win32_init() performs win32 global initialization */
+CURLcode Curl_win32_init(long flags)
+{
+#ifdef USE_WINSOCK
+  HMODULE ws2_32Dll;
+#endif
+  /* CURL_GLOBAL_WIN32 controls the *optional* part of the initialization which
+     is just for Winsock at the moment. Any required win32 initialization
+     should take place after this block. */
+  if(flags & CURL_GLOBAL_WIN32) {
+#ifdef USE_WINSOCK
+    WORD wVersionRequested;
+    WSADATA wsaData;
+    int res;
+
+    wVersionRequested = MAKEWORD(2, 2);
+    res = WSAStartup(wVersionRequested, &wsaData);
+
+    if(res)
+      /* Tell the user that we couldn't find a usable */
+      /* winsock.dll.     */
+      return CURLE_FAILED_INIT;
+
+    /* Confirm that the Windows Sockets DLL supports what we need.*/
+    /* Note that if the DLL supports versions greater */
+    /* than wVersionRequested, it will still return */
+    /* wVersionRequested in wVersion. wHighVersion contains the */
+    /* highest supported version. */
+
+    if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
+       HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
+      /* Tell the user that we couldn't find a usable */
+
+      /* winsock.dll. */
+      WSACleanup();
+      return CURLE_FAILED_INIT;
+    }
+    /* The Windows Sockets DLL is acceptable. Proceed. */
+#elif defined(USE_LWIPSOCK)
+    lwip_init();
+#endif
+  } /* CURL_GLOBAL_WIN32 */
+
+#ifdef USE_WINDOWS_SSPI
+  {
+    CURLcode result = Curl_sspi_global_init();
+    if(result)
+      return result;
+  }
+#endif
+
+  s_hIpHlpApiDll = Curl_load_library(TEXT("iphlpapi.dll"));
+  if(s_hIpHlpApiDll) {
+    /* Get the address of the if_nametoindex function */
+    IF_NAMETOINDEX_FN pIfNameToIndex =
+      CURLX_FUNCTION_CAST(IF_NAMETOINDEX_FN,
+                          (GetProcAddress(s_hIpHlpApiDll, "if_nametoindex")));
+
+    if(pIfNameToIndex)
+      Curl_if_nametoindex = pIfNameToIndex;
+  }
+
+#ifdef USE_WINSOCK
+  ws2_32Dll = GetModuleHandleA("ws2_32");
+  if(ws2_32Dll) {
+    Curl_FreeAddrInfoExW = CURLX_FUNCTION_CAST(FREEADDRINFOEXW_FN,
+      GetProcAddress(ws2_32Dll, "FreeAddrInfoExW"));
+    Curl_GetAddrInfoExCancel = CURLX_FUNCTION_CAST(GETADDRINFOEXCANCEL_FN,
+      GetProcAddress(ws2_32Dll, "GetAddrInfoExCancel"));
+    Curl_GetAddrInfoExW = CURLX_FUNCTION_CAST(GETADDRINFOEXW_FN,
+      GetProcAddress(ws2_32Dll, "GetAddrInfoExW"));
+  }
+#endif
+
+  /* curlx_verify_windows_version must be called during init at least once
+     because it has its own initialization routine. */
+  if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
+                                  VERSION_GREATER_THAN_EQUAL)) {
+    Curl_isVistaOrGreater = TRUE;
+  }
+  else
+    Curl_isVistaOrGreater = FALSE;
+
+  if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT,
+                                  VERSION_GREATER_THAN_EQUAL)) {
+    Curl_isWindows8OrGreater = TRUE;
+  }
+  else
+    Curl_isWindows8OrGreater = FALSE;
+
+  QueryPerformanceFrequency(&Curl_freq);
+  return CURLE_OK;
+}
+
+/* Curl_win32_cleanup() is the opposite of Curl_win32_init() */
+void Curl_win32_cleanup(long init_flags)
+{
+  Curl_FreeAddrInfoExW = NULL;
+  Curl_GetAddrInfoExCancel = NULL;
+  Curl_GetAddrInfoExW = NULL;
+  if(s_hIpHlpApiDll) {
+    FreeLibrary(s_hIpHlpApiDll);
+    s_hIpHlpApiDll = NULL;
+    Curl_if_nametoindex = NULL;
+  }
+
+#ifdef USE_WINDOWS_SSPI
+  Curl_sspi_global_cleanup();
+#endif
+
+  if(init_flags & CURL_GLOBAL_WIN32) {
+#ifdef USE_WINSOCK
+    WSACleanup();
+#endif
+  }
+}
+
+#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH)
+#define LOAD_WITH_ALTERED_SEARCH_PATH  0x00000008
+#endif
+
+#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
+#define LOAD_LIBRARY_SEARCH_SYSTEM32   0x00000800
+#endif
+
+/* We use our own typedef here since some headers might lack these */
+typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD);
+
+/* See function definitions in winbase.h */
+#ifdef UNICODE
+#  ifdef _WIN32_WCE
+#    define LOADLIBARYEX  L"LoadLibraryExW"
+#  else
+#    define LOADLIBARYEX  "LoadLibraryExW"
+#  endif
+#else
+#  define LOADLIBARYEX    "LoadLibraryExA"
+#endif
+
+/*
+ * Curl_load_library()
+ *
+ * This is used to dynamically load DLLs using the most secure method available
+ * for the version of Windows that we are running on.
+ *
+ * Parameters:
+ *
+ * filename  [in] - The filename or full path of the DLL to load. If only the
+ *                  filename is passed then the DLL will be loaded from the
+ *                  Windows system directory.
+ *
+ * Returns the handle of the module on success; otherwise NULL.
+ */
+HMODULE Curl_load_library(LPCTSTR filename)
+{
+#ifndef CURL_WINDOWS_APP
+  HMODULE hModule = NULL;
+  LOADLIBRARYEX_FN pLoadLibraryEx = NULL;
+
+  /* Get a handle to kernel32 so we can access it's functions at runtime */
+  HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
+  if(!hKernel32)
+    return NULL;
+
+  /* Attempt to find LoadLibraryEx() which is only available on Windows 2000
+     and above */
+  pLoadLibraryEx =
+    CURLX_FUNCTION_CAST(LOADLIBRARYEX_FN,
+                        (GetProcAddress(hKernel32, LOADLIBARYEX)));
+
+  /* Detect if there's already a path in the filename and load the library if
+     there is. Note: Both back slashes and forward slashes have been supported
+     since the earlier days of DOS at an API level although they are not
+     supported by command prompt */
+  if(_tcspbrk(filename, TEXT("\\/"))) {
+    /** !checksrc! disable BANNEDFUNC 1 **/
+    hModule = pLoadLibraryEx ?
+      pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
+      LoadLibrary(filename);
+  }
+  /* Detect if KB2533623 is installed, as LOAD_LIBRARY_SEARCH_SYSTEM32 is only
+     supported on Windows Vista, Windows Server 2008, Windows 7 and Windows
+     Server 2008 R2 with this patch or natively on Windows 8 and above */
+  else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) {
+    /* Load the DLL from the Windows system directory */
+    hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
+  }
+  else {
+    /* Attempt to get the Windows system path */
+    UINT systemdirlen = GetSystemDirectory(NULL, 0);
+    if(systemdirlen) {
+      /* Allocate space for the full DLL path (Room for the null terminator
+         is included in systemdirlen) */
+      size_t filenamelen = _tcslen(filename);
+      TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen));
+      if(path && GetSystemDirectory(path, systemdirlen)) {
+        /* Calculate the full DLL path */
+        _tcscpy(path + _tcslen(path), TEXT("\\"));
+        _tcscpy(path + _tcslen(path), filename);
+
+        /* Load the DLL from the Windows system directory */
+        /** !checksrc! disable BANNEDFUNC 1 **/
+        hModule = pLoadLibraryEx ?
+          pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
+          LoadLibrary(path);
+
+      }
+      free(path);
+    }
+  }
+  return hModule;
+#else
+  /* the Universal Windows Platform (UWP) can't do this */
+  (void)filename;
+  return NULL;
+#endif
+}
+
+#endif /* _WIN32 */
Index: trunk/src/libs/curl-8.7.1/lib/system_win32.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/system_win32.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/system_win32.h	(revision 104083)
@@ -0,0 +1,77 @@
+#ifndef HEADER_CURL_SYSTEM_WIN32_H
+#define HEADER_CURL_SYSTEM_WIN32_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef _WIN32
+
+extern LARGE_INTEGER Curl_freq;
+extern bool Curl_isVistaOrGreater;
+extern bool Curl_isWindows8OrGreater;
+
+CURLcode Curl_win32_init(long flags);
+void Curl_win32_cleanup(long init_flags);
+
+/* We use our own typedef here since some headers might lack this */
+typedef unsigned int(WINAPI *IF_NAMETOINDEX_FN)(const char *);
+
+/* This is used instead of if_nametoindex if available on Windows */
+extern IF_NAMETOINDEX_FN Curl_if_nametoindex;
+
+/* Identical copy of addrinfoexW/ADDRINFOEXW */
+typedef struct addrinfoexW_
+{
+  int                  ai_flags;
+  int                  ai_family;
+  int                  ai_socktype;
+  int                  ai_protocol;
+  size_t               ai_addrlen;
+  PWSTR                ai_canonname;
+  struct sockaddr     *ai_addr;
+  void                *ai_blob;
+  size_t               ai_bloblen;
+  LPGUID               ai_provider;
+  struct addrinfoexW_ *ai_next;
+} ADDRINFOEXW_;
+
+typedef void (CALLBACK *LOOKUP_COMPLETION_FN)(DWORD, DWORD, LPWSAOVERLAPPED);
+typedef void (WSAAPI *FREEADDRINFOEXW_FN)(ADDRINFOEXW_*);
+typedef int (WSAAPI *GETADDRINFOEXCANCEL_FN)(LPHANDLE);
+typedef int (WSAAPI *GETADDRINFOEXW_FN)(PCWSTR, PCWSTR, DWORD, LPGUID,
+  const ADDRINFOEXW_*, ADDRINFOEXW_**, struct timeval*, LPOVERLAPPED,
+  LOOKUP_COMPLETION_FN, LPHANDLE);
+
+extern FREEADDRINFOEXW_FN Curl_FreeAddrInfoExW;
+extern GETADDRINFOEXCANCEL_FN Curl_GetAddrInfoExCancel;
+extern GETADDRINFOEXW_FN Curl_GetAddrInfoExW;
+
+/* This is used to dynamically load DLLs */
+HMODULE Curl_load_library(LPCTSTR filename);
+#else  /* _WIN32 */
+#define Curl_win32_init(x) CURLE_OK
+#endif /* !_WIN32 */
+
+#endif /* HEADER_CURL_SYSTEM_WIN32_H */
Index: trunk/src/libs/curl-8.7.1/lib/telnet.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/telnet.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/telnet.c	(revision 104083)
@@ -0,0 +1,1646 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_TELNET
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "telnet.h"
+#include "connect.h"
+#include "progress.h"
+#include "system_win32.h"
+#include "arpa_telnet.h"
+#include "select.h"
+#include "strcase.h"
+#include "warnless.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define SUBBUFSIZE 512
+
+#define CURL_SB_CLEAR(x)  x->subpointer = x->subbuffer
+#define CURL_SB_TERM(x)                                 \
+  do {                                                  \
+    x->subend = x->subpointer;                          \
+    CURL_SB_CLEAR(x);                                   \
+  } while(0)
+#define CURL_SB_ACCUM(x,c)                                      \
+  do {                                                          \
+    if(x->subpointer < (x->subbuffer + sizeof(x->subbuffer)))   \
+      *x->subpointer++ = (c);                                   \
+  } while(0)
+
+#define  CURL_SB_GET(x) ((*x->subpointer++)&0xff)
+#define  CURL_SB_LEN(x) (x->subend - x->subpointer)
+
+/* For posterity:
+#define  CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
+#define  CURL_SB_EOF(x) (x->subpointer >= x->subend) */
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+#define printoption(a,b,c,d)  Curl_nop_stmt
+#endif
+
+static
+CURLcode telrcv(struct Curl_easy *data,
+                const unsigned char *inbuf, /* Data received from socket */
+                ssize_t count);             /* Number of bytes received */
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void printoption(struct Curl_easy *data,
+                        const char *direction,
+                        int cmd, int option);
+#endif
+
+static void negotiate(struct Curl_easy *data);
+static void send_negotiation(struct Curl_easy *data, int cmd, int option);
+static void set_local_option(struct Curl_easy *data,
+                             int option, int newstate);
+static void set_remote_option(struct Curl_easy *data,
+                              int option, int newstate);
+
+static void printsub(struct Curl_easy *data,
+                     int direction, unsigned char *pointer,
+                     size_t length);
+static void suboption(struct Curl_easy *data);
+static void sendsuboption(struct Curl_easy *data, int option);
+
+static CURLcode telnet_do(struct Curl_easy *data, bool *done);
+static CURLcode telnet_done(struct Curl_easy *data,
+                                 CURLcode, bool premature);
+static CURLcode send_telnet_data(struct Curl_easy *data,
+                                 char *buffer, ssize_t nread);
+
+/* For negotiation compliant to RFC 1143 */
+#define CURL_NO          0
+#define CURL_YES         1
+#define CURL_WANTYES     2
+#define CURL_WANTNO      3
+
+#define CURL_EMPTY       0
+#define CURL_OPPOSITE    1
+
+/*
+ * Telnet receiver states for fsm
+ */
+typedef enum
+{
+   CURL_TS_DATA = 0,
+   CURL_TS_IAC,
+   CURL_TS_WILL,
+   CURL_TS_WONT,
+   CURL_TS_DO,
+   CURL_TS_DONT,
+   CURL_TS_CR,
+   CURL_TS_SB,   /* sub-option collection */
+   CURL_TS_SE   /* looking for sub-option end */
+} TelnetReceive;
+
+struct TELNET {
+  int please_negotiate;
+  int already_negotiated;
+  int us[256];
+  int usq[256];
+  int us_preferred[256];
+  int him[256];
+  int himq[256];
+  int him_preferred[256];
+  int subnegotiation[256];
+  char subopt_ttype[32];             /* Set with suboption TTYPE */
+  char subopt_xdisploc[128];         /* Set with suboption XDISPLOC */
+  unsigned short subopt_wsx;         /* Set with suboption NAWS */
+  unsigned short subopt_wsy;         /* Set with suboption NAWS */
+  TelnetReceive telrcv_state;
+  struct curl_slist *telnet_vars;    /* Environment variables */
+  struct dynbuf out;                 /* output buffer */
+
+  /* suboptions */
+  unsigned char subbuffer[SUBBUFSIZE];
+  unsigned char *subpointer, *subend;      /* buffer for sub-options */
+};
+
+
+/*
+ * TELNET protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_telnet = {
+  "TELNET",                             /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  telnet_do,                            /* do_it */
+  telnet_done,                          /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_TELNET,                          /* defport */
+  CURLPROTO_TELNET,                     /* protocol */
+  CURLPROTO_TELNET,                     /* family */
+  PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
+};
+
+
+static
+CURLcode init_telnet(struct Curl_easy *data)
+{
+  struct TELNET *tn;
+
+  tn = calloc(1, sizeof(struct TELNET));
+  if(!tn)
+    return CURLE_OUT_OF_MEMORY;
+
+  Curl_dyn_init(&tn->out, 0xffff);
+  data->req.p.telnet = tn; /* make us known */
+
+  tn->telrcv_state = CURL_TS_DATA;
+
+  /* Init suboptions */
+  CURL_SB_CLEAR(tn);
+
+  /* Set the options we want by default */
+  tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
+  tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
+
+  /* To be compliant with previous releases of libcurl
+     we enable this option by default. This behavior
+         can be changed thanks to the "BINARY" option in
+         CURLOPT_TELNETOPTIONS
+  */
+  tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
+  tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
+
+  /* We must allow the server to echo what we sent
+         but it is not necessary to request the server
+         to do so (it might forces the server to close
+         the connection). Hence, we ignore ECHO in the
+         negotiate function
+  */
+  tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
+
+  /* Set the subnegotiation fields to send information
+    just after negotiation passed (do/will)
+
+     Default values are (0,0) initialized by calloc.
+     According to the RFC1013 it is valid:
+     A value equal to zero is acceptable for the width (or height),
+         and means that no character width (or height) is being sent.
+         In this case, the width (or height) that will be assumed by the
+         Telnet server is operating system specific (it will probably be
+         based upon the terminal type information that may have been sent
+         using the TERMINAL TYPE Telnet option). */
+  tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
+  return CURLE_OK;
+}
+
+static void negotiate(struct Curl_easy *data)
+{
+  int i;
+  struct TELNET *tn = data->req.p.telnet;
+
+  for(i = 0; i < CURL_NTELOPTS; i++) {
+    if(i == CURL_TELOPT_ECHO)
+      continue;
+
+    if(tn->us_preferred[i] == CURL_YES)
+      set_local_option(data, i, CURL_YES);
+
+    if(tn->him_preferred[i] == CURL_YES)
+      set_remote_option(data, i, CURL_YES);
+  }
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void printoption(struct Curl_easy *data,
+                        const char *direction, int cmd, int option)
+{
+  if(data->set.verbose) {
+    if(cmd == CURL_IAC) {
+      if(CURL_TELCMD_OK(option))
+        infof(data, "%s IAC %s", direction, CURL_TELCMD(option));
+      else
+        infof(data, "%s IAC %d", direction, option);
+    }
+    else {
+      const char *fmt = (cmd == CURL_WILL) ? "WILL" :
+                        (cmd == CURL_WONT) ? "WONT" :
+                        (cmd == CURL_DO) ? "DO" :
+                        (cmd == CURL_DONT) ? "DONT" : 0;
+      if(fmt) {
+        const char *opt;
+        if(CURL_TELOPT_OK(option))
+          opt = CURL_TELOPT(option);
+        else if(option == CURL_TELOPT_EXOPL)
+          opt = "EXOPL";
+        else
+          opt = NULL;
+
+        if(opt)
+          infof(data, "%s %s %s", direction, fmt, opt);
+        else
+          infof(data, "%s %s %d", direction, fmt, option);
+      }
+      else
+        infof(data, "%s %d %d", direction, cmd, option);
+    }
+  }
+}
+#endif
+
+static void send_negotiation(struct Curl_easy *data, int cmd, int option)
+{
+  unsigned char buf[3];
+  ssize_t bytes_written;
+  struct connectdata *conn = data->conn;
+
+  buf[0] = CURL_IAC;
+  buf[1] = (unsigned char)cmd;
+  buf[2] = (unsigned char)option;
+
+  bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
+  if(bytes_written < 0) {
+    int err = SOCKERRNO;
+    failf(data,"Sending data failed (%d)",err);
+  }
+
+  printoption(data, "SENT", cmd, option);
+}
+
+static
+void set_remote_option(struct Curl_easy *data, int option, int newstate)
+{
+  struct TELNET *tn = data->req.p.telnet;
+  if(newstate == CURL_YES) {
+    switch(tn->him[option]) {
+    case CURL_NO:
+      tn->him[option] = CURL_WANTYES;
+      send_negotiation(data, CURL_DO, option);
+      break;
+
+    case CURL_YES:
+      /* Already enabled */
+      break;
+
+    case CURL_WANTNO:
+      switch(tn->himq[option]) {
+      case CURL_EMPTY:
+        /* Already negotiating for CURL_YES, queue the request */
+        tn->himq[option] = CURL_OPPOSITE;
+        break;
+      case CURL_OPPOSITE:
+        /* Error: already queued an enable request */
+        break;
+      }
+      break;
+
+    case CURL_WANTYES:
+      switch(tn->himq[option]) {
+      case CURL_EMPTY:
+        /* Error: already negotiating for enable */
+        break;
+      case CURL_OPPOSITE:
+        tn->himq[option] = CURL_EMPTY;
+        break;
+      }
+      break;
+    }
+  }
+  else { /* NO */
+    switch(tn->him[option]) {
+    case CURL_NO:
+      /* Already disabled */
+      break;
+
+    case CURL_YES:
+      tn->him[option] = CURL_WANTNO;
+      send_negotiation(data, CURL_DONT, option);
+      break;
+
+    case CURL_WANTNO:
+      switch(tn->himq[option]) {
+      case CURL_EMPTY:
+        /* Already negotiating for NO */
+        break;
+      case CURL_OPPOSITE:
+        tn->himq[option] = CURL_EMPTY;
+        break;
+      }
+      break;
+
+    case CURL_WANTYES:
+      switch(tn->himq[option]) {
+      case CURL_EMPTY:
+        tn->himq[option] = CURL_OPPOSITE;
+        break;
+      case CURL_OPPOSITE:
+        break;
+      }
+      break;
+    }
+  }
+}
+
+static
+void rec_will(struct Curl_easy *data, int option)
+{
+  struct TELNET *tn = data->req.p.telnet;
+  switch(tn->him[option]) {
+  case CURL_NO:
+    if(tn->him_preferred[option] == CURL_YES) {
+      tn->him[option] = CURL_YES;
+      send_negotiation(data, CURL_DO, option);
+    }
+    else
+      send_negotiation(data, CURL_DONT, option);
+
+    break;
+
+  case CURL_YES:
+    /* Already enabled */
+    break;
+
+  case CURL_WANTNO:
+    switch(tn->himq[option]) {
+    case CURL_EMPTY:
+      /* Error: DONT answered by WILL */
+      tn->him[option] = CURL_NO;
+      break;
+    case CURL_OPPOSITE:
+      /* Error: DONT answered by WILL */
+      tn->him[option] = CURL_YES;
+      tn->himq[option] = CURL_EMPTY;
+      break;
+    }
+    break;
+
+  case CURL_WANTYES:
+    switch(tn->himq[option]) {
+    case CURL_EMPTY:
+      tn->him[option] = CURL_YES;
+      break;
+    case CURL_OPPOSITE:
+      tn->him[option] = CURL_WANTNO;
+      tn->himq[option] = CURL_EMPTY;
+      send_negotiation(data, CURL_DONT, option);
+      break;
+    }
+    break;
+  }
+}
+
+static
+void rec_wont(struct Curl_easy *data, int option)
+{
+  struct TELNET *tn = data->req.p.telnet;
+  switch(tn->him[option]) {
+  case CURL_NO:
+    /* Already disabled */
+    break;
+
+  case CURL_YES:
+    tn->him[option] = CURL_NO;
+    send_negotiation(data, CURL_DONT, option);
+    break;
+
+  case CURL_WANTNO:
+    switch(tn->himq[option]) {
+    case CURL_EMPTY:
+      tn->him[option] = CURL_NO;
+      break;
+
+    case CURL_OPPOSITE:
+      tn->him[option] = CURL_WANTYES;
+      tn->himq[option] = CURL_EMPTY;
+      send_negotiation(data, CURL_DO, option);
+      break;
+    }
+    break;
+
+  case CURL_WANTYES:
+    switch(tn->himq[option]) {
+    case CURL_EMPTY:
+      tn->him[option] = CURL_NO;
+      break;
+    case CURL_OPPOSITE:
+      tn->him[option] = CURL_NO;
+      tn->himq[option] = CURL_EMPTY;
+      break;
+    }
+    break;
+  }
+}
+
+static void
+set_local_option(struct Curl_easy *data, int option, int newstate)
+{
+  struct TELNET *tn = data->req.p.telnet;
+  if(newstate == CURL_YES) {
+    switch(tn->us[option]) {
+    case CURL_NO:
+      tn->us[option] = CURL_WANTYES;
+      send_negotiation(data, CURL_WILL, option);
+      break;
+
+    case CURL_YES:
+      /* Already enabled */
+      break;
+
+    case CURL_WANTNO:
+      switch(tn->usq[option]) {
+      case CURL_EMPTY:
+        /* Already negotiating for CURL_YES, queue the request */
+        tn->usq[option] = CURL_OPPOSITE;
+        break;
+      case CURL_OPPOSITE:
+        /* Error: already queued an enable request */
+        break;
+      }
+      break;
+
+    case CURL_WANTYES:
+      switch(tn->usq[option]) {
+      case CURL_EMPTY:
+        /* Error: already negotiating for enable */
+        break;
+      case CURL_OPPOSITE:
+        tn->usq[option] = CURL_EMPTY;
+        break;
+      }
+      break;
+    }
+  }
+  else { /* NO */
+    switch(tn->us[option]) {
+    case CURL_NO:
+      /* Already disabled */
+      break;
+
+    case CURL_YES:
+      tn->us[option] = CURL_WANTNO;
+      send_negotiation(data, CURL_WONT, option);
+      break;
+
+    case CURL_WANTNO:
+      switch(tn->usq[option]) {
+      case CURL_EMPTY:
+        /* Already negotiating for NO */
+        break;
+      case CURL_OPPOSITE:
+        tn->usq[option] = CURL_EMPTY;
+        break;
+      }
+      break;
+
+    case CURL_WANTYES:
+      switch(tn->usq[option]) {
+      case CURL_EMPTY:
+        tn->usq[option] = CURL_OPPOSITE;
+        break;
+      case CURL_OPPOSITE:
+        break;
+      }
+      break;
+    }
+  }
+}
+
+static
+void rec_do(struct Curl_easy *data, int option)
+{
+  struct TELNET *tn = data->req.p.telnet;
+  switch(tn->us[option]) {
+  case CURL_NO:
+    if(tn->us_preferred[option] == CURL_YES) {
+      tn->us[option] = CURL_YES;
+      send_negotiation(data, CURL_WILL, option);
+      if(tn->subnegotiation[option] == CURL_YES)
+        /* transmission of data option */
+        sendsuboption(data, option);
+    }
+    else if(tn->subnegotiation[option] == CURL_YES) {
+      /* send information to achieve this option */
+      tn->us[option] = CURL_YES;
+      send_negotiation(data, CURL_WILL, option);
+      sendsuboption(data, option);
+    }
+    else
+      send_negotiation(data, CURL_WONT, option);
+    break;
+
+  case CURL_YES:
+    /* Already enabled */
+    break;
+
+  case CURL_WANTNO:
+    switch(tn->usq[option]) {
+    case CURL_EMPTY:
+      /* Error: DONT answered by WILL */
+      tn->us[option] = CURL_NO;
+      break;
+    case CURL_OPPOSITE:
+      /* Error: DONT answered by WILL */
+      tn->us[option] = CURL_YES;
+      tn->usq[option] = CURL_EMPTY;
+      break;
+    }
+    break;
+
+  case CURL_WANTYES:
+    switch(tn->usq[option]) {
+    case CURL_EMPTY:
+      tn->us[option] = CURL_YES;
+      if(tn->subnegotiation[option] == CURL_YES) {
+        /* transmission of data option */
+        sendsuboption(data, option);
+      }
+      break;
+    case CURL_OPPOSITE:
+      tn->us[option] = CURL_WANTNO;
+      tn->himq[option] = CURL_EMPTY;
+      send_negotiation(data, CURL_WONT, option);
+      break;
+    }
+    break;
+  }
+}
+
+static
+void rec_dont(struct Curl_easy *data, int option)
+{
+  struct TELNET *tn = data->req.p.telnet;
+  switch(tn->us[option]) {
+  case CURL_NO:
+    /* Already disabled */
+    break;
+
+  case CURL_YES:
+    tn->us[option] = CURL_NO;
+    send_negotiation(data, CURL_WONT, option);
+    break;
+
+  case CURL_WANTNO:
+    switch(tn->usq[option]) {
+    case CURL_EMPTY:
+      tn->us[option] = CURL_NO;
+      break;
+
+    case CURL_OPPOSITE:
+      tn->us[option] = CURL_WANTYES;
+      tn->usq[option] = CURL_EMPTY;
+      send_negotiation(data, CURL_WILL, option);
+      break;
+    }
+    break;
+
+  case CURL_WANTYES:
+    switch(tn->usq[option]) {
+    case CURL_EMPTY:
+      tn->us[option] = CURL_NO;
+      break;
+    case CURL_OPPOSITE:
+      tn->us[option] = CURL_NO;
+      tn->usq[option] = CURL_EMPTY;
+      break;
+    }
+    break;
+  }
+}
+
+
+static void printsub(struct Curl_easy *data,
+                     int direction,             /* '<' or '>' */
+                     unsigned char *pointer,    /* where suboption data is */
+                     size_t length)             /* length of suboption data */
+{
+  if(data->set.verbose) {
+    unsigned int i = 0;
+    if(direction) {
+      infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
+      if(length >= 3) {
+        int j;
+
+        i = pointer[length-2];
+        j = pointer[length-1];
+
+        if(i != CURL_IAC || j != CURL_SE) {
+          infof(data, "(terminated by ");
+          if(CURL_TELOPT_OK(i))
+            infof(data, "%s ", CURL_TELOPT(i));
+          else if(CURL_TELCMD_OK(i))
+            infof(data, "%s ", CURL_TELCMD(i));
+          else
+            infof(data, "%u ", i);
+          if(CURL_TELOPT_OK(j))
+            infof(data, "%s", CURL_TELOPT(j));
+          else if(CURL_TELCMD_OK(j))
+            infof(data, "%s", CURL_TELCMD(j));
+          else
+            infof(data, "%d", j);
+          infof(data, ", not IAC SE) ");
+        }
+      }
+      length -= 2;
+    }
+    if(length < 1) {
+      infof(data, "(Empty suboption?)");
+      return;
+    }
+
+    if(CURL_TELOPT_OK(pointer[0])) {
+      switch(pointer[0]) {
+      case CURL_TELOPT_TTYPE:
+      case CURL_TELOPT_XDISPLOC:
+      case CURL_TELOPT_NEW_ENVIRON:
+      case CURL_TELOPT_NAWS:
+        infof(data, "%s", CURL_TELOPT(pointer[0]));
+        break;
+      default:
+        infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
+        break;
+      }
+    }
+    else
+      infof(data, "%d (unknown)", pointer[i]);
+
+    switch(pointer[0]) {
+    case CURL_TELOPT_NAWS:
+      if(length > 4)
+        infof(data, "Width: %d ; Height: %d", (pointer[1]<<8) | pointer[2],
+              (pointer[3]<<8) | pointer[4]);
+      break;
+    default:
+      switch(pointer[1]) {
+      case CURL_TELQUAL_IS:
+        infof(data, " IS");
+        break;
+      case CURL_TELQUAL_SEND:
+        infof(data, " SEND");
+        break;
+      case CURL_TELQUAL_INFO:
+        infof(data, " INFO/REPLY");
+        break;
+      case CURL_TELQUAL_NAME:
+        infof(data, " NAME");
+        break;
+      }
+
+      switch(pointer[0]) {
+      case CURL_TELOPT_TTYPE:
+      case CURL_TELOPT_XDISPLOC:
+        pointer[length] = 0;
+        infof(data, " \"%s\"", &pointer[2]);
+        break;
+      case CURL_TELOPT_NEW_ENVIRON:
+        if(pointer[1] == CURL_TELQUAL_IS) {
+          infof(data, " ");
+          for(i = 3; i < length; i++) {
+            switch(pointer[i]) {
+            case CURL_NEW_ENV_VAR:
+              infof(data, ", ");
+              break;
+            case CURL_NEW_ENV_VALUE:
+              infof(data, " = ");
+              break;
+            default:
+              infof(data, "%c", pointer[i]);
+              break;
+            }
+          }
+        }
+        break;
+      default:
+        for(i = 2; i < length; i++)
+          infof(data, " %.2x", pointer[i]);
+        break;
+      }
+    }
+  }
+}
+
+#ifdef _MSC_VER
+#pragma warning(push)
+/* warning C4706: assignment within conditional expression */
+#pragma warning(disable:4706)
+#endif
+static bool str_is_nonascii(const char *str)
+{
+  char c;
+  while((c = *str++))
+    if(c & 0x80)
+      return TRUE;
+
+  return FALSE;
+}
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+static CURLcode check_telnet_options(struct Curl_easy *data)
+{
+  struct curl_slist *head;
+  struct curl_slist *beg;
+  struct TELNET *tn = data->req.p.telnet;
+  CURLcode result = CURLE_OK;
+
+  /* Add the user name as an environment variable if it
+     was given on the command line */
+  if(data->state.aptr.user) {
+    char buffer[256];
+    if(str_is_nonascii(data->conn->user)) {
+      DEBUGF(infof(data, "set a non ASCII user name in telnet"));
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+    msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user);
+    beg = curl_slist_append(tn->telnet_vars, buffer);
+    if(!beg) {
+      curl_slist_free_all(tn->telnet_vars);
+      tn->telnet_vars = NULL;
+      return CURLE_OUT_OF_MEMORY;
+    }
+    tn->telnet_vars = beg;
+    tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
+  }
+
+  for(head = data->set.telnet_options; head && !result; head = head->next) {
+    size_t olen;
+    char *option = head->data;
+    char *arg;
+    char *sep = strchr(option, '=');
+    if(sep) {
+      olen = sep - option;
+      arg = ++sep;
+      if(str_is_nonascii(arg))
+        continue;
+      switch(olen) {
+      case 5:
+        /* Terminal type */
+        if(strncasecompare(option, "TTYPE", 5)) {
+          size_t l = strlen(arg);
+          if(l < sizeof(tn->subopt_ttype)) {
+            strcpy(tn->subopt_ttype, arg);
+            tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
+            break;
+          }
+        }
+        result = CURLE_UNKNOWN_OPTION;
+        break;
+
+      case 8:
+        /* Display variable */
+        if(strncasecompare(option, "XDISPLOC", 8)) {
+          size_t l = strlen(arg);
+          if(l < sizeof(tn->subopt_xdisploc)) {
+            strcpy(tn->subopt_xdisploc, arg);
+            tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
+            break;
+          }
+        }
+        result = CURLE_UNKNOWN_OPTION;
+        break;
+
+      case 7:
+        /* Environment variable */
+        if(strncasecompare(option, "NEW_ENV", 7)) {
+          beg = curl_slist_append(tn->telnet_vars, arg);
+          if(!beg) {
+            result = CURLE_OUT_OF_MEMORY;
+            break;
+          }
+          tn->telnet_vars = beg;
+          tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
+        }
+        else
+          result = CURLE_UNKNOWN_OPTION;
+        break;
+
+      case 2:
+        /* Window Size */
+        if(strncasecompare(option, "WS", 2)) {
+          char *p;
+          unsigned long x = strtoul(arg, &p, 10);
+          unsigned long y = 0;
+          if(x && (x <= 0xffff) && Curl_raw_tolower(*p) == 'x') {
+            p++;
+            y = strtoul(p, NULL, 10);
+            if(y && (y <= 0xffff)) {
+              tn->subopt_wsx = (unsigned short)x;
+              tn->subopt_wsy = (unsigned short)y;
+              tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
+            }
+          }
+          if(!y) {
+            failf(data, "Syntax error in telnet option: %s", head->data);
+            result = CURLE_SETOPT_OPTION_SYNTAX;
+          }
+        }
+        else
+          result = CURLE_UNKNOWN_OPTION;
+        break;
+
+      case 6:
+        /* To take care or not of the 8th bit in data exchange */
+        if(strncasecompare(option, "BINARY", 6)) {
+          int binary_option = atoi(arg);
+          if(binary_option != 1) {
+            tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
+            tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
+          }
+        }
+        else
+          result = CURLE_UNKNOWN_OPTION;
+        break;
+      default:
+        failf(data, "Unknown telnet option %s", head->data);
+        result = CURLE_UNKNOWN_OPTION;
+        break;
+      }
+    }
+    else {
+      failf(data, "Syntax error in telnet option: %s", head->data);
+      result = CURLE_SETOPT_OPTION_SYNTAX;
+    }
+  }
+
+  if(result) {
+    curl_slist_free_all(tn->telnet_vars);
+    tn->telnet_vars = NULL;
+  }
+
+  return result;
+}
+
+/*
+ * suboption()
+ *
+ * Look at the sub-option buffer, and try to be helpful to the other
+ * side.
+ */
+
+static void suboption(struct Curl_easy *data)
+{
+  struct curl_slist *v;
+  unsigned char temp[2048];
+  ssize_t bytes_written;
+  size_t len;
+  int err;
+  struct TELNET *tn = data->req.p.telnet;
+  struct connectdata *conn = data->conn;
+
+  printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2);
+  switch(CURL_SB_GET(tn)) {
+    case CURL_TELOPT_TTYPE:
+      len = strlen(tn->subopt_ttype) + 4 + 2;
+      msnprintf((char *)temp, sizeof(temp),
+                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
+                CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
+      bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
+      if(bytes_written < 0) {
+        err = SOCKERRNO;
+        failf(data,"Sending data failed (%d)",err);
+      }
+      printsub(data, '>', &temp[2], len-2);
+      break;
+    case CURL_TELOPT_XDISPLOC:
+      len = strlen(tn->subopt_xdisploc) + 4 + 2;
+      msnprintf((char *)temp, sizeof(temp),
+                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
+                CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
+      bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
+      if(bytes_written < 0) {
+        err = SOCKERRNO;
+        failf(data,"Sending data failed (%d)",err);
+      }
+      printsub(data, '>', &temp[2], len-2);
+      break;
+    case CURL_TELOPT_NEW_ENVIRON:
+      msnprintf((char *)temp, sizeof(temp),
+                "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
+                CURL_TELQUAL_IS);
+      len = 4;
+
+      for(v = tn->telnet_vars; v; v = v->next) {
+        size_t tmplen = (strlen(v->data) + 1);
+        /* Add the variable if it fits */
+        if(len + tmplen < (int)sizeof(temp)-6) {
+          char *s = strchr(v->data, ',');
+          if(!s)
+            len += msnprintf((char *)&temp[len], sizeof(temp) - len,
+                             "%c%s", CURL_NEW_ENV_VAR, v->data);
+          else {
+            size_t vlen = s - v->data;
+            len += msnprintf((char *)&temp[len], sizeof(temp) - len,
+                             "%c%.*s%c%s", CURL_NEW_ENV_VAR,
+                             (int)vlen, v->data, CURL_NEW_ENV_VALUE, ++s);
+          }
+        }
+      }
+      msnprintf((char *)&temp[len], sizeof(temp) - len,
+                "%c%c", CURL_IAC, CURL_SE);
+      len += 2;
+      bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
+      if(bytes_written < 0) {
+        err = SOCKERRNO;
+        failf(data,"Sending data failed (%d)",err);
+      }
+      printsub(data, '>', &temp[2], len-2);
+      break;
+  }
+  return;
+}
+
+
+/*
+ * sendsuboption()
+ *
+ * Send suboption information to the server side.
+ */
+
+static void sendsuboption(struct Curl_easy *data, int option)
+{
+  ssize_t bytes_written;
+  int err;
+  unsigned short x, y;
+  unsigned char *uc1, *uc2;
+  struct TELNET *tn = data->req.p.telnet;
+  struct connectdata *conn = data->conn;
+
+  switch(option) {
+  case CURL_TELOPT_NAWS:
+    /* We prepare data to be sent */
+    CURL_SB_CLEAR(tn);
+    CURL_SB_ACCUM(tn, CURL_IAC);
+    CURL_SB_ACCUM(tn, CURL_SB);
+    CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
+    /* We must deal either with little or big endian processors */
+    /* Window size must be sent according to the 'network order' */
+    x = htons(tn->subopt_wsx);
+    y = htons(tn->subopt_wsy);
+    uc1 = (unsigned char *)&x;
+    uc2 = (unsigned char *)&y;
+    CURL_SB_ACCUM(tn, uc1[0]);
+    CURL_SB_ACCUM(tn, uc1[1]);
+    CURL_SB_ACCUM(tn, uc2[0]);
+    CURL_SB_ACCUM(tn, uc2[1]);
+
+    CURL_SB_ACCUM(tn, CURL_IAC);
+    CURL_SB_ACCUM(tn, CURL_SE);
+    CURL_SB_TERM(tn);
+    /* data suboption is now ready */
+
+    printsub(data, '>', (unsigned char *)tn->subbuffer + 2,
+             CURL_SB_LEN(tn)-2);
+
+    /* we send the header of the suboption... */
+    bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
+    if(bytes_written < 0) {
+      err = SOCKERRNO;
+      failf(data, "Sending data failed (%d)", err);
+    }
+    /* ... then the window size with the send_telnet_data() function
+       to deal with 0xFF cases ... */
+    send_telnet_data(data, (char *)tn->subbuffer + 3, 4);
+    /* ... and the footer */
+    bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2);
+    if(bytes_written < 0) {
+      err = SOCKERRNO;
+      failf(data, "Sending data failed (%d)", err);
+    }
+    break;
+  }
+}
+
+
+static
+CURLcode telrcv(struct Curl_easy *data,
+                const unsigned char *inbuf, /* Data received from socket */
+                ssize_t count)              /* Number of bytes received */
+{
+  unsigned char c;
+  CURLcode result;
+  int in = 0;
+  int startwrite = -1;
+  struct TELNET *tn = data->req.p.telnet;
+
+#define startskipping()                                       \
+  if(startwrite >= 0) {                                       \
+    result = Curl_client_write(data,                          \
+                               CLIENTWRITE_BODY,              \
+                               (char *)&inbuf[startwrite],    \
+                               in-startwrite);                \
+    if(result)                                                \
+      return result;                                          \
+  }                                                           \
+  startwrite = -1
+
+#define writebyte() \
+    if(startwrite < 0) \
+      startwrite = in
+
+#define bufferflush() startskipping()
+
+  while(count--) {
+    c = inbuf[in];
+
+    switch(tn->telrcv_state) {
+    case CURL_TS_CR:
+      tn->telrcv_state = CURL_TS_DATA;
+      if(c == '\0') {
+        startskipping();
+        break;   /* Ignore \0 after CR */
+      }
+      writebyte();
+      break;
+
+    case CURL_TS_DATA:
+      if(c == CURL_IAC) {
+        tn->telrcv_state = CURL_TS_IAC;
+        startskipping();
+        break;
+      }
+      else if(c == '\r')
+        tn->telrcv_state = CURL_TS_CR;
+      writebyte();
+      break;
+
+    case CURL_TS_IAC:
+process_iac:
+      DEBUGASSERT(startwrite < 0);
+      switch(c) {
+      case CURL_WILL:
+        tn->telrcv_state = CURL_TS_WILL;
+        break;
+      case CURL_WONT:
+        tn->telrcv_state = CURL_TS_WONT;
+        break;
+      case CURL_DO:
+        tn->telrcv_state = CURL_TS_DO;
+        break;
+      case CURL_DONT:
+        tn->telrcv_state = CURL_TS_DONT;
+        break;
+      case CURL_SB:
+        CURL_SB_CLEAR(tn);
+        tn->telrcv_state = CURL_TS_SB;
+        break;
+      case CURL_IAC:
+        tn->telrcv_state = CURL_TS_DATA;
+        writebyte();
+        break;
+      case CURL_DM:
+      case CURL_NOP:
+      case CURL_GA:
+      default:
+        tn->telrcv_state = CURL_TS_DATA;
+        printoption(data, "RCVD", CURL_IAC, c);
+        break;
+      }
+      break;
+
+      case CURL_TS_WILL:
+        printoption(data, "RCVD", CURL_WILL, c);
+        tn->please_negotiate = 1;
+        rec_will(data, c);
+        tn->telrcv_state = CURL_TS_DATA;
+        break;
+
+      case CURL_TS_WONT:
+        printoption(data, "RCVD", CURL_WONT, c);
+        tn->please_negotiate = 1;
+        rec_wont(data, c);
+        tn->telrcv_state = CURL_TS_DATA;
+        break;
+
+      case CURL_TS_DO:
+        printoption(data, "RCVD", CURL_DO, c);
+        tn->please_negotiate = 1;
+        rec_do(data, c);
+        tn->telrcv_state = CURL_TS_DATA;
+        break;
+
+      case CURL_TS_DONT:
+        printoption(data, "RCVD", CURL_DONT, c);
+        tn->please_negotiate = 1;
+        rec_dont(data, c);
+        tn->telrcv_state = CURL_TS_DATA;
+        break;
+
+      case CURL_TS_SB:
+        if(c == CURL_IAC)
+          tn->telrcv_state = CURL_TS_SE;
+        else
+          CURL_SB_ACCUM(tn, c);
+        break;
+
+      case CURL_TS_SE:
+        if(c != CURL_SE) {
+          if(c != CURL_IAC) {
+            /*
+             * This is an error.  We only expect to get "IAC IAC" or "IAC SE".
+             * Several things may have happened.  An IAC was not doubled, the
+             * IAC SE was left off, or another option got inserted into the
+             * suboption are all possibilities.  If we assume that the IAC was
+             * not doubled, and really the IAC SE was left off, we could get
+             * into an infinite loop here.  So, instead, we terminate the
+             * suboption, and process the partial suboption if we can.
+             */
+            CURL_SB_ACCUM(tn, CURL_IAC);
+            CURL_SB_ACCUM(tn, c);
+            tn->subpointer -= 2;
+            CURL_SB_TERM(tn);
+
+            printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
+            suboption(data);   /* handle sub-option */
+            tn->telrcv_state = CURL_TS_IAC;
+            goto process_iac;
+          }
+          CURL_SB_ACCUM(tn, c);
+          tn->telrcv_state = CURL_TS_SB;
+        }
+        else {
+          CURL_SB_ACCUM(tn, CURL_IAC);
+          CURL_SB_ACCUM(tn, CURL_SE);
+          tn->subpointer -= 2;
+          CURL_SB_TERM(tn);
+          suboption(data);   /* handle sub-option */
+          tn->telrcv_state = CURL_TS_DATA;
+        }
+        break;
+    }
+    ++in;
+  }
+  bufferflush();
+  return CURLE_OK;
+}
+
+/* Escape and send a telnet data block */
+static CURLcode send_telnet_data(struct Curl_easy *data,
+                                 char *buffer, ssize_t nread)
+{
+  size_t i, outlen;
+  unsigned char *outbuf;
+  CURLcode result = CURLE_OK;
+  size_t bytes_written;
+  size_t total_written = 0;
+  struct connectdata *conn = data->conn;
+  struct TELNET *tn = data->req.p.telnet;
+
+  DEBUGASSERT(tn);
+  DEBUGASSERT(nread > 0);
+  if(nread < 0)
+    return CURLE_TOO_LARGE;
+
+  if(memchr(buffer, CURL_IAC, nread)) {
+    /* only use the escape buffer when necessary */
+    Curl_dyn_reset(&tn->out);
+
+    for(i = 0; i < (size_t)nread && !result; i++) {
+      result = Curl_dyn_addn(&tn->out, &buffer[i], 1);
+      if(!result && ((unsigned char)buffer[i] == CURL_IAC))
+        /* IAC is FF in hex */
+        result = Curl_dyn_addn(&tn->out, "\xff", 1);
+    }
+
+    outlen = Curl_dyn_len(&tn->out);
+    outbuf = Curl_dyn_uptr(&tn->out);
+  }
+  else {
+    outlen = (size_t)nread;
+    outbuf = (unsigned char *)buffer;
+  }
+  while(!result && total_written < outlen) {
+    /* Make sure socket is writable to avoid EWOULDBLOCK condition */
+    struct pollfd pfd[1];
+    pfd[0].fd = conn->sock[FIRSTSOCKET];
+    pfd[0].events = POLLOUT;
+    switch(Curl_poll(pfd, 1, -1)) {
+      case -1:                    /* error, abort writing */
+      case 0:                     /* timeout (will never happen) */
+        result = CURLE_SEND_ERROR;
+        break;
+      default:                    /* write! */
+        bytes_written = 0;
+        result = Curl_xfer_send(data, outbuf + total_written,
+                                outlen - total_written, &bytes_written);
+        total_written += bytes_written;
+        break;
+    }
+  }
+
+  return result;
+}
+
+static CURLcode telnet_done(struct Curl_easy *data,
+                            CURLcode status, bool premature)
+{
+  struct TELNET *tn = data->req.p.telnet;
+  (void)status; /* unused */
+  (void)premature; /* not used */
+
+  if(!tn)
+    return CURLE_OK;
+
+  curl_slist_free_all(tn->telnet_vars);
+  tn->telnet_vars = NULL;
+  Curl_dyn_free(&tn->out);
+  return CURLE_OK;
+}
+
+static CURLcode telnet_do(struct Curl_easy *data, bool *done)
+{
+  CURLcode result;
+  struct connectdata *conn = data->conn;
+  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+#ifdef USE_WINSOCK
+  WSAEVENT event_handle;
+  WSANETWORKEVENTS events;
+  HANDLE stdin_handle;
+  HANDLE objs[2];
+  DWORD  obj_count;
+  DWORD  wait_timeout;
+  DWORD readfile_read;
+  int err;
+#else
+  timediff_t interval_ms;
+  struct pollfd pfd[2];
+  int poll_cnt;
+  curl_off_t total_dl = 0;
+  curl_off_t total_ul = 0;
+#endif
+  ssize_t nread;
+  struct curltime now;
+  bool keepon = TRUE;
+  char buffer[4*1024];
+  struct TELNET *tn;
+
+  *done = TRUE; /* unconditionally */
+
+  result = init_telnet(data);
+  if(result)
+    return result;
+
+  tn = data->req.p.telnet;
+
+  result = check_telnet_options(data);
+  if(result)
+    return result;
+
+#ifdef USE_WINSOCK
+  /* We want to wait for both stdin and the socket. Since
+  ** the select() function in winsock only works on sockets
+  ** we have to use the WaitForMultipleObjects() call.
+  */
+
+  /* First, create a sockets event object */
+  event_handle = WSACreateEvent();
+  if(event_handle == WSA_INVALID_EVENT) {
+    failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
+    return CURLE_FAILED_INIT;
+  }
+
+  /* Tell winsock what events we want to listen to */
+  if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
+    WSACloseEvent(event_handle);
+    return CURLE_OK;
+  }
+
+  /* The get the Windows file handle for stdin */
+  stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
+
+  /* Create the list of objects to wait for */
+  objs[0] = event_handle;
+  objs[1] = stdin_handle;
+
+  /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
+     else use the old WaitForMultipleObjects() way */
+  if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
+     data->set.is_fread_set) {
+    /* Don't wait for stdin_handle, just wait for event_handle */
+    obj_count = 1;
+    /* Check stdin_handle per 100 milliseconds */
+    wait_timeout = 100;
+  }
+  else {
+    obj_count = 2;
+    wait_timeout = 1000;
+  }
+
+  /* Keep on listening and act on events */
+  while(keepon) {
+    const DWORD buf_size = (DWORD)sizeof(buffer);
+    DWORD waitret = WaitForMultipleObjects(obj_count, objs,
+                                           FALSE, wait_timeout);
+    switch(waitret) {
+
+    case WAIT_TIMEOUT:
+    {
+      for(;;) {
+        if(data->set.is_fread_set) {
+          size_t n;
+          /* read from user-supplied method */
+          n = data->state.fread_func(buffer, 1, buf_size, data->state.in);
+          if(n == CURL_READFUNC_ABORT) {
+            keepon = FALSE;
+            result = CURLE_READ_ERROR;
+            break;
+          }
+
+          if(n == CURL_READFUNC_PAUSE)
+            break;
+
+          if(n == 0)                        /* no bytes */
+            break;
+
+          /* fall through with number of bytes read */
+          readfile_read = (DWORD)n;
+        }
+        else {
+          /* read from stdin */
+          if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
+                            &readfile_read, NULL)) {
+            keepon = FALSE;
+            result = CURLE_READ_ERROR;
+            break;
+          }
+
+          if(!readfile_read)
+            break;
+
+          if(!ReadFile(stdin_handle, buffer, buf_size,
+                       &readfile_read, NULL)) {
+            keepon = FALSE;
+            result = CURLE_READ_ERROR;
+            break;
+          }
+        }
+
+        result = send_telnet_data(data, buffer, readfile_read);
+        if(result) {
+          keepon = FALSE;
+          break;
+        }
+      }
+    }
+    break;
+
+    case WAIT_OBJECT_0 + 1:
+    {
+      if(!ReadFile(stdin_handle, buffer, buf_size,
+                   &readfile_read, NULL)) {
+        keepon = FALSE;
+        result = CURLE_READ_ERROR;
+        break;
+      }
+
+      result = send_telnet_data(data, buffer, readfile_read);
+      if(result) {
+        keepon = FALSE;
+        break;
+      }
+    }
+    break;
+
+    case WAIT_OBJECT_0:
+    {
+      events.lNetworkEvents = 0;
+      if(WSAEnumNetworkEvents(sockfd, event_handle, &events) == SOCKET_ERROR) {
+        err = SOCKERRNO;
+        if(err != EINPROGRESS) {
+          infof(data, "WSAEnumNetworkEvents failed (%d)", err);
+          keepon = FALSE;
+          result = CURLE_READ_ERROR;
+        }
+        break;
+      }
+      if(events.lNetworkEvents & FD_READ) {
+        /* read data from network */
+        result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
+        /* read would've blocked. Loop again */
+        if(result == CURLE_AGAIN)
+          break;
+        /* returned not-zero, this an error */
+        else if(result) {
+          keepon = FALSE;
+          break;
+        }
+        /* returned zero but actually received 0 or less here,
+           the server closed the connection and we bail out */
+        else if(nread <= 0) {
+          keepon = FALSE;
+          break;
+        }
+
+        result = telrcv(data, (unsigned char *) buffer, nread);
+        if(result) {
+          keepon = FALSE;
+          break;
+        }
+
+        /* Negotiate if the peer has started negotiating,
+           otherwise don't. We don't want to speak telnet with
+           non-telnet servers, like POP or SMTP. */
+        if(tn->please_negotiate && !tn->already_negotiated) {
+          negotiate(data);
+          tn->already_negotiated = 1;
+        }
+      }
+      if(events.lNetworkEvents & FD_CLOSE) {
+        keepon = FALSE;
+      }
+    }
+    break;
+
+    }
+
+    if(data->set.timeout) {
+      now = Curl_now();
+      if(Curl_timediff(now, conn->created) >= data->set.timeout) {
+        failf(data, "Time-out");
+        result = CURLE_OPERATION_TIMEDOUT;
+        keepon = FALSE;
+      }
+    }
+  }
+
+  /* We called WSACreateEvent, so call WSACloseEvent */
+  if(!WSACloseEvent(event_handle)) {
+    infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
+  }
+#else
+  pfd[0].fd = sockfd;
+  pfd[0].events = POLLIN;
+
+  if(data->set.is_fread_set) {
+    poll_cnt = 1;
+    interval_ms = 100; /* poll user-supplied read function */
+  }
+  else {
+    /* really using fread, so infile is a FILE* */
+    pfd[1].fd = fileno((FILE *)data->state.in);
+    pfd[1].events = POLLIN;
+    poll_cnt = 2;
+    interval_ms = 1 * 1000;
+  }
+
+  while(keepon) {
+    DEBUGF(infof(data, "telnet_do, poll %d fds", poll_cnt));
+    switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
+    case -1:                    /* error, stop reading */
+      keepon = FALSE;
+      continue;
+    case 0:                     /* timeout */
+      pfd[0].revents = 0;
+      pfd[1].revents = 0;
+      FALLTHROUGH();
+    default:                    /* read! */
+      if(pfd[0].revents & POLLIN) {
+        /* read data from network */
+        result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
+        /* read would've blocked. Loop again */
+        if(result == CURLE_AGAIN)
+          break;
+        /* returned not-zero, this an error */
+        if(result) {
+          keepon = FALSE;
+          /* TODO: in test 1452, macOS sees a ECONNRESET sometimes?
+           * Is this the telnet test server not shutting down the socket
+           * in a clean way? Seems to be timing related, happens more
+           * on slow debug build */
+          if(data->state.os_errno == ECONNRESET) {
+            DEBUGF(infof(data, "telnet_do, unexpected ECONNRESET on recv"));
+          }
+          break;
+        }
+        /* returned zero but actually received 0 or less here,
+           the server closed the connection and we bail out */
+        else if(nread <= 0) {
+          keepon = FALSE;
+          break;
+        }
+
+        total_dl += nread;
+        result = Curl_pgrsSetDownloadCounter(data, total_dl);
+        if(!result)
+          result = telrcv(data, (unsigned char *)buffer, nread);
+        if(result) {
+          keepon = FALSE;
+          break;
+        }
+
+        /* Negotiate if the peer has started negotiating,
+           otherwise don't. We don't want to speak telnet with
+           non-telnet servers, like POP or SMTP. */
+        if(tn->please_negotiate && !tn->already_negotiated) {
+          negotiate(data);
+          tn->already_negotiated = 1;
+        }
+      }
+
+      nread = 0;
+      if(poll_cnt == 2) {
+        if(pfd[1].revents & POLLIN) { /* read from in file */
+          nread = read(pfd[1].fd, buffer, sizeof(buffer));
+        }
+      }
+      else {
+        /* read from user-supplied method */
+        nread = (int)data->state.fread_func(buffer, 1, sizeof(buffer),
+                                            data->state.in);
+        if(nread == CURL_READFUNC_ABORT) {
+          keepon = FALSE;
+          break;
+        }
+        if(nread == CURL_READFUNC_PAUSE)
+          break;
+      }
+
+      if(nread > 0) {
+        result = send_telnet_data(data, buffer, nread);
+        if(result) {
+          keepon = FALSE;
+          break;
+        }
+        total_ul += nread;
+        Curl_pgrsSetUploadCounter(data, total_ul);
+      }
+      else if(nread < 0)
+        keepon = FALSE;
+
+      break;
+    } /* poll switch statement */
+
+    if(data->set.timeout) {
+      now = Curl_now();
+      if(Curl_timediff(now, conn->created) >= data->set.timeout) {
+        failf(data, "Time-out");
+        result = CURLE_OPERATION_TIMEDOUT;
+        keepon = FALSE;
+      }
+    }
+
+    if(Curl_pgrsUpdate(data)) {
+      result = CURLE_ABORTED_BY_CALLBACK;
+      break;
+    }
+  }
+#endif
+  /* mark this as "no further transfer wanted" */
+  Curl_xfer_setup(data, -1, -1, FALSE, -1);
+
+  return result;
+}
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/telnet.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/telnet.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/telnet.h	(revision 104083)
@@ -0,0 +1,30 @@
+#ifndef HEADER_CURL_TELNET_H
+#define HEADER_CURL_TELNET_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TELNET
+extern const struct Curl_handler Curl_handler_telnet;
+#endif
+
+#endif /* HEADER_CURL_TELNET_H */
Index: trunk/src/libs/curl-8.7.1/lib/tftp.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/tftp.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/tftp.c	(revision 104083)
@@ -0,0 +1,1406 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_TFTP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "cf-socket.h"
+#include "transfer.h"
+#include "sendf.h"
+#include "tftp.h"
+#include "progress.h"
+#include "connect.h"
+#include "strerror.h"
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "multiif.h"
+#include "url.h"
+#include "strcase.h"
+#include "speedcheck.h"
+#include "select.h"
+#include "escape.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* RFC2348 allows the block size to be negotiated */
+#define TFTP_BLKSIZE_DEFAULT 512
+#define TFTP_OPTION_BLKSIZE "blksize"
+
+/* from RFC2349: */
+#define TFTP_OPTION_TSIZE    "tsize"
+#define TFTP_OPTION_INTERVAL "timeout"
+
+typedef enum {
+  TFTP_MODE_NETASCII = 0,
+  TFTP_MODE_OCTET
+} tftp_mode_t;
+
+typedef enum {
+  TFTP_STATE_START = 0,
+  TFTP_STATE_RX,
+  TFTP_STATE_TX,
+  TFTP_STATE_FIN
+} tftp_state_t;
+
+typedef enum {
+  TFTP_EVENT_NONE = -1,
+  TFTP_EVENT_INIT = 0,
+  TFTP_EVENT_RRQ = 1,
+  TFTP_EVENT_WRQ = 2,
+  TFTP_EVENT_DATA = 3,
+  TFTP_EVENT_ACK = 4,
+  TFTP_EVENT_ERROR = 5,
+  TFTP_EVENT_OACK = 6,
+  TFTP_EVENT_TIMEOUT
+} tftp_event_t;
+
+typedef enum {
+  TFTP_ERR_UNDEF = 0,
+  TFTP_ERR_NOTFOUND,
+  TFTP_ERR_PERM,
+  TFTP_ERR_DISKFULL,
+  TFTP_ERR_ILLEGAL,
+  TFTP_ERR_UNKNOWNID,
+  TFTP_ERR_EXISTS,
+  TFTP_ERR_NOSUCHUSER,  /* This will never be triggered by this code */
+
+  /* The remaining error codes are internal to curl */
+  TFTP_ERR_NONE = -100,
+  TFTP_ERR_TIMEOUT,
+  TFTP_ERR_NORESPONSE
+} tftp_error_t;
+
+struct tftp_packet {
+  unsigned char *data;
+};
+
+struct tftp_state_data {
+  tftp_state_t    state;
+  tftp_mode_t     mode;
+  tftp_error_t    error;
+  tftp_event_t    event;
+  struct Curl_easy *data;
+  curl_socket_t   sockfd;
+  int             retries;
+  int             retry_time;
+  int             retry_max;
+  time_t          rx_time;
+  struct Curl_sockaddr_storage   local_addr;
+  struct Curl_sockaddr_storage   remote_addr;
+  curl_socklen_t  remote_addrlen;
+  int             rbytes;
+  int             sbytes;
+  int             blksize;
+  int             requested_blksize;
+  unsigned short  block;
+  struct tftp_packet rpacket;
+  struct tftp_packet spacket;
+};
+
+
+/* Forward declarations */
+static CURLcode tftp_rx(struct tftp_state_data *state, tftp_event_t event);
+static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event);
+static CURLcode tftp_connect(struct Curl_easy *data, bool *done);
+static CURLcode tftp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                bool dead_connection);
+static CURLcode tftp_do(struct Curl_easy *data, bool *done);
+static CURLcode tftp_done(struct Curl_easy *data,
+                          CURLcode, bool premature);
+static CURLcode tftp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done);
+static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done);
+static int tftp_getsock(struct Curl_easy *data, struct connectdata *conn,
+                        curl_socket_t *socks);
+static CURLcode tftp_translate_code(tftp_error_t error);
+
+
+/*
+ * TFTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_tftp = {
+  "TFTP",                               /* scheme */
+  tftp_setup_connection,                /* setup_connection */
+  tftp_do,                              /* do_it */
+  tftp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  tftp_connect,                         /* connect_it */
+  tftp_multi_statemach,                 /* connecting */
+  tftp_doing,                           /* doing */
+  tftp_getsock,                         /* proto_getsock */
+  tftp_getsock,                         /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  tftp_disconnect,                      /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_TFTP,                            /* defport */
+  CURLPROTO_TFTP,                       /* protocol */
+  CURLPROTO_TFTP,                       /* family */
+  PROTOPT_NOTCPPROXY | PROTOPT_NOURLQUERY /* flags */
+};
+
+/**********************************************************
+ *
+ * tftp_set_timeouts -
+ *
+ * Set timeouts based on state machine state.
+ * Use user provided connect timeouts until DATA or ACK
+ * packet is received, then use user-provided transfer timeouts
+ *
+ *
+ **********************************************************/
+static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
+{
+  time_t maxtime, timeout;
+  timediff_t timeout_ms;
+  bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE;
+
+  /* Compute drop-dead time */
+  timeout_ms = Curl_timeleft(state->data, NULL, start);
+
+  if(timeout_ms < 0) {
+    /* time-out, bail out, go home */
+    failf(state->data, "Connection time-out");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  if(timeout_ms > 0)
+    maxtime = (time_t)(timeout_ms + 500) / 1000;
+  else
+    maxtime = 3600; /* use for calculating block timeouts */
+
+  /* Set per-block timeout to total */
+  timeout = maxtime;
+
+  /* Average reposting an ACK after 5 seconds */
+  state->retry_max = (int)timeout/5;
+
+  /* But bound the total number */
+  if(state->retry_max<3)
+    state->retry_max = 3;
+
+  if(state->retry_max>50)
+    state->retry_max = 50;
+
+  /* Compute the re-ACK interval to suit the timeout */
+  state->retry_time = (int)(timeout/state->retry_max);
+  if(state->retry_time<1)
+    state->retry_time = 1;
+
+  infof(state->data,
+        "set timeouts for state %d; Total % " CURL_FORMAT_CURL_OFF_T
+        ", retry %d maxtry %d",
+        (int)state->state, timeout_ms, state->retry_time, state->retry_max);
+
+  /* init RX time */
+  time(&state->rx_time);
+
+  return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_set_send_first
+ *
+ * Event handler for the START state
+ *
+ **********************************************************/
+
+static void setpacketevent(struct tftp_packet *packet, unsigned short num)
+{
+  packet->data[0] = (unsigned char)(num >> 8);
+  packet->data[1] = (unsigned char)(num & 0xff);
+}
+
+
+static void setpacketblock(struct tftp_packet *packet, unsigned short num)
+{
+  packet->data[2] = (unsigned char)(num >> 8);
+  packet->data[3] = (unsigned char)(num & 0xff);
+}
+
+static unsigned short getrpacketevent(const struct tftp_packet *packet)
+{
+  return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
+}
+
+static unsigned short getrpacketblock(const struct tftp_packet *packet)
+{
+  return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
+}
+
+static size_t tftp_strnlen(const char *string, size_t maxlen)
+{
+  const char *end = memchr(string, '\0', maxlen);
+  return end ? (size_t) (end - string) : maxlen;
+}
+
+static const char *tftp_option_get(const char *buf, size_t len,
+                                   const char **option, const char **value)
+{
+  size_t loc;
+
+  loc = tftp_strnlen(buf, len);
+  loc++; /* NULL term */
+
+  if(loc >= len)
+    return NULL;
+  *option = buf;
+
+  loc += tftp_strnlen(buf + loc, len-loc);
+  loc++; /* NULL term */
+
+  if(loc > len)
+    return NULL;
+  *value = &buf[strlen(*option) + 1];
+
+  return &buf[loc];
+}
+
+static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
+                                      const char *ptr, int len)
+{
+  const char *tmp = ptr;
+  struct Curl_easy *data = state->data;
+
+  /* if OACK doesn't contain blksize option, the default (512) must be used */
+  state->blksize = TFTP_BLKSIZE_DEFAULT;
+
+  while(tmp < ptr + len) {
+    const char *option, *value;
+
+    tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
+    if(!tmp) {
+      failf(data, "Malformed ACK packet, rejecting");
+      return CURLE_TFTP_ILLEGAL;
+    }
+
+    infof(data, "got option=(%s) value=(%s)", option, value);
+
+    if(checkprefix(TFTP_OPTION_BLKSIZE, option)) {
+      long blksize;
+
+      blksize = strtol(value, NULL, 10);
+
+      if(!blksize) {
+        failf(data, "invalid blocksize value in OACK packet");
+        return CURLE_TFTP_ILLEGAL;
+      }
+      if(blksize > TFTP_BLKSIZE_MAX) {
+        failf(data, "%s (%d)", "blksize is larger than max supported",
+              TFTP_BLKSIZE_MAX);
+        return CURLE_TFTP_ILLEGAL;
+      }
+      else if(blksize < TFTP_BLKSIZE_MIN) {
+        failf(data, "%s (%d)", "blksize is smaller than min supported",
+              TFTP_BLKSIZE_MIN);
+        return CURLE_TFTP_ILLEGAL;
+      }
+      else if(blksize > state->requested_blksize) {
+        /* could realloc pkt buffers here, but the spec doesn't call out
+         * support for the server requesting a bigger blksize than the client
+         * requests */
+        failf(data, "%s (%ld)",
+              "server requested blksize larger than allocated", blksize);
+        return CURLE_TFTP_ILLEGAL;
+      }
+
+      state->blksize = (int)blksize;
+      infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK",
+            state->blksize, "requested", state->requested_blksize);
+    }
+    else if(checkprefix(TFTP_OPTION_TSIZE, option)) {
+      long tsize = 0;
+
+      tsize = strtol(value, NULL, 10);
+      infof(data, "%s (%ld)", "tsize parsed from OACK", tsize);
+
+      /* tsize should be ignored on upload: Who cares about the size of the
+         remote file? */
+      if(!data->state.upload) {
+        if(!tsize) {
+          failf(data, "invalid tsize -:%s:- value in OACK packet", value);
+          return CURLE_TFTP_ILLEGAL;
+        }
+        Curl_pgrsSetDownloadSize(data, tsize);
+      }
+    }
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode tftp_option_add(struct tftp_state_data *state, size_t *csize,
+                                char *buf, const char *option)
+{
+  if(( strlen(option) + *csize + 1) > (size_t)state->blksize)
+    return CURLE_TFTP_ILLEGAL;
+  strcpy(buf, option);
+  *csize += strlen(option) + 1;
+  return CURLE_OK;
+}
+
+static CURLcode tftp_connect_for_tx(struct tftp_state_data *state,
+                                    tftp_event_t event)
+{
+  CURLcode result;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  struct Curl_easy *data = state->data;
+
+  infof(data, "%s", "Connected for transmit");
+#endif
+  state->state = TFTP_STATE_TX;
+  result = tftp_set_timeouts(state);
+  if(result)
+    return result;
+  return tftp_tx(state, event);
+}
+
+static CURLcode tftp_connect_for_rx(struct tftp_state_data *state,
+                                    tftp_event_t event)
+{
+  CURLcode result;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  struct Curl_easy *data = state->data;
+
+  infof(data, "%s", "Connected for receive");
+#endif
+  state->state = TFTP_STATE_RX;
+  result = tftp_set_timeouts(state);
+  if(result)
+    return result;
+  return tftp_rx(state, event);
+}
+
+static CURLcode tftp_send_first(struct tftp_state_data *state,
+                                tftp_event_t event)
+{
+  size_t sbytes;
+  ssize_t senddata;
+  const char *mode = "octet";
+  char *filename;
+  struct Curl_easy *data = state->data;
+  CURLcode result = CURLE_OK;
+
+  /* Set ascii mode if -B flag was used */
+  if(data->state.prefer_ascii)
+    mode = "netascii";
+
+  switch(event) {
+
+  case TFTP_EVENT_INIT:    /* Send the first packet out */
+  case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
+    /* Increment the retry counter, quit if over the limit */
+    state->retries++;
+    if(state->retries>state->retry_max) {
+      state->error = TFTP_ERR_NORESPONSE;
+      state->state = TFTP_STATE_FIN;
+      return result;
+    }
+
+    if(data->state.upload) {
+      /* If we are uploading, send an WRQ */
+      setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
+      if(data->state.infilesize != -1)
+        Curl_pgrsSetUploadSize(data, data->state.infilesize);
+    }
+    else {
+      /* If we are downloading, send an RRQ */
+      setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
+    }
+    /* As RFC3617 describes the separator slash is not actually part of the
+       file name so we skip the always-present first letter of the path
+       string. */
+    result = Curl_urldecode(&state->data->state.up.path[1], 0,
+                            &filename, NULL, REJECT_ZERO);
+    if(result)
+      return result;
+
+    if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
+      failf(data, "TFTP file name too long");
+      free(filename);
+      return CURLE_TFTP_ILLEGAL; /* too long file name field */
+    }
+
+    msnprintf((char *)state->spacket.data + 2,
+              state->blksize,
+              "%s%c%s%c", filename, '\0',  mode, '\0');
+    sbytes = 4 + strlen(filename) + strlen(mode);
+
+    /* optional addition of TFTP options */
+    if(!data->set.tftp_no_options) {
+      char buf[64];
+      /* add tsize option */
+      if(data->state.upload && (data->state.infilesize != -1))
+        msnprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
+                  data->state.infilesize);
+      else
+        strcpy(buf, "0"); /* the destination is large enough */
+
+      result = tftp_option_add(state, &sbytes,
+                               (char *)state->spacket.data + sbytes,
+                               TFTP_OPTION_TSIZE);
+      if(result == CURLE_OK)
+        result = tftp_option_add(state, &sbytes,
+                                 (char *)state->spacket.data + sbytes, buf);
+
+      /* add blksize option */
+      msnprintf(buf, sizeof(buf), "%d", state->requested_blksize);
+      if(result == CURLE_OK)
+        result = tftp_option_add(state, &sbytes,
+                                 (char *)state->spacket.data + sbytes,
+                                 TFTP_OPTION_BLKSIZE);
+      if(result == CURLE_OK)
+        result = tftp_option_add(state, &sbytes,
+                                 (char *)state->spacket.data + sbytes, buf);
+
+      /* add timeout option */
+      msnprintf(buf, sizeof(buf), "%d", state->retry_time);
+      if(result == CURLE_OK)
+        result = tftp_option_add(state, &sbytes,
+                                 (char *)state->spacket.data + sbytes,
+                                 TFTP_OPTION_INTERVAL);
+      if(result == CURLE_OK)
+        result = tftp_option_add(state, &sbytes,
+                                 (char *)state->spacket.data + sbytes, buf);
+
+      if(result != CURLE_OK) {
+        failf(data, "TFTP buffer too small for options");
+        free(filename);
+        return CURLE_TFTP_ILLEGAL;
+      }
+    }
+
+    /* the typecase for the 3rd argument is mostly for systems that do
+       not have a size_t argument, like older unixes that want an 'int' */
+    senddata = sendto(state->sockfd, (void *)state->spacket.data,
+                      (SEND_TYPE_ARG3)sbytes, 0,
+                      &data->conn->remote_addr->sa_addr,
+                      data->conn->remote_addr->addrlen);
+    if(senddata != (ssize_t)sbytes) {
+      char buffer[STRERROR_LEN];
+      failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+    }
+    free(filename);
+    break;
+
+  case TFTP_EVENT_OACK:
+    if(data->state.upload) {
+      result = tftp_connect_for_tx(state, event);
+    }
+    else {
+      result = tftp_connect_for_rx(state, event);
+    }
+    break;
+
+  case TFTP_EVENT_ACK: /* Connected for transmit */
+    result = tftp_connect_for_tx(state, event);
+    break;
+
+  case TFTP_EVENT_DATA: /* Connected for receive */
+    result = tftp_connect_for_rx(state, event);
+    break;
+
+  case TFTP_EVENT_ERROR:
+    state->state = TFTP_STATE_FIN;
+    break;
+
+  default:
+    failf(state->data, "tftp_send_first: internal error");
+    break;
+  }
+
+  return result;
+}
+
+/* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
+   boundary */
+#define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff)
+
+/**********************************************************
+ *
+ * tftp_rx
+ *
+ * Event handler for the RX state
+ *
+ **********************************************************/
+static CURLcode tftp_rx(struct tftp_state_data *state,
+                        tftp_event_t event)
+{
+  ssize_t sbytes;
+  int rblock;
+  struct Curl_easy *data = state->data;
+  char buffer[STRERROR_LEN];
+
+  switch(event) {
+
+  case TFTP_EVENT_DATA:
+    /* Is this the block we expect? */
+    rblock = getrpacketblock(&state->rpacket);
+    if(NEXT_BLOCKNUM(state->block) == rblock) {
+      /* This is the expected block.  Reset counters and ACK it. */
+      state->retries = 0;
+    }
+    else if(state->block == rblock) {
+      /* This is the last recently received block again. Log it and ACK it
+         again. */
+      infof(data, "Received last DATA packet block %d again.", rblock);
+    }
+    else {
+      /* totally unexpected, just log it */
+      infof(data,
+            "Received unexpected DATA packet block %d, expecting block %d",
+            rblock, NEXT_BLOCKNUM(state->block));
+      break;
+    }
+
+    /* ACK this block. */
+    state->block = (unsigned short)rblock;
+    setpacketevent(&state->spacket, TFTP_EVENT_ACK);
+    setpacketblock(&state->spacket, state->block);
+    sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+                    4, SEND_4TH_ARG,
+                    (struct sockaddr *)&state->remote_addr,
+                    state->remote_addrlen);
+    if(sbytes < 0) {
+      failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+      return CURLE_SEND_ERROR;
+    }
+
+    /* Check if completed (That is, a less than full packet is received) */
+    if(state->rbytes < (ssize_t)state->blksize + 4) {
+      state->state = TFTP_STATE_FIN;
+    }
+    else {
+      state->state = TFTP_STATE_RX;
+    }
+    time(&state->rx_time);
+    break;
+
+  case TFTP_EVENT_OACK:
+    /* ACK option acknowledgement so we can move on to data */
+    state->block = 0;
+    state->retries = 0;
+    setpacketevent(&state->spacket, TFTP_EVENT_ACK);
+    setpacketblock(&state->spacket, state->block);
+    sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+                    4, SEND_4TH_ARG,
+                    (struct sockaddr *)&state->remote_addr,
+                    state->remote_addrlen);
+    if(sbytes < 0) {
+      failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+      return CURLE_SEND_ERROR;
+    }
+
+    /* we're ready to RX data */
+    state->state = TFTP_STATE_RX;
+    time(&state->rx_time);
+    break;
+
+  case TFTP_EVENT_TIMEOUT:
+    /* Increment the retry count and fail if over the limit */
+    state->retries++;
+    infof(data,
+          "Timeout waiting for block %d ACK.  Retries = %d",
+          NEXT_BLOCKNUM(state->block), state->retries);
+    if(state->retries > state->retry_max) {
+      state->error = TFTP_ERR_TIMEOUT;
+      state->state = TFTP_STATE_FIN;
+    }
+    else {
+      /* Resend the previous ACK */
+      sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+                      4, SEND_4TH_ARG,
+                      (struct sockaddr *)&state->remote_addr,
+                      state->remote_addrlen);
+      if(sbytes<0) {
+        failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+        return CURLE_SEND_ERROR;
+      }
+    }
+    break;
+
+  case TFTP_EVENT_ERROR:
+    setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
+    setpacketblock(&state->spacket, state->block);
+    (void)sendto(state->sockfd, (void *)state->spacket.data,
+                 4, SEND_4TH_ARG,
+                 (struct sockaddr *)&state->remote_addr,
+                 state->remote_addrlen);
+    /* don't bother with the return code, but if the socket is still up we
+     * should be a good TFTP client and let the server know we're done */
+    state->state = TFTP_STATE_FIN;
+    break;
+
+  default:
+    failf(data, "%s", "tftp_rx: internal error");
+    return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
+                                  this */
+  }
+  return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_tx
+ *
+ * Event handler for the TX state
+ *
+ **********************************************************/
+static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
+{
+  struct Curl_easy *data = state->data;
+  ssize_t sbytes;
+  CURLcode result = CURLE_OK;
+  struct SingleRequest *k = &data->req;
+  size_t cb; /* Bytes currently read */
+  char buffer[STRERROR_LEN];
+  char *bufptr;
+  bool eos;
+
+  switch(event) {
+
+  case TFTP_EVENT_ACK:
+  case TFTP_EVENT_OACK:
+    if(event == TFTP_EVENT_ACK) {
+      /* Ack the packet */
+      int rblock = getrpacketblock(&state->rpacket);
+
+      if(rblock != state->block &&
+         /* There's a bug in tftpd-hpa that causes it to send us an ack for
+          * 65535 when the block number wraps to 0. So when we're expecting
+          * 0, also accept 65535. See
+          * https://www.syslinux.org/archives/2010-September/015612.html
+          * */
+         !(state->block == 0 && rblock == 65535)) {
+        /* This isn't the expected block.  Log it and up the retry counter */
+        infof(data, "Received ACK for block %d, expecting %d",
+              rblock, state->block);
+        state->retries++;
+        /* Bail out if over the maximum */
+        if(state->retries>state->retry_max) {
+          failf(data, "tftp_tx: giving up waiting for block %d ack",
+                state->block);
+          result = CURLE_SEND_ERROR;
+        }
+        else {
+          /* Re-send the data packet */
+          sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+                          4 + state->sbytes, SEND_4TH_ARG,
+                          (struct sockaddr *)&state->remote_addr,
+                          state->remote_addrlen);
+          /* Check all sbytes were sent */
+          if(sbytes<0) {
+            failf(data, "%s", Curl_strerror(SOCKERRNO,
+                                            buffer, sizeof(buffer)));
+            result = CURLE_SEND_ERROR;
+          }
+        }
+
+        return result;
+      }
+      /* This is the expected packet.  Reset the counters and send the next
+         block */
+      time(&state->rx_time);
+      state->block++;
+    }
+    else
+      state->block = 1; /* first data block is 1 when using OACK */
+
+    state->retries = 0;
+    setpacketevent(&state->spacket, TFTP_EVENT_DATA);
+    setpacketblock(&state->spacket, state->block);
+    if(state->block > 1 && state->sbytes < state->blksize) {
+      state->state = TFTP_STATE_FIN;
+      return CURLE_OK;
+    }
+
+    /* TFTP considers data block size < 512 bytes as an end of session. So
+     * in some cases we must wait for additional data to build full (512 bytes)
+     * data block.
+     * */
+    state->sbytes = 0;
+    bufptr = (char *)state->spacket.data + 4;
+    do {
+      result = Curl_client_read(data, bufptr, state->blksize - state->sbytes,
+                                &cb, &eos);
+      if(result)
+        return result;
+      state->sbytes += (int)cb;
+      bufptr += cb;
+    } while(state->sbytes < state->blksize && cb);
+
+    sbytes = sendto(state->sockfd, (void *) state->spacket.data,
+                    4 + state->sbytes, SEND_4TH_ARG,
+                    (struct sockaddr *)&state->remote_addr,
+                    state->remote_addrlen);
+    /* Check all sbytes were sent */
+    if(sbytes<0) {
+      failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+      return CURLE_SEND_ERROR;
+    }
+    /* Update the progress meter */
+    k->writebytecount += state->sbytes;
+    Curl_pgrsSetUploadCounter(data, k->writebytecount);
+    break;
+
+  case TFTP_EVENT_TIMEOUT:
+    /* Increment the retry counter and log the timeout */
+    state->retries++;
+    infof(data, "Timeout waiting for block %d ACK. "
+          " Retries = %d", NEXT_BLOCKNUM(state->block), state->retries);
+    /* Decide if we've had enough */
+    if(state->retries > state->retry_max) {
+      state->error = TFTP_ERR_TIMEOUT;
+      state->state = TFTP_STATE_FIN;
+    }
+    else {
+      /* Re-send the data packet */
+      sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+                      4 + state->sbytes, SEND_4TH_ARG,
+                      (struct sockaddr *)&state->remote_addr,
+                      state->remote_addrlen);
+      /* Check all sbytes were sent */
+      if(sbytes<0) {
+        failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+        return CURLE_SEND_ERROR;
+      }
+      /* since this was a re-send, we remain at the still byte position */
+      Curl_pgrsSetUploadCounter(data, k->writebytecount);
+    }
+    break;
+
+  case TFTP_EVENT_ERROR:
+    state->state = TFTP_STATE_FIN;
+    setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
+    setpacketblock(&state->spacket, state->block);
+    (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
+                 (struct sockaddr *)&state->remote_addr,
+                 state->remote_addrlen);
+    /* don't bother with the return code, but if the socket is still up we
+     * should be a good TFTP client and let the server know we're done */
+    state->state = TFTP_STATE_FIN;
+    break;
+
+  default:
+    failf(data, "tftp_tx: internal error, event: %i", (int)(event));
+    break;
+  }
+
+  return result;
+}
+
+/**********************************************************
+ *
+ * tftp_translate_code
+ *
+ * Translate internal error codes to CURL error codes
+ *
+ **********************************************************/
+static CURLcode tftp_translate_code(tftp_error_t error)
+{
+  CURLcode result = CURLE_OK;
+
+  if(error != TFTP_ERR_NONE) {
+    switch(error) {
+    case TFTP_ERR_NOTFOUND:
+      result = CURLE_TFTP_NOTFOUND;
+      break;
+    case TFTP_ERR_PERM:
+      result = CURLE_TFTP_PERM;
+      break;
+    case TFTP_ERR_DISKFULL:
+      result = CURLE_REMOTE_DISK_FULL;
+      break;
+    case TFTP_ERR_UNDEF:
+    case TFTP_ERR_ILLEGAL:
+      result = CURLE_TFTP_ILLEGAL;
+      break;
+    case TFTP_ERR_UNKNOWNID:
+      result = CURLE_TFTP_UNKNOWNID;
+      break;
+    case TFTP_ERR_EXISTS:
+      result = CURLE_REMOTE_FILE_EXISTS;
+      break;
+    case TFTP_ERR_NOSUCHUSER:
+      result = CURLE_TFTP_NOSUCHUSER;
+      break;
+    case TFTP_ERR_TIMEOUT:
+      result = CURLE_OPERATION_TIMEDOUT;
+      break;
+    case TFTP_ERR_NORESPONSE:
+      result = CURLE_COULDNT_CONNECT;
+      break;
+    default:
+      result = CURLE_ABORTED_BY_CALLBACK;
+      break;
+    }
+  }
+  else
+    result = CURLE_OK;
+
+  return result;
+}
+
+/**********************************************************
+ *
+ * tftp_state_machine
+ *
+ * The tftp state machine event dispatcher
+ *
+ **********************************************************/
+static CURLcode tftp_state_machine(struct tftp_state_data *state,
+                                   tftp_event_t event)
+{
+  CURLcode result = CURLE_OK;
+  struct Curl_easy *data = state->data;
+
+  switch(state->state) {
+  case TFTP_STATE_START:
+    DEBUGF(infof(data, "TFTP_STATE_START"));
+    result = tftp_send_first(state, event);
+    break;
+  case TFTP_STATE_RX:
+    DEBUGF(infof(data, "TFTP_STATE_RX"));
+    result = tftp_rx(state, event);
+    break;
+  case TFTP_STATE_TX:
+    DEBUGF(infof(data, "TFTP_STATE_TX"));
+    result = tftp_tx(state, event);
+    break;
+  case TFTP_STATE_FIN:
+    infof(data, "%s", "TFTP finished");
+    break;
+  default:
+    DEBUGF(infof(data, "STATE: %d", state->state));
+    failf(data, "%s", "Internal state machine error");
+    result = CURLE_TFTP_ILLEGAL;
+    break;
+  }
+
+  return result;
+}
+
+/**********************************************************
+ *
+ * tftp_disconnect
+ *
+ * The disconnect callback
+ *
+ **********************************************************/
+static CURLcode tftp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead_connection)
+{
+  struct tftp_state_data *state = conn->proto.tftpc;
+  (void) data;
+  (void) dead_connection;
+
+  /* done, free dynamically allocated pkt buffers */
+  if(state) {
+    Curl_safefree(state->rpacket.data);
+    Curl_safefree(state->spacket.data);
+    free(state);
+  }
+
+  return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_connect
+ *
+ * The connect callback
+ *
+ **********************************************************/
+static CURLcode tftp_connect(struct Curl_easy *data, bool *done)
+{
+  struct tftp_state_data *state;
+  int blksize;
+  int need_blksize;
+  struct connectdata *conn = data->conn;
+
+  blksize = TFTP_BLKSIZE_DEFAULT;
+
+  state = conn->proto.tftpc = calloc(1, sizeof(struct tftp_state_data));
+  if(!state)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* alloc pkt buffers based on specified blksize */
+  if(data->set.tftp_blksize)
+    /* range checked when set */
+    blksize = (int)data->set.tftp_blksize;
+
+  need_blksize = blksize;
+  /* default size is the fallback when no OACK is received */
+  if(need_blksize < TFTP_BLKSIZE_DEFAULT)
+    need_blksize = TFTP_BLKSIZE_DEFAULT;
+
+  if(!state->rpacket.data) {
+    state->rpacket.data = calloc(1, need_blksize + 2 + 2);
+
+    if(!state->rpacket.data)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(!state->spacket.data) {
+    state->spacket.data = calloc(1, need_blksize + 2 + 2);
+
+    if(!state->spacket.data)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* we don't keep TFTP connections up basically because there's none or very
+   * little gain for UDP */
+  connclose(conn, "TFTP");
+
+  state->data = data;
+  state->sockfd = conn->sock[FIRSTSOCKET];
+  state->state = TFTP_STATE_START;
+  state->error = TFTP_ERR_NONE;
+  state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */
+  state->requested_blksize = blksize;
+
+  ((struct sockaddr *)&state->local_addr)->sa_family =
+    (CURL_SA_FAMILY_T)(conn->remote_addr->family);
+
+  tftp_set_timeouts(state);
+
+  if(!conn->bits.bound) {
+    /* If not already bound, bind to any interface, random UDP port. If it is
+     * reused or a custom local port was desired, this has already been done!
+     *
+     * We once used the size of the local_addr struct as the third argument
+     * for bind() to better work with IPv6 or whatever size the struct could
+     * have, but we learned that at least Tru64, AIX and IRIX *requires* the
+     * size of that argument to match the exact size of a 'sockaddr_in' struct
+     * when running IPv4-only.
+     *
+     * Therefore we use the size from the address we connected to, which we
+     * assume uses the same IP version and thus hopefully this works for both
+     * IPv4 and IPv6...
+     */
+    int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
+                  conn->remote_addr->addrlen);
+    if(rc) {
+      char buffer[STRERROR_LEN];
+      failf(data, "bind() failed; %s",
+            Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+      return CURLE_COULDNT_CONNECT;
+    }
+    conn->bits.bound = TRUE;
+  }
+
+  Curl_pgrsStartNow(data);
+
+  *done = TRUE;
+
+  return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_done
+ *
+ * The done callback
+ *
+ **********************************************************/
+static CURLcode tftp_done(struct Curl_easy *data, CURLcode status,
+                          bool premature)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct tftp_state_data *state = conn->proto.tftpc;
+
+  (void)status; /* unused */
+  (void)premature; /* not used */
+
+  if(Curl_pgrsDone(data))
+    return CURLE_ABORTED_BY_CALLBACK;
+
+  /* If we have encountered an error */
+  if(state)
+    result = tftp_translate_code(state->error);
+
+  return result;
+}
+
+/**********************************************************
+ *
+ * tftp_getsock
+ *
+ * The getsock callback
+ *
+ **********************************************************/
+static int tftp_getsock(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks)
+{
+  (void)data;
+  socks[0] = conn->sock[FIRSTSOCKET];
+  return GETSOCK_READSOCK(0);
+}
+
+/**********************************************************
+ *
+ * tftp_receive_packet
+ *
+ * Called once select fires and data is ready on the socket
+ *
+ **********************************************************/
+static CURLcode tftp_receive_packet(struct Curl_easy *data)
+{
+  struct Curl_sockaddr_storage fromaddr;
+  curl_socklen_t        fromlen;
+  CURLcode              result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct tftp_state_data *state = conn->proto.tftpc;
+
+  /* Receive the packet */
+  fromlen = sizeof(fromaddr);
+  state->rbytes = (int)recvfrom(state->sockfd,
+                                (void *)state->rpacket.data,
+                                state->blksize + 4,
+                                0,
+                                (struct sockaddr *)&fromaddr,
+                                &fromlen);
+  if(state->remote_addrlen == 0) {
+    memcpy(&state->remote_addr, &fromaddr, fromlen);
+    state->remote_addrlen = fromlen;
+  }
+
+  /* Sanity check packet length */
+  if(state->rbytes < 4) {
+    failf(data, "Received too short packet");
+    /* Not a timeout, but how best to handle it? */
+    state->event = TFTP_EVENT_TIMEOUT;
+  }
+  else {
+    /* The event is given by the TFTP packet time */
+    unsigned short event = getrpacketevent(&state->rpacket);
+    state->event = (tftp_event_t)event;
+
+    switch(state->event) {
+    case TFTP_EVENT_DATA:
+      /* Don't pass to the client empty or retransmitted packets */
+      if(state->rbytes > 4 &&
+         (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
+        result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                   (char *)state->rpacket.data + 4,
+                                   state->rbytes-4);
+        if(result) {
+          tftp_state_machine(state, TFTP_EVENT_ERROR);
+          return result;
+        }
+      }
+      break;
+    case TFTP_EVENT_ERROR:
+    {
+      unsigned short error = getrpacketblock(&state->rpacket);
+      char *str = (char *)state->rpacket.data + 4;
+      size_t strn = state->rbytes - 4;
+      state->error = (tftp_error_t)error;
+      if(tftp_strnlen(str, strn) < strn)
+        infof(data, "TFTP error: %s", str);
+      break;
+    }
+    case TFTP_EVENT_ACK:
+      break;
+    case TFTP_EVENT_OACK:
+      result = tftp_parse_option_ack(state,
+                                     (const char *)state->rpacket.data + 2,
+                                     state->rbytes-2);
+      if(result)
+        return result;
+      break;
+    case TFTP_EVENT_RRQ:
+    case TFTP_EVENT_WRQ:
+    default:
+      failf(data, "%s", "Internal error: Unexpected packet");
+      break;
+    }
+
+    /* Update the progress meter */
+    if(Curl_pgrsUpdate(data)) {
+      tftp_state_machine(state, TFTP_EVENT_ERROR);
+      return CURLE_ABORTED_BY_CALLBACK;
+    }
+  }
+  return result;
+}
+
+/**********************************************************
+ *
+ * tftp_state_timeout
+ *
+ * Check if timeouts have been reached
+ *
+ **********************************************************/
+static timediff_t tftp_state_timeout(struct Curl_easy *data,
+                                     tftp_event_t *event)
+{
+  time_t current;
+  struct connectdata *conn = data->conn;
+  struct tftp_state_data *state = conn->proto.tftpc;
+  timediff_t timeout_ms;
+
+  if(event)
+    *event = TFTP_EVENT_NONE;
+
+  timeout_ms = Curl_timeleft(state->data, NULL,
+                             (state->state == TFTP_STATE_START));
+  if(timeout_ms < 0) {
+    state->error = TFTP_ERR_TIMEOUT;
+    state->state = TFTP_STATE_FIN;
+    return 0;
+  }
+  time(&current);
+  if(current > state->rx_time + state->retry_time) {
+    if(event)
+      *event = TFTP_EVENT_TIMEOUT;
+    time(&state->rx_time); /* update even though we received nothing */
+  }
+
+  return timeout_ms;
+}
+
+/**********************************************************
+ *
+ * tftp_multi_statemach
+ *
+ * Handle single RX socket event and return
+ *
+ **********************************************************/
+static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
+{
+  tftp_event_t event;
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct tftp_state_data *state = conn->proto.tftpc;
+  timediff_t timeout_ms = tftp_state_timeout(data, &event);
+
+  *done = FALSE;
+
+  if(timeout_ms < 0) {
+    failf(data, "TFTP response timeout");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+  if(event != TFTP_EVENT_NONE) {
+    result = tftp_state_machine(state, event);
+    if(result)
+      return result;
+    *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
+    if(*done)
+      /* Tell curl we're done */
+      Curl_xfer_setup(data, -1, -1, FALSE, -1);
+  }
+  else {
+    /* no timeouts to handle, check our socket */
+    int rc = SOCKET_READABLE(state->sockfd, 0);
+
+    if(rc == -1) {
+      /* bail out */
+      int error = SOCKERRNO;
+      char buffer[STRERROR_LEN];
+      failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer)));
+      state->event = TFTP_EVENT_ERROR;
+    }
+    else if(rc) {
+      result = tftp_receive_packet(data);
+      if(result)
+        return result;
+      result = tftp_state_machine(state, state->event);
+      if(result)
+        return result;
+      *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
+      if(*done)
+        /* Tell curl we're done */
+        Curl_xfer_setup(data, -1, -1, FALSE, -1);
+    }
+    /* if rc == 0, then select() timed out */
+  }
+
+  return result;
+}
+
+/**********************************************************
+ *
+ * tftp_doing
+ *
+ * Called from multi.c while DOing
+ *
+ **********************************************************/
+static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
+{
+  CURLcode result;
+  result = tftp_multi_statemach(data, dophase_done);
+
+  if(*dophase_done) {
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+  else if(!result) {
+    /* The multi code doesn't have this logic for the DOING state so we
+       provide it for TFTP since it may do the entire transfer in this
+       state. */
+    if(Curl_pgrsUpdate(data))
+      result = CURLE_ABORTED_BY_CALLBACK;
+    else
+      result = Curl_speedcheck(data, Curl_now());
+  }
+  return result;
+}
+
+/**********************************************************
+ *
+ * tftp_perform
+ *
+ * Entry point for transfer from tftp_do, starts state mach
+ *
+ **********************************************************/
+static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct tftp_state_data *state = conn->proto.tftpc;
+
+  *dophase_done = FALSE;
+
+  result = tftp_state_machine(state, TFTP_EVENT_INIT);
+
+  if((state->state == TFTP_STATE_FIN) || result)
+    return result;
+
+  tftp_multi_statemach(data, dophase_done);
+
+  if(*dophase_done)
+    DEBUGF(infof(data, "DO phase is complete"));
+
+  return result;
+}
+
+
+/**********************************************************
+ *
+ * tftp_do
+ *
+ * The do callback
+ *
+ * This callback initiates the TFTP transfer
+ *
+ **********************************************************/
+
+static CURLcode tftp_do(struct Curl_easy *data, bool *done)
+{
+  struct tftp_state_data *state;
+  CURLcode result;
+  struct connectdata *conn = data->conn;
+
+  *done = FALSE;
+
+  if(!conn->proto.tftpc) {
+    result = tftp_connect(data, done);
+    if(result)
+      return result;
+  }
+
+  state = conn->proto.tftpc;
+  if(!state)
+    return CURLE_TFTP_ILLEGAL;
+
+  result = tftp_perform(data, done);
+
+  /* If tftp_perform() returned an error, use that for return code. If it
+     was OK, see if tftp_translate_code() has an error. */
+  if(!result)
+    /* If we have encountered an internal tftp error, translate it. */
+    result = tftp_translate_code(state->error);
+
+  return result;
+}
+
+static CURLcode tftp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  char *type;
+
+  conn->transport = TRNSPRT_UDP;
+
+  /* TFTP URLs support an extension like ";mode=<typecode>" that
+   * we'll try to get now! */
+  type = strstr(data->state.up.path, ";mode=");
+
+  if(!type)
+    type = strstr(conn->host.rawalloc, ";mode=");
+
+  if(type) {
+    char command;
+    *type = 0;                   /* it was in the middle of the hostname */
+    command = Curl_raw_toupper(type[6]);
+
+    switch(command) {
+    case 'A': /* ASCII mode */
+    case 'N': /* NETASCII mode */
+      data->state.prefer_ascii = TRUE;
+      break;
+
+    case 'O': /* octet mode */
+    case 'I': /* binary mode */
+    default:
+      /* switch off ASCII */
+      data->state.prefer_ascii = FALSE;
+      break;
+    }
+  }
+
+  return CURLE_OK;
+}
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/tftp.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/tftp.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/tftp.h	(revision 104083)
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_TFTP_H
+#define HEADER_CURL_TFTP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TFTP
+extern const struct Curl_handler Curl_handler_tftp;
+
+#define TFTP_BLKSIZE_MIN 8
+#define TFTP_BLKSIZE_MAX 65464
+#endif
+
+#endif /* HEADER_CURL_TFTP_H */
Index: trunk/src/libs/curl-8.7.1/lib/timediff.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/timediff.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/timediff.c	(revision 104083)
@@ -0,0 +1,88 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "timediff.h"
+
+#include <limits.h>
+
+/*
+ * Converts number of milliseconds into a timeval structure.
+ *
+ * Return values:
+ *    NULL IF tv is NULL or ms < 0 (eg. no timeout -> blocking select)
+ *    tv with 0 in both fields IF ms == 0 (eg. 0ms timeout -> polling select)
+ *    tv with converted fields IF ms > 0 (eg. >0ms timeout -> waiting select)
+ */
+struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms)
+{
+  if(!tv)
+    return NULL;
+
+  if(ms < 0)
+    return NULL;
+
+  if(ms > 0) {
+    timediff_t tv_sec = ms / 1000;
+    timediff_t tv_usec = (ms % 1000) * 1000; /* max=999999 */
+#ifdef HAVE_SUSECONDS_T
+#if TIMEDIFF_T_MAX > TIME_T_MAX
+    /* tv_sec overflow check in case time_t is signed */
+    if(tv_sec > TIME_T_MAX)
+      tv_sec = TIME_T_MAX;
+#endif
+    tv->tv_sec = (time_t)tv_sec;
+    tv->tv_usec = (suseconds_t)tv_usec;
+#elif defined(_WIN32) /* maybe also others in the future */
+#if TIMEDIFF_T_MAX > LONG_MAX
+    /* tv_sec overflow check on Windows there we know it is long */
+    if(tv_sec > LONG_MAX)
+      tv_sec = LONG_MAX;
+#endif
+    tv->tv_sec = (long)tv_sec;
+    tv->tv_usec = (long)tv_usec;
+#else
+#if TIMEDIFF_T_MAX > INT_MAX
+    /* tv_sec overflow check in case time_t is signed */
+    if(tv_sec > INT_MAX)
+      tv_sec = INT_MAX;
+#endif
+    tv->tv_sec = (int)tv_sec;
+    tv->tv_usec = (int)tv_usec;
+#endif
+  }
+  else {
+    tv->tv_sec = 0;
+    tv->tv_usec = 0;
+  }
+
+  return tv;
+}
+
+/*
+ * Converts a timeval structure into number of milliseconds.
+ */
+timediff_t curlx_tvtoms(struct timeval *tv)
+{
+  return (tv->tv_sec*1000) + (timediff_t)(((double)tv->tv_usec)/1000.0);
+}
Index: trunk/src/libs/curl-8.7.1/lib/timediff.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/timediff.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/timediff.h	(revision 104083)
@@ -0,0 +1,52 @@
+#ifndef HEADER_CURL_TIMEDIFF_H
+#define HEADER_CURL_TIMEDIFF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+/* Use a larger type even for 32 bit time_t systems so that we can keep
+   microsecond accuracy in it */
+typedef curl_off_t timediff_t;
+#define CURL_FORMAT_TIMEDIFF_T CURL_FORMAT_CURL_OFF_T
+
+#define TIMEDIFF_T_MAX CURL_OFF_T_MAX
+#define TIMEDIFF_T_MIN CURL_OFF_T_MIN
+
+/*
+ * Converts number of milliseconds into a timeval structure.
+ *
+ * Return values:
+ *    NULL IF tv is NULL or ms < 0 (eg. no timeout -> blocking select)
+ *    tv with 0 in both fields IF ms == 0 (eg. 0ms timeout -> polling select)
+ *    tv with converted fields IF ms > 0 (eg. >0ms timeout -> waiting select)
+ */
+struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms);
+
+/*
+ * Converts a timeval structure into number of milliseconds.
+ */
+timediff_t curlx_tvtoms(struct timeval *tv);
+
+#endif /* HEADER_CURL_TIMEDIFF_H */
Index: trunk/src/libs/curl-8.7.1/lib/timeval.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/timeval.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/timeval.c	(revision 104083)
@@ -0,0 +1,237 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "timeval.h"
+
+#if defined(_WIN32)
+
+#include <curl/curl.h>
+#include "system_win32.h"
+
+/* In case of bug fix this function has a counterpart in tool_util.c */
+struct curltime Curl_now(void)
+{
+  struct curltime now;
+  if(Curl_isVistaOrGreater) { /* QPC timer might have issues pre-Vista */
+    LARGE_INTEGER count;
+    QueryPerformanceCounter(&count);
+    now.tv_sec = (time_t)(count.QuadPart / Curl_freq.QuadPart);
+    now.tv_usec = (int)((count.QuadPart % Curl_freq.QuadPart) * 1000000 /
+                        Curl_freq.QuadPart);
+  }
+  else {
+    /* Disable /analyze warning that GetTickCount64 is preferred  */
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:28159)
+#endif
+    DWORD milliseconds = GetTickCount();
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+    now.tv_sec = milliseconds / 1000;
+    now.tv_usec = (milliseconds % 1000) * 1000;
+  }
+  return now;
+}
+
+#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) ||  \
+  defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
+
+struct curltime Curl_now(void)
+{
+  /*
+  ** clock_gettime() is granted to be increased monotonically when the
+  ** monotonic clock is queried. Time starting point is unspecified, it
+  ** could be the system start-up time, the Epoch, or something else,
+  ** in any case the time starting point does not change once that the
+  ** system has started up.
+  */
+#ifdef HAVE_GETTIMEOFDAY
+  struct timeval now;
+#endif
+  struct curltime cnow;
+  struct timespec tsnow;
+
+  /*
+  ** clock_gettime() may be defined by Apple's SDK as weak symbol thus
+  ** code compiles but fails during run-time if clock_gettime() is
+  ** called on unsupported OS version.
+  */
+#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
+        (HAVE_BUILTIN_AVAILABLE == 1)
+  bool have_clock_gettime = FALSE;
+  if(__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *))
+    have_clock_gettime = TRUE;
+#endif
+
+#ifdef HAVE_CLOCK_GETTIME_MONOTONIC_RAW
+  if(
+#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) &&    \
+        (HAVE_BUILTIN_AVAILABLE == 1)
+    have_clock_gettime &&
+#endif
+    (0 == clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow))) {
+    cnow.tv_sec = tsnow.tv_sec;
+    cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
+  }
+  else
+#endif
+
+  if(
+#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
+        (HAVE_BUILTIN_AVAILABLE == 1)
+    have_clock_gettime &&
+#endif
+    (0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) {
+    cnow.tv_sec = tsnow.tv_sec;
+    cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
+  }
+  /*
+  ** Even when the configure process has truly detected monotonic clock
+  ** availability, it might happen that it is not actually available at
+  ** run-time. When this occurs simply fallback to other time source.
+  */
+#ifdef HAVE_GETTIMEOFDAY
+  else {
+    (void)gettimeofday(&now, NULL);
+    cnow.tv_sec = now.tv_sec;
+    cnow.tv_usec = (unsigned int)now.tv_usec;
+  }
+#else
+  else {
+    cnow.tv_sec = time(NULL);
+    cnow.tv_usec = 0;
+  }
+#endif
+  return cnow;
+}
+
+#elif defined(HAVE_MACH_ABSOLUTE_TIME)
+
+#include <stdint.h>
+#include <mach/mach_time.h>
+
+struct curltime Curl_now(void)
+{
+  /*
+  ** Monotonic timer on Mac OS is provided by mach_absolute_time(), which
+  ** returns time in Mach "absolute time units," which are platform-dependent.
+  ** To convert to nanoseconds, one must use conversion factors specified by
+  ** mach_timebase_info().
+  */
+  static mach_timebase_info_data_t timebase;
+  struct curltime cnow;
+  uint64_t usecs;
+
+  if(0 == timebase.denom)
+    (void) mach_timebase_info(&timebase);
+
+  usecs = mach_absolute_time();
+  usecs *= timebase.numer;
+  usecs /= timebase.denom;
+  usecs /= 1000;
+
+  cnow.tv_sec = usecs / 1000000;
+  cnow.tv_usec = (int)(usecs % 1000000);
+
+  return cnow;
+}
+
+#elif defined(HAVE_GETTIMEOFDAY)
+
+struct curltime Curl_now(void)
+{
+  /*
+  ** gettimeofday() is not granted to be increased monotonically, due to
+  ** clock drifting and external source time synchronization it can jump
+  ** forward or backward in time.
+  */
+  struct timeval now;
+  struct curltime ret;
+  (void)gettimeofday(&now, NULL);
+  ret.tv_sec = now.tv_sec;
+  ret.tv_usec = (int)now.tv_usec;
+  return ret;
+}
+
+#else
+
+struct curltime Curl_now(void)
+{
+  /*
+  ** time() returns the value of time in seconds since the Epoch.
+  */
+  struct curltime now;
+  now.tv_sec = time(NULL);
+  now.tv_usec = 0;
+  return now;
+}
+
+#endif
+
+/*
+ * Returns: time difference in number of milliseconds. For too large diffs it
+ * returns max value.
+ *
+ * @unittest: 1323
+ */
+timediff_t Curl_timediff(struct curltime newer, struct curltime older)
+{
+  timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
+  if(diff >= (TIMEDIFF_T_MAX/1000))
+    return TIMEDIFF_T_MAX;
+  else if(diff <= (TIMEDIFF_T_MIN/1000))
+    return TIMEDIFF_T_MIN;
+  return diff * 1000 + (newer.tv_usec-older.tv_usec)/1000;
+}
+
+/*
+ * Returns: time difference in number of milliseconds, rounded up.
+ * For too large diffs it returns max value.
+ */
+timediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older)
+{
+  timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
+  if(diff >= (TIMEDIFF_T_MAX/1000))
+    return TIMEDIFF_T_MAX;
+  else if(diff <= (TIMEDIFF_T_MIN/1000))
+    return TIMEDIFF_T_MIN;
+  return diff * 1000 + (newer.tv_usec - older.tv_usec + 999)/1000;
+}
+
+/*
+ * Returns: time difference in number of microseconds. For too large diffs it
+ * returns max value.
+ */
+timediff_t Curl_timediff_us(struct curltime newer, struct curltime older)
+{
+  timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
+  if(diff >= (TIMEDIFF_T_MAX/1000000))
+    return TIMEDIFF_T_MAX;
+  else if(diff <= (TIMEDIFF_T_MIN/1000000))
+    return TIMEDIFF_T_MIN;
+  return diff * 1000000 + newer.tv_usec-older.tv_usec;
+}
Index: trunk/src/libs/curl-8.7.1/lib/timeval.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/timeval.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/timeval.h	(revision 104083)
@@ -0,0 +1,62 @@
+#ifndef HEADER_CURL_TIMEVAL_H
+#define HEADER_CURL_TIMEVAL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "timediff.h"
+
+struct curltime {
+  time_t tv_sec; /* seconds */
+  int tv_usec;   /* microseconds */
+};
+
+struct curltime Curl_now(void);
+
+/*
+ * Make sure that the first argument (newer) is the more recent time and older
+ * is the older time, as otherwise you get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds.
+ */
+timediff_t Curl_timediff(struct curltime newer, struct curltime older);
+
+/*
+ * Make sure that the first argument (newer) is the more recent time and older
+ * is the older time, as otherwise you get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds, rounded up.
+ */
+timediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older);
+
+/*
+ * Make sure that the first argument (newer) is the more recent time and older
+ * is the older time, as otherwise you get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of microseconds.
+ */
+timediff_t Curl_timediff_us(struct curltime newer, struct curltime older);
+
+#endif /* HEADER_CURL_TIMEVAL_H */
Index: trunk/src/libs/curl-8.7.1/lib/transfer.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/transfer.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/transfer.c	(revision 104083)
@@ -0,0 +1,1253 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "strtoofft.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <signal.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#elif defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#ifndef HAVE_SOCKET
+#error "We can't compile without socket() support!"
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "netrc.h"
+
+#include "content_encoding.h"
+#include "hostip.h"
+#include "cfilters.h"
+#include "cw-out.h"
+#include "transfer.h"
+#include "sendf.h"
+#include "speedcheck.h"
+#include "progress.h"
+#include "http.h"
+#include "url.h"
+#include "getinfo.h"
+#include "vtls/vtls.h"
+#include "vquic/vquic.h"
+#include "select.h"
+#include "multiif.h"
+#include "connect.h"
+#include "http2.h"
+#include "mime.h"
+#include "strcase.h"
+#include "urlapi-int.h"
+#include "hsts.h"
+#include "setopt.h"
+#include "headers.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \
+    !defined(CURL_DISABLE_IMAP)
+/*
+ * checkheaders() checks the linked list of custom headers for a
+ * particular header (prefix). Provide the prefix without colon!
+ *
+ * Returns a pointer to the first matching header or NULL if none matched.
+ */
+char *Curl_checkheaders(const struct Curl_easy *data,
+                        const char *thisheader,
+                        const size_t thislen)
+{
+  struct curl_slist *head;
+  DEBUGASSERT(thislen);
+  DEBUGASSERT(thisheader[thislen-1] != ':');
+
+  for(head = data->set.headers; head; head = head->next) {
+    if(strncasecompare(head->data, thisheader, thislen) &&
+       Curl_headersep(head->data[thislen]) )
+      return head->data;
+  }
+
+  return NULL;
+}
+#endif
+
+static int data_pending(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+
+  if(conn->handler->protocol&PROTO_FAMILY_FTP)
+    return Curl_conn_data_pending(data, SECONDARYSOCKET);
+
+  /* in the case of libssh2, we can never be really sure that we have emptied
+     its internal buffers so we MUST always try until we get EAGAIN back */
+  return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) ||
+    Curl_conn_data_pending(data, FIRSTSOCKET);
+}
+
+/*
+ * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the
+ * remote document with the time provided by CURLOPT_TIMEVAL
+ */
+bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
+{
+  if((timeofdoc == 0) || (data->set.timevalue == 0))
+    return TRUE;
+
+  switch(data->set.timecondition) {
+  case CURL_TIMECOND_IFMODSINCE:
+  default:
+    if(timeofdoc <= data->set.timevalue) {
+      infof(data,
+            "The requested document is not new enough");
+      data->info.timecond = TRUE;
+      return FALSE;
+    }
+    break;
+  case CURL_TIMECOND_IFUNMODSINCE:
+    if(timeofdoc >= data->set.timevalue) {
+      infof(data,
+            "The requested document is not old enough");
+      data->info.timecond = TRUE;
+      return FALSE;
+    }
+    break;
+  }
+
+  return TRUE;
+}
+
+/**
+ * Receive raw response data for the transfer.
+ * @param data         the transfer
+ * @param buf          buffer to keep response data received
+ * @param blen         length of `buf`
+ * @param eos_reliable if EOS detection in underlying connection is reliable
+ * @param err error    code in case of -1 return
+ * @return number of bytes read or -1 for error
+ */
+static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data,
+                                   char *buf, size_t blen,
+                                   bool eos_reliable,
+                                   CURLcode *err)
+{
+  ssize_t nread;
+
+  DEBUGASSERT(blen > 0);
+  /* If we are reading BODY data and the connection does NOT handle EOF
+   * and we know the size of the BODY data, limit the read amount */
+  if(!eos_reliable && !data->req.header && data->req.size != -1) {
+    curl_off_t totalleft = data->req.size - data->req.bytecount;
+    if(totalleft <= 0)
+      blen = 0;
+    else if(totalleft < (curl_off_t)blen)
+      blen = (size_t)totalleft;
+  }
+
+  if(!blen) {
+    /* want nothing - continue as if read nothing. */
+    DEBUGF(infof(data, "readwrite_data: we're done"));
+    *err = CURLE_OK;
+    return 0;
+  }
+
+  *err = Curl_xfer_recv(data, buf, blen, &nread);
+  if(*err)
+    return -1;
+  DEBUGASSERT(nread >= 0);
+  *err = CURLE_OK;
+  return nread;
+}
+
+/*
+ * Go ahead and do a read if we have a readable socket or if
+ * the stream was rewound (in which case we have data in a
+ * buffer)
+ */
+static CURLcode readwrite_data(struct Curl_easy *data,
+                               struct SingleRequest *k,
+                               int *didwhat)
+{
+  struct connectdata *conn = data->conn;
+  CURLcode result = CURLE_OK;
+  char *buf, *xfer_buf;
+  size_t blen, xfer_blen;
+  int maxloops = 10;
+  curl_off_t total_received = 0;
+  bool is_multiplex = FALSE;
+
+  result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
+  if(result)
+    goto out;
+
+  /* This is where we loop until we have read everything there is to
+     read or we get a CURLE_AGAIN */
+  do {
+    bool is_eos = FALSE;
+    size_t bytestoread;
+    ssize_t nread;
+
+    if(!is_multiplex) {
+      /* Multiplexed connection have inherent handling of EOF and we do not
+       * have to carefully restrict the amount we try to read.
+       * Multiplexed changes only in one direction. */
+      is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
+    }
+
+    buf = xfer_buf;
+    bytestoread = xfer_blen;
+
+    if(bytestoread && data->set.max_recv_speed) {
+      /* In case of speed limit on receiving: if this loop already got
+       * data, break out. If not, limit the amount of bytes to receive.
+       * The overall, timed, speed limiting is done in multi.c */
+      if(total_received)
+        break;
+      if((size_t)data->set.max_recv_speed < bytestoread)
+        bytestoread = (size_t)data->set.max_recv_speed;
+    }
+
+    nread = Curl_xfer_recv_resp(data, buf, bytestoread,
+                                is_multiplex, &result);
+    if(nread < 0) {
+      if(CURLE_AGAIN == result) {
+        result = CURLE_OK;
+        break; /* get out of loop */
+      }
+      goto out; /* real error */
+    }
+
+    /* We only get a 0-length read on EndOfStream */
+    blen = (size_t)nread;
+    is_eos = (blen == 0);
+    *didwhat |= KEEP_RECV;
+
+    if(!blen) {
+      /* if we receive 0 or less here, either the data transfer is done or the
+         server closed the connection and we bail out from this! */
+      if(is_multiplex)
+        DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
+      else
+        DEBUGF(infof(data, "nread <= 0, server closed connection, bailing"));
+      if(k->eos_written) { /* already did write this to client, leave */
+        k->keepon = 0; /* stop sending as well */
+        break;
+      }
+    }
+    total_received += blen;
+
+    result = Curl_xfer_write_resp(data, buf, blen, is_eos);
+    if(result || data->req.done)
+      goto out;
+
+    /* if we are done, we stop receiving. On multiplexed connections,
+     * we should read the EOS. Which may arrive as meta data after
+     * the bytes. Not taking it in might lead to RST of streams. */
+    if((!is_multiplex && data->req.download_done) || is_eos) {
+      data->req.keepon &= ~KEEP_RECV;
+    }
+    /* if we are PAUSEd or stopped receiving, leave the loop */
+    if((k->keepon & KEEP_RECV_PAUSE) || !(k->keepon & KEEP_RECV))
+      break;
+
+  } while(maxloops-- && data_pending(data));
+
+  if(maxloops <= 0) {
+    /* did not read until EAGAIN, mark read-again-please */
+    data->state.select_bits = CURL_CSELECT_IN;
+    if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
+      data->state.select_bits |= CURL_CSELECT_OUT;
+  }
+
+  if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
+     (conn->bits.close || is_multiplex)) {
+    /* When we've read the entire thing and the close bit is set, the server
+       may now close the connection. If there's now any kind of sending going
+       on from our side, we need to stop that immediately. */
+    infof(data, "we are done reading and this is set to close, stop send");
+    k->keepon &= ~KEEP_SEND; /* no writing anymore either */
+    k->keepon &= ~KEEP_SEND_PAUSE; /* no pausing anymore either */
+  }
+
+out:
+  Curl_multi_xfer_buf_release(data, xfer_buf);
+  if(result)
+    DEBUGF(infof(data, "readwrite_data() -> %d", result));
+  return result;
+}
+
+#if defined(_WIN32) && defined(USE_WINSOCK)
+#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
+#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
+#endif
+
+static void win_update_buffer_size(curl_socket_t sockfd)
+{
+  int result;
+  ULONG ideal;
+  DWORD ideallen;
+  result = WSAIoctl(sockfd, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
+                    &ideal, sizeof(ideal), &ideallen, 0, 0);
+  if(result == 0) {
+    setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF,
+               (const char *)&ideal, sizeof(ideal));
+  }
+}
+#else
+#define win_update_buffer_size(x)
+#endif
+
+#define curl_upload_refill_watermark(data) \
+        ((size_t)((data)->set.upload_buffer_size >> 5))
+
+/*
+ * Send data to upload to the server, when the socket is writable.
+ */
+static CURLcode readwrite_upload(struct Curl_easy *data, int *didwhat)
+{
+  CURLcode result = CURLE_OK;
+
+  if((data->req.keepon & KEEP_SEND_PAUSE))
+    return CURLE_OK;
+
+  /* We should not get here when the sending is already done. It
+   * probably means that someone set `data-req.keepon |= KEEP_SEND`
+   * when it should not. */
+  DEBUGASSERT(!Curl_req_done_sending(data));
+
+  if(!Curl_req_done_sending(data)) {
+    *didwhat |= KEEP_SEND;
+    result = Curl_req_send_more(data);
+    if(result)
+      return result;
+
+#if defined(_WIN32) && defined(USE_WINSOCK)
+    /* FIXME: this looks like it would fit better into cf-socket.c
+     * but then I do not know enough Windows to say... */
+    {
+      struct curltime n = Curl_now();
+      if(Curl_timediff(n, data->conn->last_sndbuf_update) > 1000) {
+        win_update_buffer_size(data->conn->writesockfd);
+        data->conn->last_sndbuf_update = n;
+      }
+    }
+#endif
+  }
+  return result;
+}
+
+static int select_bits_paused(struct Curl_easy *data, int select_bits)
+{
+  /* See issue #11982: we really need to be careful not to progress
+   * a transfer direction when that direction is paused. Not all parts
+   * of our state machine are handling PAUSED transfers correctly. So, we
+   * do not want to go there.
+   * NOTE: we are only interested in PAUSE, not HOLD. */
+
+  /* if there is data in a direction not paused, return false */
+  if(((select_bits & CURL_CSELECT_IN) &&
+      !(data->req.keepon & KEEP_RECV_PAUSE)) ||
+     ((select_bits & CURL_CSELECT_OUT) &&
+      !(data->req.keepon & KEEP_SEND_PAUSE)))
+    return FALSE;
+
+  return (data->req.keepon & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE));
+}
+
+/*
+ * Curl_readwrite() is the low-level function to be called when data is to
+ * be read and written to/from the connection.
+ */
+CURLcode Curl_readwrite(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+  struct SingleRequest *k = &data->req;
+  CURLcode result;
+  struct curltime now;
+  int didwhat = 0;
+  int select_bits;
+
+  if(data->state.select_bits) {
+    if(select_bits_paused(data, data->state.select_bits)) {
+      /* leave the bits unchanged, so they'll tell us what to do when
+       * this transfer gets unpaused. */
+      DEBUGF(infof(data, "readwrite, select_bits, early return on PAUSED"));
+      result = CURLE_OK;
+      goto out;
+    }
+    select_bits = data->state.select_bits;
+    data->state.select_bits = 0;
+  }
+  else {
+    curl_socket_t fd_read;
+    curl_socket_t fd_write;
+    /* only use the proper socket if the *_HOLD bit is not set simultaneously
+       as then we are in rate limiting state in that transfer direction */
+    if((k->keepon & KEEP_RECVBITS) == KEEP_RECV)
+      fd_read = conn->sockfd;
+    else
+      fd_read = CURL_SOCKET_BAD;
+
+    if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
+      fd_write = conn->writesockfd;
+    else
+      fd_write = CURL_SOCKET_BAD;
+
+    select_bits = Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, 0);
+  }
+
+  if(select_bits == CURL_CSELECT_ERR) {
+    failf(data, "select/poll returned error");
+    result = CURLE_SEND_ERROR;
+    goto out;
+  }
+
+#ifdef USE_HYPER
+  if(conn->datastream) {
+    result = conn->datastream(data, conn, &didwhat, select_bits);
+    if(result || data->req.done)
+      goto out;
+  }
+  else {
+#endif
+  /* We go ahead and do a read if we have a readable socket or if
+     the stream was rewound (in which case we have data in a
+     buffer) */
+  if((k->keepon & KEEP_RECV) && (select_bits & CURL_CSELECT_IN)) {
+    result = readwrite_data(data, k, &didwhat);
+    if(result || data->req.done)
+      goto out;
+  }
+
+  /* If we still have writing to do, we check if we have a writable socket. */
+  if(((k->keepon & KEEP_SEND) && (select_bits & CURL_CSELECT_OUT)) ||
+     (k->keepon & KEEP_SEND_TIMED)) {
+    /* write */
+
+    result = readwrite_upload(data, &didwhat);
+    if(result)
+      goto out;
+  }
+#ifdef USE_HYPER
+  }
+#endif
+
+  now = Curl_now();
+  if(!didwhat) {
+    result = Curl_conn_ev_data_idle(data);
+    if(result)
+      goto out;
+  }
+
+  if(Curl_pgrsUpdate(data))
+    result = CURLE_ABORTED_BY_CALLBACK;
+  else
+    result = Curl_speedcheck(data, now);
+  if(result)
+    goto out;
+
+  if(k->keepon) {
+    if(0 > Curl_timeleft(data, &now, FALSE)) {
+      if(k->size != -1) {
+        failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+              " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
+              CURL_FORMAT_CURL_OFF_T " bytes received",
+              Curl_timediff(now, data->progress.t_startsingle),
+              k->bytecount, k->size);
+      }
+      else {
+        failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+              " milliseconds with %" CURL_FORMAT_CURL_OFF_T " bytes received",
+              Curl_timediff(now, data->progress.t_startsingle),
+              k->bytecount);
+      }
+      result = CURLE_OPERATION_TIMEDOUT;
+      goto out;
+    }
+  }
+  else {
+    /*
+     * The transfer has been performed. Just make some general checks before
+     * returning.
+     */
+    if(!(data->req.no_body) && (k->size != -1) &&
+       (k->bytecount != k->size) &&
+#ifdef CURL_DO_LINEEND_CONV
+       /* Most FTP servers don't adjust their file SIZE response for CRLFs,
+          so we'll check to see if the discrepancy can be explained
+          by the number of CRLFs we've changed to LFs.
+       */
+       (k->bytecount != (k->size + data->state.crlf_conversions)) &&
+#endif /* CURL_DO_LINEEND_CONV */
+       !k->newurl) {
+      failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T
+            " bytes remaining to read", k->size - k->bytecount);
+      result = CURLE_PARTIAL_FILE;
+      goto out;
+    }
+    if(Curl_pgrsUpdate(data)) {
+      result = CURLE_ABORTED_BY_CALLBACK;
+      goto out;
+    }
+  }
+
+  /* If there is nothing more to send/recv, the request is done */
+  if(0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS)))
+    data->req.done = TRUE;
+
+out:
+  if(result)
+    DEBUGF(infof(data, "Curl_readwrite() -> %d", result));
+  return result;
+}
+
+/* Curl_init_CONNECT() gets called each time the handle switches to CONNECT
+   which means this gets called once for each subsequent redirect etc */
+void Curl_init_CONNECT(struct Curl_easy *data)
+{
+  data->state.fread_func = data->set.fread_func_set;
+  data->state.in = data->set.in_set;
+  data->state.upload = (data->state.httpreq == HTTPREQ_PUT);
+}
+
+/*
+ * Curl_pretransfer() is called immediately before a transfer starts, and only
+ * once for one transfer no matter if it has redirects or do multi-pass
+ * authentication etc.
+ */
+CURLcode Curl_pretransfer(struct Curl_easy *data)
+{
+  CURLcode result;
+
+  if(!data->state.url && !data->set.uh) {
+    /* we can't do anything without URL */
+    failf(data, "No URL set");
+    return CURLE_URL_MALFORMAT;
+  }
+
+  /* since the URL may have been redirected in a previous use of this handle */
+  if(data->state.url_alloc) {
+    /* the already set URL is allocated, free it first! */
+    Curl_safefree(data->state.url);
+    data->state.url_alloc = FALSE;
+  }
+
+  if(!data->state.url && data->set.uh) {
+    CURLUcode uc;
+    free(data->set.str[STRING_SET_URL]);
+    uc = curl_url_get(data->set.uh,
+                      CURLUPART_URL, &data->set.str[STRING_SET_URL], 0);
+    if(uc) {
+      failf(data, "No URL set");
+      return CURLE_URL_MALFORMAT;
+    }
+  }
+
+  if(data->set.postfields && data->set.set_resume_from) {
+    /* we can't */
+    failf(data, "cannot mix POSTFIELDS with RESUME_FROM");
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
+  data->state.prefer_ascii = data->set.prefer_ascii;
+#ifdef CURL_LIST_ONLY_PROTOCOL
+  data->state.list_only = data->set.list_only;
+#endif
+  data->state.httpreq = data->set.method;
+  data->state.url = data->set.str[STRING_SET_URL];
+
+  /* Init the SSL session ID cache here. We do it here since we want to do it
+     after the *_setopt() calls (that could specify the size of the cache) but
+     before any transfer takes place. */
+  result = Curl_ssl_initsessions(data, data->set.general_ssl.max_ssl_sessions);
+  if(result)
+    return result;
+
+  data->state.requests = 0;
+  data->state.followlocation = 0; /* reset the location-follow counter */
+  data->state.this_is_a_follow = FALSE; /* reset this */
+  data->state.errorbuf = FALSE; /* no error has occurred */
+  data->state.httpwant = data->set.httpwant;
+  data->state.httpversion = 0;
+  data->state.authproblem = FALSE;
+  data->state.authhost.want = data->set.httpauth;
+  data->state.authproxy.want = data->set.proxyauth;
+  Curl_safefree(data->info.wouldredirect);
+  Curl_data_priority_clear_state(data);
+
+  if(data->state.httpreq == HTTPREQ_PUT)
+    data->state.infilesize = data->set.filesize;
+  else if((data->state.httpreq != HTTPREQ_GET) &&
+          (data->state.httpreq != HTTPREQ_HEAD)) {
+    data->state.infilesize = data->set.postfieldsize;
+    if(data->set.postfields && (data->state.infilesize == -1))
+      data->state.infilesize = (curl_off_t)strlen(data->set.postfields);
+  }
+  else
+    data->state.infilesize = 0;
+
+  /* If there is a list of cookie files to read, do it now! */
+  Curl_cookie_loadfiles(data);
+
+  /* If there is a list of host pairs to deal with */
+  if(data->state.resolve)
+    result = Curl_loadhostpairs(data);
+
+  /* If there is a list of hsts files to read */
+  Curl_hsts_loadfiles(data);
+
+  if(!result) {
+    /* Allow data->set.use_port to set which port to use. This needs to be
+     * disabled for example when we follow Location: headers to URLs using
+     * different ports! */
+    data->state.allow_port = TRUE;
+
+#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
+    /*************************************************************
+     * Tell signal handler to ignore SIGPIPE
+     *************************************************************/
+    if(!data->set.no_signal)
+      data->state.prev_signal = signal(SIGPIPE, SIG_IGN);
+#endif
+
+    Curl_initinfo(data); /* reset session-specific information "variables" */
+    Curl_pgrsResetTransferSizes(data);
+    Curl_pgrsStartNow(data);
+
+    /* In case the handle is reused and an authentication method was picked
+       in the session we need to make sure we only use the one(s) we now
+       consider to be fine */
+    data->state.authhost.picked &= data->state.authhost.want;
+    data->state.authproxy.picked &= data->state.authproxy.want;
+
+#ifndef CURL_DISABLE_FTP
+    data->state.wildcardmatch = data->set.wildcard_enabled;
+    if(data->state.wildcardmatch) {
+      struct WildcardData *wc;
+      if(!data->wildcard) {
+        data->wildcard = calloc(1, sizeof(struct WildcardData));
+        if(!data->wildcard)
+          return CURLE_OUT_OF_MEMORY;
+      }
+      wc = data->wildcard;
+      if(wc->state < CURLWC_INIT) {
+        if(wc->ftpwc)
+          wc->dtor(wc->ftpwc);
+        Curl_safefree(wc->pattern);
+        Curl_safefree(wc->path);
+        result = Curl_wildcard_init(wc); /* init wildcard structures */
+        if(result)
+          return CURLE_OUT_OF_MEMORY;
+      }
+    }
+#endif
+    result = Curl_hsts_loadcb(data, data->hsts);
+  }
+
+  /*
+   * Set user-agent. Used for HTTP, but since we can attempt to tunnel
+   * basically anything through an HTTP proxy we can't limit this based on
+   * protocol.
+   */
+  if(data->set.str[STRING_USERAGENT]) {
+    Curl_safefree(data->state.aptr.uagent);
+    data->state.aptr.uagent =
+      aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
+    if(!data->state.aptr.uagent)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(!result)
+    result = Curl_setstropt(&data->state.aptr.user,
+                            data->set.str[STRING_USERNAME]);
+  if(!result)
+    result = Curl_setstropt(&data->state.aptr.passwd,
+                            data->set.str[STRING_PASSWORD]);
+  if(!result)
+    result = Curl_setstropt(&data->state.aptr.proxyuser,
+                            data->set.str[STRING_PROXYUSERNAME]);
+  if(!result)
+    result = Curl_setstropt(&data->state.aptr.proxypasswd,
+                            data->set.str[STRING_PROXYPASSWORD]);
+
+  data->req.headerbytecount = 0;
+  Curl_headers_cleanup(data);
+  return result;
+}
+
+/*
+ * Curl_posttransfer() is called immediately after a transfer ends
+ */
+CURLcode Curl_posttransfer(struct Curl_easy *data)
+{
+#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
+  /* restore the signal handler for SIGPIPE before we get back */
+  if(!data->set.no_signal)
+    signal(SIGPIPE, data->state.prev_signal);
+#else
+  (void)data; /* unused parameter */
+#endif
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
+ * as given by the remote server and set up the new URL to request.
+ *
+ * This function DOES NOT FREE the given url.
+ */
+CURLcode Curl_follow(struct Curl_easy *data,
+                     char *newurl,    /* the Location: string */
+                     followtype type) /* see transfer.h */
+{
+#ifdef CURL_DISABLE_HTTP
+  (void)data;
+  (void)newurl;
+  (void)type;
+  /* Location: following will not happen when HTTP is disabled */
+  return CURLE_TOO_MANY_REDIRECTS;
+#else
+
+  /* Location: redirect */
+  bool disallowport = FALSE;
+  bool reachedmax = FALSE;
+  CURLUcode uc;
+
+  DEBUGASSERT(type != FOLLOW_NONE);
+
+  if(type != FOLLOW_FAKE)
+    data->state.requests++; /* count all real follows */
+  if(type == FOLLOW_REDIR) {
+    if((data->set.maxredirs != -1) &&
+       (data->state.followlocation >= data->set.maxredirs)) {
+      reachedmax = TRUE;
+      type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected
+                             to URL */
+    }
+    else {
+      data->state.followlocation++; /* count redirect-followings, including
+                                       auth reloads */
+
+      if(data->set.http_auto_referer) {
+        CURLU *u;
+        char *referer = NULL;
+
+        /* We are asked to automatically set the previous URL as the referer
+           when we get the next URL. We pick the ->url field, which may or may
+           not be 100% correct */
+
+        if(data->state.referer_alloc) {
+          Curl_safefree(data->state.referer);
+          data->state.referer_alloc = FALSE;
+        }
+
+        /* Make a copy of the URL without credentials and fragment */
+        u = curl_url();
+        if(!u)
+          return CURLE_OUT_OF_MEMORY;
+
+        uc = curl_url_set(u, CURLUPART_URL, data->state.url, 0);
+        if(!uc)
+          uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0);
+        if(!uc)
+          uc = curl_url_set(u, CURLUPART_USER, NULL, 0);
+        if(!uc)
+          uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0);
+        if(!uc)
+          uc = curl_url_get(u, CURLUPART_URL, &referer, 0);
+
+        curl_url_cleanup(u);
+
+        if(uc || !referer)
+          return CURLE_OUT_OF_MEMORY;
+
+        data->state.referer = referer;
+        data->state.referer_alloc = TRUE; /* yes, free this later */
+      }
+    }
+  }
+
+  if((type != FOLLOW_RETRY) &&
+     (data->req.httpcode != 401) && (data->req.httpcode != 407) &&
+     Curl_is_absolute_url(newurl, NULL, 0, FALSE)) {
+    /* If this is not redirect due to a 401 or 407 response and an absolute
+       URL: don't allow a custom port number */
+    disallowport = TRUE;
+  }
+
+  DEBUGASSERT(data->state.uh);
+  uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl,
+                    (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
+                    ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
+                    CURLU_ALLOW_SPACE |
+                    (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
+  if(uc) {
+    if(type != FOLLOW_FAKE) {
+      failf(data, "The redirect target URL could not be parsed: %s",
+            curl_url_strerror(uc));
+      return Curl_uc_to_curlcode(uc);
+    }
+
+    /* the URL could not be parsed for some reason, but since this is FAKE
+       mode, just duplicate the field as-is */
+    newurl = strdup(newurl);
+    if(!newurl)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  else {
+    uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0);
+    if(uc)
+      return Curl_uc_to_curlcode(uc);
+
+    /* Clear auth if this redirects to a different port number or protocol,
+       unless permitted */
+    if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) {
+      char *portnum;
+      int port;
+      bool clear = FALSE;
+
+      if(data->set.use_port && data->state.allow_port)
+        /* a custom port is used */
+        port = (int)data->set.use_port;
+      else {
+        uc = curl_url_get(data->state.uh, CURLUPART_PORT, &portnum,
+                          CURLU_DEFAULT_PORT);
+        if(uc) {
+          free(newurl);
+          return Curl_uc_to_curlcode(uc);
+        }
+        port = atoi(portnum);
+        free(portnum);
+      }
+      if(port != data->info.conn_remote_port) {
+        infof(data, "Clear auth, redirects to port from %u to %u",
+              data->info.conn_remote_port, port);
+        clear = TRUE;
+      }
+      else {
+        char *scheme;
+        const struct Curl_handler *p;
+        uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0);
+        if(uc) {
+          free(newurl);
+          return Curl_uc_to_curlcode(uc);
+        }
+
+        p = Curl_get_scheme_handler(scheme);
+        if(p && (p->protocol != data->info.conn_protocol)) {
+          infof(data, "Clear auth, redirects scheme from %s to %s",
+                data->info.conn_scheme, scheme);
+          clear = TRUE;
+        }
+        free(scheme);
+      }
+      if(clear) {
+        Curl_safefree(data->state.aptr.user);
+        Curl_safefree(data->state.aptr.passwd);
+      }
+    }
+  }
+
+  if(type == FOLLOW_FAKE) {
+    /* we're only figuring out the new url if we would've followed locations
+       but now we're done so we can get out! */
+    data->info.wouldredirect = newurl;
+
+    if(reachedmax) {
+      failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs);
+      return CURLE_TOO_MANY_REDIRECTS;
+    }
+    return CURLE_OK;
+  }
+
+  if(disallowport)
+    data->state.allow_port = FALSE;
+
+  if(data->state.url_alloc)
+    Curl_safefree(data->state.url);
+
+  data->state.url = newurl;
+  data->state.url_alloc = TRUE;
+  Curl_req_soft_reset(&data->req, data);
+  infof(data, "Issue another request to this URL: '%s'", data->state.url);
+
+  /*
+   * We get here when the HTTP code is 300-399 (and 401). We need to perform
+   * differently based on exactly what return code there was.
+   *
+   * News from 7.10.6: we can also get here on a 401 or 407, in case we act on
+   * an HTTP (proxy-) authentication scheme other than Basic.
+   */
+  switch(data->info.httpcode) {
+    /* 401 - Act on a WWW-Authenticate, we keep on moving and do the
+       Authorization: XXXX header in the HTTP request code snippet */
+    /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the
+       Proxy-Authorization: XXXX header in the HTTP request code snippet */
+    /* 300 - Multiple Choices */
+    /* 306 - Not used */
+    /* 307 - Temporary Redirect */
+  default:  /* for all above (and the unknown ones) */
+    /* Some codes are explicitly mentioned since I've checked RFC2616 and they
+     * seem to be OK to POST to.
+     */
+    break;
+  case 301: /* Moved Permanently */
+    /* (quote from RFC7231, section 6.4.2)
+     *
+     * Note: For historical reasons, a user agent MAY change the request
+     * method from POST to GET for the subsequent request.  If this
+     * behavior is undesired, the 307 (Temporary Redirect) status code
+     * can be used instead.
+     *
+     * ----
+     *
+     * Many webservers expect this, so these servers often answers to a POST
+     * request with an error page. To be sure that libcurl gets the page that
+     * most user agents would get, libcurl has to force GET.
+     *
+     * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
+     * can be overridden with CURLOPT_POSTREDIR.
+     */
+    if((data->state.httpreq == HTTPREQ_POST
+        || data->state.httpreq == HTTPREQ_POST_FORM
+        || data->state.httpreq == HTTPREQ_POST_MIME)
+       && !(data->set.keep_post & CURL_REDIR_POST_301)) {
+      infof(data, "Switch from POST to GET");
+      data->state.httpreq = HTTPREQ_GET;
+      Curl_creader_set_rewind(data, FALSE);
+    }
+    break;
+  case 302: /* Found */
+    /* (quote from RFC7231, section 6.4.3)
+     *
+     * Note: For historical reasons, a user agent MAY change the request
+     * method from POST to GET for the subsequent request.  If this
+     * behavior is undesired, the 307 (Temporary Redirect) status code
+     * can be used instead.
+     *
+     * ----
+     *
+     * Many webservers expect this, so these servers often answers to a POST
+     * request with an error page. To be sure that libcurl gets the page that
+     * most user agents would get, libcurl has to force GET.
+     *
+     * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
+     * can be overridden with CURLOPT_POSTREDIR.
+     */
+    if((data->state.httpreq == HTTPREQ_POST
+        || data->state.httpreq == HTTPREQ_POST_FORM
+        || data->state.httpreq == HTTPREQ_POST_MIME)
+       && !(data->set.keep_post & CURL_REDIR_POST_302)) {
+      infof(data, "Switch from POST to GET");
+      data->state.httpreq = HTTPREQ_GET;
+      Curl_creader_set_rewind(data, FALSE);
+    }
+    break;
+
+  case 303: /* See Other */
+    /* 'See Other' location is not the resource but a substitute for the
+     * resource. In this case we switch the method to GET/HEAD, unless the
+     * method is POST and the user specified to keep it as POST.
+     * https://github.com/curl/curl/issues/5237#issuecomment-614641049
+     */
+    if(data->state.httpreq != HTTPREQ_GET &&
+       ((data->state.httpreq != HTTPREQ_POST &&
+         data->state.httpreq != HTTPREQ_POST_FORM &&
+         data->state.httpreq != HTTPREQ_POST_MIME) ||
+        !(data->set.keep_post & CURL_REDIR_POST_303))) {
+      data->state.httpreq = HTTPREQ_GET;
+      infof(data, "Switch to %s",
+            data->req.no_body?"HEAD":"GET");
+    }
+    break;
+  case 304: /* Not Modified */
+    /* 304 means we did a conditional request and it was "Not modified".
+     * We shouldn't get any Location: header in this response!
+     */
+    break;
+  case 305: /* Use Proxy */
+    /* (quote from RFC2616, section 10.3.6):
+     * "The requested resource MUST be accessed through the proxy given
+     * by the Location field. The Location field gives the URI of the
+     * proxy.  The recipient is expected to repeat this single request
+     * via the proxy. 305 responses MUST only be generated by origin
+     * servers."
+     */
+    break;
+  }
+  Curl_pgrsTime(data, TIMER_REDIRECT);
+  Curl_pgrsResetTransferSizes(data);
+
+  return CURLE_OK;
+#endif /* CURL_DISABLE_HTTP */
+}
+
+/* Returns CURLE_OK *and* sets '*url' if a request retry is wanted.
+
+   NOTE: that the *url is malloc()ed. */
+CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
+{
+  struct connectdata *conn = data->conn;
+  bool retry = FALSE;
+  *url = NULL;
+
+  /* if we're talking upload, we can't do the checks below, unless the protocol
+     is HTTP as when uploading over HTTP we will still get a response */
+  if(data->state.upload &&
+     !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)))
+    return CURLE_OK;
+
+  if((data->req.bytecount + data->req.headerbytecount == 0) &&
+     conn->bits.reuse &&
+     (!data->req.no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP))
+#ifndef CURL_DISABLE_RTSP
+     && (data->set.rtspreq != RTSPREQ_RECEIVE)
+#endif
+    )
+    /* We got no data, we attempted to reuse a connection. For HTTP this
+       can be a retry so we try again regardless if we expected a body.
+       For other protocols we only try again only if we expected a body.
+
+       This might happen if the connection was left alive when we were
+       done using it before, but that was closed when we wanted to read from
+       it again. Bad luck. Retry the same request on a fresh connect! */
+    retry = TRUE;
+  else if(data->state.refused_stream &&
+          (data->req.bytecount + data->req.headerbytecount == 0) ) {
+    /* This was sent on a refused stream, safe to rerun. A refused stream
+       error can typically only happen on HTTP/2 level if the stream is safe
+       to issue again, but the nghttp2 API can deliver the message to other
+       streams as well, which is why this adds the check the data counters
+       too. */
+    infof(data, "REFUSED_STREAM, retrying a fresh connect");
+    data->state.refused_stream = FALSE; /* clear again */
+    retry = TRUE;
+  }
+  if(retry) {
+#define CONN_MAX_RETRIES 5
+    if(data->state.retrycount++ >= CONN_MAX_RETRIES) {
+      failf(data, "Connection died, tried %d times before giving up",
+            CONN_MAX_RETRIES);
+      data->state.retrycount = 0;
+      return CURLE_SEND_ERROR;
+    }
+    infof(data, "Connection died, retrying a fresh connect (retry count: %d)",
+          data->state.retrycount);
+    *url = strdup(data->state.url);
+    if(!*url)
+      return CURLE_OUT_OF_MEMORY;
+
+    connclose(conn, "retry"); /* close this connection */
+    conn->bits.retry = TRUE; /* mark this as a connection we're about
+                                to retry. Marking it this way should
+                                prevent i.e HTTP transfers to return
+                                error just because nothing has been
+                                transferred! */
+    Curl_creader_set_rewind(data, TRUE);
+  }
+  return CURLE_OK;
+}
+
+/*
+ * Curl_xfer_setup() is called to setup some basic properties for the
+ * upcoming transfer.
+ */
+void Curl_xfer_setup(
+  struct Curl_easy *data,   /* transfer */
+  int sockindex,            /* socket index to read from or -1 */
+  curl_off_t size,          /* -1 if unknown at this point */
+  bool getheader,           /* TRUE if header parsing is wanted */
+  int writesockindex        /* socket index to write to, it may very well be
+                               the same we read from. -1 disables */
+  )
+{
+  struct SingleRequest *k = &data->req;
+  struct connectdata *conn = data->conn;
+  bool want_send = Curl_req_want_send(data);
+
+  DEBUGASSERT(conn != NULL);
+  DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
+  DEBUGASSERT((writesockindex <= 1) && (writesockindex >= -1));
+
+  if(conn->bits.multiplex || conn->httpversion >= 20 || want_send) {
+    /* when multiplexing, the read/write sockets need to be the same! */
+    conn->sockfd = sockindex == -1 ?
+      ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) :
+      conn->sock[sockindex];
+    conn->writesockfd = conn->sockfd;
+    if(want_send)
+      /* special and very HTTP-specific */
+      writesockindex = FIRSTSOCKET;
+  }
+  else {
+    conn->sockfd = sockindex == -1 ?
+      CURL_SOCKET_BAD : conn->sock[sockindex];
+    conn->writesockfd = writesockindex == -1 ?
+      CURL_SOCKET_BAD:conn->sock[writesockindex];
+  }
+  k->getheader = getheader;
+
+  k->size = size;
+
+  /* The code sequence below is placed in this function just because all
+     necessary input is not always known in do_complete() as this function may
+     be called after that */
+
+  if(!k->getheader) {
+    k->header = FALSE;
+    if(size > 0)
+      Curl_pgrsSetDownloadSize(data, size);
+  }
+  /* we want header and/or body, if neither then don't do this! */
+  if(k->getheader || !data->req.no_body) {
+
+    if(sockindex != -1)
+      k->keepon |= KEEP_RECV;
+
+    if(writesockindex != -1)
+      k->keepon |= KEEP_SEND;
+  } /* if(k->getheader || !data->req.no_body) */
+
+}
+
+CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
+                              char *buf, size_t blen,
+                              bool is_eos)
+{
+  CURLcode result = CURLE_OK;
+
+  if(data->conn->handler->write_resp) {
+    /* protocol handlers offering this function take full responsibility
+     * for writing all received download data to the client. */
+    result = data->conn->handler->write_resp(data, buf, blen, is_eos);
+  }
+  else {
+    /* No special handling by protocol handler, write all received data
+     * as BODY to the client. */
+    if(blen || is_eos) {
+      int cwtype = CLIENTWRITE_BODY;
+      if(is_eos)
+        cwtype |= CLIENTWRITE_EOS;
+
+#ifndef CURL_DISABLE_POP3
+      if(blen && data->conn->handler->protocol & PROTO_FAMILY_POP3) {
+        result = data->req.ignorebody? CURLE_OK :
+                 Curl_pop3_write(data, buf, blen);
+      }
+      else
+#endif /* CURL_DISABLE_POP3 */
+        result = Curl_client_write(data, cwtype, buf, blen);
+    }
+  }
+
+  if(!result && is_eos) {
+    /* If we wrote the EOS, we are definitely done */
+    data->req.eos_written = TRUE;
+    data->req.download_done = TRUE;
+  }
+  return result;
+}
+
+CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature)
+{
+  (void)premature;
+  return Curl_cw_out_done(data);
+}
+
+CURLcode Curl_xfer_send(struct Curl_easy *data,
+                        const void *buf, size_t blen,
+                        size_t *pnwritten)
+{
+  CURLcode result;
+  int sockindex;
+
+  if(!data || !data->conn)
+    return CURLE_FAILED_INIT;
+  /* FIXME: would like to enable this, but some protocols (MQTT) do not
+   * setup the transfer correctly, it seems
+  if(data->conn->writesockfd == CURL_SOCKET_BAD) {
+    failf(data, "transfer not setup for sending");
+    DEBUGASSERT(0);
+    return CURLE_SEND_ERROR;
+  } */
+  sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
+               (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
+  result = Curl_conn_send(data, sockindex, buf, blen, pnwritten);
+  if(result == CURLE_AGAIN) {
+    result = CURLE_OK;
+    *pnwritten = 0;
+  }
+  return result;
+}
+
+CURLcode Curl_xfer_recv(struct Curl_easy *data,
+                        char *buf, size_t blen,
+                        ssize_t *pnrcvd)
+{
+  int sockindex;
+
+  if(!data || !data->conn)
+    return CURLE_FAILED_INIT;
+  /* FIXME: would like to enable this, but some protocols (MQTT) do not
+   * setup the transfer correctly, it seems
+  if(data->conn->sockfd == CURL_SOCKET_BAD) {
+    failf(data, "transfer not setup for receiving");
+    DEBUGASSERT(0);
+    return CURLE_RECV_ERROR;
+  } */
+  sockindex = ((data->conn->sockfd != CURL_SOCKET_BAD) &&
+               (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]));
+  if(data->set.buffer_size > 0 && (size_t)data->set.buffer_size < blen)
+    blen = (size_t)data->set.buffer_size;
+  return Curl_conn_recv(data, sockindex, buf, blen, pnrcvd);
+}
+
+CURLcode Curl_xfer_send_close(struct Curl_easy *data)
+{
+  Curl_conn_ev_data_done_send(data);
+  return CURLE_OK;
+}
Index: trunk/src/libs/curl-8.7.1/lib/transfer.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/transfer.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/transfer.h	(revision 104083)
@@ -0,0 +1,107 @@
+#ifndef HEADER_CURL_TRANSFER_H
+#define HEADER_CURL_TRANSFER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#define Curl_headersep(x) ((((x)==':') || ((x)==';')))
+char *Curl_checkheaders(const struct Curl_easy *data,
+                        const char *thisheader,
+                        const size_t thislen);
+
+void Curl_init_CONNECT(struct Curl_easy *data);
+
+CURLcode Curl_pretransfer(struct Curl_easy *data);
+CURLcode Curl_posttransfer(struct Curl_easy *data);
+
+typedef enum {
+  FOLLOW_NONE,  /* not used within the function, just a placeholder to
+                   allow initing to this */
+  FOLLOW_FAKE,  /* only records stuff, not actually following */
+  FOLLOW_RETRY, /* set if this is a request retry as opposed to a real
+                   redirect following */
+  FOLLOW_REDIR /* a full true redirect */
+} followtype;
+
+CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
+                     followtype type);
+CURLcode Curl_readwrite(struct Curl_easy *data);
+int Curl_single_getsock(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks);
+CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
+bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc);
+
+/**
+ * Write the transfer raw response bytes, as received from the connection.
+ * Will handle all passed bytes or return an error. By default, this will
+ * write the bytes as BODY to the client. Protocols may provide a
+ * "write_resp" callback in their handler to add specific treatment. E.g.
+ * HTTP parses response headers and passes them differently to the client.
+ * @param data     the transfer
+ * @param buf      the raw response bytes
+ * @param blen     the amount of bytes in `buf`
+ * @param is_eos   TRUE iff the connection indicates this to be the last
+ *                 bytes of the response
+ * @param done     on returnm, TRUE iff the response is complete
+ */
+CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
+                              char *buf, size_t blen,
+                              bool is_eos);
+
+/* This sets up a forthcoming transfer */
+void Curl_xfer_setup(struct Curl_easy *data,
+                     int sockindex,     /* socket index to read from or -1 */
+                     curl_off_t size,   /* -1 if unknown at this point */
+                     bool getheader,    /* TRUE if header parsing is wanted */
+                     int writesockindex /* socket index to write to. May be
+                                           the same we read from. -1
+                                           disables */
+  );
+
+/**
+ * Multi has set transfer to DONE. Last chance to trigger
+ * missing response things like writing an EOS to the client.
+ */
+CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature);
+
+/**
+ * Send data on the socket/connection filter designated
+ * for transfer's outgoing data.
+ * Will return CURLE_OK on blocking with (*pnwritten == 0).
+ */
+CURLcode Curl_xfer_send(struct Curl_easy *data,
+                        const void *buf, size_t blen,
+                        size_t *pnwritten);
+
+/**
+ * Receive data on the socket/connection filter designated
+ * for transfer's incoming data.
+ * Will return CURLE_AGAIN on blocking with (*pnrcvd == 0).
+ */
+CURLcode Curl_xfer_recv(struct Curl_easy *data,
+                        char *buf, size_t blen,
+                        ssize_t *pnrcvd);
+
+CURLcode Curl_xfer_send_close(struct Curl_easy *data);
+
+#endif /* HEADER_CURL_TRANSFER_H */
Index: trunk/src/libs/curl-8.7.1/lib/url.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/url.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/url.c	(revision 104083)
@@ -0,0 +1,4014 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_IPHLPAPI_H
+#include <Iphlpapi.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
+#ifndef HAVE_SOCKET
+#error "We can't compile without socket() support!"
+#endif
+
+#include <limits.h>
+
+#include "doh.h"
+#include "urldata.h"
+#include "netrc.h"
+#include "formdata.h"
+#include "mime.h"
+#include "vtls/vtls.h"
+#include "hostip.h"
+#include "transfer.h"
+#include "sendf.h"
+#include "progress.h"
+#include "cookie.h"
+#include "strcase.h"
+#include "strerror.h"
+#include "escape.h"
+#include "strtok.h"
+#include "share.h"
+#include "content_encoding.h"
+#include "http_digest.h"
+#include "http_negotiate.h"
+#include "select.h"
+#include "multiif.h"
+#include "easyif.h"
+#include "speedcheck.h"
+#include "warnless.h"
+#include "getinfo.h"
+#include "urlapi-int.h"
+#include "system_win32.h"
+#include "hsts.h"
+#include "noproxy.h"
+#include "cfilters.h"
+#include "idn.h"
+
+/* And now for the protocols */
+#include "ftp.h"
+#include "dict.h"
+#include "telnet.h"
+#include "tftp.h"
+#include "http.h"
+#include "http2.h"
+#include "file.h"
+#include "curl_ldap.h"
+#include "vssh/ssh.h"
+#include "imap.h"
+#include "url.h"
+#include "connect.h"
+#include "inet_ntop.h"
+#include "http_ntlm.h"
+#include "curl_rtmp.h"
+#include "gopher.h"
+#include "mqtt.h"
+#include "http_proxy.h"
+#include "conncache.h"
+#include "multihandle.h"
+#include "strdup.h"
+#include "setopt.h"
+#include "altsvc.h"
+#include "dynbuf.h"
+#include "headers.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+#ifdef USE_NGHTTP2
+static void data_priority_cleanup(struct Curl_easy *data);
+#else
+#define data_priority_cleanup(x)
+#endif
+
+/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
+ * more than just a few bytes to play with. Don't let it become too small or
+ * bad things will happen.
+ */
+#if READBUFFER_SIZE < READBUFFER_MIN
+# error READBUFFER_SIZE is too small
+#endif
+
+#ifdef USE_UNIX_SOCKETS
+#define UNIX_SOCKET_PREFIX "localhost"
+#endif
+
+/* Reject URLs exceeding this length */
+#define MAX_URL_LEN 0xffff
+
+/*
+* get_protocol_family()
+*
+* This is used to return the protocol family for a given protocol.
+*
+* Parameters:
+*
+* 'h'  [in]  - struct Curl_handler pointer.
+*
+* Returns the family as a single bit protocol identifier.
+*/
+static curl_prot_t get_protocol_family(const struct Curl_handler *h)
+{
+  DEBUGASSERT(h);
+  DEBUGASSERT(h->family);
+  return h->family;
+}
+
+void Curl_freeset(struct Curl_easy *data)
+{
+  /* Free all dynamic strings stored in the data->set substructure. */
+  enum dupstring i;
+  enum dupblob j;
+
+  for(i = (enum dupstring)0; i < STRING_LAST; i++) {
+    Curl_safefree(data->set.str[i]);
+  }
+
+  for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
+    Curl_safefree(data->set.blobs[j]);
+  }
+
+  if(data->state.referer_alloc) {
+    Curl_safefree(data->state.referer);
+    data->state.referer_alloc = FALSE;
+  }
+  data->state.referer = NULL;
+  if(data->state.url_alloc) {
+    Curl_safefree(data->state.url);
+    data->state.url_alloc = FALSE;
+  }
+  data->state.url = NULL;
+
+  Curl_mime_cleanpart(&data->set.mimepost);
+
+#ifndef CURL_DISABLE_COOKIES
+  curl_slist_free_all(data->state.cookielist);
+  data->state.cookielist = NULL;
+#endif
+}
+
+/* free the URL pieces */
+static void up_free(struct Curl_easy *data)
+{
+  struct urlpieces *up = &data->state.up;
+  Curl_safefree(up->scheme);
+  Curl_safefree(up->hostname);
+  Curl_safefree(up->port);
+  Curl_safefree(up->user);
+  Curl_safefree(up->password);
+  Curl_safefree(up->options);
+  Curl_safefree(up->path);
+  Curl_safefree(up->query);
+  curl_url_cleanup(data->state.uh);
+  data->state.uh = NULL;
+}
+
+/*
+ * This is the internal function curl_easy_cleanup() calls. This should
+ * cleanup and free all resources associated with this sessionhandle.
+ *
+ * We ignore SIGPIPE when this is called from curl_easy_cleanup.
+ */
+
+CURLcode Curl_close(struct Curl_easy **datap)
+{
+  struct Curl_easy *data;
+
+  if(!datap || !*datap)
+    return CURLE_OK;
+
+  data = *datap;
+  *datap = NULL;
+
+  Curl_expire_clear(data); /* shut off timers */
+
+  /* Detach connection if any is left. This should not be normal, but can be
+     the case for example with CONNECT_ONLY + recv/send (test 556) */
+  Curl_detach_connection(data);
+  if(!data->state.internal) {
+    if(data->multi)
+      /* This handle is still part of a multi handle, take care of this first
+         and detach this handle from there. */
+      curl_multi_remove_handle(data->multi, data);
+
+    if(data->multi_easy) {
+      /* when curl_easy_perform() is used, it creates its own multi handle to
+         use and this is the one */
+      curl_multi_cleanup(data->multi_easy);
+      data->multi_easy = NULL;
+    }
+  }
+
+  data->magic = 0; /* force a clear AFTER the possibly enforced removal from
+                      the multi handle, since that function uses the magic
+                      field! */
+
+  if(data->state.rangestringalloc)
+    free(data->state.range);
+
+  /* freed here just in case DONE wasn't called */
+  Curl_req_free(&data->req, data);
+
+  /* Close down all open SSL info and sessions */
+  Curl_ssl_close_all(data);
+  Curl_safefree(data->state.first_host);
+  Curl_safefree(data->state.scratch);
+  Curl_ssl_free_certinfo(data);
+
+  if(data->state.referer_alloc) {
+    Curl_safefree(data->state.referer);
+    data->state.referer_alloc = FALSE;
+  }
+  data->state.referer = NULL;
+
+  up_free(data);
+  Curl_dyn_free(&data->state.headerb);
+  Curl_flush_cookies(data, TRUE);
+  Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
+  Curl_altsvc_cleanup(&data->asi);
+  Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
+#ifndef CURL_DISABLE_HSTS
+  if(!data->share || !data->share->hsts)
+    Curl_hsts_cleanup(&data->hsts);
+  curl_slist_free_all(data->state.hstslist); /* clean up list */
+#endif
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
+  Curl_http_auth_cleanup_digest(data);
+#endif
+  Curl_safefree(data->info.contenttype);
+  Curl_safefree(data->info.wouldredirect);
+
+  /* this destroys the channel and we cannot use it anymore after this */
+  Curl_resolver_cancel(data);
+  Curl_resolver_cleanup(data->state.async.resolver);
+
+  data_priority_cleanup(data);
+
+  /* No longer a dirty share, if it exists */
+  if(data->share) {
+    Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+    data->share->dirty--;
+    Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+  }
+
+  Curl_safefree(data->state.aptr.proxyuserpwd);
+  Curl_safefree(data->state.aptr.uagent);
+  Curl_safefree(data->state.aptr.userpwd);
+  Curl_safefree(data->state.aptr.accept_encoding);
+  Curl_safefree(data->state.aptr.te);
+  Curl_safefree(data->state.aptr.rangeline);
+  Curl_safefree(data->state.aptr.ref);
+  Curl_safefree(data->state.aptr.host);
+  Curl_safefree(data->state.aptr.cookiehost);
+  Curl_safefree(data->state.aptr.rtsp_transport);
+  Curl_safefree(data->state.aptr.user);
+  Curl_safefree(data->state.aptr.passwd);
+  Curl_safefree(data->state.aptr.proxyuser);
+  Curl_safefree(data->state.aptr.proxypasswd);
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
+  Curl_mime_cleanpart(data->state.formp);
+  Curl_safefree(data->state.formp);
+#endif
+
+  /* destruct wildcard structures if it is needed */
+  Curl_wildcard_dtor(&data->wildcard);
+  Curl_freeset(data);
+  Curl_headers_cleanup(data);
+  free(data);
+  return CURLE_OK;
+}
+
+/*
+ * Initialize the UserDefined fields within a Curl_easy.
+ * This may be safely called on a new or existing Curl_easy.
+ */
+CURLcode Curl_init_userdefined(struct Curl_easy *data)
+{
+  struct UserDefined *set = &data->set;
+  CURLcode result = CURLE_OK;
+
+  set->out = stdout; /* default output to stdout */
+  set->in_set = stdin;  /* default input from stdin */
+  set->err  = stderr;  /* default stderr to stderr */
+
+  /* use fwrite as default function to store output */
+  set->fwrite_func = (curl_write_callback)fwrite;
+
+  /* use fread as default function to read input */
+  set->fread_func_set = (curl_read_callback)fread;
+  set->is_fread_set = 0;
+
+  set->seek_client = ZERO_NULL;
+
+  set->filesize = -1;        /* we don't know the size */
+  set->postfieldsize = -1;   /* unknown size */
+  set->maxredirs = 30;       /* sensible default */
+
+  set->method = HTTPREQ_GET; /* Default HTTP request */
+#ifndef CURL_DISABLE_RTSP
+  set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
+#endif
+#ifndef CURL_DISABLE_FTP
+  set->ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
+  set->ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
+  set->ftp_use_pret = FALSE;  /* mainly useful for drftpd servers */
+  set->ftp_filemethod = FTPFILE_MULTICWD;
+  set->ftp_skip_ip = TRUE;    /* skip PASV IP by default */
+#endif
+  set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
+
+  /* Set the default size of the SSL session ID cache */
+  set->general_ssl.max_ssl_sessions = 5;
+  /* Timeout every 24 hours by default */
+  set->general_ssl.ca_cache_timeout = 24 * 60 * 60;
+
+  set->httpauth = CURLAUTH_BASIC;  /* defaults to basic */
+
+#ifndef CURL_DISABLE_PROXY
+  set->proxyport = 0;
+  set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
+  set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
+  /* SOCKS5 proxy auth defaults to username/password + GSS-API */
+  set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI;
+#endif
+
+  /* make libcurl quiet by default: */
+  set->hide_progress = TRUE;  /* CURLOPT_NOPROGRESS changes these */
+
+  Curl_mime_initpart(&set->mimepost);
+
+  Curl_ssl_easy_config_init(data);
+#ifndef CURL_DISABLE_DOH
+  set->doh_verifyhost = TRUE;
+  set->doh_verifypeer = TRUE;
+#endif
+#ifdef USE_SSH
+  /* defaults to any auth type */
+  set->ssh_auth_types = CURLSSH_AUTH_DEFAULT;
+  set->new_directory_perms = 0755; /* Default permissions */
+#endif
+
+  set->new_file_perms = 0644;    /* Default permissions */
+  set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL;
+  set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP |
+                         CURLPROTO_FTPS;
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  /*
+   * disallow unprotected protection negotiation NEC reference implementation
+   * seem not to follow rfc1961 section 4.3/4.4
+   */
+  set->socks5_gssapi_nec = FALSE;
+#endif
+
+  /* Set the default CA cert bundle/path detected/specified at build time.
+   *
+   * If Schannel or SecureTransport is the selected SSL backend then these
+   * locations are ignored. We allow setting CA location for schannel and
+   * securetransport when explicitly specified by the user via
+   *  CURLOPT_CAINFO / --cacert.
+   */
+  if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL &&
+     Curl_ssl_backend() != CURLSSLBACKEND_SECURETRANSPORT) {
+#if defined(CURL_CA_BUNDLE)
+    result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
+    if(result)
+      return result;
+
+    result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
+                            CURL_CA_BUNDLE);
+    if(result)
+      return result;
+#endif
+#if defined(CURL_CA_PATH)
+    result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
+    if(result)
+      return result;
+
+    result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
+    if(result)
+      return result;
+#endif
+  }
+
+#ifndef CURL_DISABLE_FTP
+  set->wildcard_enabled = FALSE;
+  set->chunk_bgn      = ZERO_NULL;
+  set->chunk_end      = ZERO_NULL;
+  set->fnmatch = ZERO_NULL;
+#endif
+  set->tcp_keepalive = FALSE;
+  set->tcp_keepintvl = 60;
+  set->tcp_keepidle = 60;
+  set->tcp_fastopen = FALSE;
+  set->tcp_nodelay = TRUE;
+  set->ssl_enable_alpn = TRUE;
+  set->expect_100_timeout = 1000L; /* Wait for a second by default. */
+  set->sep_headers = TRUE; /* separated header lists by default */
+  set->buffer_size = READBUFFER_SIZE;
+  set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
+  set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
+  set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
+  set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
+  set->maxage_conn = 118;
+  set->maxlifetime_conn = 0;
+  set->http09_allowed = FALSE;
+#ifdef USE_HTTP2
+  set->httpwant = CURL_HTTP_VERSION_2TLS
+#else
+  set->httpwant = CURL_HTTP_VERSION_1_1
+#endif
+    ;
+#if defined(USE_HTTP2) || defined(USE_HTTP3)
+  memset(&set->priority, 0, sizeof(set->priority));
+#endif
+  set->quick_exit = 0L;
+  return result;
+}
+
+/**
+ * Curl_open()
+ *
+ * @param curl is a pointer to a sessionhandle pointer that gets set by this
+ * function.
+ * @return CURLcode
+ */
+
+CURLcode Curl_open(struct Curl_easy **curl)
+{
+  CURLcode result;
+  struct Curl_easy *data;
+
+  /* Very simple start-up: alloc the struct, init it with zeroes and return */
+  data = calloc(1, sizeof(struct Curl_easy));
+  if(!data) {
+    /* this is a very serious error */
+    DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n"));
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  data->magic = CURLEASY_MAGIC_NUMBER;
+
+  result = Curl_req_init(&data->req);
+  if(result) {
+    DEBUGF(fprintf(stderr, "Error: request init failed\n"));
+    free(data);
+    return result;
+  }
+
+  result = Curl_resolver_init(data, &data->state.async.resolver);
+  if(result) {
+    DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
+    Curl_req_free(&data->req, data);
+    free(data);
+    return result;
+  }
+
+  result = Curl_init_userdefined(data);
+  if(!result) {
+    Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
+    Curl_initinfo(data);
+
+    /* most recent connection is not yet defined */
+    data->state.lastconnect_id = -1;
+    data->state.recent_conn_id = -1;
+    /* and not assigned an id yet */
+    data->id = -1;
+
+    data->progress.flags |= PGRS_HIDE;
+    data->state.current_speed = -1; /* init to negative == impossible */
+  }
+
+  if(result) {
+    Curl_resolver_cleanup(data->state.async.resolver);
+    Curl_dyn_free(&data->state.headerb);
+    Curl_freeset(data);
+    Curl_req_free(&data->req, data);
+    free(data);
+    data = NULL;
+  }
+  else
+    *curl = data;
+
+  return result;
+}
+
+static void conn_shutdown(struct Curl_easy *data)
+{
+  DEBUGASSERT(data);
+  infof(data, "Closing connection");
+
+  /* possible left-overs from the async name resolvers */
+  Curl_resolver_cancel(data);
+
+  Curl_conn_close(data, SECONDARYSOCKET);
+  Curl_conn_close(data, FIRSTSOCKET);
+}
+
+static void conn_free(struct Curl_easy *data, struct connectdata *conn)
+{
+  size_t i;
+
+  DEBUGASSERT(conn);
+
+  for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
+    Curl_conn_cf_discard_all(data, conn, (int)i);
+  }
+
+  Curl_free_idnconverted_hostname(&conn->host);
+  Curl_free_idnconverted_hostname(&conn->conn_to_host);
+#ifndef CURL_DISABLE_PROXY
+  Curl_free_idnconverted_hostname(&conn->http_proxy.host);
+  Curl_free_idnconverted_hostname(&conn->socks_proxy.host);
+  Curl_safefree(conn->http_proxy.user);
+  Curl_safefree(conn->socks_proxy.user);
+  Curl_safefree(conn->http_proxy.passwd);
+  Curl_safefree(conn->socks_proxy.passwd);
+  Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
+  Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
+#endif
+  Curl_safefree(conn->user);
+  Curl_safefree(conn->passwd);
+  Curl_safefree(conn->sasl_authzid);
+  Curl_safefree(conn->options);
+  Curl_safefree(conn->oauth_bearer);
+  Curl_safefree(conn->host.rawalloc); /* host name buffer */
+  Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
+  Curl_safefree(conn->hostname_resolve);
+  Curl_safefree(conn->secondaryhostname);
+  Curl_safefree(conn->localdev);
+  Curl_ssl_conn_config_cleanup(conn);
+
+#ifdef USE_UNIX_SOCKETS
+  Curl_safefree(conn->unix_domain_socket);
+#endif
+
+  free(conn); /* free all the connection oriented data */
+}
+
+/*
+ * Disconnects the given connection. Note the connection may not be the
+ * primary connection, like when freeing room in the connection cache or
+ * killing of a dead old connection.
+ *
+ * A connection needs an easy handle when closing down. We support this passed
+ * in separately since the connection to get closed here is often already
+ * disassociated from an easy handle.
+ *
+ * This function MUST NOT reset state in the Curl_easy struct if that
+ * isn't strictly bound to the life-time of *this* particular connection.
+ *
+ */
+
+void Curl_disconnect(struct Curl_easy *data,
+                     struct connectdata *conn, bool dead_connection)
+{
+  /* there must be a connection to close */
+  DEBUGASSERT(conn);
+
+  /* it must be removed from the connection cache */
+  DEBUGASSERT(!conn->bundle);
+
+  /* there must be an associated transfer */
+  DEBUGASSERT(data);
+
+  /* the transfer must be detached from the connection */
+  DEBUGASSERT(!data->conn);
+
+  DEBUGF(infof(data, "Curl_disconnect(conn #%"
+         CURL_FORMAT_CURL_OFF_T ", dead=%d)",
+         conn->connection_id, dead_connection));
+  /*
+   * If this connection isn't marked to force-close, leave it open if there
+   * are other users of it
+   */
+  if(CONN_INUSE(conn) && !dead_connection) {
+    DEBUGF(infof(data, "Curl_disconnect when inuse: %zu", CONN_INUSE(conn)));
+    return;
+  }
+
+  if(conn->dns_entry) {
+    Curl_resolv_unlock(data, conn->dns_entry);
+    conn->dns_entry = NULL;
+  }
+
+  /* Cleanup NTLM connection-related data */
+  Curl_http_auth_cleanup_ntlm(conn);
+
+  /* Cleanup NEGOTIATE connection-related data */
+  Curl_http_auth_cleanup_negotiate(conn);
+
+  if(conn->connect_only)
+    /* treat the connection as dead in CONNECT_ONLY situations */
+    dead_connection = TRUE;
+
+  /* temporarily attach the connection to this transfer handle for the
+     disconnect and shutdown */
+  Curl_attach_connection(data, conn);
+
+  if(conn->handler && conn->handler->disconnect)
+    /* This is set if protocol-specific cleanups should be made */
+    conn->handler->disconnect(data, conn, dead_connection);
+
+  conn_shutdown(data);
+
+  /* detach it again */
+  Curl_detach_connection(data);
+
+  conn_free(data, conn);
+}
+
+/*
+ * IsMultiplexingPossible()
+ *
+ * Return a bitmask with the available multiplexing options for the given
+ * requested connection.
+ */
+static int IsMultiplexingPossible(const struct Curl_easy *handle,
+                                  const struct connectdata *conn)
+{
+  int avail = 0;
+
+  /* If an HTTP protocol and multiplexing is enabled */
+  if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+     (!conn->bits.protoconnstart || !conn->bits.close)) {
+
+    if(Curl_multiplex_wanted(handle->multi) &&
+       (handle->state.httpwant >= CURL_HTTP_VERSION_2))
+      /* allows HTTP/2 */
+      avail |= CURLPIPE_MULTIPLEX;
+  }
+  return avail;
+}
+
+#ifndef CURL_DISABLE_PROXY
+static bool
+proxy_info_matches(const struct proxy_info *data,
+                   const struct proxy_info *needle)
+{
+  if((data->proxytype == needle->proxytype) &&
+     (data->port == needle->port) &&
+     strcasecompare(data->host.name, needle->host.name))
+    return TRUE;
+
+  return FALSE;
+}
+
+static bool
+socks_proxy_info_matches(const struct proxy_info *data,
+                         const struct proxy_info *needle)
+{
+  if(!proxy_info_matches(data, needle))
+    return FALSE;
+
+  /* the user information is case-sensitive
+     or at least it is not defined as case-insensitive
+     see https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1 */
+
+  /* curl_strequal does a case insensitive comparison,
+     so do not use it here! */
+  if(Curl_timestrcmp(data->user, needle->user) ||
+     Curl_timestrcmp(data->passwd, needle->passwd))
+    return FALSE;
+  return TRUE;
+}
+#else
+/* disabled, won't get called */
+#define proxy_info_matches(x,y) FALSE
+#define socks_proxy_info_matches(x,y) FALSE
+#endif
+
+/* A connection has to have been idle for a shorter time than 'maxage_conn'
+   (the success rate is just too low after this), or created less than
+   'maxlifetime_conn' ago, to be subject for reuse. */
+
+static bool conn_maxage(struct Curl_easy *data,
+                        struct connectdata *conn,
+                        struct curltime now)
+{
+  timediff_t idletime, lifetime;
+
+  idletime = Curl_timediff(now, conn->lastused);
+  idletime /= 1000; /* integer seconds is fine */
+
+  if(idletime > data->set.maxage_conn) {
+    infof(data, "Too old connection (%" CURL_FORMAT_TIMEDIFF_T
+          " seconds idle), disconnect it", idletime);
+    return TRUE;
+  }
+
+  lifetime = Curl_timediff(now, conn->created);
+  lifetime /= 1000; /* integer seconds is fine */
+
+  if(data->set.maxlifetime_conn && lifetime > data->set.maxlifetime_conn) {
+    infof(data,
+          "Too old connection (%" CURL_FORMAT_TIMEDIFF_T
+          " seconds since creation), disconnect it", lifetime);
+    return TRUE;
+  }
+
+
+  return FALSE;
+}
+
+/*
+ * This function checks if the given connection is dead and extracts it from
+ * the connection cache if so.
+ *
+ * When this is called as a Curl_conncache_foreach() callback, the connection
+ * cache lock is held!
+ *
+ * Returns TRUE if the connection was dead and extracted.
+ */
+static bool extract_if_dead(struct connectdata *conn,
+                            struct Curl_easy *data)
+{
+  if(!CONN_INUSE(conn)) {
+    /* The check for a dead socket makes sense only if the connection isn't in
+       use */
+    bool dead;
+    struct curltime now = Curl_now();
+    if(conn_maxage(data, conn, now)) {
+      /* avoid check if already too old */
+      dead = TRUE;
+    }
+    else if(conn->handler->connection_check) {
+      /* The protocol has a special method for checking the state of the
+         connection. Use it to check if the connection is dead. */
+      unsigned int state;
+
+      /* briefly attach the connection to this transfer for the purpose of
+         checking it */
+      Curl_attach_connection(data, conn);
+
+      state = conn->handler->connection_check(data, conn, CONNCHECK_ISDEAD);
+      dead = (state & CONNRESULT_DEAD);
+      /* detach the connection again */
+      Curl_detach_connection(data);
+
+    }
+    else {
+      bool input_pending;
+
+      Curl_attach_connection(data, conn);
+      dead = !Curl_conn_is_alive(data, conn, &input_pending);
+      if(input_pending) {
+        /* For reuse, we want a "clean" connection state. The includes
+         * that we expect - in general - no waiting input data. Input
+         * waiting might be a TLS Notify Close, for example. We reject
+         * that.
+         * For protocols where data from other end may arrive at
+         * any time (HTTP/2 PING for example), the protocol handler needs
+         * to install its own `connection_check` callback.
+         */
+        dead = TRUE;
+      }
+      Curl_detach_connection(data);
+    }
+
+    if(dead) {
+      infof(data, "Connection %" CURL_FORMAT_CURL_OFF_T " seems to be dead",
+            conn->connection_id);
+      Curl_conncache_remove_conn(data, conn, FALSE);
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+struct prunedead {
+  struct Curl_easy *data;
+  struct connectdata *extracted;
+};
+
+/*
+ * Wrapper to use extract_if_dead() function in Curl_conncache_foreach()
+ *
+ */
+static int call_extract_if_dead(struct Curl_easy *data,
+                                struct connectdata *conn, void *param)
+{
+  struct prunedead *p = (struct prunedead *)param;
+  if(extract_if_dead(conn, data)) {
+    /* stop the iteration here, pass back the connection that was extracted */
+    p->extracted = conn;
+    return 1;
+  }
+  return 0; /* continue iteration */
+}
+
+/*
+ * This function scans the connection cache for half-open/dead connections,
+ * closes and removes them. The cleanup is done at most once per second.
+ *
+ * When called, this transfer has no connection attached.
+ */
+static void prune_dead_connections(struct Curl_easy *data)
+{
+  struct curltime now = Curl_now();
+  timediff_t elapsed;
+
+  DEBUGASSERT(!data->conn); /* no connection */
+  CONNCACHE_LOCK(data);
+  elapsed =
+    Curl_timediff(now, data->state.conn_cache->last_cleanup);
+  CONNCACHE_UNLOCK(data);
+
+  if(elapsed >= 1000L) {
+    struct prunedead prune;
+    prune.data = data;
+    prune.extracted = NULL;
+    while(Curl_conncache_foreach(data, data->state.conn_cache, &prune,
+                                 call_extract_if_dead)) {
+      /* unlocked */
+
+      /* remove connection from cache */
+      Curl_conncache_remove_conn(data, prune.extracted, TRUE);
+
+      /* disconnect it */
+      Curl_disconnect(data, prune.extracted, TRUE);
+    }
+    CONNCACHE_LOCK(data);
+    data->state.conn_cache->last_cleanup = now;
+    CONNCACHE_UNLOCK(data);
+  }
+}
+
+#ifdef USE_SSH
+static bool ssh_config_matches(struct connectdata *one,
+                               struct connectdata *two)
+{
+  return (Curl_safecmp(one->proto.sshc.rsa, two->proto.sshc.rsa) &&
+          Curl_safecmp(one->proto.sshc.rsa_pub, two->proto.sshc.rsa_pub));
+}
+#else
+#define ssh_config_matches(x,y) FALSE
+#endif
+
+/*
+ * Given one filled in connection struct (named needle), this function should
+ * detect if there already is one that has all the significant details
+ * exactly the same and thus should be used instead.
+ *
+ * If there is a match, this function returns TRUE - and has marked the
+ * connection as 'in-use'. It must later be called with ConnectionDone() to
+ * return back to 'idle' (unused) state.
+ *
+ * The force_reuse flag is set if the connection must be used.
+ */
+static bool
+ConnectionExists(struct Curl_easy *data,
+                 struct connectdata *needle,
+                 struct connectdata **usethis,
+                 bool *force_reuse,
+                 bool *waitpipe)
+{
+  struct connectdata *chosen = NULL;
+  bool foundPendingCandidate = FALSE;
+  bool canmultiplex = FALSE;
+  struct connectbundle *bundle;
+  struct Curl_llist_element *curr;
+
+#ifdef USE_NTLM
+  bool wantNTLMhttp = ((data->state.authhost.want &
+                        (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+                       (needle->handler->protocol & PROTO_FAMILY_HTTP));
+#ifndef CURL_DISABLE_PROXY
+  bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd &&
+                            ((data->state.authproxy.want &
+                              (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+                             (needle->handler->protocol & PROTO_FAMILY_HTTP)));
+#else
+  bool wantProxyNTLMhttp = FALSE;
+#endif
+#endif
+  /* plain HTTP with upgrade */
+  bool h2upgrade = (data->state.httpwant == CURL_HTTP_VERSION_2_0) &&
+    (needle->handler->protocol & CURLPROTO_HTTP);
+
+  *usethis = NULL;
+  *force_reuse = FALSE;
+  *waitpipe = FALSE;
+
+  /* Look up the bundle with all the connections to this particular host.
+     Locks the connection cache, beware of early returns! */
+  bundle = Curl_conncache_find_bundle(data, needle, data->state.conn_cache);
+  if(!bundle) {
+    CONNCACHE_UNLOCK(data);
+    return FALSE;
+  }
+  infof(data, "Found bundle for host: %p [%s]",
+        (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ?
+                         "can multiplex" : "serially"));
+
+  /* We can only multiplex iff the transfer allows it AND we know
+   * that the server we want to talk to supports it as well. */
+  canmultiplex = FALSE;
+  if(IsMultiplexingPossible(data, needle)) {
+    if(bundle->multiuse == BUNDLE_UNKNOWN) {
+      if(data->set.pipewait) {
+        infof(data, "Server doesn't support multiplex yet, wait");
+        *waitpipe = TRUE;
+        CONNCACHE_UNLOCK(data);
+        return FALSE; /* no reuse */
+      }
+      infof(data, "Server doesn't support multiplex (yet)");
+    }
+    else if(bundle->multiuse == BUNDLE_MULTIPLEX) {
+      if(Curl_multiplex_wanted(data->multi))
+        canmultiplex = TRUE;
+      else
+        infof(data, "Could multiplex, but not asked to");
+    }
+    else if(bundle->multiuse == BUNDLE_NO_MULTIUSE) {
+      infof(data, "Can not multiplex, even if we wanted to");
+    }
+  }
+
+  curr = bundle->conn_list.head;
+  while(curr) {
+    struct connectdata *check = curr->ptr;
+    /* Get next node now. We might remove a dead `check` connection which
+     * would invalidate `curr` as well. */
+    curr = curr->next;
+
+    /* Note that if we use an HTTP proxy in normal mode (no tunneling), we
+     * check connections to that proxy and not to the actual remote server.
+     */
+    if(check->connect_only || check->bits.close)
+      /* connect-only or to-be-closed connections will not be reused */
+      continue;
+
+    if(data->set.ipver != CURL_IPRESOLVE_WHATEVER
+       && data->set.ipver != check->ip_version) {
+      /* skip because the connection is not via the requested IP version */
+      continue;
+    }
+
+    if(!canmultiplex) {
+      if(Curl_resolver_asynch() &&
+         /* remote_ip[0] is NUL only if the resolving of the name hasn't
+            completed yet and until then we don't reuse this connection */
+         !check->primary.remote_ip[0])
+        continue;
+    }
+
+    if(CONN_INUSE(check)) {
+      if(!canmultiplex) {
+        /* transfer can't be multiplexed and check is in use */
+        continue;
+      }
+      else {
+        /* Could multiplex, but not when check belongs to another multi */
+        struct Curl_llist_element *e = check->easyq.head;
+        struct Curl_easy *entry = e->ptr;
+        if(entry->multi != data->multi)
+          continue;
+      }
+    }
+
+    if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
+      foundPendingCandidate = TRUE;
+      /* Don't pick a connection that hasn't connected yet */
+      infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T
+            " isn't open enough, can't reuse", check->connection_id);
+      continue;
+    }
+
+    /* `check` is connected. if it is in use and does not support multiplex,
+     * we cannot use it. */
+    if(!check->bits.multiplex && CONN_INUSE(check))
+      continue;
+
+#ifdef USE_UNIX_SOCKETS
+    if(needle->unix_domain_socket) {
+      if(!check->unix_domain_socket)
+        continue;
+      if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
+        continue;
+      if(needle->bits.abstract_unix_socket !=
+         check->bits.abstract_unix_socket)
+        continue;
+    }
+    else if(check->unix_domain_socket)
+      continue;
+#endif
+
+    if((needle->handler->flags&PROTOPT_SSL) !=
+       (check->handler->flags&PROTOPT_SSL))
+      /* don't do mixed SSL and non-SSL connections */
+      if(get_protocol_family(check->handler) !=
+         needle->handler->protocol || !check->bits.tls_upgraded)
+        /* except protocols that have been upgraded via TLS */
+        continue;
+
+    if(needle->bits.conn_to_host != check->bits.conn_to_host)
+      /* don't mix connections that use the "connect to host" feature and
+       * connections that don't use this feature */
+      continue;
+
+    if(needle->bits.conn_to_port != check->bits.conn_to_port)
+      /* don't mix connections that use the "connect to port" feature and
+       * connections that don't use this feature */
+      continue;
+
+#ifndef CURL_DISABLE_PROXY
+    if(needle->bits.httpproxy != check->bits.httpproxy ||
+       needle->bits.socksproxy != check->bits.socksproxy)
+      continue;
+
+    if(needle->bits.socksproxy &&
+      !socks_proxy_info_matches(&needle->socks_proxy,
+                                &check->socks_proxy))
+      continue;
+
+    if(needle->bits.httpproxy) {
+      if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy)
+        continue;
+
+      if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy))
+        continue;
+
+      if(IS_HTTPS_PROXY(needle->http_proxy.proxytype)) {
+        /* https proxies come in different types, http/1.1, h2, ... */
+        if(needle->http_proxy.proxytype != check->http_proxy.proxytype)
+          continue;
+        /* match SSL config to proxy */
+        if(!Curl_ssl_conn_config_match(data, check, TRUE)) {
+          DEBUGF(infof(data,
+            "Connection #%" CURL_FORMAT_CURL_OFF_T
+            " has different SSL proxy parameters, can't reuse",
+            check->connection_id));
+          continue;
+        }
+        /* the SSL config to the server, which may apply here is checked
+         * further below */
+      }
+    }
+#endif
+
+    if(h2upgrade && !check->httpversion && canmultiplex) {
+      if(data->set.pipewait) {
+        infof(data, "Server upgrade doesn't support multiplex yet, wait");
+        *waitpipe = TRUE;
+        CONNCACHE_UNLOCK(data);
+        return FALSE; /* no reuse */
+      }
+      infof(data, "Server upgrade cannot be used");
+      continue; /* can't be used atm */
+    }
+
+    if(needle->localdev || needle->localport) {
+      /* If we are bound to a specific local end (IP+port), we must not
+         reuse a random other one, although if we didn't ask for a
+         particular one we can reuse one that was bound.
+
+         This comparison is a bit rough and too strict. Since the input
+         parameters can be specified in numerous ways and still end up the
+         same it would take a lot of processing to make it really accurate.
+         Instead, this matching will assume that reuses of bound connections
+         will most likely also reuse the exact same binding parameters and
+         missing out a few edge cases shouldn't hurt anyone very much.
+      */
+      if((check->localport != needle->localport) ||
+         (check->localportrange != needle->localportrange) ||
+         (needle->localdev &&
+          (!check->localdev || strcmp(check->localdev, needle->localdev))))
+        continue;
+    }
+
+    if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
+      /* This protocol requires credentials per connection,
+         so verify that we're using the same name and password as well */
+      if(Curl_timestrcmp(needle->user, check->user) ||
+         Curl_timestrcmp(needle->passwd, check->passwd) ||
+         Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) ||
+         Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) {
+        /* one of them was different */
+        continue;
+      }
+    }
+
+    /* GSS delegation differences do not actually affect every connection
+       and auth method, but this check takes precaution before efficiency */
+    if(needle->gssapi_delegation != check->gssapi_delegation)
+      continue;
+
+    /* If looking for HTTP and the HTTP version  we want is less
+     * than the HTTP version of the check connection, continue looking */
+    if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
+       (((check->httpversion >= 20) &&
+         (data->state.httpwant < CURL_HTTP_VERSION_2_0))
+        || ((check->httpversion >= 30) &&
+            (data->state.httpwant < CURL_HTTP_VERSION_3))))
+      continue;
+#ifdef USE_SSH
+    else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
+      if(!ssh_config_matches(needle, check))
+        continue;
+    }
+#endif
+#ifndef CURL_DISABLE_FTP
+    else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) {
+      /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */
+      if(Curl_timestrcmp(needle->proto.ftpc.account,
+                         check->proto.ftpc.account) ||
+         Curl_timestrcmp(needle->proto.ftpc.alternative_to_user,
+                         check->proto.ftpc.alternative_to_user) ||
+         (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) ||
+         (needle->proto.ftpc.ccc != check->proto.ftpc.ccc))
+        continue;
+    }
+#endif
+
+    /* Additional match requirements if talking TLS OR
+     * not talking to a HTTP proxy OR using a tunnel through a proxy */
+    if((needle->handler->flags&PROTOPT_SSL)
+#ifndef CURL_DISABLE_PROXY
+       || !needle->bits.httpproxy || needle->bits.tunnel_proxy
+#endif
+      ) {
+      /* Talking the same protocol scheme or a TLS upgraded protocol in the
+       * same protocol family? */
+      if(!strcasecompare(needle->handler->scheme, check->handler->scheme) &&
+         (get_protocol_family(check->handler) !=
+          needle->handler->protocol || !check->bits.tls_upgraded))
+        continue;
+
+      /* If needle has "conn_to_*" set, check must match this */
+      if((needle->bits.conn_to_host && !strcasecompare(
+          needle->conn_to_host.name, check->conn_to_host.name)) ||
+         (needle->bits.conn_to_port &&
+           needle->conn_to_port != check->conn_to_port))
+        continue;
+
+      /* hostname and port must match */
+      if(!strcasecompare(needle->host.name, check->host.name) ||
+         needle->remote_port != check->remote_port)
+        continue;
+
+      /* If talking TLS, check needs to use the same SSL options. */
+      if((needle->handler->flags & PROTOPT_SSL) &&
+         !Curl_ssl_conn_config_match(data, check, FALSE)) {
+        DEBUGF(infof(data,
+                     "Connection #%" CURL_FORMAT_CURL_OFF_T
+                     " has different SSL parameters, can't reuse",
+                     check->connection_id));
+        continue;
+      }
+    }
+
+#if defined(USE_NTLM)
+    /* If we are looking for an HTTP+NTLM connection, check if this is
+       already authenticating with the right credentials. If not, keep
+       looking so that we can reuse NTLM connections if
+       possible. (Especially we must not reuse the same connection if
+       partway through a handshake!) */
+    if(wantNTLMhttp) {
+      if(Curl_timestrcmp(needle->user, check->user) ||
+         Curl_timestrcmp(needle->passwd, check->passwd)) {
+
+        /* we prefer a credential match, but this is at least a connection
+           that can be reused and "upgraded" to NTLM */
+        if(check->http_ntlm_state == NTLMSTATE_NONE)
+          chosen = check;
+        continue;
+      }
+    }
+    else if(check->http_ntlm_state != NTLMSTATE_NONE) {
+      /* Connection is using NTLM auth but we don't want NTLM */
+      continue;
+    }
+
+#ifndef CURL_DISABLE_PROXY
+    /* Same for Proxy NTLM authentication */
+    if(wantProxyNTLMhttp) {
+      /* Both check->http_proxy.user and check->http_proxy.passwd can be
+       * NULL */
+      if(!check->http_proxy.user || !check->http_proxy.passwd)
+        continue;
+
+      if(Curl_timestrcmp(needle->http_proxy.user,
+                         check->http_proxy.user) ||
+         Curl_timestrcmp(needle->http_proxy.passwd,
+                         check->http_proxy.passwd))
+        continue;
+    }
+    else if(check->proxy_ntlm_state != NTLMSTATE_NONE) {
+      /* Proxy connection is using NTLM auth but we don't want NTLM */
+      continue;
+    }
+#endif
+    if(wantNTLMhttp || wantProxyNTLMhttp) {
+      /* Credentials are already checked, we may use this connection.
+       * With NTLM being weird as it is, we MUST use a
+       * connection where it has already been fully negotiated.
+       * If it has not, we keep on looking for a better one. */
+      chosen = check;
+
+      if((wantNTLMhttp &&
+         (check->http_ntlm_state != NTLMSTATE_NONE)) ||
+          (wantProxyNTLMhttp &&
+           (check->proxy_ntlm_state != NTLMSTATE_NONE))) {
+        /* We must use this connection, no other */
+        *force_reuse = TRUE;
+        break;
+      }
+      /* Continue look up for a better connection */
+      continue;
+    }
+#endif
+
+    if(CONN_INUSE(check)) {
+      DEBUGASSERT(canmultiplex);
+      DEBUGASSERT(check->bits.multiplex);
+      /* If multiplexed, make sure we don't go over concurrency limit */
+      if(CONN_INUSE(check) >=
+              Curl_multi_max_concurrent_streams(data->multi)) {
+        infof(data, "client side MAX_CONCURRENT_STREAMS reached"
+              ", skip (%zu)", CONN_INUSE(check));
+        continue;
+      }
+      if(CONN_INUSE(check) >=
+              Curl_conn_get_max_concurrent(data, check, FIRSTSOCKET)) {
+        infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
+              CONN_INUSE(check));
+        continue;
+      }
+      /* When not multiplexed, we have a match here! */
+      infof(data, "Multiplexed connection found");
+    }
+    else if(extract_if_dead(check, data)) {
+      /* disconnect it */
+      Curl_disconnect(data, check, TRUE);
+      continue;
+    }
+
+    /* We have found a connection. Let's stop searching. */
+    chosen = check;
+    break;
+  } /* loop over connection bundle */
+
+  if(chosen) {
+    /* mark it as used before releasing the lock */
+    Curl_attach_connection(data, chosen);
+    CONNCACHE_UNLOCK(data);
+    *usethis = chosen;
+    return TRUE; /* yes, we found one to use! */
+  }
+  CONNCACHE_UNLOCK(data);
+
+  if(foundPendingCandidate && data->set.pipewait) {
+    infof(data,
+          "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
+    *waitpipe = TRUE;
+  }
+
+  return FALSE; /* no matching connecting exists */
+}
+
+/*
+ * verboseconnect() displays verbose information after a connect
+ */
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+void Curl_verboseconnect(struct Curl_easy *data,
+                         struct connectdata *conn, int sockindex)
+{
+  if(data->set.verbose && sockindex == SECONDARYSOCKET)
+    infof(data, "Connected 2nd connection to %s port %u",
+          conn->secondary.remote_ip, conn->secondary.remote_port);
+  else
+    infof(data, "Connected to %s (%s) port %u",
+          CURL_CONN_HOST_DISPNAME(conn), conn->primary.remote_ip,
+          conn->primary.remote_port);
+}
+#endif
+
+/*
+ * Allocate and initialize a new connectdata object.
+ */
+static struct connectdata *allocate_conn(struct Curl_easy *data)
+{
+  struct connectdata *conn = calloc(1, sizeof(struct connectdata));
+  if(!conn)
+    return NULL;
+
+  /* and we setup a few fields in case we end up actually using this struct */
+
+  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
+  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
+  conn->sockfd = CURL_SOCKET_BAD;
+  conn->writesockfd = CURL_SOCKET_BAD;
+  conn->connection_id = -1;    /* no ID */
+  conn->primary.remote_port = -1; /* unknown at this point */
+  conn->remote_port = -1; /* unknown at this point */
+
+  /* Default protocol-independent behavior doesn't support persistent
+     connections, so we set this to force-close. Protocols that support
+     this need to set this to FALSE in their "curl_do" functions. */
+  connclose(conn, "Default to force-close");
+
+  /* Store creation time to help future close decision making */
+  conn->created = Curl_now();
+
+  /* Store current time to give a baseline to keepalive connection times. */
+  conn->keepalive = conn->created;
+
+#ifndef CURL_DISABLE_PROXY
+  conn->http_proxy.proxytype = data->set.proxytype;
+  conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
+
+  /* note that these two proxy bits are now just on what looks to be
+     requested, they may be altered down the road */
+  conn->bits.proxy = (data->set.str[STRING_PROXY] &&
+                      *data->set.str[STRING_PROXY]) ? TRUE : FALSE;
+  conn->bits.httpproxy = (conn->bits.proxy &&
+                          (conn->http_proxy.proxytype == CURLPROXY_HTTP ||
+                           conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
+                           IS_HTTPS_PROXY(conn->http_proxy.proxytype))) ?
+    TRUE : FALSE;
+  conn->bits.socksproxy = (conn->bits.proxy &&
+                           !conn->bits.httpproxy) ? TRUE : FALSE;
+
+  if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
+    conn->bits.proxy = TRUE;
+    conn->bits.socksproxy = TRUE;
+  }
+
+  conn->bits.proxy_user_passwd =
+    (data->state.aptr.proxyuser) ? TRUE : FALSE;
+  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
+#endif /* CURL_DISABLE_PROXY */
+
+#ifndef CURL_DISABLE_FTP
+  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
+  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
+#endif
+  conn->ip_version = data->set.ipver;
+  conn->connect_only = data->set.connect_only;
+  conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+    defined(NTLM_WB_ENABLED)
+  conn->ntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+  conn->proxyntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+#endif
+
+  /* Initialize the easy handle list */
+  Curl_llist_init(&conn->easyq, NULL);
+
+#ifdef HAVE_GSSAPI
+  conn->data_prot = PROT_CLEAR;
+#endif
+
+  /* Store the local bind parameters that will be used for this connection */
+  if(data->set.str[STRING_DEVICE]) {
+    conn->localdev = strdup(data->set.str[STRING_DEVICE]);
+    if(!conn->localdev)
+      goto error;
+  }
+#ifndef CURL_DISABLE_BINDLOCAL
+  conn->localportrange = data->set.localportrange;
+  conn->localport = data->set.localport;
+#endif
+
+  /* the close socket stuff needs to be copied to the connection struct as
+     it may live on without (this specific) Curl_easy */
+  conn->fclosesocket = data->set.fclosesocket;
+  conn->closesocket_client = data->set.closesocket_client;
+  conn->lastused = conn->created;
+  conn->gssapi_delegation = data->set.gssapi_delegation;
+
+  return conn;
+error:
+
+  free(conn->localdev);
+  free(conn);
+  return NULL;
+}
+
+const struct Curl_handler *Curl_get_scheme_handler(const char *scheme)
+{
+  return Curl_getn_scheme_handler(scheme, strlen(scheme));
+}
+
+/* returns the handler if the given scheme is built-in */
+const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
+                                                    size_t len)
+{
+  /* table generated by schemetable.c:
+     1. gcc schemetable.c && ./a.out
+     2. check how small the table gets
+     3. tweak the hash algorithm, then rerun from 1
+     4. when the table is good enough
+     5. copy the table into this source code
+     6. make sure this function uses the same hash function that worked for
+     schemetable.c
+     7. if needed, adjust the #ifdefs in schemetable.c and rerun
+     */
+  static const struct Curl_handler * const protocols[67] = {
+#ifndef CURL_DISABLE_FILE
+    &Curl_handler_file,
+#else
+    NULL,
+#endif
+    NULL, NULL,
+#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)
+    &Curl_handler_gophers,
+#else
+    NULL,
+#endif
+    NULL,
+#ifdef USE_LIBRTMP
+    &Curl_handler_rtmpe,
+#else
+    NULL,
+#endif
+#ifndef CURL_DISABLE_SMTP
+    &Curl_handler_smtp,
+#else
+    NULL,
+#endif
+#if defined(USE_SSH)
+    &Curl_handler_sftp,
+#else
+    NULL,
+#endif
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
+  (SIZEOF_CURL_OFF_T > 4)
+    &Curl_handler_smb,
+#else
+    NULL,
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
+    &Curl_handler_smtps,
+#else
+    NULL,
+#endif
+#ifndef CURL_DISABLE_TELNET
+    &Curl_handler_telnet,
+#else
+    NULL,
+#endif
+#ifndef CURL_DISABLE_GOPHER
+    &Curl_handler_gopher,
+#else
+    NULL,
+#endif
+#ifndef CURL_DISABLE_TFTP
+    &Curl_handler_tftp,
+#else
+    NULL,
+#endif
+    NULL, NULL, NULL,
+#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
+    &Curl_handler_ftps,
+#else
+    NULL,
+#endif
+#ifndef CURL_DISABLE_HTTP
+    &Curl_handler_http,
+#else
+    NULL,
+#endif
+#ifndef CURL_DISABLE_IMAP
+    &Curl_handler_imap,
+#else
+    NULL,
+#endif
+#ifdef USE_LIBRTMP
+    &Curl_handler_rtmps,
+#else
+    NULL,
+#endif
+#ifdef USE_LIBRTMP
+    &Curl_handler_rtmpt,
+#else
+    NULL,
+#endif
+    NULL, NULL, NULL,
+#if !defined(CURL_DISABLE_LDAP) && \
+  !defined(CURL_DISABLE_LDAPS) && \
+  ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
+   (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
+    &Curl_handler_ldaps,
+#else
+    NULL,
+#endif
+#if defined(USE_WEBSOCKETS) && \
+  defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+    &Curl_handler_wss,
+#else
+    NULL,
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+    &Curl_handler_https,
+#else
+    NULL,
+#endif
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+#ifndef CURL_DISABLE_RTSP
+    &Curl_handler_rtsp,
+#else
+    NULL,
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_SMB) && \
+  defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)
+    &Curl_handler_smbs,
+#else
+    NULL,
+#endif
+#if defined(USE_SSH) && !defined(USE_WOLFSSH)
+    &Curl_handler_scp,
+#else
+    NULL,
+#endif
+    NULL, NULL, NULL,
+#ifndef CURL_DISABLE_POP3
+    &Curl_handler_pop3,
+#else
+    NULL,
+#endif
+    NULL, NULL,
+#ifdef USE_LIBRTMP
+    &Curl_handler_rtmp,
+#else
+    NULL,
+#endif
+    NULL, NULL, NULL,
+#ifdef USE_LIBRTMP
+    &Curl_handler_rtmpte,
+#else
+    NULL,
+#endif
+    NULL, NULL, NULL,
+#ifndef CURL_DISABLE_DICT
+    &Curl_handler_dict,
+#else
+    NULL,
+#endif
+    NULL, NULL, NULL,
+#ifndef CURL_DISABLE_MQTT
+    &Curl_handler_mqtt,
+#else
+    NULL,
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
+    &Curl_handler_pop3s,
+#else
+    NULL,
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
+    &Curl_handler_imaps,
+#else
+    NULL,
+#endif
+    NULL,
+#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+    &Curl_handler_ws,
+#else
+    NULL,
+#endif
+    NULL,
+#ifdef USE_LIBRTMP
+    &Curl_handler_rtmpts,
+#else
+    NULL,
+#endif
+#ifndef CURL_DISABLE_LDAP
+    &Curl_handler_ldap,
+#else
+    NULL,
+#endif
+    NULL, NULL,
+#ifndef CURL_DISABLE_FTP
+    &Curl_handler_ftp,
+#else
+    NULL,
+#endif
+  };
+
+  if(len && (len <= 7)) {
+    const char *s = scheme;
+    size_t l = len;
+    const struct Curl_handler *h;
+    unsigned int c = 978;
+    while(l) {
+      c <<= 5;
+      c += Curl_raw_tolower(*s);
+      s++;
+      l--;
+    }
+
+    h = protocols[c % 67];
+    if(h && strncasecompare(scheme, h->scheme, len) && !h->scheme[len])
+      return h;
+  }
+  return NULL;
+}
+
+static CURLcode findprotocol(struct Curl_easy *data,
+                             struct connectdata *conn,
+                             const char *protostr)
+{
+  const struct Curl_handler *p = Curl_get_scheme_handler(protostr);
+
+  if(p && /* Protocol found in table. Check if allowed */
+     (data->set.allowed_protocols & p->protocol)) {
+
+    /* it is allowed for "normal" request, now do an extra check if this is
+       the result of a redirect */
+    if(data->state.this_is_a_follow &&
+       !(data->set.redir_protocols & p->protocol))
+      /* nope, get out */
+      ;
+    else {
+      /* Perform setup complement if some. */
+      conn->handler = conn->given = p;
+      /* 'port' and 'remote_port' are set in setup_connection_internals() */
+      return CURLE_OK;
+    }
+  }
+
+  /* The protocol was not found in the table, but we don't have to assign it
+     to anything since it is already assigned to a dummy-struct in the
+     create_conn() function when the connectdata struct is allocated. */
+  failf(data, "Protocol \"%s\" %s%s", protostr,
+        p ? "disabled" : "not supported",
+        data->state.this_is_a_follow ? " (in redirect)":"");
+
+  return CURLE_UNSUPPORTED_PROTOCOL;
+}
+
+
+CURLcode Curl_uc_to_curlcode(CURLUcode uc)
+{
+  switch(uc) {
+  default:
+    return CURLE_URL_MALFORMAT;
+  case CURLUE_UNSUPPORTED_SCHEME:
+    return CURLE_UNSUPPORTED_PROTOCOL;
+  case CURLUE_OUT_OF_MEMORY:
+    return CURLE_OUT_OF_MEMORY;
+  case CURLUE_USER_NOT_ALLOWED:
+    return CURLE_LOGIN_DENIED;
+  }
+}
+
+#ifdef ENABLE_IPV6
+/*
+ * If the URL was set with an IPv6 numerical address with a zone id part, set
+ * the scope_id based on that!
+ */
+
+static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
+                         struct connectdata *conn)
+{
+  char *zoneid;
+  CURLUcode uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)data;
+#endif
+
+  if(!uc && zoneid) {
+    char *endp;
+    unsigned long scope = strtoul(zoneid, &endp, 10);
+    if(!*endp && (scope < UINT_MAX))
+      /* A plain number, use it directly as a scope id. */
+      conn->scope_id = (unsigned int)scope;
+#if defined(HAVE_IF_NAMETOINDEX)
+    else {
+#elif defined(_WIN32)
+    else if(Curl_if_nametoindex) {
+#endif
+
+#if defined(HAVE_IF_NAMETOINDEX) || defined(_WIN32)
+      /* Zone identifier is not numeric */
+      unsigned int scopeidx = 0;
+#if defined(_WIN32)
+      scopeidx = Curl_if_nametoindex(zoneid);
+#else
+      scopeidx = if_nametoindex(zoneid);
+#endif
+      if(!scopeidx) {
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+        char buffer[STRERROR_LEN];
+        infof(data, "Invalid zoneid: %s; %s", zoneid,
+              Curl_strerror(errno, buffer, sizeof(buffer)));
+#endif
+      }
+      else
+        conn->scope_id = scopeidx;
+    }
+#endif /* HAVE_IF_NAMETOINDEX || _WIN32 */
+
+    free(zoneid);
+  }
+}
+#else
+#define zonefrom_url(a,b,c) Curl_nop_stmt
+#endif
+
+/*
+ * Parse URL and fill in the relevant members of the connection struct.
+ */
+static CURLcode parseurlandfillconn(struct Curl_easy *data,
+                                    struct connectdata *conn)
+{
+  CURLcode result;
+  CURLU *uh;
+  CURLUcode uc;
+  char *hostname;
+  bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
+
+  up_free(data); /* cleanup previous leftovers first */
+
+  /* parse the URL */
+  if(use_set_uh) {
+    uh = data->state.uh = curl_url_dup(data->set.uh);
+  }
+  else {
+    uh = data->state.uh = curl_url();
+  }
+
+  if(!uh)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
+     !Curl_is_absolute_url(data->state.url, NULL, 0, TRUE)) {
+    char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL],
+                        data->state.url);
+    if(!url)
+      return CURLE_OUT_OF_MEMORY;
+    if(data->state.url_alloc)
+      free(data->state.url);
+    data->state.url = url;
+    data->state.url_alloc = TRUE;
+  }
+
+  if(!use_set_uh) {
+    char *newurl;
+    uc = curl_url_set(uh, CURLUPART_URL, data->state.url,
+                      CURLU_GUESS_SCHEME |
+                      CURLU_NON_SUPPORT_SCHEME |
+                      (data->set.disallow_username_in_url ?
+                       CURLU_DISALLOW_USER : 0) |
+                      (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
+    if(uc) {
+      failf(data, "URL rejected: %s", curl_url_strerror(uc));
+      return Curl_uc_to_curlcode(uc);
+    }
+
+    /* after it was parsed, get the generated normalized version */
+    uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
+    if(uc)
+      return Curl_uc_to_curlcode(uc);
+    if(data->state.url_alloc)
+      free(data->state.url);
+    data->state.url = newurl;
+    data->state.url_alloc = TRUE;
+  }
+
+  uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
+  if(uc)
+    return Curl_uc_to_curlcode(uc);
+
+  uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
+  if(uc) {
+    if(!strcasecompare("file", data->state.up.scheme))
+      return CURLE_OUT_OF_MEMORY;
+  }
+  else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
+    failf(data, "Too long host name (maximum is %d)", MAX_URL_LEN);
+    return CURLE_URL_MALFORMAT;
+  }
+  hostname = data->state.up.hostname;
+
+  if(hostname && hostname[0] == '[') {
+    /* This looks like an IPv6 address literal. See if there is an address
+       scope. */
+    size_t hlen;
+    conn->bits.ipv6_ip = TRUE;
+    /* cut off the brackets! */
+    hostname++;
+    hlen = strlen(hostname);
+    hostname[hlen - 1] = 0;
+
+    zonefrom_url(uh, data, conn);
+  }
+
+  /* make sure the connect struct gets its own copy of the host name */
+  conn->host.rawalloc = strdup(hostname ? hostname : "");
+  if(!conn->host.rawalloc)
+    return CURLE_OUT_OF_MEMORY;
+  conn->host.name = conn->host.rawalloc;
+
+  /*************************************************************
+   * IDN-convert the hostnames
+   *************************************************************/
+  result = Curl_idnconvert_hostname(&conn->host);
+  if(result)
+    return result;
+
+#ifndef CURL_DISABLE_HSTS
+  /* HSTS upgrade */
+  if(data->hsts && strcasecompare("http", data->state.up.scheme)) {
+    /* This MUST use the IDN decoded name */
+    if(Curl_hsts(data->hsts, conn->host.name, TRUE)) {
+      char *url;
+      Curl_safefree(data->state.up.scheme);
+      uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0);
+      if(uc)
+        return Curl_uc_to_curlcode(uc);
+      if(data->state.url_alloc)
+        Curl_safefree(data->state.url);
+      /* after update, get the updated version */
+      uc = curl_url_get(uh, CURLUPART_URL, &url, 0);
+      if(uc)
+        return Curl_uc_to_curlcode(uc);
+      uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
+      if(uc) {
+        free(url);
+        return Curl_uc_to_curlcode(uc);
+      }
+      data->state.url = url;
+      data->state.url_alloc = TRUE;
+      infof(data, "Switched from HTTP to HTTPS due to HSTS => %s",
+            data->state.url);
+    }
+  }
+#endif
+
+  result = findprotocol(data, conn, data->state.up.scheme);
+  if(result)
+    return result;
+
+  /*
+   * User name and password set with their own options override the
+   * credentials possibly set in the URL.
+   */
+  if(!data->set.str[STRING_PASSWORD]) {
+    uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
+    if(!uc) {
+      char *decoded;
+      result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL,
+                              conn->handler->flags&PROTOPT_USERPWDCTRL ?
+                              REJECT_ZERO : REJECT_CTRL);
+      if(result)
+        return result;
+      conn->passwd = decoded;
+      result = Curl_setstropt(&data->state.aptr.passwd, decoded);
+      if(result)
+        return result;
+    }
+    else if(uc != CURLUE_NO_PASSWORD)
+      return Curl_uc_to_curlcode(uc);
+  }
+
+  if(!data->set.str[STRING_USERNAME]) {
+    /* we don't use the URL API's URL decoder option here since it rejects
+       control codes and we want to allow them for some schemes in the user
+       and password fields */
+    uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
+    if(!uc) {
+      char *decoded;
+      result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL,
+                              conn->handler->flags&PROTOPT_USERPWDCTRL ?
+                              REJECT_ZERO : REJECT_CTRL);
+      if(result)
+        return result;
+      conn->user = decoded;
+      result = Curl_setstropt(&data->state.aptr.user, decoded);
+    }
+    else if(uc != CURLUE_NO_USER)
+      return Curl_uc_to_curlcode(uc);
+    else if(data->state.aptr.passwd) {
+      /* no user was set but a password, set a blank user */
+      result = Curl_setstropt(&data->state.aptr.user, "");
+    }
+    if(result)
+      return result;
+  }
+
+  uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
+                    CURLU_URLDECODE);
+  if(!uc) {
+    conn->options = strdup(data->state.up.options);
+    if(!conn->options)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  else if(uc != CURLUE_NO_OPTIONS)
+    return Curl_uc_to_curlcode(uc);
+
+  uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path,
+                    CURLU_URLENCODE);
+  if(uc)
+    return Curl_uc_to_curlcode(uc);
+
+  uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port,
+                    CURLU_DEFAULT_PORT);
+  if(uc) {
+    if(!strcasecompare("file", data->state.up.scheme))
+      return CURLE_OUT_OF_MEMORY;
+  }
+  else {
+    unsigned long port = strtoul(data->state.up.port, NULL, 10);
+    conn->primary.remote_port = conn->remote_port =
+      (data->set.use_port && data->state.allow_port) ?
+      data->set.use_port : curlx_ultous(port);
+  }
+
+  (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
+
+#ifdef ENABLE_IPV6
+  if(data->set.scope_id)
+    /* Override any scope that was set above.  */
+    conn->scope_id = data->set.scope_id;
+#endif
+
+  return CURLE_OK;
+}
+
+
+/*
+ * If we're doing a resumed transfer, we need to setup our stuff
+ * properly.
+ */
+static CURLcode setup_range(struct Curl_easy *data)
+{
+  struct UrlState *s = &data->state;
+  s->resume_from = data->set.set_resume_from;
+  if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
+    if(s->rangestringalloc)
+      free(s->range);
+
+    if(s->resume_from)
+      s->range = aprintf("%" CURL_FORMAT_CURL_OFF_T "-", s->resume_from);
+    else
+      s->range = strdup(data->set.str[STRING_SET_RANGE]);
+
+    s->rangestringalloc = (s->range) ? TRUE : FALSE;
+
+    if(!s->range)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* tell ourselves to fetch this range */
+    s->use_range = TRUE;        /* enable range download */
+  }
+  else
+    s->use_range = FALSE; /* disable range download */
+
+  return CURLE_OK;
+}
+
+
+/*
+ * setup_connection_internals() -
+ *
+ * Setup connection internals specific to the requested protocol in the
+ * Curl_easy. This is inited and setup before the connection is made but
+ * is about the particular protocol that is to be used.
+ *
+ * This MUST get called after proxy magic has been figured out.
+ */
+static CURLcode setup_connection_internals(struct Curl_easy *data,
+                                           struct connectdata *conn)
+{
+  const struct Curl_handler *p;
+  CURLcode result;
+
+  /* Perform setup complement if some. */
+  p = conn->handler;
+
+  if(p->setup_connection) {
+    result = (*p->setup_connection)(data, conn);
+
+    if(result)
+      return result;
+
+    p = conn->handler;              /* May have changed. */
+  }
+
+  if(conn->primary.remote_port < 0)
+    /* we check for -1 here since if proxy was detected already, this
+       was very likely already set to the proxy port */
+    conn->primary.remote_port = p->defport;
+
+  return CURLE_OK;
+}
+
+
+#ifndef CURL_DISABLE_PROXY
+
+#ifndef CURL_DISABLE_HTTP
+/****************************************************************
+* Detect what (if any) proxy to use. Remember that this selects a host
+* name and is not limited to HTTP proxies only.
+* The returned pointer must be freed by the caller (unless NULL)
+****************************************************************/
+static char *detect_proxy(struct Curl_easy *data,
+                          struct connectdata *conn)
+{
+  char *proxy = NULL;
+
+  /* If proxy was not specified, we check for default proxy environment
+   * variables, to enable i.e Lynx compliance:
+   *
+   * http_proxy=http://some.server.dom:port/
+   * https_proxy=http://some.server.dom:port/
+   * ftp_proxy=http://some.server.dom:port/
+   * no_proxy=domain1.dom,host.domain2.dom
+   *   (a comma-separated list of hosts which should
+   *   not be proxied, or an asterisk to override
+   *   all proxy variables)
+   * all_proxy=http://some.server.dom:port/
+   *   (seems to exist for the CERN www lib. Probably
+   *   the first to check for.)
+   *
+   * For compatibility, the all-uppercase versions of these variables are
+   * checked if the lowercase versions don't exist.
+   */
+  char proxy_env[128];
+  const char *protop = conn->handler->scheme;
+  char *envp = proxy_env;
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)data;
+#endif
+
+  /* Now, build <protocol>_proxy and check for such a one to use */
+  while(*protop)
+    *envp++ = Curl_raw_tolower(*protop++);
+
+  /* append _proxy */
+  strcpy(envp, "_proxy");
+
+  /* read the protocol proxy: */
+  proxy = curl_getenv(proxy_env);
+
+  /*
+   * We don't try the uppercase version of HTTP_PROXY because of
+   * security reasons:
+   *
+   * When curl is used in a webserver application
+   * environment (cgi or php), this environment variable can
+   * be controlled by the web server user by setting the
+   * http header 'Proxy:' to some value.
+   *
+   * This can cause 'internal' http/ftp requests to be
+   * arbitrarily redirected by any external attacker.
+   */
+  if(!proxy && !strcasecompare("http_proxy", proxy_env)) {
+    /* There was no lowercase variable, try the uppercase version: */
+    Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
+    proxy = curl_getenv(proxy_env);
+  }
+
+  envp = proxy_env;
+  if(!proxy) {
+#ifdef USE_WEBSOCKETS
+    /* websocket proxy fallbacks */
+    if(strcasecompare("ws_proxy", proxy_env)) {
+      proxy = curl_getenv("http_proxy");
+    }
+    else if(strcasecompare("wss_proxy", proxy_env)) {
+      proxy = curl_getenv("https_proxy");
+      if(!proxy)
+        proxy = curl_getenv("HTTPS_PROXY");
+    }
+    if(!proxy) {
+#endif
+      envp = (char *)"all_proxy";
+      proxy = curl_getenv(envp); /* default proxy to use */
+      if(!proxy) {
+        envp = (char *)"ALL_PROXY";
+        proxy = curl_getenv(envp);
+      }
+#ifdef USE_WEBSOCKETS
+    }
+#endif
+  }
+  if(proxy)
+    infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
+
+  return proxy;
+}
+#endif /* CURL_DISABLE_HTTP */
+
+/*
+ * If this is supposed to use a proxy, we need to figure out the proxy
+ * host name, so that we can reuse an existing connection
+ * that may exist registered to the same proxy host.
+ */
+static CURLcode parse_proxy(struct Curl_easy *data,
+                            struct connectdata *conn, char *proxy,
+                            curl_proxytype proxytype)
+{
+  char *portptr = NULL;
+  int port = -1;
+  char *proxyuser = NULL;
+  char *proxypasswd = NULL;
+  char *host = NULL;
+  bool sockstype;
+  CURLUcode uc;
+  struct proxy_info *proxyinfo;
+  CURLU *uhp = curl_url();
+  CURLcode result = CURLE_OK;
+  char *scheme = NULL;
+#ifdef USE_UNIX_SOCKETS
+  char *path = NULL;
+  bool is_unix_proxy = FALSE;
+#endif
+
+
+  if(!uhp) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+
+  /* When parsing the proxy, allowing non-supported schemes since we have
+     these made up ones for proxies. Guess scheme for URLs without it. */
+  uc = curl_url_set(uhp, CURLUPART_URL, proxy,
+                    CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
+  if(!uc) {
+    /* parsed okay as a URL */
+    uc = curl_url_get(uhp, CURLUPART_SCHEME, &scheme, 0);
+    if(uc) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
+
+    if(strcasecompare("https", scheme)) {
+      if(proxytype != CURLPROXY_HTTPS2)
+        proxytype = CURLPROXY_HTTPS;
+      else
+        proxytype = CURLPROXY_HTTPS2;
+    }
+    else if(strcasecompare("socks5h", scheme))
+      proxytype = CURLPROXY_SOCKS5_HOSTNAME;
+    else if(strcasecompare("socks5", scheme))
+      proxytype = CURLPROXY_SOCKS5;
+    else if(strcasecompare("socks4a", scheme))
+      proxytype = CURLPROXY_SOCKS4A;
+    else if(strcasecompare("socks4", scheme) ||
+            strcasecompare("socks", scheme))
+      proxytype = CURLPROXY_SOCKS4;
+    else if(strcasecompare("http", scheme))
+      ; /* leave it as HTTP or HTTP/1.0 */
+    else {
+      /* Any other xxx:// reject! */
+      failf(data, "Unsupported proxy scheme for \'%s\'", proxy);
+      result = CURLE_COULDNT_CONNECT;
+      goto error;
+    }
+  }
+  else {
+    failf(data, "Unsupported proxy syntax in \'%s\': %s", proxy,
+          curl_url_strerror(uc));
+    result = CURLE_COULDNT_RESOLVE_PROXY;
+    goto error;
+  }
+
+#ifdef USE_SSL
+  if(!Curl_ssl_supports(data, SSLSUPP_HTTPS_PROXY))
+#endif
+    if(IS_HTTPS_PROXY(proxytype)) {
+      failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
+            "HTTPS-proxy support.", proxy);
+      result = CURLE_NOT_BUILT_IN;
+      goto error;
+    }
+
+  sockstype =
+    proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
+    proxytype == CURLPROXY_SOCKS5 ||
+    proxytype == CURLPROXY_SOCKS4A ||
+    proxytype == CURLPROXY_SOCKS4;
+
+  proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy;
+  proxyinfo->proxytype = (unsigned char)proxytype;
+
+  /* Is there a username and password given in this proxy url? */
+  uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
+  if(uc && (uc != CURLUE_NO_USER))
+    goto error;
+  uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
+  if(uc && (uc != CURLUE_NO_PASSWORD))
+    goto error;
+
+  if(proxyuser || proxypasswd) {
+    Curl_safefree(proxyinfo->user);
+    proxyinfo->user = proxyuser;
+    result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser);
+    proxyuser = NULL;
+    if(result)
+      goto error;
+    Curl_safefree(proxyinfo->passwd);
+    if(!proxypasswd) {
+      proxypasswd = strdup("");
+      if(!proxypasswd) {
+        result = CURLE_OUT_OF_MEMORY;
+        goto error;
+      }
+    }
+    proxyinfo->passwd = proxypasswd;
+    result = Curl_setstropt(&data->state.aptr.proxypasswd, proxypasswd);
+    proxypasswd = NULL;
+    if(result)
+      goto error;
+    conn->bits.proxy_user_passwd = TRUE; /* enable it */
+  }
+
+  (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
+
+  if(portptr) {
+    port = (int)strtol(portptr, NULL, 10);
+    free(portptr);
+  }
+  else {
+    if(data->set.proxyport)
+      /* None given in the proxy string, then get the default one if it is
+         given */
+      port = (int)data->set.proxyport;
+    else {
+      if(IS_HTTPS_PROXY(proxytype))
+        port = CURL_DEFAULT_HTTPS_PROXY_PORT;
+      else
+        port = CURL_DEFAULT_PROXY_PORT;
+    }
+  }
+  if(port >= 0) {
+    proxyinfo->port = port;
+    if(conn->primary.remote_port < 0 || sockstype ||
+       !conn->socks_proxy.host.rawalloc)
+      conn->primary.remote_port = port;
+  }
+
+  /* now, clone the proxy host name */
+  uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
+  if(uc) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+#ifdef USE_UNIX_SOCKETS
+  if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) {
+    uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE);
+    if(uc) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
+    /* path will be "/", if no path was found */
+    if(strcmp("/", path)) {
+      is_unix_proxy = TRUE;
+      free(host);
+      host = aprintf(UNIX_SOCKET_PREFIX"%s", path);
+      if(!host) {
+        result = CURLE_OUT_OF_MEMORY;
+        goto error;
+      }
+      Curl_safefree(proxyinfo->host.rawalloc);
+      proxyinfo->host.rawalloc = host;
+      proxyinfo->host.name = host;
+      host = NULL;
+    }
+  }
+
+  if(!is_unix_proxy) {
+#endif
+    Curl_safefree(proxyinfo->host.rawalloc);
+    proxyinfo->host.rawalloc = host;
+    if(host[0] == '[') {
+      /* this is a numerical IPv6, strip off the brackets */
+      size_t len = strlen(host);
+      host[len-1] = 0; /* clear the trailing bracket */
+      host++;
+      zonefrom_url(uhp, data, conn);
+    }
+    proxyinfo->host.name = host;
+    host = NULL;
+#ifdef USE_UNIX_SOCKETS
+  }
+#endif
+
+error:
+  free(proxyuser);
+  free(proxypasswd);
+  free(host);
+  free(scheme);
+#ifdef USE_UNIX_SOCKETS
+  free(path);
+#endif
+  curl_url_cleanup(uhp);
+  return result;
+}
+
+/*
+ * Extract the user and password from the authentication string
+ */
+static CURLcode parse_proxy_auth(struct Curl_easy *data,
+                                 struct connectdata *conn)
+{
+  const char *proxyuser = data->state.aptr.proxyuser ?
+    data->state.aptr.proxyuser : "";
+  const char *proxypasswd = data->state.aptr.proxypasswd ?
+    data->state.aptr.proxypasswd : "";
+  CURLcode result = Curl_urldecode(proxyuser, 0, &conn->http_proxy.user, NULL,
+                                   REJECT_ZERO);
+  if(!result)
+    result = Curl_setstropt(&data->state.aptr.proxyuser,
+                            conn->http_proxy.user);
+  if(!result)
+    result = Curl_urldecode(proxypasswd, 0, &conn->http_proxy.passwd,
+                            NULL, REJECT_ZERO);
+  if(!result)
+    result = Curl_setstropt(&data->state.aptr.proxypasswd,
+                            conn->http_proxy.passwd);
+  return result;
+}
+
+/* create_conn helper to parse and init proxy values. to be called after unix
+   socket init but before any proxy vars are evaluated. */
+static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
+                                              struct connectdata *conn)
+{
+  char *proxy = NULL;
+  char *socksproxy = NULL;
+  char *no_proxy = NULL;
+  CURLcode result = CURLE_OK;
+  bool spacesep = FALSE;
+
+  /*************************************************************
+   * Extract the user and password from the authentication string
+   *************************************************************/
+  if(conn->bits.proxy_user_passwd) {
+    result = parse_proxy_auth(data, conn);
+    if(result)
+      goto out;
+  }
+
+  /*************************************************************
+   * Detect what (if any) proxy to use
+   *************************************************************/
+  if(data->set.str[STRING_PROXY]) {
+    proxy = strdup(data->set.str[STRING_PROXY]);
+    /* if global proxy is set, this is it */
+    if(!proxy) {
+      failf(data, "memory shortage");
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
+  }
+
+  if(data->set.str[STRING_PRE_PROXY]) {
+    socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
+    /* if global socks proxy is set, this is it */
+    if(!socksproxy) {
+      failf(data, "memory shortage");
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
+  }
+
+  if(!data->set.str[STRING_NOPROXY]) {
+    const char *p = "no_proxy";
+    no_proxy = curl_getenv(p);
+    if(!no_proxy) {
+      p = "NO_PROXY";
+      no_proxy = curl_getenv(p);
+    }
+    if(no_proxy) {
+      infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
+    }
+  }
+
+  if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
+                        data->set.str[STRING_NOPROXY] : no_proxy,
+                        &spacesep)) {
+    Curl_safefree(proxy);
+    Curl_safefree(socksproxy);
+  }
+#ifndef CURL_DISABLE_HTTP
+  else if(!proxy && !socksproxy)
+    /* if the host is not in the noproxy list, detect proxy. */
+    proxy = detect_proxy(data, conn);
+#endif /* CURL_DISABLE_HTTP */
+  if(spacesep)
+    infof(data, "space-separated NOPROXY patterns are deprecated");
+
+  Curl_safefree(no_proxy);
+
+#ifdef USE_UNIX_SOCKETS
+  /* For the time being do not mix proxy and unix domain sockets. See #1274 */
+  if(proxy && conn->unix_domain_socket) {
+    free(proxy);
+    proxy = NULL;
+  }
+#endif
+
+  if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
+    free(proxy);  /* Don't bother with an empty proxy string or if the
+                     protocol doesn't work with network */
+    proxy = NULL;
+  }
+  if(socksproxy && (!*socksproxy ||
+                    (conn->handler->flags & PROTOPT_NONETWORK))) {
+    free(socksproxy);  /* Don't bother with an empty socks proxy string or if
+                          the protocol doesn't work with network */
+    socksproxy = NULL;
+  }
+
+  /***********************************************************************
+   * If this is supposed to use a proxy, we need to figure out the proxy host
+   * name, proxy type and port number, so that we can reuse an existing
+   * connection that may exist registered to the same proxy host.
+   ***********************************************************************/
+  if(proxy || socksproxy) {
+    curl_proxytype ptype = (curl_proxytype)conn->http_proxy.proxytype;
+    if(proxy) {
+      result = parse_proxy(data, conn, proxy, ptype);
+      Curl_safefree(proxy); /* parse_proxy copies the proxy string */
+      if(result)
+        goto out;
+    }
+
+    if(socksproxy) {
+      result = parse_proxy(data, conn, socksproxy, ptype);
+      /* parse_proxy copies the socks proxy string */
+      Curl_safefree(socksproxy);
+      if(result)
+        goto out;
+    }
+
+    if(conn->http_proxy.host.rawalloc) {
+#ifdef CURL_DISABLE_HTTP
+      /* asking for an HTTP proxy is a bit funny when HTTP is disabled... */
+      result = CURLE_UNSUPPORTED_PROTOCOL;
+      goto out;
+#else
+      /* force this connection's protocol to become HTTP if compatible */
+      if(!(conn->handler->protocol & PROTO_FAMILY_HTTP)) {
+        if((conn->handler->flags & PROTOPT_PROXY_AS_HTTP) &&
+           !conn->bits.tunnel_proxy)
+          conn->handler = &Curl_handler_http;
+        else
+          /* if not converting to HTTP over the proxy, enforce tunneling */
+          conn->bits.tunnel_proxy = TRUE;
+      }
+      conn->bits.httpproxy = TRUE;
+#endif
+    }
+    else {
+      conn->bits.httpproxy = FALSE; /* not an HTTP proxy */
+      conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
+    }
+
+    if(conn->socks_proxy.host.rawalloc) {
+      if(!conn->http_proxy.host.rawalloc) {
+        /* once a socks proxy */
+        if(!conn->socks_proxy.user) {
+          conn->socks_proxy.user = conn->http_proxy.user;
+          conn->http_proxy.user = NULL;
+          Curl_safefree(conn->socks_proxy.passwd);
+          conn->socks_proxy.passwd = conn->http_proxy.passwd;
+          conn->http_proxy.passwd = NULL;
+        }
+      }
+      conn->bits.socksproxy = TRUE;
+    }
+    else
+      conn->bits.socksproxy = FALSE; /* not a socks proxy */
+  }
+  else {
+    conn->bits.socksproxy = FALSE;
+    conn->bits.httpproxy = FALSE;
+  }
+  conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
+
+  if(!conn->bits.proxy) {
+    /* we aren't using the proxy after all... */
+    conn->bits.proxy = FALSE;
+    conn->bits.httpproxy = FALSE;
+    conn->bits.socksproxy = FALSE;
+    conn->bits.proxy_user_passwd = FALSE;
+    conn->bits.tunnel_proxy = FALSE;
+    /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
+       to signal that CURLPROXY_HTTPS is not used for this connection */
+    conn->http_proxy.proxytype = CURLPROXY_HTTP;
+  }
+
+out:
+
+  free(socksproxy);
+  free(proxy);
+  return result;
+}
+#endif /* CURL_DISABLE_PROXY */
+
+/*
+ * Curl_parse_login_details()
+ *
+ * This is used to parse a login string for user name, password and options in
+ * the following formats:
+ *
+ *   user
+ *   user:password
+ *   user:password;options
+ *   user;options
+ *   user;options:password
+ *   :password
+ *   :password;options
+ *   ;options
+ *   ;options:password
+ *
+ * Parameters:
+ *
+ * login    [in]     - The login string.
+ * len      [in]     - The length of the login string.
+ * userp    [in/out] - The address where a pointer to newly allocated memory
+ *                     holding the user will be stored upon completion.
+ * passwdp  [in/out] - The address where a pointer to newly allocated memory
+ *                     holding the password will be stored upon completion.
+ * optionsp [in/out] - The address where a pointer to newly allocated memory
+ *                     holding the options will be stored upon completion.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_parse_login_details(const char *login, const size_t len,
+                                  char **userp, char **passwdp,
+                                  char **optionsp)
+{
+  CURLcode result = CURLE_OK;
+  char *ubuf = NULL;
+  char *pbuf = NULL;
+  char *obuf = NULL;
+  const char *psep = NULL;
+  const char *osep = NULL;
+  size_t ulen;
+  size_t plen;
+  size_t olen;
+
+  /* Attempt to find the password separator */
+  if(passwdp)
+    psep = memchr(login, ':', len);
+
+  /* Attempt to find the options separator */
+  if(optionsp)
+    osep = memchr(login, ';', len);
+
+  /* Calculate the portion lengths */
+  ulen = (psep ?
+          (size_t)(osep && psep > osep ? osep - login : psep - login) :
+          (osep ? (size_t)(osep - login) : len));
+  plen = (psep ?
+          (osep && osep > psep ? (size_t)(osep - psep) :
+                                 (size_t)(login + len - psep)) - 1 : 0);
+  olen = (osep ?
+          (psep && psep > osep ? (size_t)(psep - osep) :
+                                 (size_t)(login + len - osep)) - 1 : 0);
+
+  /* Allocate the user portion buffer, which can be zero length */
+  if(userp) {
+    ubuf = malloc(ulen + 1);
+    if(!ubuf)
+      result = CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Allocate the password portion buffer */
+  if(!result && passwdp && psep) {
+    pbuf = malloc(plen + 1);
+    if(!pbuf) {
+      free(ubuf);
+      result = CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  /* Allocate the options portion buffer */
+  if(!result && optionsp && olen) {
+    obuf = malloc(olen + 1);
+    if(!obuf) {
+      free(pbuf);
+      free(ubuf);
+      result = CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  if(!result) {
+    /* Store the user portion if necessary */
+    if(ubuf) {
+      memcpy(ubuf, login, ulen);
+      ubuf[ulen] = '\0';
+      Curl_safefree(*userp);
+      *userp = ubuf;
+    }
+
+    /* Store the password portion if necessary */
+    if(pbuf) {
+      memcpy(pbuf, psep + 1, plen);
+      pbuf[plen] = '\0';
+      Curl_safefree(*passwdp);
+      *passwdp = pbuf;
+    }
+
+    /* Store the options portion if necessary */
+    if(obuf) {
+      memcpy(obuf, osep + 1, olen);
+      obuf[olen] = '\0';
+      Curl_safefree(*optionsp);
+      *optionsp = obuf;
+    }
+  }
+
+  return result;
+}
+
+/*************************************************************
+ * Figure out the remote port number and fix it in the URL
+ *
+ * No matter if we use a proxy or not, we have to figure out the remote
+ * port number of various reasons.
+ *
+ * The port number embedded in the URL is replaced, if necessary.
+ *************************************************************/
+static CURLcode parse_remote_port(struct Curl_easy *data,
+                                  struct connectdata *conn)
+{
+
+  if(data->set.use_port && data->state.allow_port) {
+    /* if set, we use this instead of the port possibly given in the URL */
+    char portbuf[16];
+    CURLUcode uc;
+    conn->remote_port = data->set.use_port;
+    msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port);
+    uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
+    if(uc)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Override the login details from the URL with that in the CURLOPT_USERPWD
+ * option or a .netrc file, if applicable.
+ */
+static CURLcode override_login(struct Curl_easy *data,
+                               struct connectdata *conn)
+{
+  CURLUcode uc;
+  char **userp = &conn->user;
+  char **passwdp = &conn->passwd;
+  char **optionsp = &conn->options;
+
+  if(data->set.str[STRING_OPTIONS]) {
+    free(*optionsp);
+    *optionsp = strdup(data->set.str[STRING_OPTIONS]);
+    if(!*optionsp)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+#ifndef CURL_DISABLE_NETRC
+  if(data->set.use_netrc == CURL_NETRC_REQUIRED) {
+    Curl_safefree(*userp);
+    Curl_safefree(*passwdp);
+  }
+  conn->bits.netrc = FALSE;
+  if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
+    int ret;
+    bool url_provided = FALSE;
+
+    if(data->state.aptr.user) {
+      /* there was a user name in the URL. Use the URL decoded version */
+      userp = &data->state.aptr.user;
+      url_provided = TRUE;
+    }
+
+    ret = Curl_parsenetrc(conn->host.name,
+                          userp, passwdp,
+                          data->set.str[STRING_NETRC_FILE]);
+    if(ret > 0) {
+      infof(data, "Couldn't find host %s in the %s file; using defaults",
+            conn->host.name,
+            (data->set.str[STRING_NETRC_FILE] ?
+             data->set.str[STRING_NETRC_FILE] : ".netrc"));
+    }
+    else if(ret < 0) {
+      failf(data, ".netrc parser error");
+      return CURLE_READ_ERROR;
+    }
+    else {
+      /* set bits.netrc TRUE to remember that we got the name from a .netrc
+         file, so that it is safe to use even if we followed a Location: to a
+         different host or similar. */
+      conn->bits.netrc = TRUE;
+    }
+    if(url_provided) {
+      Curl_safefree(conn->user);
+      conn->user = strdup(*userp);
+      if(!conn->user)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    /* no user was set but a password, set a blank user */
+    if(!*userp && *passwdp) {
+      *userp = strdup("");
+      if(!*userp)
+        return CURLE_OUT_OF_MEMORY;
+    }
+  }
+#endif
+
+  /* for updated strings, we update them in the URL */
+  if(*userp) {
+    CURLcode result;
+    if(data->state.aptr.user != *userp) {
+      /* nothing to do then */
+      result = Curl_setstropt(&data->state.aptr.user, *userp);
+      if(result)
+        return result;
+    }
+  }
+  if(data->state.aptr.user) {
+    uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
+                      CURLU_URLENCODE);
+    if(uc)
+      return Curl_uc_to_curlcode(uc);
+    if(!*userp) {
+      *userp = strdup(data->state.aptr.user);
+      if(!*userp)
+        return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  if(*passwdp) {
+    CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
+    if(result)
+      return result;
+  }
+  if(data->state.aptr.passwd) {
+    uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
+                      data->state.aptr.passwd, CURLU_URLENCODE);
+    if(uc)
+      return Curl_uc_to_curlcode(uc);
+    if(!*passwdp) {
+      *passwdp = strdup(data->state.aptr.passwd);
+      if(!*passwdp)
+        return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Set the login details so they're available in the connection
+ */
+static CURLcode set_login(struct Curl_easy *data,
+                          struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  const char *setuser = CURL_DEFAULT_USER;
+  const char *setpasswd = CURL_DEFAULT_PASSWORD;
+
+  /* If our protocol needs a password and we have none, use the defaults */
+  if((conn->handler->flags & PROTOPT_NEEDSPWD) && !data->state.aptr.user)
+    ;
+  else {
+    setuser = "";
+    setpasswd = "";
+  }
+  /* Store the default user */
+  if(!conn->user) {
+    conn->user = strdup(setuser);
+    if(!conn->user)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Store the default password */
+  if(!conn->passwd) {
+    conn->passwd = strdup(setpasswd);
+    if(!conn->passwd)
+      result = CURLE_OUT_OF_MEMORY;
+  }
+
+  return result;
+}
+
+/*
+ * Parses a "host:port" string to connect to.
+ * The hostname and the port may be empty; in this case, NULL is returned for
+ * the hostname and -1 for the port.
+ */
+static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
+                                           const char *host,
+                                           char **hostname_result,
+                                           int *port_result)
+{
+  char *host_dup;
+  char *hostptr;
+  char *host_portno;
+  char *portptr;
+  int port = -1;
+  CURLcode result = CURLE_OK;
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) data;
+#endif
+
+  *hostname_result = NULL;
+  *port_result = -1;
+
+  if(!host || !*host)
+    return CURLE_OK;
+
+  host_dup = strdup(host);
+  if(!host_dup)
+    return CURLE_OUT_OF_MEMORY;
+
+  hostptr = host_dup;
+
+  /* start scanning for port number at this point */
+  portptr = hostptr;
+
+  /* detect and extract RFC6874-style IPv6-addresses */
+  if(*hostptr == '[') {
+#ifdef ENABLE_IPV6
+    char *ptr = ++hostptr; /* advance beyond the initial bracket */
+    while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
+      ptr++;
+    if(*ptr == '%') {
+      /* There might be a zone identifier */
+      if(strncmp("%25", ptr, 3))
+        infof(data, "Please URL encode %% as %%25, see RFC 6874.");
+      ptr++;
+      /* Allow unreserved characters as defined in RFC 3986 */
+      while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
+                     (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
+        ptr++;
+    }
+    if(*ptr == ']')
+      /* yeps, it ended nicely with a bracket as well */
+      *ptr++ = '\0';
+    else
+      infof(data, "Invalid IPv6 address format");
+    portptr = ptr;
+    /* Note that if this didn't end with a bracket, we still advanced the
+     * hostptr first, but I can't see anything wrong with that as no host
+     * name nor a numeric can legally start with a bracket.
+     */
+#else
+    failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
+    result = CURLE_NOT_BUILT_IN;
+    goto error;
+#endif
+  }
+
+  /* Get port number off server.com:1080 */
+  host_portno = strchr(portptr, ':');
+  if(host_portno) {
+    char *endp = NULL;
+    *host_portno = '\0'; /* cut off number from host name */
+    host_portno++;
+    if(*host_portno) {
+      long portparse = strtol(host_portno, &endp, 10);
+      if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
+        failf(data, "No valid port number in connect to host string (%s)",
+              host_portno);
+        result = CURLE_SETOPT_OPTION_SYNTAX;
+        goto error;
+      }
+      else
+        port = (int)portparse; /* we know it will fit */
+    }
+  }
+
+  /* now, clone the cleaned host name */
+  DEBUGASSERT(hostptr);
+  *hostname_result = strdup(hostptr);
+  if(!*hostname_result) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto error;
+  }
+
+  *port_result = port;
+
+error:
+  free(host_dup);
+  return result;
+}
+
+/*
+ * Parses one "connect to" string in the form:
+ * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
+ */
+static CURLcode parse_connect_to_string(struct Curl_easy *data,
+                                        struct connectdata *conn,
+                                        const char *conn_to_host,
+                                        char **host_result,
+                                        int *port_result)
+{
+  CURLcode result = CURLE_OK;
+  const char *ptr = conn_to_host;
+  int host_match = FALSE;
+  int port_match = FALSE;
+
+  *host_result = NULL;
+  *port_result = -1;
+
+  if(*ptr == ':') {
+    /* an empty hostname always matches */
+    host_match = TRUE;
+    ptr++;
+  }
+  else {
+    /* check whether the URL's hostname matches */
+    size_t hostname_to_match_len;
+    char *hostname_to_match = aprintf("%s%s%s",
+                                      conn->bits.ipv6_ip ? "[" : "",
+                                      conn->host.name,
+                                      conn->bits.ipv6_ip ? "]" : "");
+    if(!hostname_to_match)
+      return CURLE_OUT_OF_MEMORY;
+    hostname_to_match_len = strlen(hostname_to_match);
+    host_match = strncasecompare(ptr, hostname_to_match,
+                                 hostname_to_match_len);
+    free(hostname_to_match);
+    ptr += hostname_to_match_len;
+
+    host_match = host_match && *ptr == ':';
+    ptr++;
+  }
+
+  if(host_match) {
+    if(*ptr == ':') {
+      /* an empty port always matches */
+      port_match = TRUE;
+      ptr++;
+    }
+    else {
+      /* check whether the URL's port matches */
+      char *ptr_next = strchr(ptr, ':');
+      if(ptr_next) {
+        char *endp = NULL;
+        long port_to_match = strtol(ptr, &endp, 10);
+        if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
+          port_match = TRUE;
+          ptr = ptr_next + 1;
+        }
+      }
+    }
+  }
+
+  if(host_match && port_match) {
+    /* parse the hostname and port to connect to */
+    result = parse_connect_to_host_port(data, ptr, host_result, port_result);
+  }
+
+  return result;
+}
+
+/*
+ * Processes all strings in the "connect to" slist, and uses the "connect
+ * to host" and "connect to port" of the first string that matches.
+ */
+static CURLcode parse_connect_to_slist(struct Curl_easy *data,
+                                       struct connectdata *conn,
+                                       struct curl_slist *conn_to_host)
+{
+  CURLcode result = CURLE_OK;
+  char *host = NULL;
+  int port = -1;
+
+  while(conn_to_host && !host && port == -1) {
+    result = parse_connect_to_string(data, conn, conn_to_host->data,
+                                     &host, &port);
+    if(result)
+      return result;
+
+    if(host && *host) {
+      conn->conn_to_host.rawalloc = host;
+      conn->conn_to_host.name = host;
+      conn->bits.conn_to_host = TRUE;
+
+      infof(data, "Connecting to hostname: %s", host);
+    }
+    else {
+      /* no "connect to host" */
+      conn->bits.conn_to_host = FALSE;
+      Curl_safefree(host);
+    }
+
+    if(port >= 0) {
+      conn->conn_to_port = port;
+      conn->bits.conn_to_port = TRUE;
+      infof(data, "Connecting to port: %d", port);
+    }
+    else {
+      /* no "connect to port" */
+      conn->bits.conn_to_port = FALSE;
+      port = -1;
+    }
+
+    conn_to_host = conn_to_host->next;
+  }
+
+#ifndef CURL_DISABLE_ALTSVC
+  if(data->asi && !host && (port == -1) &&
+     ((conn->handler->protocol == CURLPROTO_HTTPS) ||
+#ifdef CURLDEBUG
+      /* allow debug builds to circumvent the HTTPS restriction */
+      getenv("CURL_ALTSVC_HTTP")
+#else
+      0
+#endif
+       )) {
+    /* no connect_to match, try alt-svc! */
+    enum alpnid srcalpnid;
+    bool hit;
+    struct altsvc *as;
+    const int allowed_versions = ( ALPN_h1
+#ifdef USE_HTTP2
+                                   | ALPN_h2
+#endif
+#ifdef ENABLE_QUIC
+                                   | ALPN_h3
+#endif
+      ) & data->asi->flags;
+
+    host = conn->host.rawalloc;
+#ifdef USE_HTTP2
+    /* with h2 support, check that first */
+    srcalpnid = ALPN_h2;
+    hit = Curl_altsvc_lookup(data->asi,
+                             srcalpnid, host, conn->remote_port, /* from */
+                             &as /* to */,
+                             allowed_versions);
+    if(!hit)
+#endif
+    {
+      srcalpnid = ALPN_h1;
+      hit = Curl_altsvc_lookup(data->asi,
+                               srcalpnid, host, conn->remote_port, /* from */
+                               &as /* to */,
+                               allowed_versions);
+    }
+    if(hit) {
+      char *hostd = strdup((char *)as->dst.host);
+      if(!hostd)
+        return CURLE_OUT_OF_MEMORY;
+      conn->conn_to_host.rawalloc = hostd;
+      conn->conn_to_host.name = hostd;
+      conn->bits.conn_to_host = TRUE;
+      conn->conn_to_port = as->dst.port;
+      conn->bits.conn_to_port = TRUE;
+      conn->bits.altused = TRUE;
+      infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d",
+            Curl_alpnid2str(srcalpnid), host, conn->remote_port,
+            Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
+      if(srcalpnid != as->dst.alpnid) {
+        /* protocol version switch */
+        switch(as->dst.alpnid) {
+        case ALPN_h1:
+          conn->httpversion = 11;
+          break;
+        case ALPN_h2:
+          conn->httpversion = 20;
+          break;
+        case ALPN_h3:
+          conn->transport = TRNSPRT_QUIC;
+          conn->httpversion = 30;
+          break;
+        default: /* shouldn't be possible */
+          break;
+        }
+      }
+    }
+  }
+#endif
+
+  return result;
+}
+
+#ifdef USE_UNIX_SOCKETS
+static CURLcode resolve_unix(struct Curl_easy *data,
+                             struct connectdata *conn,
+                             char *unix_path)
+{
+  struct Curl_dns_entry *hostaddr = NULL;
+  bool longpath = FALSE;
+
+  DEBUGASSERT(unix_path);
+  DEBUGASSERT(conn->dns_entry == NULL);
+
+  /* Unix domain sockets are local. The host gets ignored, just use the
+   * specified domain socket address. Do not cache "DNS entries". There is
+   * no DNS involved and we already have the filesystem path available. */
+  hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
+  if(!hostaddr)
+    return CURLE_OUT_OF_MEMORY;
+
+  hostaddr->addr = Curl_unix2addr(unix_path, &longpath,
+                                  conn->bits.abstract_unix_socket);
+  if(!hostaddr->addr) {
+    if(longpath)
+      /* Long paths are not supported for now */
+      failf(data, "Unix socket path too long: '%s'", unix_path);
+    free(hostaddr);
+    return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY;
+  }
+
+  hostaddr->inuse++;
+  conn->dns_entry = hostaddr;
+  return CURLE_OK;
+}
+#endif
+
+#ifndef CURL_DISABLE_PROXY
+static CURLcode resolve_proxy(struct Curl_easy *data,
+                              struct connectdata *conn,
+                              bool *async)
+{
+  struct Curl_dns_entry *hostaddr = NULL;
+  struct hostname *host;
+  timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+  int rc;
+
+  DEBUGASSERT(conn->dns_entry == NULL);
+
+  host = conn->bits.socksproxy ? &conn->socks_proxy.host :
+    &conn->http_proxy.host;
+
+  conn->hostname_resolve = strdup(host->name);
+  if(!conn->hostname_resolve)
+    return CURLE_OUT_OF_MEMORY;
+
+  rc = Curl_resolv_timeout(data, conn->hostname_resolve,
+                           conn->primary.remote_port, &hostaddr, timeout_ms);
+  conn->dns_entry = hostaddr;
+  if(rc == CURLRESOLV_PENDING)
+    *async = TRUE;
+  else if(rc == CURLRESOLV_TIMEDOUT)
+    return CURLE_OPERATION_TIMEDOUT;
+  else if(!hostaddr) {
+    failf(data, "Couldn't resolve proxy '%s'", host->dispname);
+    return CURLE_COULDNT_RESOLVE_PROXY;
+  }
+
+  return CURLE_OK;
+}
+#endif
+
+static CURLcode resolve_host(struct Curl_easy *data,
+                             struct connectdata *conn,
+                             bool *async)
+{
+  struct Curl_dns_entry *hostaddr = NULL;
+  struct hostname *connhost;
+  timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+  int rc;
+
+  DEBUGASSERT(conn->dns_entry == NULL);
+
+  connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
+
+  /* If not connecting via a proxy, extract the port from the URL, if it is
+   * there, thus overriding any defaults that might have been set above. */
+  conn->primary.remote_port = conn->bits.conn_to_port ? conn->conn_to_port :
+    conn->remote_port;
+
+  /* Resolve target host right on */
+  conn->hostname_resolve = strdup(connhost->name);
+  if(!conn->hostname_resolve)
+    return CURLE_OUT_OF_MEMORY;
+
+  rc = Curl_resolv_timeout(data, conn->hostname_resolve,
+                           conn->primary.remote_port, &hostaddr, timeout_ms);
+  conn->dns_entry = hostaddr;
+  if(rc == CURLRESOLV_PENDING)
+    *async = TRUE;
+  else if(rc == CURLRESOLV_TIMEDOUT) {
+    failf(data, "Failed to resolve host '%s' with timeout after %"
+          CURL_FORMAT_TIMEDIFF_T " ms", connhost->dispname,
+          Curl_timediff(Curl_now(), data->progress.t_startsingle));
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+  else if(!hostaddr) {
+    failf(data, "Could not resolve host: %s", connhost->dispname);
+    return CURLE_COULDNT_RESOLVE_HOST;
+  }
+
+  return CURLE_OK;
+}
+
+/* Perform a fresh resolve */
+static CURLcode resolve_fresh(struct Curl_easy *data,
+                              struct connectdata *conn,
+                              bool *async)
+{
+#ifdef USE_UNIX_SOCKETS
+  char *unix_path = conn->unix_domain_socket;
+
+#ifndef CURL_DISABLE_PROXY
+  if(!unix_path && conn->socks_proxy.host.name &&
+     !strncmp(UNIX_SOCKET_PREFIX"/",
+              conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
+    unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
+#endif
+
+  if(unix_path) {
+    conn->transport = TRNSPRT_UNIX;
+    return resolve_unix(data, conn, unix_path);
+  }
+#endif
+
+#ifndef CURL_DISABLE_PROXY
+  if(CONN_IS_PROXIED(conn))
+    return resolve_proxy(data, conn, async);
+#endif
+
+  return resolve_host(data, conn, async);
+}
+
+/*************************************************************
+ * Resolve the address of the server or proxy
+ *************************************************************/
+static CURLcode resolve_server(struct Curl_easy *data,
+                               struct connectdata *conn,
+                               bool *async)
+{
+  DEBUGASSERT(conn);
+  DEBUGASSERT(data);
+
+  /* Resolve the name of the server or proxy */
+  if(conn->bits.reuse) {
+    /* We're reusing the connection - no need to resolve anything, and
+       idnconvert_hostname() was called already in create_conn() for the reuse
+       case. */
+    *async = FALSE;
+    return CURLE_OK;
+  }
+
+  return resolve_fresh(data, conn, async);
+}
+
+/*
+ * Cleanup the connection `temp`, just allocated for `data`, before using the
+ * previously `existing` one for `data`.  All relevant info is copied over
+ * and `temp` is freed.
+ */
+static void reuse_conn(struct Curl_easy *data,
+                       struct connectdata *temp,
+                       struct connectdata *existing)
+{
+  /* get the user+password information from the temp struct since it may
+   * be new for this request even when we reuse an existing connection */
+  if(temp->user) {
+    /* use the new user name and password though */
+    Curl_safefree(existing->user);
+    Curl_safefree(existing->passwd);
+    existing->user = temp->user;
+    existing->passwd = temp->passwd;
+    temp->user = NULL;
+    temp->passwd = NULL;
+  }
+
+#ifndef CURL_DISABLE_PROXY
+  existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
+  if(existing->bits.proxy_user_passwd) {
+    /* use the new proxy user name and proxy password though */
+    Curl_safefree(existing->http_proxy.user);
+    Curl_safefree(existing->socks_proxy.user);
+    Curl_safefree(existing->http_proxy.passwd);
+    Curl_safefree(existing->socks_proxy.passwd);
+    existing->http_proxy.user = temp->http_proxy.user;
+    existing->socks_proxy.user = temp->socks_proxy.user;
+    existing->http_proxy.passwd = temp->http_proxy.passwd;
+    existing->socks_proxy.passwd = temp->socks_proxy.passwd;
+    temp->http_proxy.user = NULL;
+    temp->socks_proxy.user = NULL;
+    temp->http_proxy.passwd = NULL;
+    temp->socks_proxy.passwd = NULL;
+  }
+#endif
+
+  /* Finding a connection for reuse in the cache matches, among other
+   * things on the "remote-relevant" hostname. This is not necessarily
+   * the authority of the URL, e.g. conn->host. For example:
+   * - we use a proxy (not tunneling). we want to send all requests
+   *   that use the same proxy on this connection.
+   * - we have a "connect-to" setting that may redirect the hostname of
+   *   a new request to the same remote endpoint of an existing conn.
+   *   We want to reuse an existing conn to the remote endpoint.
+   * Since connection reuse does not match on conn->host necessarily, we
+   * switch `existing` conn to `temp` conn's host settings.
+   * TODO: is this correct in the case of TLS connections that have
+   *       used the original hostname in SNI to negotiate? Do we send
+   *       requests for another host through the different SNI?
+   */
+  Curl_free_idnconverted_hostname(&existing->host);
+  Curl_free_idnconverted_hostname(&existing->conn_to_host);
+  Curl_safefree(existing->host.rawalloc);
+  Curl_safefree(existing->conn_to_host.rawalloc);
+  existing->host = temp->host;
+  temp->host.rawalloc = NULL;
+  temp->host.encalloc = NULL;
+  existing->conn_to_host = temp->conn_to_host;
+  temp->conn_to_host.rawalloc = NULL;
+  existing->conn_to_port = temp->conn_to_port;
+  existing->remote_port = temp->remote_port;
+  Curl_safefree(existing->hostname_resolve);
+
+  existing->hostname_resolve = temp->hostname_resolve;
+  temp->hostname_resolve = NULL;
+
+  /* reuse init */
+  existing->bits.reuse = TRUE; /* yes, we're reusing here */
+
+  conn_free(data, temp);
+}
+
+/**
+ * create_conn() sets up a new connectdata struct, or reuses an already
+ * existing one, and resolves host name.
+ *
+ * if this function returns CURLE_OK and *async is set to TRUE, the resolve
+ * response will be coming asynchronously. If *async is FALSE, the name is
+ * already resolved.
+ *
+ * @param data The sessionhandle pointer
+ * @param in_connect is set to the next connection data pointer
+ * @param async is set TRUE when an async DNS resolution is pending
+ * @see Curl_setup_conn()
+ *
+ */
+
+static CURLcode create_conn(struct Curl_easy *data,
+                            struct connectdata **in_connect,
+                            bool *async)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn;
+  struct connectdata *existing = NULL;
+  bool reuse;
+  bool connections_available = TRUE;
+  bool force_reuse = FALSE;
+  bool waitpipe = FALSE;
+  size_t max_host_connections = Curl_multi_max_host_connections(data->multi);
+  size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
+
+  *async = FALSE;
+  *in_connect = NULL;
+
+  /*************************************************************
+   * Check input data
+   *************************************************************/
+  if(!data->state.url) {
+    result = CURLE_URL_MALFORMAT;
+    goto out;
+  }
+
+  /* First, split up the current URL in parts so that we can use the
+     parts for checking against the already present connections. In order
+     to not have to modify everything at once, we allocate a temporary
+     connection data struct and fill in for comparison purposes. */
+  conn = allocate_conn(data);
+
+  if(!conn) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+
+  /* We must set the return variable as soon as possible, so that our
+     parent can cleanup any possible allocs we may have done before
+     any failure */
+  *in_connect = conn;
+
+  result = parseurlandfillconn(data, conn);
+  if(result)
+    goto out;
+
+  if(data->set.str[STRING_SASL_AUTHZID]) {
+    conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
+    if(!conn->sasl_authzid) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
+  }
+
+  if(data->set.str[STRING_BEARER]) {
+    conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
+    if(!conn->oauth_bearer) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
+  }
+
+#ifdef USE_UNIX_SOCKETS
+  if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
+    conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
+    if(!conn->unix_domain_socket) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto out;
+    }
+    conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
+  }
+#endif
+
+  /* After the unix socket init but before the proxy vars are used, parse and
+     initialize the proxy vars */
+#ifndef CURL_DISABLE_PROXY
+  result = create_conn_helper_init_proxy(data, conn);
+  if(result)
+    goto out;
+
+  /*************************************************************
+   * If the protocol is using SSL and HTTP proxy is used, we set
+   * the tunnel_proxy bit.
+   *************************************************************/
+  if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
+    conn->bits.tunnel_proxy = TRUE;
+#endif
+
+  /*************************************************************
+   * Figure out the remote port number and fix it in the URL
+   *************************************************************/
+  result = parse_remote_port(data, conn);
+  if(result)
+    goto out;
+
+  /* Check for overridden login details and set them accordingly so that
+     they are known when protocol->setup_connection is called! */
+  result = override_login(data, conn);
+  if(result)
+    goto out;
+
+  result = set_login(data, conn); /* default credentials */
+  if(result)
+    goto out;
+
+  /*************************************************************
+   * Process the "connect to" linked list of hostname/port mappings.
+   * Do this after the remote port number has been fixed in the URL.
+   *************************************************************/
+  result = parse_connect_to_slist(data, conn, data->set.connect_to);
+  if(result)
+    goto out;
+
+  /*************************************************************
+   * IDN-convert the proxy hostnames
+   *************************************************************/
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.httpproxy) {
+    result = Curl_idnconvert_hostname(&conn->http_proxy.host);
+    if(result)
+      return result;
+  }
+  if(conn->bits.socksproxy) {
+    result = Curl_idnconvert_hostname(&conn->socks_proxy.host);
+    if(result)
+      return result;
+  }
+#endif
+  if(conn->bits.conn_to_host) {
+    result = Curl_idnconvert_hostname(&conn->conn_to_host);
+    if(result)
+      return result;
+  }
+
+  /*************************************************************
+   * Check whether the host and the "connect to host" are equal.
+   * Do this after the hostnames have been IDN-converted.
+   *************************************************************/
+  if(conn->bits.conn_to_host &&
+     strcasecompare(conn->conn_to_host.name, conn->host.name)) {
+    conn->bits.conn_to_host = FALSE;
+  }
+
+  /*************************************************************
+   * Check whether the port and the "connect to port" are equal.
+   * Do this after the remote port number has been fixed in the URL.
+   *************************************************************/
+  if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
+    conn->bits.conn_to_port = FALSE;
+  }
+
+#ifndef CURL_DISABLE_PROXY
+  /*************************************************************
+   * If the "connect to" feature is used with an HTTP proxy,
+   * we set the tunnel_proxy bit.
+   *************************************************************/
+  if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
+      conn->bits.httpproxy)
+    conn->bits.tunnel_proxy = TRUE;
+#endif
+
+  /*************************************************************
+   * Setup internals depending on protocol. Needs to be done after
+   * we figured out what/if proxy to use.
+   *************************************************************/
+  result = setup_connection_internals(data, conn);
+  if(result)
+    goto out;
+
+  /***********************************************************************
+   * file: is a special case in that it doesn't need a network connection
+   ***********************************************************************/
+#ifndef CURL_DISABLE_FILE
+  if(conn->handler->flags & PROTOPT_NONETWORK) {
+    bool done;
+    /* this is supposed to be the connect function so we better at least check
+       that the file is present here! */
+    DEBUGASSERT(conn->handler->connect_it);
+    Curl_persistconninfo(data, conn, NULL);
+    result = conn->handler->connect_it(data, &done);
+
+    /* Setup a "faked" transfer that'll do nothing */
+    if(!result) {
+      Curl_attach_connection(data, conn);
+      result = Curl_conncache_add_conn(data);
+      if(result)
+        goto out;
+
+      /*
+       * Setup whatever necessary for a resumed transfer
+       */
+      result = setup_range(data);
+      if(result) {
+        DEBUGASSERT(conn->handler->done);
+        /* we ignore the return code for the protocol-specific DONE */
+        (void)conn->handler->done(data, result, FALSE);
+        goto out;
+      }
+      Curl_xfer_setup(data, -1, -1, FALSE, -1);
+    }
+
+    /* since we skip do_init() */
+    Curl_init_do(data, conn);
+
+    goto out;
+  }
+#endif
+
+  /* Setup filter for network connections */
+  conn->recv[FIRSTSOCKET] = Curl_cf_recv;
+  conn->send[FIRSTSOCKET] = Curl_cf_send;
+  conn->recv[SECONDARYSOCKET] = Curl_cf_recv;
+  conn->send[SECONDARYSOCKET] = Curl_cf_send;
+  conn->bits.tcp_fastopen = data->set.tcp_fastopen;
+
+  /* Complete the easy's SSL configuration for connection cache matching */
+  result = Curl_ssl_easy_config_complete(data);
+  if(result)
+    goto out;
+
+  prune_dead_connections(data);
+
+  /*************************************************************
+   * Check the current list of connections to see if we can
+   * reuse an already existing one or if we have to create a
+   * new one.
+   *************************************************************/
+
+  DEBUGASSERT(conn->user);
+  DEBUGASSERT(conn->passwd);
+
+  /* reuse_fresh is TRUE if we are told to use a new connection by force, but
+     we only acknowledge this option if this is not a reused connection
+     already (which happens due to follow-location or during an HTTP
+     authentication phase). CONNECT_ONLY transfers also refuse reuse. */
+  if((data->set.reuse_fresh && !data->state.followlocation) ||
+     data->set.connect_only)
+    reuse = FALSE;
+  else
+    reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
+
+  if(reuse) {
+    /*
+     * We already have a connection for this, we got the former connection in
+     * `existing` and thus we need to cleanup the one we just
+     * allocated before we can move along and use `existing`.
+     */
+    reuse_conn(data, conn, existing);
+    conn = existing;
+    *in_connect = conn;
+
+#ifndef CURL_DISABLE_PROXY
+    infof(data, "Re-using existing connection with %s %s",
+          conn->bits.proxy?"proxy":"host",
+          conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
+          conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
+          conn->host.dispname);
+#else
+    infof(data, "Re-using existing connection with host %s",
+          conn->host.dispname);
+#endif
+  }
+  else {
+    /* We have decided that we want a new connection. However, we may not
+       be able to do that if we have reached the limit of how many
+       connections we are allowed to open. */
+
+    if(conn->handler->flags & PROTOPT_ALPN) {
+      /* The protocol wants it, so set the bits if enabled in the easy handle
+         (default) */
+      if(data->set.ssl_enable_alpn)
+        conn->bits.tls_enable_alpn = TRUE;
+    }
+
+    if(waitpipe)
+      /* There is a connection that *might* become usable for multiplexing
+         "soon", and we wait for that */
+      connections_available = FALSE;
+    else {
+      /* this gets a lock on the conncache */
+      struct connectbundle *bundle =
+        Curl_conncache_find_bundle(data, conn, data->state.conn_cache);
+
+      if(max_host_connections > 0 && bundle &&
+         (bundle->num_connections >= max_host_connections)) {
+        struct connectdata *conn_candidate;
+
+        /* The bundle is full. Extract the oldest connection. */
+        conn_candidate = Curl_conncache_extract_bundle(data, bundle);
+        CONNCACHE_UNLOCK(data);
+
+        if(conn_candidate)
+          Curl_disconnect(data, conn_candidate, FALSE);
+        else {
+          infof(data, "No more connections allowed to host: %zu",
+                max_host_connections);
+          connections_available = FALSE;
+        }
+      }
+      else
+        CONNCACHE_UNLOCK(data);
+
+    }
+
+    if(connections_available &&
+       (max_total_connections > 0) &&
+       (Curl_conncache_size(data) >= max_total_connections)) {
+      struct connectdata *conn_candidate;
+
+      /* The cache is full. Let's see if we can kill a connection. */
+      conn_candidate = Curl_conncache_extract_oldest(data);
+      if(conn_candidate)
+        Curl_disconnect(data, conn_candidate, FALSE);
+      else {
+        infof(data, "No connections available in cache");
+        connections_available = FALSE;
+      }
+    }
+
+    if(!connections_available) {
+      infof(data, "No connections available.");
+
+      conn_free(data, conn);
+      *in_connect = NULL;
+
+      result = CURLE_NO_CONNECTION_AVAILABLE;
+      goto out;
+    }
+    else {
+      /*
+       * This is a brand new connection, so let's store it in the connection
+       * cache of ours!
+       */
+      result = Curl_ssl_conn_config_init(data, conn);
+      if(result) {
+        DEBUGF(fprintf(stderr, "Error: init connection ssl config\n"));
+        goto out;
+      }
+
+      Curl_attach_connection(data, conn);
+      result = Curl_conncache_add_conn(data);
+      if(result)
+        goto out;
+    }
+
+#if defined(USE_NTLM)
+    /* If NTLM is requested in a part of this connection, make sure we don't
+       assume the state is fine as this is a fresh connection and NTLM is
+       connection based. */
+    if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+       data->state.authhost.done) {
+      infof(data, "NTLM picked AND auth done set, clear picked");
+      data->state.authhost.picked = CURLAUTH_NONE;
+      data->state.authhost.done = FALSE;
+    }
+
+    if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+       data->state.authproxy.done) {
+      infof(data, "NTLM-proxy picked AND auth done set, clear picked");
+      data->state.authproxy.picked = CURLAUTH_NONE;
+      data->state.authproxy.done = FALSE;
+    }
+#endif
+  }
+
+  /* Setup and init stuff before DO starts, in preparing for the transfer. */
+  Curl_init_do(data, conn);
+
+  /*
+   * Setup whatever necessary for a resumed transfer
+   */
+  result = setup_range(data);
+  if(result)
+    goto out;
+
+  /* Continue connectdata initialization here. */
+
+  /*************************************************************
+   * Resolve the address of the server or proxy
+   *************************************************************/
+  result = resolve_server(data, conn, async);
+  if(result)
+    goto out;
+
+  /* Everything general done, inform filters that they need
+   * to prepare for a data transfer.
+   */
+  result = Curl_conn_ev_data_setup(data);
+
+out:
+  return result;
+}
+
+/* Curl_setup_conn() is called after the name resolve initiated in
+ * create_conn() is all done.
+ *
+ * Curl_setup_conn() also handles reused connections
+ */
+CURLcode Curl_setup_conn(struct Curl_easy *data,
+                         bool *protocol_done)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+
+  Curl_pgrsTime(data, TIMER_NAMELOOKUP);
+
+  if(conn->handler->flags & PROTOPT_NONETWORK) {
+    /* nothing to setup when not using a network */
+    *protocol_done = TRUE;
+    return result;
+  }
+
+#ifndef CURL_DISABLE_PROXY
+  /* set proxy_connect_closed to false unconditionally already here since it
+     is used strictly to provide extra information to a parent function in the
+     case of proxy CONNECT failures and we must make sure we don't have it
+     lingering set from a previous invoke */
+  conn->bits.proxy_connect_closed = FALSE;
+#endif
+
+#ifdef CURL_DO_LINEEND_CONV
+  data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
+#endif /* CURL_DO_LINEEND_CONV */
+
+  /* set start time here for timeout purposes in the connect procedure, it
+     is later set again for the progress meter purpose */
+  conn->now = Curl_now();
+  if(!conn->bits.reuse)
+    result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry,
+                             CURL_CF_SSL_DEFAULT);
+  if(!result)
+    result = Curl_headers_init(data);
+
+  /* not sure we need this flag to be passed around any more */
+  *protocol_done = FALSE;
+  return result;
+}
+
+CURLcode Curl_connect(struct Curl_easy *data,
+                      bool *asyncp,
+                      bool *protocol_done)
+{
+  CURLcode result;
+  struct connectdata *conn;
+
+  *asyncp = FALSE; /* assume synchronous resolves by default */
+
+  /* Set the request to virgin state based on transfer settings */
+  Curl_req_hard_reset(&data->req, data);
+
+  /* call the stuff that needs to be called */
+  result = create_conn(data, &conn, asyncp);
+
+  if(!result) {
+    if(CONN_INUSE(conn) > 1)
+      /* multiplexed */
+      *protocol_done = TRUE;
+    else if(!*asyncp) {
+      /* DNS resolution is done: that's either because this is a reused
+         connection, in which case DNS was unnecessary, or because DNS
+         really did finish already (synch resolver/fast async resolve) */
+      result = Curl_setup_conn(data, protocol_done);
+    }
+  }
+
+  if(result == CURLE_NO_CONNECTION_AVAILABLE) {
+    return result;
+  }
+  else if(result && conn) {
+    /* We're not allowed to return failure with memory left allocated in the
+       connectdata struct, free those here */
+    Curl_detach_connection(data);
+    Curl_conncache_remove_conn(data, conn, TRUE);
+    Curl_disconnect(data, conn, TRUE);
+  }
+
+  return result;
+}
+
+/*
+ * Curl_init_do() inits the readwrite session. This is inited each time (in
+ * the DO function before the protocol-specific DO functions are invoked) for
+ * a transfer, sometimes multiple times on the same Curl_easy. Make sure
+ * nothing in here depends on stuff that are setup dynamically for the
+ * transfer.
+ *
+ * Allow this function to get called with 'conn' set to NULL.
+ */
+
+CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
+{
+  /* if this is a pushed stream, we need this: */
+  CURLcode result = Curl_preconnect(data);
+  if(result)
+    return result;
+
+  if(conn) {
+    conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
+                                   use */
+    /* if the protocol used doesn't support wildcards, switch it off */
+    if(data->state.wildcardmatch &&
+       !(conn->handler->flags & PROTOPT_WILDCARD))
+      data->state.wildcardmatch = FALSE;
+  }
+
+  data->state.done = FALSE; /* *_done() is not called yet */
+
+  if(data->req.no_body)
+    /* in HTTP lingo, no body means using the HEAD request... */
+    data->state.httpreq = HTTPREQ_HEAD;
+
+  result = Curl_req_start(&data->req, data);
+  if(result)
+    return result;
+
+  Curl_speedinit(data);
+  Curl_pgrsSetUploadCounter(data, 0);
+  Curl_pgrsSetDownloadCounter(data, 0);
+
+  return CURLE_OK;
+}
+
+#if defined(USE_HTTP2) || defined(USE_HTTP3)
+
+#ifdef USE_NGHTTP2
+
+static void priority_remove_child(struct Curl_easy *parent,
+                                  struct Curl_easy *child)
+{
+  struct Curl_data_prio_node **pnext = &parent->set.priority.children;
+  struct Curl_data_prio_node *pnode = parent->set.priority.children;
+
+  DEBUGASSERT(child->set.priority.parent == parent);
+  while(pnode && pnode->data != child) {
+    pnext = &pnode->next;
+    pnode = pnode->next;
+  }
+
+  DEBUGASSERT(pnode);
+  if(pnode) {
+    *pnext = pnode->next;
+    free(pnode);
+  }
+
+  child->set.priority.parent = 0;
+  child->set.priority.exclusive = FALSE;
+}
+
+CURLcode Curl_data_priority_add_child(struct Curl_easy *parent,
+                                      struct Curl_easy *child,
+                                      bool exclusive)
+{
+  if(child->set.priority.parent) {
+    priority_remove_child(child->set.priority.parent, child);
+  }
+
+  if(parent) {
+    struct Curl_data_prio_node **tail;
+    struct Curl_data_prio_node *pnode;
+
+    pnode = calloc(1, sizeof(*pnode));
+    if(!pnode)
+      return CURLE_OUT_OF_MEMORY;
+    pnode->data = child;
+
+    if(parent->set.priority.children && exclusive) {
+      /* exclusive: move all existing children underneath the new child */
+      struct Curl_data_prio_node *node = parent->set.priority.children;
+      while(node) {
+        node->data->set.priority.parent = child;
+        node = node->next;
+      }
+
+      tail = &child->set.priority.children;
+      while(*tail)
+        tail = &(*tail)->next;
+
+      DEBUGASSERT(!*tail);
+      *tail = parent->set.priority.children;
+      parent->set.priority.children = 0;
+    }
+
+    tail = &parent->set.priority.children;
+    while(*tail) {
+      (*tail)->data->set.priority.exclusive = FALSE;
+      tail = &(*tail)->next;
+    }
+
+    DEBUGASSERT(!*tail);
+    *tail = pnode;
+  }
+
+  child->set.priority.parent = parent;
+  child->set.priority.exclusive = exclusive;
+  return CURLE_OK;
+}
+
+#endif /* USE_NGHTTP2 */
+
+#ifdef USE_NGHTTP2
+static void data_priority_cleanup(struct Curl_easy *data)
+{
+  while(data->set.priority.children) {
+    struct Curl_easy *tmp = data->set.priority.children->data;
+    priority_remove_child(data, tmp);
+    if(data->set.priority.parent)
+      Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE);
+  }
+
+  if(data->set.priority.parent)
+    priority_remove_child(data->set.priority.parent, data);
+}
+#endif
+
+void Curl_data_priority_clear_state(struct Curl_easy *data)
+{
+  memset(&data->state.priority, 0, sizeof(data->state.priority));
+}
+
+#endif /* defined(USE_HTTP2) || defined(USE_HTTP3) */
Index: trunk/src/libs/curl-8.7.1/lib/url.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/url.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/url.h	(revision 104083)
@@ -0,0 +1,81 @@
+#ifndef HEADER_CURL_URL_H
+#define HEADER_CURL_URL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+/*
+ * Prototypes for library-wide functions provided by url.c
+ */
+
+CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn);
+CURLcode Curl_open(struct Curl_easy **curl);
+CURLcode Curl_init_userdefined(struct Curl_easy *data);
+
+void Curl_freeset(struct Curl_easy *data);
+CURLcode Curl_uc_to_curlcode(CURLUcode uc);
+CURLcode Curl_close(struct Curl_easy **datap); /* opposite of curl_open() */
+CURLcode Curl_connect(struct Curl_easy *, bool *async, bool *protocol_connect);
+void Curl_disconnect(struct Curl_easy *data,
+                     struct connectdata *, bool dead_connection);
+CURLcode Curl_setup_conn(struct Curl_easy *data,
+                         bool *protocol_done);
+CURLcode Curl_parse_login_details(const char *login, const size_t len,
+                                  char **userptr, char **passwdptr,
+                                  char **optionsptr);
+
+/* Get protocol handler for a URI scheme
+ * @param scheme URI scheme, case-insensitive
+ * @return NULL of handler not found
+ */
+const struct Curl_handler *Curl_get_scheme_handler(const char *scheme);
+const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
+                                                    size_t len);
+
+#define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */
+#define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless
+                                             specified */
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+#define Curl_verboseconnect(x,y,z)  Curl_nop_stmt
+#else
+void Curl_verboseconnect(struct Curl_easy *data, struct connectdata *conn,
+                         int sockindex);
+#endif
+
+#if defined(USE_HTTP2) || defined(USE_HTTP3)
+void Curl_data_priority_clear_state(struct Curl_easy *data);
+#else
+#define Curl_data_priority_clear_state(x)
+#endif /* !(defined(USE_HTTP2) || defined(USE_HTTP3)) */
+
+#ifdef USE_NGHTTP2
+CURLcode Curl_data_priority_add_child(struct Curl_easy *parent,
+                                      struct Curl_easy *child,
+                                      bool exclusive);
+#else
+#define Curl_data_priority_add_child(x, y, z) CURLE_NOT_BUILT_IN
+#endif
+
+#endif /* HEADER_CURL_URL_H */
Index: trunk/src/libs/curl-8.7.1/lib/urlapi-int.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/urlapi-int.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/urlapi-int.h	(revision 104083)
@@ -0,0 +1,39 @@
+#ifndef HEADER_CURL_URLAPI_INT_H
+#define HEADER_CURL_URLAPI_INT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
+                            bool guess_scheme);
+
+CURLUcode Curl_url_set_authority(CURLU *u, const char *authority,
+                                 unsigned int flags);
+
+#ifdef DEBUGBUILD
+CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
+                          bool has_scheme);
+#endif
+
+#endif /* HEADER_CURL_URLAPI_INT_H */
Index: trunk/src/libs/curl-8.7.1/lib/urlapi.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/urlapi.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/urlapi.c	(revision 104083)
@@ -0,0 +1,1974 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "urldata.h"
+#include "urlapi-int.h"
+#include "strcase.h"
+#include "url.h"
+#include "escape.h"
+#include "curl_ctype.h"
+#include "inet_pton.h"
+#include "inet_ntop.h"
+#include "strdup.h"
+#include "idn.h"
+#include "curl_memrchr.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+  /* MSDOS/Windows style drive prefix, eg c: in c:foo */
+#define STARTS_WITH_DRIVE_PREFIX(str) \
+  ((('a' <= str[0] && str[0] <= 'z') || \
+    ('A' <= str[0] && str[0] <= 'Z')) && \
+   (str[1] == ':'))
+
+  /* MSDOS/Windows style drive prefix, optionally with
+   * a '|' instead of ':', followed by a slash or NUL */
+#define STARTS_WITH_URL_DRIVE_PREFIX(str) \
+  ((('a' <= (str)[0] && (str)[0] <= 'z') || \
+    ('A' <= (str)[0] && (str)[0] <= 'Z')) && \
+   ((str)[1] == ':' || (str)[1] == '|') && \
+   ((str)[2] == '/' || (str)[2] == '\\' || (str)[2] == 0))
+
+/* scheme is not URL encoded, the longest libcurl supported ones are... */
+#define MAX_SCHEME_LEN 40
+
+/*
+ * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * sure we have _some_ value for AF_INET6 without polluting our fake value
+ * everywhere.
+ */
+#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#define AF_INET6 (AF_INET + 1)
+#endif
+
+/* Internal representation of CURLU. Point to URL-encoded strings. */
+struct Curl_URL {
+  char *scheme;
+  char *user;
+  char *password;
+  char *options; /* IMAP only? */
+  char *host;
+  char *zoneid; /* for numerical IPv6 addresses */
+  char *port;
+  char *path;
+  char *query;
+  char *fragment;
+  long portnum; /* the numerical version */
+};
+
+#define DEFAULT_SCHEME "https"
+
+static void free_urlhandle(struct Curl_URL *u)
+{
+  free(u->scheme);
+  free(u->user);
+  free(u->password);
+  free(u->options);
+  free(u->host);
+  free(u->zoneid);
+  free(u->port);
+  free(u->path);
+  free(u->query);
+  free(u->fragment);
+}
+
+/*
+ * Find the separator at the end of the host name, or the '?' in cases like
+ * http://www.example.com?id=2380
+ */
+static const char *find_host_sep(const char *url)
+{
+  const char *sep;
+  const char *query;
+
+  /* Find the start of the hostname */
+  sep = strstr(url, "//");
+  if(!sep)
+    sep = url;
+  else
+    sep += 2;
+
+  query = strchr(sep, '?');
+  sep = strchr(sep, '/');
+
+  if(!sep)
+    sep = url + strlen(url);
+
+  if(!query)
+    query = url + strlen(url);
+
+  return sep < query ? sep : query;
+}
+
+/* convert CURLcode to CURLUcode */
+#define cc2cu(x) ((x) == CURLE_TOO_LARGE ? CURLUE_TOO_LARGE :   \
+                  CURLUE_OUT_OF_MEMORY)
+/*
+ * Decide whether a character in a URL must be escaped.
+ */
+#define urlchar_needs_escaping(c) (!(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c)))
+
+static const char hexdigits[] = "0123456789abcdef";
+/* urlencode_str() writes data into an output dynbuf and URL-encodes the
+ * spaces in the source URL accordingly.
+ *
+ * URL encoding should be skipped for host names, otherwise IDN resolution
+ * will fail.
+ */
+static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
+                               size_t len, bool relative,
+                               bool query)
+{
+  /* we must add this with whitespace-replacing */
+  bool left = !query;
+  const unsigned char *iptr;
+  const unsigned char *host_sep = (const unsigned char *) url;
+  CURLcode result;
+
+  if(!relative)
+    host_sep = (const unsigned char *) find_host_sep(url);
+
+  for(iptr = (unsigned char *)url;    /* read from here */
+      len; iptr++, len--) {
+
+    if(iptr < host_sep) {
+      result = Curl_dyn_addn(o, iptr, 1);
+      if(result)
+        return cc2cu(result);
+      continue;
+    }
+
+    if(*iptr == ' ') {
+      if(left)
+        result = Curl_dyn_addn(o, "%20", 3);
+      else
+        result = Curl_dyn_addn(o, "+", 1);
+      if(result)
+        return cc2cu(result);
+      continue;
+    }
+
+    if(*iptr == '?')
+      left = FALSE;
+
+    if(urlchar_needs_escaping(*iptr)) {
+      char out[3]={'%'};
+      out[1] = hexdigits[*iptr>>4];
+      out[2] = hexdigits[*iptr & 0xf];
+      result = Curl_dyn_addn(o, out, 3);
+    }
+    else
+      result = Curl_dyn_addn(o, iptr, 1);
+    if(result)
+      return cc2cu(result);
+  }
+
+  return CURLUE_OK;
+}
+
+/*
+ * Returns the length of the scheme if the given URL is absolute (as opposed
+ * to relative). Stores the scheme in the buffer if TRUE and 'buf' is
+ * non-NULL. The buflen must be larger than MAX_SCHEME_LEN if buf is set.
+ *
+ * If 'guess_scheme' is TRUE, it means the URL might be provided without
+ * scheme.
+ */
+size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
+                            bool guess_scheme)
+{
+  int i = 0;
+  DEBUGASSERT(!buf || (buflen > MAX_SCHEME_LEN));
+  (void)buflen; /* only used in debug-builds */
+  if(buf)
+    buf[0] = 0; /* always leave a defined value in buf */
+#ifdef _WIN32
+  if(guess_scheme && STARTS_WITH_DRIVE_PREFIX(url))
+    return 0;
+#endif
+  if(ISALPHA(url[0]))
+    for(i = 1; i < MAX_SCHEME_LEN; ++i) {
+      char s = url[i];
+      if(s && (ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') )) {
+        /* RFC 3986 3.1 explains:
+           scheme      = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+        */
+      }
+      else {
+        break;
+      }
+    }
+  if(i && (url[i] == ':') && ((url[i + 1] == '/') || !guess_scheme)) {
+    /* If this does not guess scheme, the scheme always ends with the colon so
+       that this also detects data: URLs etc. In guessing mode, data: could
+       be the host name "data" with a specified port number. */
+
+    /* the length of the scheme is the name part only */
+    size_t len = i;
+    if(buf) {
+      buf[i] = 0;
+      while(i--) {
+        buf[i] = Curl_raw_tolower(url[i]);
+      }
+    }
+    return len;
+  }
+  return 0;
+}
+
+/*
+ * Concatenate a relative URL to a base URL making it absolute.
+ * URL-encodes any spaces.
+ * The returned pointer must be freed by the caller unless NULL
+ * (returns NULL on out of memory).
+ *
+ * Note that this function destroys the 'base' string.
+ */
+static CURLcode concat_url(char *base, const char *relurl, char **newurl)
+{
+  /***
+   TRY to append this new path to the old URL
+   to the right of the host part. Oh crap, this is doomed to cause
+   problems in the future...
+  */
+  struct dynbuf newest;
+  char *protsep;
+  char *pathsep;
+  bool host_changed = FALSE;
+  const char *useurl = relurl;
+  CURLcode result = CURLE_OK;
+  CURLUcode uc;
+  *newurl = NULL;
+
+  /* protsep points to the start of the host name */
+  protsep = strstr(base, "//");
+  if(!protsep)
+    protsep = base;
+  else
+    protsep += 2; /* pass the slashes */
+
+  if('/' != relurl[0]) {
+    int level = 0;
+
+    /* First we need to find out if there's a ?-letter in the URL,
+       and cut it and the right-side of that off */
+    pathsep = strchr(protsep, '?');
+    if(pathsep)
+      *pathsep = 0;
+
+    /* we have a relative path to append to the last slash if there's one
+       available, or if the new URL is just a query string (starts with a
+       '?')  we append the new one at the end of the entire currently worked
+       out URL */
+    if(useurl[0] != '?') {
+      pathsep = strrchr(protsep, '/');
+      if(pathsep)
+        *pathsep = 0;
+    }
+
+    /* Check if there's any slash after the host name, and if so, remember
+       that position instead */
+    pathsep = strchr(protsep, '/');
+    if(pathsep)
+      protsep = pathsep + 1;
+    else
+      protsep = NULL;
+
+    /* now deal with one "./" or any amount of "../" in the newurl
+       and act accordingly */
+
+    if((useurl[0] == '.') && (useurl[1] == '/'))
+      useurl += 2; /* just skip the "./" */
+
+    while((useurl[0] == '.') &&
+          (useurl[1] == '.') &&
+          (useurl[2] == '/')) {
+      level++;
+      useurl += 3; /* pass the "../" */
+    }
+
+    if(protsep) {
+      while(level--) {
+        /* cut off one more level from the right of the original URL */
+        pathsep = strrchr(protsep, '/');
+        if(pathsep)
+          *pathsep = 0;
+        else {
+          *protsep = 0;
+          break;
+        }
+      }
+    }
+  }
+  else {
+    /* We got a new absolute path for this server */
+
+    if(relurl[1] == '/') {
+      /* the new URL starts with //, just keep the protocol part from the
+         original one */
+      *protsep = 0;
+      useurl = &relurl[2]; /* we keep the slashes from the original, so we
+                              skip the new ones */
+      host_changed = TRUE;
+    }
+    else {
+      /* cut off the original URL from the first slash, or deal with URLs
+         without slash */
+      pathsep = strchr(protsep, '/');
+      if(pathsep) {
+        /* When people use badly formatted URLs, such as
+           "http://www.example.com?dir=/home/daniel" we must not use the first
+           slash, if there's a ?-letter before it! */
+        char *sep = strchr(protsep, '?');
+        if(sep && (sep < pathsep))
+          pathsep = sep;
+        *pathsep = 0;
+      }
+      else {
+        /* There was no slash. Now, since we might be operating on a badly
+           formatted URL, such as "http://www.example.com?id=2380" which
+           doesn't use a slash separator as it is supposed to, we need to check
+           for a ?-letter as well! */
+        pathsep = strchr(protsep, '?');
+        if(pathsep)
+          *pathsep = 0;
+      }
+    }
+  }
+
+  Curl_dyn_init(&newest, CURL_MAX_INPUT_LENGTH);
+
+  /* copy over the root url part */
+  result = Curl_dyn_add(&newest, base);
+  if(result)
+    return result;
+
+  /* check if we need to append a slash */
+  if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
+    ;
+  else {
+    result = Curl_dyn_addn(&newest, "/", 1);
+    if(result)
+      return result;
+  }
+
+  /* then append the new piece on the right side */
+  uc = urlencode_str(&newest, useurl, strlen(useurl), !host_changed,
+                     FALSE);
+  if(uc)
+    return (uc == CURLUE_TOO_LARGE) ? CURLE_TOO_LARGE : CURLE_OUT_OF_MEMORY;
+
+  *newurl = Curl_dyn_ptr(&newest);
+  return CURLE_OK;
+}
+
+/* scan for byte values <= 31, 127 and sometimes space */
+static CURLUcode junkscan(const char *url, size_t *urllen, unsigned int flags)
+{
+  static const char badbytes[]={
+    /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x7f, 0x00 /* null-terminate */
+  };
+  size_t n = strlen(url);
+  size_t nfine;
+
+  if(n > CURL_MAX_INPUT_LENGTH)
+    /* excessive input length */
+    return CURLUE_MALFORMED_INPUT;
+
+  nfine = strcspn(url, badbytes);
+  if((nfine != n) ||
+     (!(flags & CURLU_ALLOW_SPACE) && strchr(url, ' ')))
+    return CURLUE_MALFORMED_INPUT;
+
+  *urllen = n;
+  return CURLUE_OK;
+}
+
+/*
+ * parse_hostname_login()
+ *
+ * Parse the login details (user name, password and options) from the URL and
+ * strip them out of the host name
+ *
+ */
+static CURLUcode parse_hostname_login(struct Curl_URL *u,
+                                      const char *login,
+                                      size_t len,
+                                      unsigned int flags,
+                                      size_t *offset) /* to the host name */
+{
+  CURLUcode result = CURLUE_OK;
+  CURLcode ccode;
+  char *userp = NULL;
+  char *passwdp = NULL;
+  char *optionsp = NULL;
+  const struct Curl_handler *h = NULL;
+
+  /* At this point, we assume all the other special cases have been taken
+   * care of, so the host is at most
+   *
+   *   [user[:password][;options]]@]hostname
+   *
+   * We need somewhere to put the embedded details, so do that first.
+   */
+  char *ptr;
+
+  DEBUGASSERT(login);
+
+  *offset = 0;
+  ptr = memchr(login, '@', len);
+  if(!ptr)
+    goto out;
+
+  /* We will now try to extract the
+   * possible login information in a string like:
+   * ftp://user:password@ftp.my.site:8021/README */
+  ptr++;
+
+  /* if this is a known scheme, get some details */
+  if(u->scheme)
+    h = Curl_get_scheme_handler(u->scheme);
+
+  /* We could use the login information in the URL so extract it. Only parse
+     options if the handler says we should. Note that 'h' might be NULL! */
+  ccode = Curl_parse_login_details(login, ptr - login - 1,
+                                   &userp, &passwdp,
+                                   (h && (h->flags & PROTOPT_URLOPTIONS)) ?
+                                   &optionsp:NULL);
+  if(ccode) {
+    result = CURLUE_BAD_LOGIN;
+    goto out;
+  }
+
+  if(userp) {
+    if(flags & CURLU_DISALLOW_USER) {
+      /* Option DISALLOW_USER is set and url contains username. */
+      result = CURLUE_USER_NOT_ALLOWED;
+      goto out;
+    }
+    free(u->user);
+    u->user = userp;
+  }
+
+  if(passwdp) {
+    free(u->password);
+    u->password = passwdp;
+  }
+
+  if(optionsp) {
+    free(u->options);
+    u->options = optionsp;
+  }
+
+  /* the host name starts at this offset */
+  *offset = ptr - login;
+  return CURLUE_OK;
+
+out:
+
+  free(userp);
+  free(passwdp);
+  free(optionsp);
+  u->user = NULL;
+  u->password = NULL;
+  u->options = NULL;
+
+  return result;
+}
+
+UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
+                                   bool has_scheme)
+{
+  char *portptr;
+  char *hostname = Curl_dyn_ptr(host);
+  /*
+   * Find the end of an IPv6 address on the ']' ending bracket.
+   */
+  if(hostname[0] == '[') {
+    portptr = strchr(hostname, ']');
+    if(!portptr)
+      return CURLUE_BAD_IPV6;
+    portptr++;
+    /* this is a RFC2732-style specified IP-address */
+    if(*portptr) {
+      if(*portptr != ':')
+        return CURLUE_BAD_PORT_NUMBER;
+    }
+    else
+      portptr = NULL;
+  }
+  else
+    portptr = strchr(hostname, ':');
+
+  if(portptr) {
+    char *rest = NULL;
+    long port;
+    size_t keep = portptr - hostname;
+
+    /* Browser behavior adaptation. If there's a colon with no digits after,
+       just cut off the name there which makes us ignore the colon and just
+       use the default port. Firefox, Chrome and Safari all do that.
+
+       Don't do it if the URL has no scheme, to make something that looks like
+       a scheme not work!
+    */
+    Curl_dyn_setlen(host, keep);
+    portptr++;
+    if(!*portptr)
+      return has_scheme ? CURLUE_OK : CURLUE_BAD_PORT_NUMBER;
+
+    if(!ISDIGIT(*portptr))
+      return CURLUE_BAD_PORT_NUMBER;
+
+    port = strtol(portptr, &rest, 10);  /* Port number must be decimal */
+
+    if(port > 0xffff)
+      return CURLUE_BAD_PORT_NUMBER;
+
+    if(rest[0])
+      return CURLUE_BAD_PORT_NUMBER;
+
+    u->portnum = port;
+    /* generate a new port number string to get rid of leading zeroes etc */
+    free(u->port);
+    u->port = aprintf("%ld", port);
+    if(!u->port)
+      return CURLUE_OUT_OF_MEMORY;
+  }
+
+  return CURLUE_OK;
+}
+
+/* this assumes 'hostname' now starts with [ */
+static CURLUcode ipv6_parse(struct Curl_URL *u, char *hostname,
+                            size_t hlen) /* length of hostname */
+{
+  size_t len;
+  DEBUGASSERT(*hostname == '[');
+  if(hlen < 4) /* '[::]' is the shortest possible valid string */
+    return CURLUE_BAD_IPV6;
+  hostname++;
+  hlen -= 2;
+
+  /* only valid IPv6 letters are ok */
+  len = strspn(hostname, "0123456789abcdefABCDEF:.");
+
+  if(hlen != len) {
+    hlen = len;
+    if(hostname[len] == '%') {
+      /* this could now be '%[zone id]' */
+      char zoneid[16];
+      int i = 0;
+      char *h = &hostname[len + 1];
+      /* pass '25' if present and is a url encoded percent sign */
+      if(!strncmp(h, "25", 2) && h[2] && (h[2] != ']'))
+        h += 2;
+      while(*h && (*h != ']') && (i < 15))
+        zoneid[i++] = *h++;
+      if(!i || (']' != *h))
+        return CURLUE_BAD_IPV6;
+      zoneid[i] = 0;
+      u->zoneid = strdup(zoneid);
+      if(!u->zoneid)
+        return CURLUE_OUT_OF_MEMORY;
+      hostname[len] = ']'; /* insert end bracket */
+      hostname[len + 1] = 0; /* terminate the hostname */
+    }
+    else
+      return CURLUE_BAD_IPV6;
+    /* hostname is fine */
+  }
+
+  /* Check the IPv6 address. */
+  {
+    char dest[16]; /* fits a binary IPv6 address */
+    char norm[MAX_IPADR_LEN];
+    hostname[hlen] = 0; /* end the address there */
+    if(1 != Curl_inet_pton(AF_INET6, hostname, dest))
+      return CURLUE_BAD_IPV6;
+
+    /* check if it can be done shorter */
+    if(Curl_inet_ntop(AF_INET6, dest, norm, sizeof(norm)) &&
+       (strlen(norm) < hlen)) {
+      strcpy(hostname, norm);
+      hlen = strlen(norm);
+      hostname[hlen + 1] = 0;
+    }
+    hostname[hlen] = ']'; /* restore ending bracket */
+  }
+  return CURLUE_OK;
+}
+
+static CURLUcode hostname_check(struct Curl_URL *u, char *hostname,
+                                size_t hlen) /* length of hostname */
+{
+  size_t len;
+  DEBUGASSERT(hostname);
+
+  if(!hlen)
+    return CURLUE_NO_HOST;
+  else if(hostname[0] == '[')
+    return ipv6_parse(u, hostname, hlen);
+  else {
+    /* letters from the second string are not ok */
+    len = strcspn(hostname, " \r\n\t/:#?!@{}[]\\$\'\"^`*<>=;,+&()%");
+    if(hlen != len)
+      /* hostname with bad content */
+      return CURLUE_BAD_HOSTNAME;
+  }
+  return CURLUE_OK;
+}
+
+/*
+ * Handle partial IPv4 numerical addresses and different bases, like
+ * '16843009', '0x7f', '0x7f.1' '0177.1.1.1' etc.
+ *
+ * If the given input string is syntactically wrong IPv4 or any part for
+ * example is too big, this function returns HOST_NAME.
+ *
+ * Output the "normalized" version of that input string in plain quad decimal
+ * integers.
+ *
+ * Returns the host type.
+ */
+
+#define HOST_ERROR   -1 /* out of memory */
+#define HOST_BAD     -2 /* bad IPv4 address */
+
+#define HOST_NAME    1
+#define HOST_IPV4    2
+#define HOST_IPV6    3
+
+static int ipv4_normalize(struct dynbuf *host)
+{
+  bool done = FALSE;
+  int n = 0;
+  const char *c = Curl_dyn_ptr(host);
+  unsigned long parts[4] = {0, 0, 0, 0};
+  CURLcode result = CURLE_OK;
+
+  if(*c == '[')
+    return HOST_IPV6;
+
+  while(!done) {
+    char *endp = NULL;
+    unsigned long l;
+    if(!ISDIGIT(*c))
+      /* most importantly this doesn't allow a leading plus or minus */
+      return HOST_NAME;
+    l = strtoul(c, &endp, 0);
+
+    parts[n] = l;
+    c = endp;
+
+    switch(*c) {
+    case '.':
+      if(n == 3)
+        return HOST_NAME;
+      n++;
+      c++;
+      break;
+
+    case '\0':
+      done = TRUE;
+      break;
+
+    default:
+      return HOST_NAME;
+    }
+
+    /* overflow */
+    if((l == ULONG_MAX) && (errno == ERANGE))
+      return HOST_NAME;
+
+#if SIZEOF_LONG > 4
+    /* a value larger than 32 bits */
+    if(l > UINT_MAX)
+      return HOST_NAME;
+#endif
+  }
+
+  switch(n) {
+  case 0: /* a -- 32 bits */
+    Curl_dyn_reset(host);
+
+    result = Curl_dyn_addf(host, "%u.%u.%u.%u",
+                           (unsigned int)(parts[0] >> 24),
+                           (unsigned int)((parts[0] >> 16) & 0xff),
+                           (unsigned int)((parts[0] >> 8) & 0xff),
+                           (unsigned int)(parts[0] & 0xff));
+    break;
+  case 1: /* a.b -- 8.24 bits */
+    if((parts[0] > 0xff) || (parts[1] > 0xffffff))
+      return HOST_NAME;
+    Curl_dyn_reset(host);
+    result = Curl_dyn_addf(host, "%u.%u.%u.%u",
+                           (unsigned int)(parts[0]),
+                           (unsigned int)((parts[1] >> 16) & 0xff),
+                           (unsigned int)((parts[1] >> 8) & 0xff),
+                           (unsigned int)(parts[1] & 0xff));
+    break;
+  case 2: /* a.b.c -- 8.8.16 bits */
+    if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xffff))
+      return HOST_NAME;
+    Curl_dyn_reset(host);
+    result = Curl_dyn_addf(host, "%u.%u.%u.%u",
+                           (unsigned int)(parts[0]),
+                           (unsigned int)(parts[1]),
+                           (unsigned int)((parts[2] >> 8) & 0xff),
+                           (unsigned int)(parts[2] & 0xff));
+    break;
+  case 3: /* a.b.c.d -- 8.8.8.8 bits */
+    if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff) ||
+       (parts[3] > 0xff))
+      return HOST_NAME;
+    Curl_dyn_reset(host);
+    result = Curl_dyn_addf(host, "%u.%u.%u.%u",
+                           (unsigned int)(parts[0]),
+                           (unsigned int)(parts[1]),
+                           (unsigned int)(parts[2]),
+                           (unsigned int)(parts[3]));
+    break;
+  }
+  if(result)
+    return HOST_ERROR;
+  return HOST_IPV4;
+}
+
+/* if necessary, replace the host content with a URL decoded version */
+static CURLUcode urldecode_host(struct dynbuf *host)
+{
+  char *per = NULL;
+  const char *hostname = Curl_dyn_ptr(host);
+  per = strchr(hostname, '%');
+  if(!per)
+    /* nothing to decode */
+    return CURLUE_OK;
+  else {
+    /* encoded */
+    size_t dlen;
+    char *decoded;
+    CURLcode result = Curl_urldecode(hostname, 0, &decoded, &dlen,
+                                     REJECT_CTRL);
+    if(result)
+      return CURLUE_BAD_HOSTNAME;
+    Curl_dyn_reset(host);
+    result = Curl_dyn_addn(host, decoded, dlen);
+    free(decoded);
+    if(result)
+      return cc2cu(result);
+  }
+
+  return CURLUE_OK;
+}
+
+static CURLUcode parse_authority(struct Curl_URL *u,
+                                 const char *auth, size_t authlen,
+                                 unsigned int flags,
+                                 struct dynbuf *host,
+                                 bool has_scheme)
+{
+  size_t offset;
+  CURLUcode uc;
+  CURLcode result;
+
+  /*
+   * Parse the login details and strip them out of the host name.
+   */
+  uc = parse_hostname_login(u, auth, authlen, flags, &offset);
+  if(uc)
+    goto out;
+
+  result = Curl_dyn_addn(host, auth + offset, authlen - offset);
+  if(result) {
+    uc = cc2cu(result);
+    goto out;
+  }
+
+  uc = Curl_parse_port(u, host, has_scheme);
+  if(uc)
+    goto out;
+
+  if(!Curl_dyn_len(host))
+    return CURLUE_NO_HOST;
+
+  switch(ipv4_normalize(host)) {
+  case HOST_IPV4:
+    break;
+  case HOST_IPV6:
+    uc = ipv6_parse(u, Curl_dyn_ptr(host), Curl_dyn_len(host));
+    break;
+  case HOST_NAME:
+    uc = urldecode_host(host);
+    if(!uc)
+      uc = hostname_check(u, Curl_dyn_ptr(host), Curl_dyn_len(host));
+    break;
+  case HOST_ERROR:
+    uc = CURLUE_OUT_OF_MEMORY;
+    break;
+  case HOST_BAD:
+  default:
+    uc = CURLUE_BAD_HOSTNAME; /* Bad IPv4 address even */
+    break;
+  }
+
+out:
+  return uc;
+}
+
+CURLUcode Curl_url_set_authority(CURLU *u, const char *authority,
+                                 unsigned int flags)
+{
+  CURLUcode result;
+  struct dynbuf host;
+
+  DEBUGASSERT(authority);
+  Curl_dyn_init(&host, CURL_MAX_INPUT_LENGTH);
+
+  result = parse_authority(u, authority, strlen(authority), flags,
+                           &host, !!u->scheme);
+  if(result)
+    Curl_dyn_free(&host);
+  else {
+    free(u->host);
+    u->host = Curl_dyn_ptr(&host);
+  }
+  return result;
+}
+
+/*
+ * "Remove Dot Segments"
+ * https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4
+ */
+
+/*
+ * dedotdotify()
+ * @unittest: 1395
+ *
+ * This function gets a null-terminated path with dot and dotdot sequences
+ * passed in and strips them off according to the rules in RFC 3986 section
+ * 5.2.4.
+ *
+ * The function handles a query part ('?' + stuff) appended but it expects
+ * that fragments ('#' + stuff) have already been cut off.
+ *
+ * RETURNS
+ *
+ * Zero for success and 'out' set to an allocated dedotdotified string.
+ */
+UNITTEST int dedotdotify(const char *input, size_t clen, char **outp);
+UNITTEST int dedotdotify(const char *input, size_t clen, char **outp)
+{
+  char *outptr;
+  const char *endp = &input[clen];
+  char *out;
+
+  *outp = NULL;
+  /* the path always starts with a slash, and a slash has not dot */
+  if((clen < 2) || !memchr(input, '.', clen))
+    return 0;
+
+  out = malloc(clen + 1);
+  if(!out)
+    return 1; /* out of memory */
+
+  *out = 0; /* null-terminates, for inputs like "./" */
+  outptr = out;
+
+  do {
+    bool dotdot = TRUE;
+    if(*input == '.') {
+      /*  A.  If the input buffer begins with a prefix of "../" or "./", then
+          remove that prefix from the input buffer; otherwise, */
+
+      if(!strncmp("./", input, 2)) {
+        input += 2;
+        clen -= 2;
+      }
+      else if(!strncmp("../", input, 3)) {
+        input += 3;
+        clen -= 3;
+      }
+      /*  D.  if the input buffer consists only of "." or "..", then remove
+          that from the input buffer; otherwise, */
+
+      else if(!strcmp(".", input) || !strcmp("..", input) ||
+              !strncmp(".?", input, 2) || !strncmp("..?", input, 3)) {
+        *out = 0;
+        break;
+      }
+      else
+        dotdot = FALSE;
+    }
+    else if(*input == '/') {
+      /*  B.  if the input buffer begins with a prefix of "/./" or "/.", where
+          "."  is a complete path segment, then replace that prefix with "/" in
+          the input buffer; otherwise, */
+      if(!strncmp("/./", input, 3)) {
+        input += 2;
+        clen -= 2;
+      }
+      else if(!strcmp("/.", input) || !strncmp("/.?", input, 3)) {
+        *outptr++ = '/';
+        *outptr = 0;
+        break;
+      }
+
+      /*  C.  if the input buffer begins with a prefix of "/../" or "/..",
+          where ".." is a complete path segment, then replace that prefix with
+          "/" in the input buffer and remove the last segment and its
+          preceding "/" (if any) from the output buffer; otherwise, */
+
+      else if(!strncmp("/../", input, 4)) {
+        input += 3;
+        clen -= 3;
+        /* remove the last segment from the output buffer */
+        while(outptr > out) {
+          outptr--;
+          if(*outptr == '/')
+            break;
+        }
+        *outptr = 0; /* null-terminate where it stops */
+      }
+      else if(!strcmp("/..", input) || !strncmp("/..?", input, 4)) {
+        /* remove the last segment from the output buffer */
+        while(outptr > out) {
+          outptr--;
+          if(*outptr == '/')
+            break;
+        }
+        *outptr++ = '/';
+        *outptr = 0; /* null-terminate where it stops */
+        break;
+      }
+      else
+        dotdot = FALSE;
+    }
+    else
+      dotdot = FALSE;
+
+    if(!dotdot) {
+      /*  E.  move the first path segment in the input buffer to the end of
+          the output buffer, including the initial "/" character (if any) and
+          any subsequent characters up to, but not including, the next "/"
+          character or the end of the input buffer. */
+
+      do {
+        *outptr++ = *input++;
+        clen--;
+      } while(*input && (*input != '/') && (*input != '?'));
+      *outptr = 0;
+    }
+
+    /* continue until end of path */
+  } while(input < endp);
+
+  *outp = out;
+  return 0; /* success */
+}
+
+static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
+{
+  const char *path;
+  size_t pathlen;
+  char *query = NULL;
+  char *fragment = NULL;
+  char schemebuf[MAX_SCHEME_LEN + 1];
+  size_t schemelen = 0;
+  size_t urllen;
+  CURLUcode result = CURLUE_OK;
+  size_t fraglen = 0;
+  struct dynbuf host;
+
+  DEBUGASSERT(url);
+
+  Curl_dyn_init(&host, CURL_MAX_INPUT_LENGTH);
+
+  result = junkscan(url, &urllen, flags);
+  if(result)
+    goto fail;
+
+  schemelen = Curl_is_absolute_url(url, schemebuf, sizeof(schemebuf),
+                                   flags & (CURLU_GUESS_SCHEME|
+                                            CURLU_DEFAULT_SCHEME));
+
+  /* handle the file: scheme */
+  if(schemelen && !strcmp(schemebuf, "file")) {
+    bool uncpath = FALSE;
+    if(urllen <= 6) {
+      /* file:/ is not enough to actually be a complete file: URL */
+      result = CURLUE_BAD_FILE_URL;
+      goto fail;
+    }
+
+    /* path has been allocated large enough to hold this */
+    path = (char *)&url[5];
+    pathlen = urllen - 5;
+
+    u->scheme = strdup("file");
+    if(!u->scheme) {
+      result = CURLUE_OUT_OF_MEMORY;
+      goto fail;
+    }
+
+    /* Extra handling URLs with an authority component (i.e. that start with
+     * "file://")
+     *
+     * We allow omitted hostname (e.g. file:/<path>) -- valid according to
+     * RFC 8089, but not the (current) WHAT-WG URL spec.
+     */
+    if(path[0] == '/' && path[1] == '/') {
+      /* swallow the two slashes */
+      const char *ptr = &path[2];
+
+      /*
+       * According to RFC 8089, a file: URL can be reliably dereferenced if:
+       *
+       *  o it has no/blank hostname, or
+       *
+       *  o the hostname matches "localhost" (case-insensitively), or
+       *
+       *  o the hostname is a FQDN that resolves to this machine, or
+       *
+       *  o it is an UNC String transformed to an URI (Windows only, RFC 8089
+       *    Appendix E.3).
+       *
+       * For brevity, we only consider URLs with empty, "localhost", or
+       * "127.0.0.1" hostnames as local, otherwise as an UNC String.
+       *
+       * Additionally, there is an exception for URLs with a Windows drive
+       * letter in the authority (which was accidentally omitted from RFC 8089
+       * Appendix E, but believe me, it was meant to be there. --MK)
+       */
+      if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) {
+        /* the URL includes a host name, it must match "localhost" or
+           "127.0.0.1" to be valid */
+        if(checkprefix("localhost/", ptr) ||
+           checkprefix("127.0.0.1/", ptr)) {
+          ptr += 9; /* now points to the slash after the host */
+        }
+        else {
+#if defined(_WIN32)
+          size_t len;
+
+          /* the host name, NetBIOS computer name, can not contain disallowed
+             chars, and the delimiting slash character must be appended to the
+             host name */
+          path = strpbrk(ptr, "/\\:*?\"<>|");
+          if(!path || *path != '/') {
+            result = CURLUE_BAD_FILE_URL;
+            goto fail;
+          }
+
+          len = path - ptr;
+          if(len) {
+            CURLcode code = Curl_dyn_addn(&host, ptr, len);
+            if(code) {
+              result = cc2cu(code);
+              goto fail;
+            }
+            uncpath = TRUE;
+          }
+
+          ptr -= 2; /* now points to the // before the host in UNC */
+#else
+          /* Invalid file://hostname/, expected localhost or 127.0.0.1 or
+             none */
+          result = CURLUE_BAD_FILE_URL;
+          goto fail;
+#endif
+        }
+      }
+
+      path = ptr;
+      pathlen = urllen - (ptr - url);
+    }
+
+    if(!uncpath)
+      /* no host for file: URLs by default */
+      Curl_dyn_reset(&host);
+
+#if !defined(_WIN32) && !defined(MSDOS) && !defined(__CYGWIN__)
+    /* Don't allow Windows drive letters when not in Windows.
+     * This catches both "file:/c:" and "file:c:" */
+    if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
+       STARTS_WITH_URL_DRIVE_PREFIX(path)) {
+      /* File drive letters are only accepted in MSDOS/Windows */
+      result = CURLUE_BAD_FILE_URL;
+      goto fail;
+    }
+#else
+    /* If the path starts with a slash and a drive letter, ditch the slash */
+    if('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) {
+      /* This cannot be done with strcpy, as the memory chunks overlap! */
+      path++;
+      pathlen--;
+    }
+#endif
+
+  }
+  else {
+    /* clear path */
+    const char *schemep = NULL;
+    const char *hostp;
+    size_t hostlen;
+
+    if(schemelen) {
+      int i = 0;
+      const char *p = &url[schemelen + 1];
+      while((*p == '/') && (i < 4)) {
+        p++;
+        i++;
+      }
+
+      schemep = schemebuf;
+      if(!Curl_get_scheme_handler(schemep) &&
+         !(flags & CURLU_NON_SUPPORT_SCHEME)) {
+        result = CURLUE_UNSUPPORTED_SCHEME;
+        goto fail;
+      }
+
+      if((i < 1) || (i > 3)) {
+        /* less than one or more than three slashes */
+        result = CURLUE_BAD_SLASHES;
+        goto fail;
+      }
+      hostp = p; /* host name starts here */
+    }
+    else {
+      /* no scheme! */
+
+      if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME))) {
+        result = CURLUE_BAD_SCHEME;
+        goto fail;
+      }
+      if(flags & CURLU_DEFAULT_SCHEME)
+        schemep = DEFAULT_SCHEME;
+
+      /*
+       * The URL was badly formatted, let's try without scheme specified.
+       */
+      hostp = url;
+    }
+
+    if(schemep) {
+      u->scheme = strdup(schemep);
+      if(!u->scheme) {
+        result = CURLUE_OUT_OF_MEMORY;
+        goto fail;
+      }
+    }
+
+    /* find the end of the host name + port number */
+    hostlen = strcspn(hostp, "/?#");
+    path = &hostp[hostlen];
+
+    /* this pathlen also contains the query and the fragment */
+    pathlen = urllen - (path - url);
+    if(hostlen) {
+
+      result = parse_authority(u, hostp, hostlen, flags, &host, schemelen);
+      if(result)
+        goto fail;
+
+      if((flags & CURLU_GUESS_SCHEME) && !schemep) {
+        const char *hostname = Curl_dyn_ptr(&host);
+        /* legacy curl-style guess based on host name */
+        if(checkprefix("ftp.", hostname))
+          schemep = "ftp";
+        else if(checkprefix("dict.", hostname))
+          schemep = "dict";
+        else if(checkprefix("ldap.", hostname))
+          schemep = "ldap";
+        else if(checkprefix("imap.", hostname))
+          schemep = "imap";
+        else if(checkprefix("smtp.", hostname))
+          schemep = "smtp";
+        else if(checkprefix("pop3.", hostname))
+          schemep = "pop3";
+        else
+          schemep = "http";
+
+        u->scheme = strdup(schemep);
+        if(!u->scheme) {
+          result = CURLUE_OUT_OF_MEMORY;
+          goto fail;
+        }
+      }
+    }
+    else if(flags & CURLU_NO_AUTHORITY) {
+      /* allowed to be empty. */
+      if(Curl_dyn_add(&host, "")) {
+        result = CURLUE_OUT_OF_MEMORY;
+        goto fail;
+      }
+    }
+    else {
+      result = CURLUE_NO_HOST;
+      goto fail;
+    }
+  }
+
+  fragment = strchr(path, '#');
+  if(fragment) {
+    fraglen = pathlen - (fragment - path);
+    if(fraglen > 1) {
+      /* skip the leading '#' in the copy but include the terminating null */
+      if(flags & CURLU_URLENCODE) {
+        struct dynbuf enc;
+        Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
+        result = urlencode_str(&enc, fragment + 1, fraglen - 1, TRUE, FALSE);
+        if(result)
+          goto fail;
+        u->fragment = Curl_dyn_ptr(&enc);
+      }
+      else {
+        u->fragment = Curl_memdup0(fragment + 1, fraglen - 1);
+        if(!u->fragment) {
+          result = CURLUE_OUT_OF_MEMORY;
+          goto fail;
+        }
+      }
+    }
+    /* after this, pathlen still contains the query */
+    pathlen -= fraglen;
+  }
+
+  query = memchr(path, '?', pathlen);
+  if(query) {
+    size_t qlen = fragment ? (size_t)(fragment - query) :
+      pathlen - (query - path);
+    pathlen -= qlen;
+    if(qlen > 1) {
+      if(flags & CURLU_URLENCODE) {
+        struct dynbuf enc;
+        Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
+        /* skip the leading question mark */
+        result = urlencode_str(&enc, query + 1, qlen - 1, TRUE, TRUE);
+        if(result)
+          goto fail;
+        u->query = Curl_dyn_ptr(&enc);
+      }
+      else {
+        u->query = Curl_memdup0(query + 1, qlen - 1);
+        if(!u->query) {
+          result = CURLUE_OUT_OF_MEMORY;
+          goto fail;
+        }
+      }
+    }
+    else {
+      /* single byte query */
+      u->query = strdup("");
+      if(!u->query) {
+        result = CURLUE_OUT_OF_MEMORY;
+        goto fail;
+      }
+    }
+  }
+
+  if(pathlen && (flags & CURLU_URLENCODE)) {
+    struct dynbuf enc;
+    Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
+    result = urlencode_str(&enc, path, pathlen, TRUE, FALSE);
+    if(result)
+      goto fail;
+    pathlen = Curl_dyn_len(&enc);
+    path = u->path = Curl_dyn_ptr(&enc);
+  }
+
+  if(pathlen <= 1) {
+    /* there is no path left or just the slash, unset */
+    path = NULL;
+  }
+  else {
+    if(!u->path) {
+      u->path = Curl_memdup0(path, pathlen);
+      if(!u->path) {
+        result = CURLUE_OUT_OF_MEMORY;
+        goto fail;
+      }
+      path = u->path;
+    }
+    else if(flags & CURLU_URLENCODE)
+      /* it might have encoded more than just the path so cut it */
+      u->path[pathlen] = 0;
+
+    if(!(flags & CURLU_PATH_AS_IS)) {
+      /* remove ../ and ./ sequences according to RFC3986 */
+      char *dedot;
+      int err = dedotdotify((char *)path, pathlen, &dedot);
+      if(err) {
+        result = CURLUE_OUT_OF_MEMORY;
+        goto fail;
+      }
+      if(dedot) {
+        free(u->path);
+        u->path = dedot;
+      }
+    }
+  }
+
+  u->host = Curl_dyn_ptr(&host);
+
+  return result;
+fail:
+  Curl_dyn_free(&host);
+  free_urlhandle(u);
+  return result;
+}
+
+/*
+ * Parse the URL and, if successful, replace everything in the Curl_URL struct.
+ */
+static CURLUcode parseurl_and_replace(const char *url, CURLU *u,
+                                      unsigned int flags)
+{
+  CURLUcode result;
+  CURLU tmpurl;
+  memset(&tmpurl, 0, sizeof(tmpurl));
+  result = parseurl(url, &tmpurl, flags);
+  if(!result) {
+    free_urlhandle(u);
+    *u = tmpurl;
+  }
+  return result;
+}
+
+/*
+ */
+CURLU *curl_url(void)
+{
+  return calloc(1, sizeof(struct Curl_URL));
+}
+
+void curl_url_cleanup(CURLU *u)
+{
+  if(u) {
+    free_urlhandle(u);
+    free(u);
+  }
+}
+
+#define DUP(dest, src, name)                    \
+  do {                                          \
+    if(src->name) {                             \
+      dest->name = strdup(src->name);           \
+      if(!dest->name)                           \
+        goto fail;                              \
+    }                                           \
+  } while(0)
+
+CURLU *curl_url_dup(const CURLU *in)
+{
+  struct Curl_URL *u = calloc(1, sizeof(struct Curl_URL));
+  if(u) {
+    DUP(u, in, scheme);
+    DUP(u, in, user);
+    DUP(u, in, password);
+    DUP(u, in, options);
+    DUP(u, in, host);
+    DUP(u, in, port);
+    DUP(u, in, path);
+    DUP(u, in, query);
+    DUP(u, in, fragment);
+    DUP(u, in, zoneid);
+    u->portnum = in->portnum;
+  }
+  return u;
+fail:
+  curl_url_cleanup(u);
+  return NULL;
+}
+
+CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
+                       char **part, unsigned int flags)
+{
+  const char *ptr;
+  CURLUcode ifmissing = CURLUE_UNKNOWN_PART;
+  char portbuf[7];
+  bool urldecode = (flags & CURLU_URLDECODE)?1:0;
+  bool urlencode = (flags & CURLU_URLENCODE)?1:0;
+  bool punycode = FALSE;
+  bool depunyfy = FALSE;
+  bool plusdecode = FALSE;
+  (void)flags;
+  if(!u)
+    return CURLUE_BAD_HANDLE;
+  if(!part)
+    return CURLUE_BAD_PARTPOINTER;
+  *part = NULL;
+
+  switch(what) {
+  case CURLUPART_SCHEME:
+    ptr = u->scheme;
+    ifmissing = CURLUE_NO_SCHEME;
+    urldecode = FALSE; /* never for schemes */
+    break;
+  case CURLUPART_USER:
+    ptr = u->user;
+    ifmissing = CURLUE_NO_USER;
+    break;
+  case CURLUPART_PASSWORD:
+    ptr = u->password;
+    ifmissing = CURLUE_NO_PASSWORD;
+    break;
+  case CURLUPART_OPTIONS:
+    ptr = u->options;
+    ifmissing = CURLUE_NO_OPTIONS;
+    break;
+  case CURLUPART_HOST:
+    ptr = u->host;
+    ifmissing = CURLUE_NO_HOST;
+    punycode = (flags & CURLU_PUNYCODE)?1:0;
+    depunyfy = (flags & CURLU_PUNY2IDN)?1:0;
+    break;
+  case CURLUPART_ZONEID:
+    ptr = u->zoneid;
+    ifmissing = CURLUE_NO_ZONEID;
+    break;
+  case CURLUPART_PORT:
+    ptr = u->port;
+    ifmissing = CURLUE_NO_PORT;
+    urldecode = FALSE; /* never for port */
+    if(!ptr && (flags & CURLU_DEFAULT_PORT) && u->scheme) {
+      /* there's no stored port number, but asked to deliver
+         a default one for the scheme */
+      const struct Curl_handler *h = Curl_get_scheme_handler(u->scheme);
+      if(h) {
+        msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
+        ptr = portbuf;
+      }
+    }
+    else if(ptr && u->scheme) {
+      /* there is a stored port number, but ask to inhibit if
+         it matches the default one for the scheme */
+      const struct Curl_handler *h = Curl_get_scheme_handler(u->scheme);
+      if(h && (h->defport == u->portnum) &&
+         (flags & CURLU_NO_DEFAULT_PORT))
+        ptr = NULL;
+    }
+    break;
+  case CURLUPART_PATH:
+    ptr = u->path;
+    if(!ptr)
+      ptr = "/";
+    break;
+  case CURLUPART_QUERY:
+    ptr = u->query;
+    ifmissing = CURLUE_NO_QUERY;
+    plusdecode = urldecode;
+    break;
+  case CURLUPART_FRAGMENT:
+    ptr = u->fragment;
+    ifmissing = CURLUE_NO_FRAGMENT;
+    break;
+  case CURLUPART_URL: {
+    char *url;
+    char *scheme;
+    char *options = u->options;
+    char *port = u->port;
+    char *allochost = NULL;
+    punycode = (flags & CURLU_PUNYCODE)?1:0;
+    depunyfy = (flags & CURLU_PUNY2IDN)?1:0;
+    if(u->scheme && strcasecompare("file", u->scheme)) {
+      url = aprintf("file://%s%s%s",
+                    u->path,
+                    u->fragment? "#": "",
+                    u->fragment? u->fragment : "");
+    }
+    else if(!u->host)
+      return CURLUE_NO_HOST;
+    else {
+      const struct Curl_handler *h = NULL;
+      if(u->scheme)
+        scheme = u->scheme;
+      else if(flags & CURLU_DEFAULT_SCHEME)
+        scheme = (char *) DEFAULT_SCHEME;
+      else
+        return CURLUE_NO_SCHEME;
+
+      h = Curl_get_scheme_handler(scheme);
+      if(!port && (flags & CURLU_DEFAULT_PORT)) {
+        /* there's no stored port number, but asked to deliver
+           a default one for the scheme */
+        if(h) {
+          msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
+          port = portbuf;
+        }
+      }
+      else if(port) {
+        /* there is a stored port number, but asked to inhibit if it matches
+           the default one for the scheme */
+        if(h && (h->defport == u->portnum) &&
+           (flags & CURLU_NO_DEFAULT_PORT))
+          port = NULL;
+      }
+
+      if(h && !(h->flags & PROTOPT_URLOPTIONS))
+        options = NULL;
+
+      if(u->host[0] == '[') {
+        if(u->zoneid) {
+          /* make it '[ host %25 zoneid ]' */
+          struct dynbuf enc;
+          size_t hostlen = strlen(u->host);
+          Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
+          if(Curl_dyn_addf(&enc, "%.*s%%25%s]", (int)hostlen - 1, u->host,
+                           u->zoneid))
+            return CURLUE_OUT_OF_MEMORY;
+          allochost = Curl_dyn_ptr(&enc);
+        }
+      }
+      else if(urlencode) {
+        allochost = curl_easy_escape(NULL, u->host, 0);
+        if(!allochost)
+          return CURLUE_OUT_OF_MEMORY;
+      }
+      else if(punycode) {
+        if(!Curl_is_ASCII_name(u->host)) {
+#ifndef USE_IDN
+          return CURLUE_LACKS_IDN;
+#else
+          CURLcode result = Curl_idn_decode(u->host, &allochost);
+          if(result)
+            return (result == CURLE_OUT_OF_MEMORY) ?
+              CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
+#endif
+        }
+      }
+      else if(depunyfy) {
+        if(Curl_is_ASCII_name(u->host) && !strncmp("xn--", u->host, 4)) {
+#ifndef USE_IDN
+          return CURLUE_LACKS_IDN;
+#else
+          CURLcode result = Curl_idn_encode(u->host, &allochost);
+          if(result)
+            /* this is the most likely error */
+            return (result == CURLE_OUT_OF_MEMORY) ?
+              CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
+#endif
+        }
+      }
+
+      url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+                    scheme,
+                    u->user ? u->user : "",
+                    u->password ? ":": "",
+                    u->password ? u->password : "",
+                    options ? ";" : "",
+                    options ? options : "",
+                    (u->user || u->password || options) ? "@": "",
+                    allochost ? allochost : u->host,
+                    port ? ":": "",
+                    port ? port : "",
+                    u->path ? u->path : "/",
+                    (u->query && u->query[0]) ? "?": "",
+                    (u->query && u->query[0]) ? u->query : "",
+                    u->fragment? "#": "",
+                    u->fragment? u->fragment : "");
+      free(allochost);
+    }
+    if(!url)
+      return CURLUE_OUT_OF_MEMORY;
+    *part = url;
+    return CURLUE_OK;
+  }
+  default:
+    ptr = NULL;
+    break;
+  }
+  if(ptr) {
+    size_t partlen = strlen(ptr);
+    size_t i = 0;
+    *part = Curl_memdup0(ptr, partlen);
+    if(!*part)
+      return CURLUE_OUT_OF_MEMORY;
+    if(plusdecode) {
+      /* convert + to space */
+      char *plus = *part;
+      for(i = 0; i < partlen; ++plus, i++) {
+        if(*plus == '+')
+          *plus = ' ';
+      }
+    }
+    if(urldecode) {
+      char *decoded;
+      size_t dlen;
+      /* this unconditional rejection of control bytes is documented
+         API behavior */
+      CURLcode res = Curl_urldecode(*part, 0, &decoded, &dlen, REJECT_CTRL);
+      free(*part);
+      if(res) {
+        *part = NULL;
+        return CURLUE_URLDECODE;
+      }
+      *part = decoded;
+      partlen = dlen;
+    }
+    if(urlencode) {
+      struct dynbuf enc;
+      CURLUcode uc;
+      Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
+      uc = urlencode_str(&enc, *part, partlen, TRUE, what == CURLUPART_QUERY);
+      if(uc)
+        return uc;
+      free(*part);
+      *part = Curl_dyn_ptr(&enc);
+    }
+    else if(punycode) {
+      if(!Curl_is_ASCII_name(u->host)) {
+#ifndef USE_IDN
+        return CURLUE_LACKS_IDN;
+#else
+        char *allochost;
+        CURLcode result = Curl_idn_decode(*part, &allochost);
+        if(result)
+          return (result == CURLE_OUT_OF_MEMORY) ?
+            CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
+        free(*part);
+        *part = allochost;
+#endif
+      }
+    }
+    else if(depunyfy) {
+      if(Curl_is_ASCII_name(u->host)  && !strncmp("xn--", u->host, 4)) {
+#ifndef USE_IDN
+        return CURLUE_LACKS_IDN;
+#else
+        char *allochost;
+        CURLcode result = Curl_idn_encode(*part, &allochost);
+        if(result)
+          return (result == CURLE_OUT_OF_MEMORY) ?
+            CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
+        free(*part);
+        *part = allochost;
+#endif
+      }
+    }
+
+    return CURLUE_OK;
+  }
+  else
+    return ifmissing;
+}
+
+CURLUcode curl_url_set(CURLU *u, CURLUPart what,
+                       const char *part, unsigned int flags)
+{
+  char **storep = NULL;
+  long port = 0;
+  bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0;
+  bool plusencode = FALSE;
+  bool urlskipslash = FALSE;
+  bool leadingslash = FALSE;
+  bool appendquery = FALSE;
+  bool equalsencode = FALSE;
+  size_t nalloc;
+
+  if(!u)
+    return CURLUE_BAD_HANDLE;
+  if(!part) {
+    /* setting a part to NULL clears it */
+    switch(what) {
+    case CURLUPART_URL:
+      break;
+    case CURLUPART_SCHEME:
+      storep = &u->scheme;
+      break;
+    case CURLUPART_USER:
+      storep = &u->user;
+      break;
+    case CURLUPART_PASSWORD:
+      storep = &u->password;
+      break;
+    case CURLUPART_OPTIONS:
+      storep = &u->options;
+      break;
+    case CURLUPART_HOST:
+      storep = &u->host;
+      break;
+    case CURLUPART_ZONEID:
+      storep = &u->zoneid;
+      break;
+    case CURLUPART_PORT:
+      u->portnum = 0;
+      storep = &u->port;
+      break;
+    case CURLUPART_PATH:
+      storep = &u->path;
+      break;
+    case CURLUPART_QUERY:
+      storep = &u->query;
+      break;
+    case CURLUPART_FRAGMENT:
+      storep = &u->fragment;
+      break;
+    default:
+      return CURLUE_UNKNOWN_PART;
+    }
+    if(storep && *storep) {
+      Curl_safefree(*storep);
+    }
+    else if(!storep) {
+      free_urlhandle(u);
+      memset(u, 0, sizeof(struct Curl_URL));
+    }
+    return CURLUE_OK;
+  }
+
+  nalloc = strlen(part);
+  if(nalloc > CURL_MAX_INPUT_LENGTH)
+    /* excessive input length */
+    return CURLUE_MALFORMED_INPUT;
+
+  switch(what) {
+  case CURLUPART_SCHEME: {
+    size_t plen = strlen(part);
+    const char *s = part;
+    if((plen > MAX_SCHEME_LEN) || (plen < 1))
+      /* too long or too short */
+      return CURLUE_BAD_SCHEME;
+   /* verify that it is a fine scheme */
+    if(!(flags & CURLU_NON_SUPPORT_SCHEME) && !Curl_get_scheme_handler(part))
+      return CURLUE_UNSUPPORTED_SCHEME;
+    storep = &u->scheme;
+    urlencode = FALSE; /* never */
+    if(ISALPHA(*s)) {
+      /* ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */
+      while(--plen) {
+        if(ISALNUM(*s) || (*s == '+') || (*s == '-') || (*s == '.'))
+          s++; /* fine */
+        else
+          return CURLUE_BAD_SCHEME;
+      }
+    }
+    else
+      return CURLUE_BAD_SCHEME;
+    break;
+  }
+  case CURLUPART_USER:
+    storep = &u->user;
+    break;
+  case CURLUPART_PASSWORD:
+    storep = &u->password;
+    break;
+  case CURLUPART_OPTIONS:
+    storep = &u->options;
+    break;
+  case CURLUPART_HOST:
+    storep = &u->host;
+    Curl_safefree(u->zoneid);
+    break;
+  case CURLUPART_ZONEID:
+    storep = &u->zoneid;
+    break;
+  case CURLUPART_PORT:
+  {
+    char *endp;
+    urlencode = FALSE; /* never */
+    port = strtol(part, &endp, 10);  /* Port number must be decimal */
+    if((port <= 0) || (port > 0xffff))
+      return CURLUE_BAD_PORT_NUMBER;
+    if(*endp)
+      /* weirdly provided number, not good! */
+      return CURLUE_BAD_PORT_NUMBER;
+    storep = &u->port;
+  }
+  break;
+  case CURLUPART_PATH:
+    urlskipslash = TRUE;
+    leadingslash = TRUE; /* enforce */
+    storep = &u->path;
+    break;
+  case CURLUPART_QUERY:
+    plusencode = urlencode;
+    appendquery = (flags & CURLU_APPENDQUERY)?1:0;
+    equalsencode = appendquery;
+    storep = &u->query;
+    break;
+  case CURLUPART_FRAGMENT:
+    storep = &u->fragment;
+    break;
+  case CURLUPART_URL: {
+    /*
+     * Allow a new URL to replace the existing (if any) contents.
+     *
+     * If the existing contents is enough for a URL, allow a relative URL to
+     * replace it.
+     */
+    CURLcode result;
+    CURLUcode uc;
+    char *oldurl;
+    char *redired_url;
+
+    if(!nalloc)
+      /* a blank URL is not a valid URL */
+      return CURLUE_MALFORMED_INPUT;
+
+    /* if the new thing is absolute or the old one is not
+     * (we could not get an absolute url in 'oldurl'),
+     * then replace the existing with the new. */
+    if(Curl_is_absolute_url(part, NULL, 0,
+                            flags & (CURLU_GUESS_SCHEME|
+                                     CURLU_DEFAULT_SCHEME))
+       || curl_url_get(u, CURLUPART_URL, &oldurl, flags)) {
+      return parseurl_and_replace(part, u, flags);
+    }
+
+    /* apply the relative part to create a new URL
+     * and replace the existing one with it. */
+    result = concat_url(oldurl, part, &redired_url);
+    free(oldurl);
+    if(result)
+      return cc2cu(result);
+
+    uc = parseurl_and_replace(redired_url, u, flags);
+    free(redired_url);
+    return uc;
+  }
+  default:
+    return CURLUE_UNKNOWN_PART;
+  }
+  DEBUGASSERT(storep);
+  {
+    const char *newp;
+    struct dynbuf enc;
+    Curl_dyn_init(&enc, nalloc * 3 + 1 + leadingslash);
+
+    if(leadingslash && (part[0] != '/')) {
+      CURLcode result = Curl_dyn_addn(&enc, "/", 1);
+      if(result)
+        return cc2cu(result);
+    }
+    if(urlencode) {
+      const unsigned char *i;
+
+      for(i = (const unsigned char *)part; *i; i++) {
+        CURLcode result;
+        if((*i == ' ') && plusencode) {
+          result = Curl_dyn_addn(&enc, "+", 1);
+          if(result)
+            return CURLUE_OUT_OF_MEMORY;
+        }
+        else if(ISUNRESERVED(*i) ||
+                ((*i == '/') && urlskipslash) ||
+                ((*i == '=') && equalsencode)) {
+          if((*i == '=') && equalsencode)
+            /* only skip the first equals sign */
+            equalsencode = FALSE;
+          result = Curl_dyn_addn(&enc, i, 1);
+          if(result)
+            return cc2cu(result);
+        }
+        else {
+          char out[3]={'%'};
+          out[1] = hexdigits[*i>>4];
+          out[2] = hexdigits[*i & 0xf];
+          result = Curl_dyn_addn(&enc, out, 3);
+          if(result)
+            return cc2cu(result);
+        }
+      }
+    }
+    else {
+      char *p;
+      CURLcode result = Curl_dyn_add(&enc, part);
+      if(result)
+        return cc2cu(result);
+      p = Curl_dyn_ptr(&enc);
+      while(*p) {
+        /* make sure percent encoded are lower case */
+        if((*p == '%') && ISXDIGIT(p[1]) && ISXDIGIT(p[2]) &&
+           (ISUPPER(p[1]) || ISUPPER(p[2]))) {
+          p[1] = Curl_raw_tolower(p[1]);
+          p[2] = Curl_raw_tolower(p[2]);
+          p += 3;
+        }
+        else
+          p++;
+      }
+    }
+    newp = Curl_dyn_ptr(&enc);
+
+    if(appendquery && newp) {
+      /* Append the 'newp' string onto the old query. Add a '&' separator if
+         none is present at the end of the existing query already */
+
+      size_t querylen = u->query ? strlen(u->query) : 0;
+      bool addamperand = querylen && (u->query[querylen -1] != '&');
+      if(querylen) {
+        struct dynbuf qbuf;
+        Curl_dyn_init(&qbuf, CURL_MAX_INPUT_LENGTH);
+
+        if(Curl_dyn_addn(&qbuf, u->query, querylen)) /* add original query */
+          goto nomem;
+
+        if(addamperand) {
+          if(Curl_dyn_addn(&qbuf, "&", 1))
+            goto nomem;
+        }
+        if(Curl_dyn_add(&qbuf, newp))
+          goto nomem;
+        Curl_dyn_free(&enc);
+        free(*storep);
+        *storep = Curl_dyn_ptr(&qbuf);
+        return CURLUE_OK;
+nomem:
+        Curl_dyn_free(&enc);
+        return CURLUE_OUT_OF_MEMORY;
+      }
+    }
+
+    else if(what == CURLUPART_HOST) {
+      size_t n = Curl_dyn_len(&enc);
+      if(!n && (flags & CURLU_NO_AUTHORITY)) {
+        /* Skip hostname check, it's allowed to be empty. */
+      }
+      else {
+        if(!n || hostname_check(u, (char *)newp, n)) {
+          Curl_dyn_free(&enc);
+          return CURLUE_BAD_HOSTNAME;
+        }
+      }
+    }
+
+    free(*storep);
+    *storep = (char *)newp;
+  }
+  /* set after the string, to make it not assigned if the allocation above
+     fails */
+  if(port)
+    u->portnum = port;
+  return CURLUE_OK;
+}
Index: trunk/src/libs/curl-8.7.1/lib/urldata.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/urldata.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/urldata.h	(revision 104083)
@@ -0,0 +1,1914 @@
+#ifndef HEADER_CURL_URLDATA_H
+#define HEADER_CURL_URLDATA_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* This file is for lib internal stuff */
+
+#include "curl_setup.h"
+
+#define PORT_FTP 21
+#define PORT_FTPS 990
+#define PORT_TELNET 23
+#define PORT_HTTP 80
+#define PORT_HTTPS 443
+#define PORT_DICT 2628
+#define PORT_LDAP 389
+#define PORT_LDAPS 636
+#define PORT_TFTP 69
+#define PORT_SSH 22
+#define PORT_IMAP 143
+#define PORT_IMAPS 993
+#define PORT_POP3 110
+#define PORT_POP3S 995
+#define PORT_SMB 445
+#define PORT_SMBS 445
+#define PORT_SMTP 25
+#define PORT_SMTPS 465 /* sometimes called SSMTP */
+#define PORT_RTSP 554
+#define PORT_RTMP 1935
+#define PORT_RTMPT PORT_HTTP
+#define PORT_RTMPS PORT_HTTPS
+#define PORT_GOPHER 70
+#define PORT_MQTT 1883
+
+struct curl_trc_featt;
+
+#ifdef USE_WEBSOCKETS
+/* CURLPROTO_GOPHERS (29) is the highest publicly used protocol bit number,
+ * the rest are internal information. If we use higher bits we only do this on
+ * platforms that have a >= 64 bit type and then we use such a type for the
+ * protocol fields in the protocol handler.
+ */
+#define CURLPROTO_WS     (1<<30)
+#define CURLPROTO_WSS    ((curl_prot_t)1<<31)
+#else
+#define CURLPROTO_WS 0
+#define CURLPROTO_WSS 0
+#endif
+
+/* This should be undefined once we need bit 32 or higher */
+#define PROTO_TYPE_SMALL
+
+#ifndef PROTO_TYPE_SMALL
+typedef curl_off_t curl_prot_t;
+#else
+typedef unsigned int curl_prot_t;
+#endif
+
+/* This mask is for all the old protocols that are provided and defined in the
+   public header and shall exclude protocols added since which are not exposed
+   in the API */
+#define CURLPROTO_MASK   (0x3ffffff)
+
+#define DICT_MATCH "/MATCH:"
+#define DICT_MATCH2 "/M:"
+#define DICT_MATCH3 "/FIND:"
+#define DICT_DEFINE "/DEFINE:"
+#define DICT_DEFINE2 "/D:"
+#define DICT_DEFINE3 "/LOOKUP:"
+
+#define CURL_DEFAULT_USER "anonymous"
+#define CURL_DEFAULT_PASSWORD "ftp@example.com"
+
+/* Convenience defines for checking protocols or their SSL based version. Each
+   protocol handler should only ever have a single CURLPROTO_ in its protocol
+   field. */
+#define PROTO_FAMILY_HTTP (CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_WS| \
+                           CURLPROTO_WSS)
+#define PROTO_FAMILY_FTP  (CURLPROTO_FTP|CURLPROTO_FTPS)
+#define PROTO_FAMILY_POP3 (CURLPROTO_POP3|CURLPROTO_POP3S)
+#define PROTO_FAMILY_SMB  (CURLPROTO_SMB|CURLPROTO_SMBS)
+#define PROTO_FAMILY_SMTP (CURLPROTO_SMTP|CURLPROTO_SMTPS)
+#define PROTO_FAMILY_SSH  (CURLPROTO_SCP|CURLPROTO_SFTP)
+
+#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) ||   \
+  !defined(CURL_DISABLE_POP3)
+/* these protocols support CURLOPT_DIRLISTONLY */
+#define CURL_LIST_ONLY_PROTOCOL 1
+#endif
+
+#define DEFAULT_CONNCACHE_SIZE 5
+
+/* length of longest IPv6 address string including the trailing null */
+#define MAX_IPADR_LEN sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")
+
+/* Default FTP/IMAP etc response timeout in milliseconds */
+#define RESP_TIMEOUT (120*1000)
+
+/* Max string input length is a precaution against abuse and to detect junk
+   input easier and better. */
+#define CURL_MAX_INPUT_LENGTH 8000000
+
+
+#include "cookie.h"
+#include "psl.h"
+#include "formdata.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+
+#include "timeval.h"
+
+#include <curl/curl.h>
+
+#include "http_chunks.h" /* for the structs and enum stuff */
+#include "hostip.h"
+#include "hash.h"
+#include "splay.h"
+#include "dynbuf.h"
+#include "dynhds.h"
+#include "request.h"
+
+/* return the count of bytes sent, or -1 on error */
+typedef ssize_t (Curl_send)(struct Curl_easy *data,   /* transfer */
+                            int sockindex,            /* socketindex */
+                            const void *buf,          /* data to write */
+                            size_t len,               /* max amount to write */
+                            CURLcode *err);           /* error to return */
+
+/* return the count of bytes read, or -1 on error */
+typedef ssize_t (Curl_recv)(struct Curl_easy *data,   /* transfer */
+                            int sockindex,            /* socketindex */
+                            char *buf,                /* store data here */
+                            size_t len,               /* max amount to read */
+                            CURLcode *err);           /* error to return */
+
+#ifdef USE_HYPER
+typedef CURLcode (*Curl_datastream)(struct Curl_easy *data,
+                                    struct connectdata *conn,
+                                    int *didwhat,
+                                    int select_res);
+#endif
+
+#include "mime.h"
+#include "imap.h"
+#include "pop3.h"
+#include "smtp.h"
+#include "ftp.h"
+#include "file.h"
+#include "vssh/ssh.h"
+#include "http.h"
+#include "rtsp.h"
+#include "smb.h"
+#include "mqtt.h"
+#include "ftplistparser.h"
+#include "multihandle.h"
+#include "c-hyper.h"
+#include "cf-socket.h"
+
+#ifdef HAVE_GSSAPI
+# ifdef HAVE_GSSGNU
+#  include <gss.h>
+# elif defined HAVE_GSSAPI_GSSAPI_H
+#  include <gssapi/gssapi.h>
+# else
+#  include <gssapi.h>
+# endif
+# ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
+#  include <gssapi/gssapi_generic.h>
+# endif
+#endif
+
+#ifdef USE_LIBSSH2
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+#endif /* USE_LIBSSH2 */
+
+#define READBUFFER_SIZE CURL_MAX_WRITE_SIZE
+#define READBUFFER_MAX  CURL_MAX_READ_SIZE
+#define READBUFFER_MIN  1024
+
+/* The default upload buffer size, should not be smaller than
+   CURL_MAX_WRITE_SIZE, as it needs to hold a full buffer as could be sent in
+   a write callback.
+
+   The size was 16KB for many years but was bumped to 64KB because it makes
+   libcurl able to do significantly faster uploads in some circumstances. Even
+   larger buffers can help further, but this is deemed a fair memory/speed
+   compromise. */
+#define UPLOADBUFFER_DEFAULT 65536
+#define UPLOADBUFFER_MAX (2*1024*1024)
+#define UPLOADBUFFER_MIN CURL_MAX_WRITE_SIZE
+
+#define CURLEASY_MAGIC_NUMBER 0xc0dedbadU
+#ifdef DEBUGBUILD
+/* On a debug build, we want to fail hard on easy handles that
+ * are not NULL, but no longer have the MAGIC touch. This gives
+ * us early warning on things only discovered by valgrind otherwise. */
+#define GOOD_EASY_HANDLE(x) \
+  (((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER))? TRUE: \
+  (DEBUGASSERT(!(x)), FALSE))
+#else
+#define GOOD_EASY_HANDLE(x) \
+  ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER))
+#endif
+
+#ifdef HAVE_GSSAPI
+/* Types needed for krb5-ftp connections */
+struct krb5buffer {
+  void *data;
+  size_t size;
+  size_t index;
+  BIT(eof_flag);
+};
+
+enum protection_level {
+  PROT_NONE, /* first in list */
+  PROT_CLEAR,
+  PROT_SAFE,
+  PROT_CONFIDENTIAL,
+  PROT_PRIVATE,
+  PROT_CMD,
+  PROT_LAST /* last in list */
+};
+#endif
+
+/* enum for the nonblocking SSL connection state machine */
+typedef enum {
+  ssl_connect_1,
+  ssl_connect_2,
+  ssl_connect_2_reading,
+  ssl_connect_2_writing,
+  ssl_connect_3,
+  ssl_connect_done
+} ssl_connect_state;
+
+typedef enum {
+  ssl_connection_none,
+  ssl_connection_negotiating,
+  ssl_connection_complete
+} ssl_connection_state;
+
+/* SSL backend-specific data; declared differently by each SSL backend */
+struct ssl_backend_data;
+
+typedef enum {
+  CURL_SSL_PEER_DNS,
+  CURL_SSL_PEER_IPV4,
+  CURL_SSL_PEER_IPV6
+} ssl_peer_type;
+
+struct ssl_peer {
+  char *hostname;        /* hostname for verification */
+  char *dispname;        /* display version of hostname */
+  char *sni;             /* SNI version of hostname or NULL if not usable */
+  ssl_peer_type type;    /* type of the peer information */
+};
+
+struct ssl_primary_config {
+  char *CApath;          /* certificate dir (doesn't work on windows) */
+  char *CAfile;          /* certificate to verify peer against */
+  char *issuercert;      /* optional issuer certificate filename */
+  char *clientcert;
+  char *cipher_list;     /* list of ciphers to use */
+  char *cipher_list13;   /* list of TLS 1.3 cipher suites to use */
+  char *pinned_key;
+  char *CRLfile;         /* CRL to check certificate revocation */
+  struct curl_blob *cert_blob;
+  struct curl_blob *ca_info_blob;
+  struct curl_blob *issuercert_blob;
+#ifdef USE_TLS_SRP
+  char *username; /* TLS username (for, e.g., SRP) */
+  char *password; /* TLS password (for, e.g., SRP) */
+#endif
+  char *curves;          /* list of curves to use */
+  unsigned char ssl_options;  /* the CURLOPT_SSL_OPTIONS bitmask */
+  unsigned int version_max; /* max supported version the client wants to use */
+  unsigned char version;    /* what version the client wants to use */
+  BIT(verifypeer);       /* set TRUE if this is desired */
+  BIT(verifyhost);       /* set TRUE if CN/SAN must match hostname */
+  BIT(verifystatus);     /* set TRUE if certificate status must be checked */
+  BIT(sessionid);        /* cache session IDs or not */
+};
+
+struct ssl_config_data {
+  struct ssl_primary_config primary;
+  long certverifyresult; /* result from the certificate verification */
+  curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
+  void *fsslctxp;        /* parameter for call back */
+  char *cert_type; /* format for certificate (default: PEM)*/
+  char *key; /* private key file name */
+  struct curl_blob *key_blob;
+  char *key_type; /* format for private key (default: PEM) */
+  char *key_passwd; /* plain text private key password */
+  BIT(certinfo);     /* gather lots of certificate info */
+  BIT(falsestart);
+  BIT(enable_beast); /* allow this flaw for interoperability's sake */
+  BIT(no_revoke);    /* disable SSL certificate revocation checks */
+  BIT(no_partialchain); /* don't accept partial certificate chains */
+  BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation
+                              list errors */
+  BIT(native_ca_store); /* use the native ca store of operating system */
+  BIT(auto_client_cert);   /* automatically locate and use a client
+                              certificate for authentication (Schannel) */
+};
+
+struct ssl_general_config {
+  size_t max_ssl_sessions; /* SSL session id cache size */
+  int ca_cache_timeout;  /* Certificate store cache timeout (seconds) */
+};
+
+/* information stored about one single SSL session */
+struct Curl_ssl_session {
+  char *name;       /* host name for which this ID was used */
+  char *conn_to_host; /* host name for the connection (may be NULL) */
+  const char *scheme; /* protocol scheme used */
+  void *sessionid;  /* as returned from the SSL layer */
+  size_t idsize;    /* if known, otherwise 0 */
+  long age;         /* just a number, the higher the more recent */
+  int remote_port;  /* remote port */
+  int conn_to_port; /* remote port for the connection (may be -1) */
+  struct ssl_primary_config ssl_config; /* setup for this session */
+};
+
+#ifdef USE_WINDOWS_SSPI
+#include "curl_sspi.h"
+#endif
+
+#ifndef CURL_DISABLE_DIGEST_AUTH
+/* Struct used for Digest challenge-response authentication */
+struct digestdata {
+#if defined(USE_WINDOWS_SSPI)
+  BYTE *input_token;
+  size_t input_token_len;
+  CtxtHandle *http_context;
+  /* copy of user/passwd used to make the identity for http_context.
+     either may be NULL. */
+  char *user;
+  char *passwd;
+#else
+  char *nonce;
+  char *cnonce;
+  char *realm;
+  char *opaque;
+  char *qop;
+  char *algorithm;
+  int nc; /* nonce count */
+  unsigned char algo;
+  BIT(stale); /* set true for re-negotiation */
+  BIT(userhash);
+#endif
+};
+#endif
+
+typedef enum {
+  NTLMSTATE_NONE,
+  NTLMSTATE_TYPE1,
+  NTLMSTATE_TYPE2,
+  NTLMSTATE_TYPE3,
+  NTLMSTATE_LAST
+} curlntlm;
+
+typedef enum {
+  GSS_AUTHNONE,
+  GSS_AUTHRECV,
+  GSS_AUTHSENT,
+  GSS_AUTHDONE,
+  GSS_AUTHSUCC
+} curlnegotiate;
+
+/* Struct used for GSSAPI (Kerberos V5) authentication */
+#if defined(USE_KERBEROS5)
+struct kerberos5data {
+#if defined(USE_WINDOWS_SSPI)
+  CredHandle *credentials;
+  CtxtHandle *context;
+  TCHAR *spn;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  size_t token_max;
+  BYTE *output_token;
+#else
+  gss_ctx_id_t context;
+  gss_name_t spn;
+#endif
+};
+#endif
+
+/* Struct used for SCRAM-SHA-1 authentication */
+#ifdef USE_GSASL
+#include <gsasl.h>
+struct gsasldata {
+  Gsasl *ctx;
+  Gsasl_session *client;
+};
+#endif
+
+/* Struct used for NTLM challenge-response authentication */
+#if defined(USE_NTLM)
+struct ntlmdata {
+#ifdef USE_WINDOWS_SSPI
+/* The sslContext is used for the Schannel bindings. The
+ * api is available on the Windows 7 SDK and later.
+ */
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+  CtxtHandle *sslContext;
+#endif
+  CredHandle *credentials;
+  CtxtHandle *context;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  size_t token_max;
+  BYTE *output_token;
+  BYTE *input_token;
+  size_t input_token_len;
+  TCHAR *spn;
+#else
+  unsigned int flags;
+  unsigned char nonce[8];
+  unsigned int target_info_len;
+  void *target_info; /* TargetInfo received in the ntlm type-2 message */
+
+#if defined(NTLM_WB_ENABLED)
+  /* used for communication with Samba's winbind daemon helper ntlm_auth */
+  curl_socket_t ntlm_auth_hlpr_socket;
+  pid_t ntlm_auth_hlpr_pid;
+  char *challenge; /* The received base64 encoded ntlm type-2 message */
+  char *response;  /* The generated base64 ntlm type-1/type-3 message */
+#endif
+#endif
+};
+#endif
+
+/* Struct used for Negotiate (SPNEGO) authentication */
+#ifdef USE_SPNEGO
+struct negotiatedata {
+#ifdef HAVE_GSSAPI
+  OM_uint32 status;
+  gss_ctx_id_t context;
+  gss_name_t spn;
+  gss_buffer_desc output_token;
+#else
+#ifdef USE_WINDOWS_SSPI
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+  CtxtHandle *sslContext;
+#endif
+  DWORD status;
+  CredHandle *credentials;
+  CtxtHandle *context;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  TCHAR *spn;
+  size_t token_max;
+  BYTE *output_token;
+  size_t output_token_length;
+#endif
+#endif
+  BIT(noauthpersist);
+  BIT(havenoauthpersist);
+  BIT(havenegdata);
+  BIT(havemultiplerequests);
+};
+#endif
+
+#ifdef CURL_DISABLE_PROXY
+#define CONN_IS_PROXIED(x) 0
+#else
+#define CONN_IS_PROXIED(x) x->bits.proxy
+#endif
+
+/*
+ * Boolean values that concerns this connection.
+ */
+struct ConnectBits {
+#ifndef CURL_DISABLE_PROXY
+  BIT(httpproxy);  /* if set, this transfer is done through an HTTP proxy */
+  BIT(socksproxy); /* if set, this transfer is done through a socks proxy */
+  BIT(proxy_user_passwd); /* user+password for the proxy? */
+  BIT(tunnel_proxy);  /* if CONNECT is used to "tunnel" through the proxy.
+                         This is implicit when SSL-protocols are used through
+                         proxies, but can also be enabled explicitly by
+                         apps */
+  BIT(proxy_connect_closed); /* TRUE if a proxy disconnected the connection
+                                in a CONNECT request with auth, so that
+                                libcurl should reconnect and continue. */
+  BIT(proxy); /* if set, this transfer is done through a proxy - any type */
+#endif
+  /* always modify bits.close with the connclose() and connkeep() macros! */
+  BIT(close); /* if set, we close the connection after this request */
+  BIT(reuse); /* if set, this is a reused connection */
+  BIT(altused); /* this is an alt-svc "redirect" */
+  BIT(conn_to_host); /* if set, this connection has a "connect to host"
+                        that overrides the host in the URL */
+  BIT(conn_to_port); /* if set, this connection has a "connect to port"
+                        that overrides the port in the URL (remote port) */
+  BIT(ipv6_ip); /* we communicate with a remote site specified with pure IPv6
+                   IP address */
+  BIT(ipv6);    /* we communicate with a site using an IPv6 address */
+  BIT(do_more); /* this is set TRUE if the ->curl_do_more() function is
+                   supposed to be called, after ->curl_do() */
+  BIT(protoconnstart);/* the protocol layer has STARTED its operation after
+                         the TCP layer connect */
+  BIT(retry);         /* this connection is about to get closed and then
+                         re-attempted at another connection. */
+#ifndef CURL_DISABLE_FTP
+  BIT(ftp_use_epsv);  /* As set with CURLOPT_FTP_USE_EPSV, but if we find out
+                         EPSV doesn't work we disable it for the forthcoming
+                         requests */
+  BIT(ftp_use_eprt);  /* As set with CURLOPT_FTP_USE_EPRT, but if we find out
+                         EPRT doesn't work we disable it for the forthcoming
+                         requests */
+  BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */
+  BIT(ftp_use_control_ssl); /* Enabled SSL for the control connection */
+#endif
+#ifndef CURL_DISABLE_NETRC
+  BIT(netrc);         /* name+password provided by netrc */
+#endif
+  BIT(bound); /* set true if bind() has already been done on this socket/
+                 connection */
+  BIT(multiplex); /* connection is multiplexed */
+  BIT(tcp_fastopen); /* use TCP Fast Open */
+  BIT(tls_enable_alpn); /* TLS ALPN extension? */
+#ifndef CURL_DISABLE_DOH
+  BIT(doh);
+#endif
+#ifdef USE_UNIX_SOCKETS
+  BIT(abstract_unix_socket);
+#endif
+  BIT(tls_upgraded);
+  BIT(sock_accepted); /* TRUE if the SECONDARYSOCKET was created with
+                         accept() */
+  BIT(parallel_connect); /* set TRUE when a parallel connect attempt has
+                            started (happy eyeballs) */
+};
+
+struct hostname {
+  char *rawalloc; /* allocated "raw" version of the name */
+  char *encalloc; /* allocated IDN-encoded version of the name */
+  char *name;     /* name to use internally, might be encoded, might be raw */
+  const char *dispname; /* name to display, as 'name' might be encoded */
+};
+
+/*
+ * Flags on the keepon member of the Curl_transfer_keeper
+ */
+
+#define KEEP_NONE  0
+#define KEEP_RECV  (1<<0)     /* there is or may be data to read */
+#define KEEP_SEND (1<<1)     /* there is or may be data to write */
+#define KEEP_RECV_HOLD (1<<2) /* when set, no reading should be done but there
+                                 might still be data to read */
+#define KEEP_SEND_HOLD (1<<3) /* when set, no writing should be done but there
+                                  might still be data to write */
+#define KEEP_RECV_PAUSE (1<<4) /* reading is paused */
+#define KEEP_SEND_PAUSE (1<<5) /* writing is paused */
+
+/* KEEP_SEND_TIMED is set when the transfer should attempt sending
+ * at timer (or other) events. A transfer waiting on a timer will
+  * remove KEEP_SEND to suppress POLLOUTs of the connection.
+  * Adding KEEP_SEND_TIMED will then attempt to send whenever the transfer
+  * enters the "readwrite" loop, e.g. when a timer fires.
+  * This is used in HTTP for 'Expect: 100-continue' waiting. */
+#define KEEP_SEND_TIMED (1<<6)
+
+#define KEEP_RECVBITS (KEEP_RECV | KEEP_RECV_HOLD | KEEP_RECV_PAUSE)
+#define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE)
+
+/* transfer wants to send is not PAUSE or HOLD */
+#define CURL_WANT_SEND(data) \
+  (((data)->req.keepon & KEEP_SENDBITS) == KEEP_SEND)
+/* transfer receive is not on PAUSE or HOLD */
+#define CURL_WANT_RECV(data) \
+  (((data)->req.keepon & KEEP_RECVBITS) == KEEP_RECV)
+
+#if defined(CURLRES_ASYNCH) || !defined(CURL_DISABLE_DOH)
+#define USE_CURL_ASYNC
+struct Curl_async {
+  char *hostname;
+  struct Curl_dns_entry *dns;
+  struct thread_data *tdata;
+  void *resolver; /* resolver state, if it is used in the URL state -
+                     ares_channel e.g. */
+  int port;
+  int status; /* if done is TRUE, this is the status from the callback */
+  BIT(done);  /* set TRUE when the lookup is complete */
+};
+
+#endif
+
+#define FIRSTSOCKET     0
+#define SECONDARYSOCKET 1
+
+/* Polling requested by an easy handle.
+ * `action` is CURL_POLL_IN, CURL_POLL_OUT or CURL_POLL_INOUT.
+ */
+struct easy_pollset {
+  curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
+  unsigned int num;
+  unsigned char actions[MAX_SOCKSPEREASYHANDLE];
+};
+
+enum doh_slots {
+  /* Explicit values for first two symbols so as to match hard-coded
+   * constants in existing code
+   */
+  DOH_PROBE_SLOT_IPADDR_V4 = 0, /* make 'V4' stand out for readability */
+  DOH_PROBE_SLOT_IPADDR_V6 = 1, /* 'V6' likewise */
+
+  /* Space here for (possibly build-specific) additional slot definitions */
+
+  /* for example */
+  /* #ifdef WANT_DOH_FOOBAR_TXT */
+  /*   DOH_PROBE_SLOT_FOOBAR_TXT, */
+  /* #endif */
+
+  /* AFTER all slot definitions, establish how many we have */
+  DOH_PROBE_SLOTS
+};
+
+/*
+ * Specific protocol handler.
+ */
+
+struct Curl_handler {
+  const char *scheme;        /* URL scheme name. */
+
+  /* Complement to setup_connection_internals(). This is done before the
+     transfer "owns" the connection. */
+  CURLcode (*setup_connection)(struct Curl_easy *data,
+                               struct connectdata *conn);
+
+  /* These two functions MUST be set to be protocol dependent */
+  CURLcode (*do_it)(struct Curl_easy *data, bool *done);
+  CURLcode (*done)(struct Curl_easy *, CURLcode, bool);
+
+  /* If the curl_do() function is better made in two halves, this
+   * curl_do_more() function will be called afterwards, if set. For example
+   * for doing the FTP stuff after the PASV/PORT command.
+   */
+  CURLcode (*do_more)(struct Curl_easy *, int *);
+
+  /* This function *MAY* be set to a protocol-dependent function that is run
+   * after the connect() and everything is done, as a step in the connection.
+   * The 'done' pointer points to a bool that should be set to TRUE if the
+   * function completes before return. If it doesn't complete, the caller
+   * should call the ->connecting() function until it is.
+   */
+  CURLcode (*connect_it)(struct Curl_easy *data, bool *done);
+
+  /* See above. */
+  CURLcode (*connecting)(struct Curl_easy *data, bool *done);
+  CURLcode (*doing)(struct Curl_easy *data, bool *done);
+
+  /* Called from the multi interface during the PROTOCONNECT phase, and it
+     should then return a proper fd set */
+  int (*proto_getsock)(struct Curl_easy *data,
+                       struct connectdata *conn, curl_socket_t *socks);
+
+  /* Called from the multi interface during the DOING phase, and it should
+     then return a proper fd set */
+  int (*doing_getsock)(struct Curl_easy *data,
+                       struct connectdata *conn, curl_socket_t *socks);
+
+  /* Called from the multi interface during the DO_MORE phase, and it should
+     then return a proper fd set */
+  int (*domore_getsock)(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks);
+
+  /* Called from the multi interface during the DO_DONE, PERFORM and
+     WAITPERFORM phases, and it should then return a proper fd set. Not setting
+     this will make libcurl use the generic default one. */
+  int (*perform_getsock)(struct Curl_easy *data,
+                         struct connectdata *conn, curl_socket_t *socks);
+
+  /* This function *MAY* be set to a protocol-dependent function that is run
+   * by the curl_disconnect(), as a step in the disconnection.  If the handler
+   * is called because the connection has been considered dead,
+   * dead_connection is set to TRUE. The connection is (again) associated with
+   * the transfer here.
+   */
+  CURLcode (*disconnect)(struct Curl_easy *, struct connectdata *,
+                         bool dead_connection);
+
+  /* If used, this function gets called from transfer.c:readwrite_data() to
+     allow the protocol to do extra handling in writing response to
+     the client. */
+  CURLcode (*write_resp)(struct Curl_easy *data, const char *buf, size_t blen,
+                         bool is_eos);
+
+  /* This function can perform various checks on the connection. See
+     CONNCHECK_* for more information about the checks that can be performed,
+     and CONNRESULT_* for the results that can be returned. */
+  unsigned int (*connection_check)(struct Curl_easy *data,
+                                   struct connectdata *conn,
+                                   unsigned int checks_to_perform);
+
+  /* attach() attaches this transfer to this connection */
+  void (*attach)(struct Curl_easy *data, struct connectdata *conn);
+
+  int defport;            /* Default port. */
+  curl_prot_t protocol;  /* See CURLPROTO_* - this needs to be the single
+                            specific protocol bit */
+  curl_prot_t family;    /* single bit for protocol family; basically the
+                            non-TLS name of the protocol this is */
+  unsigned int flags;     /* Extra particular characteristics, see PROTOPT_* */
+
+};
+
+#define PROTOPT_NONE 0             /* nothing extra */
+#define PROTOPT_SSL (1<<0)         /* uses SSL */
+#define PROTOPT_DUAL (1<<1)        /* this protocol uses two connections */
+#define PROTOPT_CLOSEACTION (1<<2) /* need action before socket close */
+/* some protocols will have to call the underlying functions without regard to
+   what exact state the socket signals. IE even if the socket says "readable",
+   the send function might need to be called while uploading, or vice versa.
+*/
+#define PROTOPT_DIRLOCK (1<<3)
+#define PROTOPT_NONETWORK (1<<4)   /* protocol doesn't use the network! */
+#define PROTOPT_NEEDSPWD (1<<5)    /* needs a password, and if none is set it
+                                      gets a default */
+#define PROTOPT_NOURLQUERY (1<<6)   /* protocol can't handle
+                                        url query strings (?foo=bar) ! */
+#define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per
+                                          request instead of per connection */
+#define PROTOPT_ALPN (1<<8) /* set ALPN for this */
+/* (1<<9) was PROTOPT_STREAM, now free */
+#define PROTOPT_URLOPTIONS (1<<10) /* allow options part in the userinfo field
+                                      of the URL */
+#define PROTOPT_PROXY_AS_HTTP (1<<11) /* allow this non-HTTP scheme over a
+                                         HTTP proxy as HTTP proxies may know
+                                         this protocol and act as a gateway */
+#define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */
+#define PROTOPT_USERPWDCTRL (1<<13) /* Allow "control bytes" (< 32 ascii) in
+                                       user name and password */
+#define PROTOPT_NOTCPPROXY (1<<14) /* this protocol can't proxy over TCP */
+
+#define CONNCHECK_NONE 0                 /* No checks */
+#define CONNCHECK_ISDEAD (1<<0)          /* Check if the connection is dead. */
+#define CONNCHECK_KEEPALIVE (1<<1)       /* Perform any keepalive function. */
+
+#define CONNRESULT_NONE 0                /* No extra information. */
+#define CONNRESULT_DEAD (1<<0)           /* The connection is dead. */
+
+struct ip_quadruple {
+  char remote_ip[MAX_IPADR_LEN];
+  char local_ip[MAX_IPADR_LEN];
+  int remote_port;
+  int local_port;
+};
+
+struct proxy_info {
+  struct hostname host;
+  int port;
+  unsigned char proxytype; /* curl_proxytype: what kind of proxy that is in
+                              use */
+  char *user;    /* proxy user name string, allocated */
+  char *passwd;  /* proxy password string, allocated */
+};
+
+struct ldapconninfo;
+
+#define TRNSPRT_TCP 3
+#define TRNSPRT_UDP 4
+#define TRNSPRT_QUIC 5
+#define TRNSPRT_UNIX 6
+
+/*
+ * The connectdata struct contains all fields and variables that should be
+ * unique for an entire connection.
+ */
+struct connectdata {
+  struct Curl_llist_element bundle_node; /* conncache */
+
+  curl_closesocket_callback fclosesocket; /* function closing the socket(s) */
+  void *closesocket_client;
+
+  /* This is used by the connection cache logic. If this returns TRUE, this
+     handle is still used by one or more easy handles and can only used by any
+     other easy handle without careful consideration (== only for
+     multiplexing) and it cannot be used by another multi handle! */
+#define CONN_INUSE(c) ((c)->easyq.size)
+
+  /**** Fields set when inited and not modified again */
+  curl_off_t connection_id; /* Contains a unique number to make it easier to
+                               track the connections in the log output */
+
+  /* 'dns_entry' is the particular host we use. This points to an entry in the
+     DNS cache and it will not get pruned while locked. It gets unlocked in
+     multi_done(). This entry will be NULL if the connection is reused as then
+     there is no name resolve done. */
+  struct Curl_dns_entry *dns_entry;
+
+  /* 'remote_addr' is the particular IP we connected to. it is owned, set
+   * and NULLed by the connected socket filter (if there is one). */
+  const struct Curl_sockaddr_ex *remote_addr;
+
+  struct hostname host;
+  char *hostname_resolve; /* host name to resolve to address, allocated */
+  char *secondaryhostname; /* secondary socket host name (ftp) */
+  struct hostname conn_to_host; /* the host to connect to. valid only if
+                                   bits.conn_to_host is set */
+#ifndef CURL_DISABLE_PROXY
+  struct proxy_info socks_proxy;
+  struct proxy_info http_proxy;
+#endif
+  /* 'primary' and 'secondary' get filled with IP quadruple
+     (local/remote numerical ip address and port) whenever a is *attempted*.
+     When more than one address is tried for a connection these will hold data
+     for the last attempt. When the connection is actually established
+     these are updated with data which comes directly from the socket. */
+  struct ip_quadruple primary;
+  struct ip_quadruple secondary;
+  char *user;    /* user name string, allocated */
+  char *passwd;  /* password string, allocated */
+  char *options; /* options string, allocated */
+  char *sasl_authzid;     /* authorization identity string, allocated */
+  char *oauth_bearer; /* OAUTH2 bearer, allocated */
+  struct curltime now;     /* "current" time */
+  struct curltime created; /* creation time */
+  struct curltime lastused; /* when returned to the connection cache */
+  curl_socket_t sock[2]; /* two sockets, the second is used for the data
+                            transfer when doing FTP */
+  Curl_recv *recv[2];
+  Curl_send *send[2];
+  struct Curl_cfilter *cfilter[2]; /* connection filters */
+
+  struct ssl_primary_config ssl_config;
+#ifndef CURL_DISABLE_PROXY
+  struct ssl_primary_config proxy_ssl_config;
+#endif
+  struct ConnectBits bits;    /* various state-flags for this connection */
+
+  const struct Curl_handler *handler; /* Connection's protocol handler */
+  const struct Curl_handler *given;   /* The protocol first given */
+
+  /* Protocols can use a custom keepalive mechanism to keep connections alive.
+     This allows those protocols to track the last time the keepalive mechanism
+     was used on this connection. */
+  struct curltime keepalive;
+
+  /**** curl_get() phase fields */
+
+  curl_socket_t sockfd;   /* socket to read from or CURL_SOCKET_BAD */
+  curl_socket_t writesockfd; /* socket to write to, it may very
+                                well be the same we read from.
+                                CURL_SOCKET_BAD disables */
+
+#ifdef HAVE_GSSAPI
+  BIT(sec_complete); /* if Kerberos is enabled for this connection */
+  unsigned char command_prot; /* enum protection_level */
+  unsigned char data_prot; /* enum protection_level */
+  unsigned char request_data_prot; /* enum protection_level */
+  size_t buffer_size;
+  struct krb5buffer in_buffer;
+  void *app_data;
+  const struct Curl_sec_client_mech *mech;
+  struct sockaddr_in local_addr;
+#endif
+
+#if defined(USE_KERBEROS5)    /* Consider moving some of the above GSS-API */
+  struct kerberos5data krb5;  /* variables into the structure definition, */
+#endif                        /* however, some of them are ftp specific. */
+
+  struct Curl_llist easyq;    /* List of easy handles using this connection */
+
+  /*************** Request - specific items ************/
+#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
+  CtxtHandle *sslContext;
+#endif
+
+#if defined(_WIN32) && defined(USE_WINSOCK)
+  struct curltime last_sndbuf_update;  /* last time readwrite_upload called
+                                          win_update_buffer_size */
+#endif
+
+#ifdef USE_GSASL
+  struct gsasldata gsasl;
+#endif
+
+#if defined(USE_NTLM)
+  curlntlm http_ntlm_state;
+  curlntlm proxy_ntlm_state;
+
+  struct ntlmdata ntlm;     /* NTLM differs from other authentication schemes
+                               because it authenticates connections, not
+                               single requests! */
+  struct ntlmdata proxyntlm; /* NTLM data for proxy */
+#endif
+
+#ifdef USE_SPNEGO
+  curlnegotiate http_negotiate_state;
+  curlnegotiate proxy_negotiate_state;
+
+  struct negotiatedata negotiate; /* state data for host Negotiate auth */
+  struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */
+#endif
+
+  union {
+#ifndef CURL_DISABLE_FTP
+    struct ftp_conn ftpc;
+#endif
+#ifdef USE_SSH
+    struct ssh_conn sshc;
+#endif
+#ifndef CURL_DISABLE_TFTP
+    struct tftp_state_data *tftpc;
+#endif
+#ifndef CURL_DISABLE_IMAP
+    struct imap_conn imapc;
+#endif
+#ifndef CURL_DISABLE_POP3
+    struct pop3_conn pop3c;
+#endif
+#ifndef CURL_DISABLE_SMTP
+    struct smtp_conn smtpc;
+#endif
+#ifndef CURL_DISABLE_RTSP
+    struct rtsp_conn rtspc;
+#endif
+#ifndef CURL_DISABLE_SMB
+    struct smb_conn smbc;
+#endif
+#ifdef USE_LIBRTMP
+    void *rtmp;
+#endif
+#ifdef USE_OPENLDAP
+    struct ldapconninfo *ldapc;
+#endif
+#ifndef CURL_DISABLE_MQTT
+    struct mqtt_conn mqtt;
+#endif
+#ifdef USE_WEBSOCKETS
+    struct websocket *ws;
+#endif
+    unsigned int unused:1; /* avoids empty union */
+  } proto;
+
+  struct connectbundle *bundle; /* The bundle we are member of */
+#ifdef USE_UNIX_SOCKETS
+  char *unix_domain_socket;
+#endif
+#ifdef USE_HYPER
+  /* if set, an alternative data transfer function */
+  Curl_datastream datastream;
+#endif
+  /* When this connection is created, store the conditions for the local end
+     bind. This is stored before the actual bind and before any connection is
+     made and will serve the purpose of being used for comparison reasons so
+     that subsequent bound-requested connections aren't accidentally reusing
+     wrong connections. */
+  char *localdev;
+  unsigned short localportrange;
+  int waitfor;      /* current READ/WRITE bits to wait for */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  int socks5_gssapi_enctype;
+#endif
+  /* The field below gets set in connect.c:connecthost() */
+  int remote_port; /* the remote port, not the proxy port! */
+  int conn_to_port; /* the remote port to connect to. valid only if
+                       bits.conn_to_port is set */
+#ifdef ENABLE_IPV6
+  unsigned int scope_id;  /* Scope id for IPv6 */
+#endif
+  unsigned short localport;
+  unsigned short secondary_port; /* secondary socket remote port to connect to
+                                    (ftp) */
+  unsigned char alpn; /* APLN TLS negotiated protocol, a CURL_HTTP_VERSION*
+                         value */
+#ifndef CURL_DISABLE_PROXY
+  unsigned char proxy_alpn; /* APLN of proxy tunnel, CURL_HTTP_VERSION* */
+#endif
+  unsigned char transport; /* one of the TRNSPRT_* defines */
+  unsigned char ip_version; /* copied from the Curl_easy at creation time */
+  unsigned char httpversion; /* the HTTP version*10 reported by the server */
+  unsigned char connect_only;
+  unsigned char gssapi_delegation; /* inherited from set.gssapi_delegation */
+};
+
+#ifndef CURL_DISABLE_PROXY
+#define CURL_CONN_HOST_DISPNAME(c) \
+          ((c)->bits.socksproxy ? (c)->socks_proxy.host.dispname : \
+            (c)->bits.httpproxy ? (c)->http_proxy.host.dispname : \
+              (c)->bits.conn_to_host ? (c)->conn_to_host.dispname : \
+                (c)->host.dispname)
+#else
+#define CURL_CONN_HOST_DISPNAME(c) \
+          (c)->bits.conn_to_host ? (c)->conn_to_host.dispname : \
+            (c)->host.dispname
+#endif
+
+/* The end of connectdata. */
+
+/*
+ * Struct to keep statistical and informational data.
+ * All variables in this struct must be initialized/reset in Curl_initinfo().
+ */
+struct PureInfo {
+  int httpcode;  /* Recent HTTP, FTP, RTSP or SMTP response code */
+  int httpproxycode; /* response code from proxy when received separate */
+  int httpversion; /* the http version number X.Y = X*10+Y */
+  time_t filetime; /* If requested, this is might get set. Set to -1 if the
+                      time was unretrievable. */
+  curl_off_t request_size; /* the amount of bytes sent in the request(s) */
+  unsigned long proxyauthavail; /* what proxy auth types were announced */
+  unsigned long httpauthavail;  /* what host auth types were announced */
+  long numconnects; /* how many new connection did libcurl created */
+  char *contenttype; /* the content type of the object */
+  char *wouldredirect; /* URL this would've been redirected to if asked to */
+  curl_off_t retry_after; /* info from Retry-After: header */
+  unsigned int header_size;  /* size of read header(s) in bytes */
+
+  /* PureInfo primary ip_quadruple is copied over from the connectdata
+     struct in order to allow curl_easy_getinfo() to return this information
+     even when the session handle is no longer associated with a connection,
+     and also allow curl_easy_reset() to clear this information from the
+     session handle without disturbing information which is still alive, and
+     that might be reused, in the connection cache. */
+  struct ip_quadruple primary;
+  int conn_remote_port;  /* this is the "remote port", which is the port
+                            number of the used URL, independent of proxy or
+                            not */
+  const char *conn_scheme;
+  unsigned int conn_protocol;
+  struct curl_certinfo certs; /* info about the certs. Asked for with
+                                 CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+  CURLproxycode pxcode;
+  BIT(timecond);  /* set to TRUE if the time condition didn't match, which
+                     thus made the document NOT get fetched */
+  BIT(used_proxy); /* the transfer used a proxy */
+};
+
+
+struct Progress {
+  time_t lastshow; /* time() of the last displayed progress meter or NULL to
+                      force redraw at next call */
+  curl_off_t size_dl; /* total expected size */
+  curl_off_t size_ul; /* total expected size */
+  curl_off_t downloaded; /* transferred so far */
+  curl_off_t uploaded; /* transferred so far */
+
+  curl_off_t current_speed; /* uses the currently fastest transfer */
+
+  int width; /* screen width at download start */
+  int flags; /* see progress.h */
+
+  timediff_t timespent;
+
+  curl_off_t dlspeed;
+  curl_off_t ulspeed;
+
+  timediff_t t_postqueue;
+  timediff_t t_nslookup;
+  timediff_t t_connect;
+  timediff_t t_appconnect;
+  timediff_t t_pretransfer;
+  timediff_t t_starttransfer;
+  timediff_t t_redirect;
+
+  struct curltime start;
+  struct curltime t_startsingle;
+  struct curltime t_startop;
+  struct curltime t_acceptdata;
+
+
+  /* upload speed limit */
+  struct curltime ul_limit_start;
+  curl_off_t ul_limit_size;
+  /* download speed limit */
+  struct curltime dl_limit_start;
+  curl_off_t dl_limit_size;
+
+#define CURR_TIME (5 + 1) /* 6 entries for 5 seconds */
+
+  curl_off_t speeder[ CURR_TIME ];
+  struct curltime speeder_time[ CURR_TIME ];
+  int speeder_c;
+  BIT(callback);  /* set when progress callback is used */
+  BIT(is_t_startransfer_set);
+};
+
+typedef enum {
+    RTSPREQ_NONE, /* first in list */
+    RTSPREQ_OPTIONS,
+    RTSPREQ_DESCRIBE,
+    RTSPREQ_ANNOUNCE,
+    RTSPREQ_SETUP,
+    RTSPREQ_PLAY,
+    RTSPREQ_PAUSE,
+    RTSPREQ_TEARDOWN,
+    RTSPREQ_GET_PARAMETER,
+    RTSPREQ_SET_PARAMETER,
+    RTSPREQ_RECORD,
+    RTSPREQ_RECEIVE,
+    RTSPREQ_LAST /* last in list */
+} Curl_RtspReq;
+
+struct auth {
+  unsigned long want;  /* Bitmask set to the authentication methods wanted by
+                          app (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */
+  unsigned long picked;
+  unsigned long avail; /* Bitmask for what the server reports to support for
+                          this resource */
+  BIT(done);  /* TRUE when the auth phase is done and ready to do the
+                 actual request */
+  BIT(multipass); /* TRUE if this is not yet authenticated but within the
+                     auth multipass negotiation */
+  BIT(iestyle); /* TRUE if digest should be done IE-style or FALSE if it
+                   should be RFC compliant */
+};
+
+#ifdef USE_NGHTTP2
+struct Curl_data_prio_node {
+  struct Curl_data_prio_node *next;
+  struct Curl_easy *data;
+};
+#endif
+
+/**
+ * Priority information for an easy handle in relation to others
+ * on the same connection.
+ * TODO: we need to adapt it to the new priority scheme as defined in RFC 9218
+ */
+struct Curl_data_priority {
+#ifdef USE_NGHTTP2
+  /* tree like dependencies only implemented in nghttp2 */
+  struct Curl_easy *parent;
+  struct Curl_data_prio_node *children;
+#endif
+  int weight;
+#ifdef USE_NGHTTP2
+  BIT(exclusive);
+#endif
+};
+
+/* Timers */
+typedef enum {
+  EXPIRE_100_TIMEOUT,
+  EXPIRE_ASYNC_NAME,
+  EXPIRE_CONNECTTIMEOUT,
+  EXPIRE_DNS_PER_NAME, /* family1 */
+  EXPIRE_DNS_PER_NAME2, /* family2 */
+  EXPIRE_HAPPY_EYEBALLS_DNS, /* See asyn-ares.c */
+  EXPIRE_HAPPY_EYEBALLS,
+  EXPIRE_MULTI_PENDING,
+  EXPIRE_RUN_NOW,
+  EXPIRE_SPEEDCHECK,
+  EXPIRE_TIMEOUT,
+  EXPIRE_TOOFAST,
+  EXPIRE_QUIC,
+  EXPIRE_FTP_ACCEPT,
+  EXPIRE_ALPN_EYEBALLS,
+  EXPIRE_LAST /* not an actual timer, used as a marker only */
+} expire_id;
+
+
+typedef enum {
+  TRAILERS_NONE,
+  TRAILERS_INITIALIZED,
+  TRAILERS_SENDING,
+  TRAILERS_DONE
+} trailers_state;
+
+
+/*
+ * One instance for each timeout an easy handle can set.
+ */
+struct time_node {
+  struct Curl_llist_element list;
+  struct curltime time;
+  expire_id eid;
+};
+
+/* individual pieces of the URL */
+struct urlpieces {
+  char *scheme;
+  char *hostname;
+  char *port;
+  char *user;
+  char *password;
+  char *options;
+  char *path;
+  char *query;
+};
+
+struct UrlState {
+  /* Points to the connection cache */
+  struct conncache *conn_cache;
+  /* buffers to store authentication data in, as parsed from input options */
+  struct curltime keeps_speed; /* for the progress meter really */
+
+  curl_off_t lastconnect_id; /* The last connection, -1 if undefined */
+  curl_off_t recent_conn_id; /* The most recent connection used, might no
+                              * longer exist */
+  struct dynbuf headerb; /* buffer to store headers in */
+  struct curl_slist *hstslist; /* list of HSTS files set by
+                                  curl_easy_setopt(HSTS) calls */
+  curl_off_t current_speed;  /* the ProgressShow() function sets this,
+                                bytes / second */
+
+  /* host name, port number and protocol of the first (not followed) request.
+     if set, this should be the host name that we will sent authorization to,
+     no else. Used to make Location: following not keep sending user+password.
+     This is strdup()ed data. */
+  char *first_host;
+  int first_remote_port;
+  curl_prot_t first_remote_protocol;
+
+  int retrycount; /* number of retries on a new connection */
+  struct Curl_ssl_session *session; /* array of 'max_ssl_sessions' size */
+  long sessionage;                  /* number of the most recent session */
+  int os_errno;  /* filled in with errno whenever an error occurs */
+  char *scratch; /* huge buffer[set.buffer_size*2] for upload CRLF replacing */
+  long followlocation; /* redirect counter */
+  int requests; /* request counter: redirects + authentication retakes */
+#ifdef HAVE_SIGNAL
+  /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */
+  void (*prev_signal)(int sig);
+#endif
+#ifndef CURL_DISABLE_DIGEST_AUTH
+  struct digestdata digest;      /* state data for host Digest auth */
+  struct digestdata proxydigest; /* state data for proxy Digest auth */
+#endif
+  struct auth authhost;  /* auth details for host */
+  struct auth authproxy; /* auth details for proxy */
+#ifdef USE_CURL_ASYNC
+  struct Curl_async async;  /* asynchronous name resolver data */
+#endif
+
+#if defined(USE_OPENSSL)
+  /* void instead of ENGINE to avoid bleeding OpenSSL into this header */
+  void *engine;
+#endif /* USE_OPENSSL */
+  struct curltime expiretime; /* set this with Curl_expire() only */
+  struct Curl_tree timenode; /* for the splay stuff */
+  struct Curl_llist timeoutlist; /* list of pending timeouts */
+  struct time_node expires[EXPIRE_LAST]; /* nodes for each expire type */
+
+  /* a place to store the most recently set (S)FTP entrypath */
+  char *most_recent_ftp_entrypath;
+#if !defined(_WIN32) && !defined(MSDOS) && !defined(__EMX__)
+/* do FTP line-end conversions on most platforms */
+#define CURL_DO_LINEEND_CONV
+  /* for FTP downloads: how many CRLFs did we converted to LFs? */
+  curl_off_t crlf_conversions;
+#endif
+  char *range; /* range, if used. See README for detailed specification on
+                  this syntax. */
+  curl_off_t resume_from; /* continue [ftp] transfer from here */
+
+#ifndef CURL_DISABLE_RTSP
+  /* This RTSP state information survives requests and connections */
+  long rtsp_next_client_CSeq; /* the session's next client CSeq */
+  long rtsp_next_server_CSeq; /* the session's next server CSeq */
+  long rtsp_CSeq_recv; /* most recent CSeq received */
+
+  unsigned char rtp_channel_mask[32]; /* for the correctness checking of the
+                                         interleaved data */
+#endif
+
+  curl_off_t infilesize; /* size of file to upload, -1 means unknown.
+                            Copied from set.filesize at start of operation */
+#if defined(USE_HTTP2) || defined(USE_HTTP3)
+  struct Curl_data_priority priority; /* shallow copy of data->set */
+#endif
+
+  curl_read_callback fread_func; /* read callback/function */
+  void *in;                      /* CURLOPT_READDATA */
+  CURLU *uh; /* URL handle for the current parsed URL */
+  struct urlpieces up;
+  char *url;        /* work URL, copied from UserDefined */
+  char *referer;    /* referer string */
+  struct curl_slist *resolve; /* set to point to the set.resolve list when
+                                 this should be dealt with in pretransfer */
+#ifndef CURL_DISABLE_HTTP
+  curl_mimepart *mimepost;
+#ifndef CURL_DISABLE_FORM_API
+  curl_mimepart *formp; /* storage for old API form-posting, allocated on
+                           demand */
+#endif
+  size_t trailers_bytes_sent;
+  struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
+                                 headers */
+  struct Curl_llist httphdrs; /* received headers */
+  struct curl_header headerout[2]; /* for external purposes */
+  struct Curl_header_store *prevhead; /* the latest added header */
+  trailers_state trailers_state; /* whether we are sending trailers
+                                    and what stage are we at */
+#endif
+#ifndef CURL_DISABLE_COOKIES
+  struct curl_slist *cookielist; /* list of cookie files set by
+                                    curl_easy_setopt(COOKIEFILE) calls */
+#endif
+#ifdef USE_HYPER
+  bool hconnect;  /* set if a CONNECT request */
+  CURLcode hresult; /* used to pass return codes back from hyper callbacks */
+#endif
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  struct curl_trc_feat *feat; /* opt. trace feature transfer is part of */
+#endif
+
+  /* Dynamically allocated strings, MUST be freed before this struct is
+     killed. */
+  struct dynamically_allocated_data {
+    char *proxyuserpwd;
+    char *uagent;
+    char *accept_encoding;
+    char *userpwd;
+    char *rangeline;
+    char *ref;
+    char *host;
+    char *cookiehost;
+    char *rtsp_transport;
+    char *te; /* TE: request header */
+
+    /* transfer credentials */
+    char *user;
+    char *passwd;
+    char *proxyuser;
+    char *proxypasswd;
+  } aptr;
+
+  unsigned char httpwant; /* when non-zero, a specific HTTP version requested
+                             to be used in the library's request(s) */
+  unsigned char httpversion; /* the lowest HTTP version*10 reported by any
+                                server involved in this request */
+  unsigned char httpreq; /* Curl_HttpReq; what kind of HTTP request (if any)
+                            is this */
+  unsigned char select_bits; /* != 0 -> bitmask of socket events for this
+                                 transfer overriding anything the socket may
+                                 report */
+#ifdef CURLDEBUG
+  BIT(conncache_lock);
+#endif
+  /* when curl_easy_perform() is called, the multi handle is "owned" by
+     the easy handle so curl_easy_cleanup() on such an easy handle will
+     also close the multi handle! */
+  BIT(multi_owned_by_easy);
+
+  BIT(this_is_a_follow); /* this is a followed Location: request */
+  BIT(refused_stream); /* this was refused, try again */
+  BIT(errorbuf); /* Set to TRUE if the error buffer is already filled in.
+                    This must be set to FALSE every time _easy_perform() is
+                    called. */
+  BIT(allow_port); /* Is set.use_port allowed to take effect or not. This
+                      is always set TRUE when curl_easy_perform() is called. */
+  BIT(authproblem); /* TRUE if there's some problem authenticating */
+  /* set after initial USER failure, to prevent an authentication loop */
+  BIT(wildcardmatch); /* enable wildcard matching */
+  BIT(disableexpect);    /* TRUE if Expect: is disabled due to a previous
+                            417 response */
+  BIT(use_range);
+  BIT(rangestringalloc); /* the range string is malloc()'ed */
+  BIT(done); /* set to FALSE when Curl_init_do() is called and set to TRUE
+                when multi_done() is called, to prevent multi_done() to get
+                invoked twice when the multi interface is used. */
+  BIT(previouslypending); /* this transfer WAS in the multi->pending queue */
+#ifndef CURL_DISABLE_COOKIES
+  BIT(cookie_engine);
+#endif
+  BIT(prefer_ascii);   /* ASCII rather than binary */
+#ifdef CURL_LIST_ONLY_PROTOCOL
+  BIT(list_only);      /* list directory contents */
+#endif
+  BIT(url_alloc);   /* URL string is malloc()'ed */
+  BIT(referer_alloc); /* referer string is malloc()ed */
+  BIT(wildcard_resolve); /* Set to true if any resolve change is a wildcard */
+  BIT(upload);         /* upload request */
+  BIT(internal); /* internal: true if this easy handle was created for
+                    internal use and the user does not have ownership of the
+                    handle. */
+};
+
+/*
+ * This 'UserDefined' struct must only contain data that is set once to go
+ * for many (perhaps) independent connections. Values that are generated or
+ * calculated internally for the "session handle" MUST be defined within the
+ * 'struct UrlState' instead. The only exceptions MUST note the changes in
+ * the 'DynamicStatic' struct.
+ * Character pointer fields point to dynamic storage, unless otherwise stated.
+ */
+
+struct Curl_multi;    /* declared in multihandle.c */
+
+/*
+ * This enumeration MUST not use conditional directives (#ifdefs), new
+ * null terminated strings MUST be added to the enumeration immediately
+ * before STRING_LASTZEROTERMINATED, binary fields immediately before
+ * STRING_LAST. When doing so, ensure that the packages/OS400/chkstring.c
+ * test is updated and applicable changes for EBCDIC to ASCII conversion
+ * are catered for in curl_easy_setopt_ccsid()
+ */
+enum dupstring {
+  STRING_CERT,            /* client certificate file name */
+  STRING_CERT_PROXY,      /* client certificate file name */
+  STRING_CERT_TYPE,       /* format for certificate (default: PEM)*/
+  STRING_CERT_TYPE_PROXY, /* format for certificate (default: PEM)*/
+  STRING_COOKIE,          /* HTTP cookie string to send */
+  STRING_COOKIEJAR,       /* dump all cookies to this file */
+  STRING_CUSTOMREQUEST,   /* HTTP/FTP/RTSP request/method to use */
+  STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL doesn't specify */
+  STRING_DEVICE,          /* local network interface/address to use */
+  STRING_ENCODING,        /* Accept-Encoding string */
+  STRING_FTP_ACCOUNT,     /* ftp account data */
+  STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */
+  STRING_FTPPORT,         /* port to send with the FTP PORT command */
+  STRING_KEY,             /* private key file name */
+  STRING_KEY_PROXY,       /* private key file name */
+  STRING_KEY_PASSWD,      /* plain text private key password */
+  STRING_KEY_PASSWD_PROXY, /* plain text private key password */
+  STRING_KEY_TYPE,        /* format for private key (default: PEM) */
+  STRING_KEY_TYPE_PROXY,  /* format for private key (default: PEM) */
+  STRING_KRB_LEVEL,       /* krb security level */
+  STRING_NETRC_FILE,      /* if not NULL, use this instead of trying to find
+                             $HOME/.netrc */
+  STRING_PROXY,           /* proxy to use */
+  STRING_PRE_PROXY,       /* pre socks proxy to use */
+  STRING_SET_RANGE,       /* range, if used */
+  STRING_SET_REFERER,     /* custom string for the HTTP referer field */
+  STRING_SET_URL,         /* what original URL to work on */
+  STRING_SSL_CAPATH,      /* CA directory name (doesn't work on windows) */
+  STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */
+  STRING_SSL_CAFILE,      /* certificate file to verify peer against */
+  STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */
+  STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */
+  STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */
+  STRING_SSL_CIPHER_LIST, /* list of ciphers to use */
+  STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */
+  STRING_SSL_CIPHER13_LIST, /* list of TLS 1.3 ciphers to use */
+  STRING_SSL_CIPHER13_LIST_PROXY, /* list of TLS 1.3 ciphers to use */
+  STRING_USERAGENT,       /* User-Agent string */
+  STRING_SSL_CRLFILE,     /* crl file to check certificate */
+  STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */
+  STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */
+  STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */
+  STRING_SSL_ENGINE,      /* name of ssl engine */
+  STRING_USERNAME,        /* <username>, if used */
+  STRING_PASSWORD,        /* <password>, if used */
+  STRING_OPTIONS,         /* <options>, if used */
+  STRING_PROXYUSERNAME,   /* Proxy <username>, if used */
+  STRING_PROXYPASSWORD,   /* Proxy <password>, if used */
+  STRING_NOPROXY,         /* List of hosts which should not use the proxy, if
+                             used */
+  STRING_RTSP_SESSION_ID, /* Session ID to use */
+  STRING_RTSP_STREAM_URI, /* Stream URI for this request */
+  STRING_RTSP_TRANSPORT,  /* Transport for this session */
+  STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
+  STRING_SSH_PUBLIC_KEY,  /* path to the public key file for auth */
+  STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
+  STRING_SSH_HOST_PUBLIC_KEY_SHA256, /* sha256 of host public key in base64 */
+  STRING_SSH_KNOWNHOSTS,  /* file name of knownhosts file */
+  STRING_PROXY_SERVICE_NAME, /* Proxy service name */
+  STRING_SERVICE_NAME,    /* Service name */
+  STRING_MAIL_FROM,
+  STRING_MAIL_AUTH,
+  STRING_TLSAUTH_USERNAME,  /* TLS auth <username> */
+  STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth <username> */
+  STRING_TLSAUTH_PASSWORD,  /* TLS auth <password> */
+  STRING_TLSAUTH_PASSWORD_PROXY, /* TLS auth <password> */
+  STRING_BEARER,                /* <bearer>, if used */
+  STRING_UNIX_SOCKET_PATH,      /* path to Unix socket, if used */
+  STRING_TARGET,                /* CURLOPT_REQUEST_TARGET */
+  STRING_DOH,                   /* CURLOPT_DOH_URL */
+  STRING_ALTSVC,                /* CURLOPT_ALTSVC */
+  STRING_HSTS,                  /* CURLOPT_HSTS */
+  STRING_SASL_AUTHZID,          /* CURLOPT_SASL_AUTHZID */
+  STRING_DNS_SERVERS,
+  STRING_DNS_INTERFACE,
+  STRING_DNS_LOCAL_IP4,
+  STRING_DNS_LOCAL_IP6,
+  STRING_SSL_EC_CURVES,
+  STRING_AWS_SIGV4, /* Parameters for V4 signature */
+  STRING_HAPROXY_CLIENT_IP,     /* CURLOPT_HAPROXY_CLIENT_IP */
+
+  /* -- end of null-terminated strings -- */
+
+  STRING_LASTZEROTERMINATED,
+
+  /* -- below this are pointers to binary data that cannot be strdup'ed. --- */
+
+  STRING_COPYPOSTFIELDS,  /* if POST, set the fields' values here */
+
+  STRING_LAST /* not used, just an end-of-list marker */
+};
+
+enum dupblob {
+  BLOB_CERT,
+  BLOB_CERT_PROXY,
+  BLOB_KEY,
+  BLOB_KEY_PROXY,
+  BLOB_SSL_ISSUERCERT,
+  BLOB_SSL_ISSUERCERT_PROXY,
+  BLOB_CAINFO,
+  BLOB_CAINFO_PROXY,
+  BLOB_LAST
+};
+
+/* callback that gets called when this easy handle is completed within a multi
+   handle.  Only used for internally created transfers, like for example
+   DoH. */
+typedef int (*multidone_func)(struct Curl_easy *easy, CURLcode result);
+
+struct UserDefined {
+  FILE *err;         /* the stderr user data goes here */
+  void *debugdata;   /* the data that will be passed to fdebug */
+  char *errorbuffer; /* (Static) store failure messages in here */
+  void *out;         /* CURLOPT_WRITEDATA */
+  void *in_set;      /* CURLOPT_READDATA */
+  void *writeheader; /* write the header to this if non-NULL */
+  unsigned short use_port; /* which port to use (when not using default) */
+  unsigned long httpauth;  /* kind of HTTP authentication to use (bitmask) */
+  unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */
+  long maxredirs;    /* maximum no. of http(s) redirects to follow, set to -1
+                        for infinity */
+
+  void *postfields;  /* if POST, set the fields' values here */
+  curl_seek_callback seek_func;      /* function that seeks the input */
+  curl_off_t postfieldsize; /* if POST, this might have a size to use instead
+                               of strlen(), and then the data *may* be binary
+                               (contain zero bytes) */
+#ifndef CURL_DISABLE_BINDLOCAL
+  unsigned short localport; /* local port number to bind to */
+  unsigned short localportrange; /* number of additional port numbers to test
+                                    in case the 'localport' one can't be
+                                    bind()ed */
+#endif
+  curl_write_callback fwrite_func;   /* function that stores the output */
+  curl_write_callback fwrite_header; /* function that stores headers */
+  curl_write_callback fwrite_rtp;    /* function that stores interleaved RTP */
+  curl_read_callback fread_func_set; /* function that reads the input */
+  curl_progress_callback fprogress; /* OLD and deprecated progress callback  */
+  curl_xferinfo_callback fxferinfo; /* progress callback */
+  curl_debug_callback fdebug;      /* function that write informational data */
+  curl_ioctl_callback ioctl_func;  /* function for I/O control */
+  curl_sockopt_callback fsockopt;  /* function for setting socket options */
+  void *sockopt_client; /* pointer to pass to the socket options callback */
+  curl_opensocket_callback fopensocket; /* function for checking/translating
+                                           the address and opening the
+                                           socket */
+  void *opensocket_client;
+  curl_closesocket_callback fclosesocket; /* function for closing the
+                                             socket */
+  void *closesocket_client;
+  curl_prereq_callback fprereq; /* pre-initial request callback */
+  void *prereq_userp; /* pre-initial request user data */
+
+  void *seek_client;    /* pointer to pass to the seek callback */
+#ifndef CURL_DISABLE_HSTS
+  curl_hstsread_callback hsts_read;
+  void *hsts_read_userp;
+  curl_hstswrite_callback hsts_write;
+  void *hsts_write_userp;
+#endif
+  void *progress_client; /* pointer to pass to the progress callback */
+  void *ioctl_client;   /* pointer to pass to the ioctl callback */
+  unsigned int timeout;        /* ms, 0 means no timeout */
+  unsigned int connecttimeout; /* ms, 0 means no timeout */
+  unsigned int happy_eyeballs_timeout; /* ms, 0 is a valid value */
+  unsigned int server_response_timeout; /* ms, 0 means no timeout */
+  long maxage_conn;     /* in seconds, max idle time to allow a connection that
+                           is to be reused */
+  long maxlifetime_conn; /* in seconds, max time since creation to allow a
+                            connection that is to be reused */
+#ifndef CURL_DISABLE_TFTP
+  long tftp_blksize;    /* in bytes, 0 means use default */
+#endif
+  curl_off_t filesize;  /* size of file to upload, -1 means unknown */
+  long low_speed_limit; /* bytes/second */
+  long low_speed_time;  /* number of seconds */
+  curl_off_t max_send_speed; /* high speed limit in bytes/second for upload */
+  curl_off_t max_recv_speed; /* high speed limit in bytes/second for
+                                download */
+  curl_off_t set_resume_from;  /* continue [ftp] transfer from here */
+  struct curl_slist *headers; /* linked list of extra headers */
+  struct curl_httppost *httppost;  /* linked list of old POST data */
+#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
+  curl_mimepart mimepost;  /* MIME/POST data. */
+#endif
+#ifndef CURL_DISABLE_TELNET
+  struct curl_slist *telnet_options; /* linked list of telnet options */
+#endif
+  struct curl_slist *resolve;     /* list of names to add/remove from
+                                     DNS cache */
+  struct curl_slist *connect_to; /* list of host:port mappings to override
+                                    the hostname and port to connect to */
+  time_t timevalue;       /* what time to compare with */
+  unsigned char timecondition; /* kind of time comparison: curl_TimeCond */
+  unsigned char method;   /* what kind of HTTP request: Curl_HttpReq */
+  unsigned char httpwant; /* when non-zero, a specific HTTP version requested
+                             to be used in the library's request(s) */
+  struct ssl_config_data ssl;  /* user defined SSL stuff */
+#ifndef CURL_DISABLE_PROXY
+  struct ssl_config_data proxy_ssl;  /* user defined SSL stuff for proxy */
+  struct curl_slist *proxyheaders; /* linked list of extra CONNECT headers */
+  unsigned short proxyport; /* If non-zero, use this port number by
+                               default. If the proxy string features a
+                               ":[port]" that one will override this. */
+  unsigned char proxytype; /* what kind of proxy: curl_proxytype */
+  unsigned char socks5auth;/* kind of SOCKS5 authentication to use (bitmask) */
+#endif
+  struct ssl_general_config general_ssl; /* general user defined SSL stuff */
+  int dns_cache_timeout; /* DNS cache timeout (seconds) */
+  unsigned int buffer_size;      /* size of receive buffer to use */
+  unsigned int upload_buffer_size; /* size of upload buffer to use,
+                                      keep it >= CURL_MAX_WRITE_SIZE */
+  void *private_data; /* application-private data */
+#ifndef CURL_DISABLE_HTTP
+  struct curl_slist *http200aliases; /* linked list of aliases for http200 */
+#endif
+  unsigned char ipver; /* the CURL_IPRESOLVE_* defines in the public header
+                          file 0 - whatever, 1 - v2, 2 - v6 */
+  curl_off_t max_filesize; /* Maximum file size to download */
+#ifndef CURL_DISABLE_FTP
+  unsigned char ftp_filemethod; /* how to get to a file: curl_ftpfile  */
+  unsigned char ftpsslauth; /* what AUTH XXX to try: curl_ftpauth */
+  unsigned char ftp_ccc;   /* FTP CCC options: curl_ftpccc */
+  unsigned int accepttimeout;   /* in milliseconds, 0 means no timeout */
+#endif
+#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
+  struct curl_slist *quote;     /* after connection is established */
+  struct curl_slist *postquote; /* after the transfer */
+  struct curl_slist *prequote; /* before the transfer, after type */
+  /* Despite the name, ftp_create_missing_dirs is for FTP(S) and SFTP
+     1 - create directories that don't exist
+     2 - the same but also allow MKD to fail once
+  */
+  unsigned char ftp_create_missing_dirs;
+#endif
+#ifdef USE_LIBSSH2
+  curl_sshhostkeycallback ssh_hostkeyfunc; /* hostkey check callback */
+  void *ssh_hostkeyfunc_userp;         /* custom pointer to callback */
+#endif
+#ifdef USE_SSH
+  curl_sshkeycallback ssh_keyfunc; /* key matching callback */
+  void *ssh_keyfunc_userp;         /* custom pointer to callback */
+  int ssh_auth_types;    /* allowed SSH auth types */
+  unsigned int new_directory_perms; /* when creating remote dirs */
+#endif
+#ifndef CURL_DISABLE_NETRC
+  unsigned char use_netrc;        /* enum CURL_NETRC_OPTION values  */
+#endif
+  unsigned int new_file_perms;      /* when creating remote files */
+  char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
+  struct curl_blob *blobs[BLOB_LAST];
+#ifdef ENABLE_IPV6
+  unsigned int scope_id;  /* Scope id for IPv6 */
+#endif
+  curl_prot_t allowed_protocols;
+  curl_prot_t redir_protocols;
+#ifndef CURL_DISABLE_RTSP
+  void *rtp_out;     /* write RTP to this if non-NULL */
+  /* Common RTSP header options */
+  Curl_RtspReq rtspreq; /* RTSP request type */
+#endif
+#ifndef CURL_DISABLE_FTP
+  curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer
+                                        starts */
+  curl_chunk_end_callback chunk_end; /* called after part transferring
+                                        stopped */
+  curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds
+                                    to pattern (e.g. if WILDCARDMATCH is on) */
+  void *fnmatch_data;
+  void *wildcardptr;
+#endif
+ /* GSS-API credential delegation, see the documentation of
+    CURLOPT_GSSAPI_DELEGATION */
+  unsigned char gssapi_delegation;
+
+  int tcp_keepidle;     /* seconds in idle before sending keepalive probe */
+  int tcp_keepintvl;    /* seconds between TCP keepalive probes */
+
+  long expect_100_timeout; /* in milliseconds */
+#if defined(USE_HTTP2) || defined(USE_HTTP3)
+  struct Curl_data_priority priority;
+#endif
+  curl_resolver_start_callback resolver_start; /* optional callback called
+                                                  before resolver start */
+  void *resolver_start_client; /* pointer to pass to resolver start callback */
+  long upkeep_interval_ms;      /* Time between calls for connection upkeep. */
+  multidone_func fmultidone;
+#ifndef CURL_DISABLE_DOH
+  struct Curl_easy *dohfor; /* this is a DoH request for that transfer */
+#endif
+  CURLU *uh; /* URL handle for the current parsed URL */
+#ifndef CURL_DISABLE_HTTP
+  void *trailer_data; /* pointer to pass to trailer data callback */
+  curl_trailer_callback trailer_callback; /* trailing data callback */
+#endif
+  char keep_post;     /* keep POSTs as POSTs after a 30x request; each
+                         bit represents a request, from 301 to 303 */
+#ifndef CURL_DISABLE_SMTP
+  struct curl_slist *mail_rcpt; /* linked list of mail recipients */
+  BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some
+                                recipients */
+#endif
+  unsigned int maxconnects; /* Max idle connections in the connection cache */
+  unsigned char use_ssl;   /* if AUTH TLS is to be attempted etc, for FTP or
+                              IMAP or POP3 or others! (type: curl_usessl)*/
+  unsigned char connect_only; /* make connection/request, then let
+                                 application use the socket */
+#ifndef CURL_DISABLE_MIME
+  BIT(mime_formescape);
+#endif
+  BIT(is_fread_set); /* has read callback been set to non-NULL? */
+#ifndef CURL_DISABLE_TFTP
+  BIT(tftp_no_options); /* do not send TFTP options requests */
+#endif
+  BIT(sep_headers);     /* handle host and proxy headers separately */
+#ifndef CURL_DISABLE_COOKIES
+  BIT(cookiesession);   /* new cookie session? */
+#endif
+  BIT(crlf);            /* convert crlf on ftp upload(?) */
+  BIT(ssh_compression);            /* enable SSH compression */
+
+/* Here follows boolean settings that define how to behave during
+   this session. They are STATIC, set by libcurl users or at least initially
+   and they don't change during operations. */
+  BIT(quick_exit);       /* set 1L when it is okay to leak things (like
+                            threads), as we're about to exit() anyway and
+                            don't want lengthy cleanups to delay termination,
+                            e.g. after a DNS timeout */
+  BIT(get_filetime);     /* get the time and get of the remote file */
+  BIT(tunnel_thru_httpproxy); /* use CONNECT through an HTTP proxy */
+  BIT(prefer_ascii);     /* ASCII rather than binary */
+  BIT(remote_append);    /* append, not overwrite, on upload */
+#ifdef CURL_LIST_ONLY_PROTOCOL
+  BIT(list_only);        /* list directory */
+#endif
+#ifndef CURL_DISABLE_FTP
+  BIT(ftp_use_port);     /* use the FTP PORT command */
+  BIT(ftp_use_epsv);     /* if EPSV is to be attempted or not */
+  BIT(ftp_use_eprt);     /* if EPRT is to be attempted or not */
+  BIT(ftp_use_pret);     /* if PRET is to be used before PASV or not */
+  BIT(ftp_skip_ip);      /* skip the IP address the FTP server passes on to
+                            us */
+  BIT(wildcard_enabled); /* enable wildcard matching */
+#endif
+  BIT(hide_progress);    /* don't use the progress meter */
+  BIT(http_fail_on_error);  /* fail on HTTP error codes >= 400 */
+  BIT(http_keep_sending_on_error); /* for HTTP status codes >= 300 */
+  BIT(http_follow_location); /* follow HTTP redirects */
+  BIT(http_transfer_encoding); /* request compressed HTTP transfer-encoding */
+  BIT(allow_auth_to_other_hosts);
+  BIT(include_header); /* include received protocol headers in data output */
+  BIT(http_set_referer); /* is a custom referer used */
+  BIT(http_auto_referer); /* set "correct" referer when following
+                             location: */
+  BIT(opt_no_body);    /* as set with CURLOPT_NOBODY */
+  BIT(verbose);        /* output verbosity */
+  BIT(krb);            /* Kerberos connection requested */
+  BIT(reuse_forbid);   /* forbidden to be reused, close after use */
+  BIT(reuse_fresh);    /* do not reuse an existing connection  */
+  BIT(no_signal);      /* do not use any signal/alarm handler */
+  BIT(tcp_nodelay);    /* whether to enable TCP_NODELAY or not */
+  BIT(ignorecl);       /* ignore content length */
+  BIT(http_te_skip);   /* pass the raw body data to the user, even when
+                          transfer-encoded (chunked, compressed) */
+  BIT(http_ce_skip);   /* pass the raw body data to the user, even when
+                          content-encoded (chunked, compressed) */
+  BIT(proxy_transfer_mode); /* set transfer mode (;type=<a|i>) when doing
+                               FTP via an HTTP proxy */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  BIT(socks5_gssapi_nec); /* Flag to support NEC SOCKS5 server */
+#endif
+  BIT(sasl_ir);         /* Enable/disable SASL initial response */
+  BIT(tcp_keepalive);  /* use TCP keepalives */
+  BIT(tcp_fastopen);   /* use TCP Fast Open */
+  BIT(ssl_enable_alpn);/* TLS ALPN extension? */
+  BIT(path_as_is);     /* allow dotdots? */
+  BIT(pipewait);       /* wait for multiplex status before starting a new
+                          connection */
+  BIT(suppress_connect_headers); /* suppress proxy CONNECT response headers
+                                    from user callbacks */
+  BIT(dns_shuffle_addresses); /* whether to shuffle addresses before use */
+  BIT(haproxyprotocol); /* whether to send HAProxy PROXY protocol v1
+                           header */
+  BIT(abstract_unix_socket);
+  BIT(disallow_username_in_url); /* disallow username in url */
+#ifndef CURL_DISABLE_DOH
+  BIT(doh); /* DNS-over-HTTPS enabled */
+  BIT(doh_verifypeer);     /* DoH certificate peer verification */
+  BIT(doh_verifyhost);     /* DoH certificate hostname verification */
+  BIT(doh_verifystatus);   /* DoH certificate status verification */
+#endif
+  BIT(http09_allowed); /* allow HTTP/0.9 responses */
+#ifdef USE_WEBSOCKETS
+  BIT(ws_raw_mode);
+#endif
+};
+
+#ifndef CURL_DISABLE_MIME
+#define IS_MIME_POST(a) ((a)->set.mimepost.kind != MIMEKIND_NONE)
+#else
+#define IS_MIME_POST(a) FALSE
+#endif
+
+struct Names {
+  struct Curl_hash *hostcache;
+  enum {
+    HCACHE_NONE,    /* not pointing to anything */
+    HCACHE_MULTI,   /* points to a shared one in the multi handle */
+    HCACHE_SHARED   /* points to a shared one in a shared object */
+  } hostcachetype;
+};
+
+/*
+ * The 'connectdata' struct MUST have all the connection oriented stuff as we
+ * may have several simultaneous connections and connection structs in memory.
+ *
+ * The 'struct UserDefined' must only contain data that is set once to go for
+ * many (perhaps) independent connections. Values that are generated or
+ * calculated internally for the "session handle" must be defined within the
+ * 'struct UrlState' instead.
+ */
+
+struct Curl_easy {
+  /* First a simple identifier to easier detect if a user mix up this easy
+     handle with a multi handle. Set this to CURLEASY_MAGIC_NUMBER */
+  unsigned int magic;
+  /* once an easy handle is tied to a connection cache
+     a non-negative number to distinguish this transfer from
+     other using the same cache. For easier tracking
+     in log output.
+     This may wrap around after LONG_MAX to 0 again, so it
+     has no uniqueness guarantee for very large processings. */
+  curl_off_t id;
+
+  /* first, two fields for the linked list of these */
+  struct Curl_easy *next;
+  struct Curl_easy *prev;
+
+  struct connectdata *conn;
+  struct Curl_llist_element connect_queue; /* for the pending and msgsent
+                                              lists */
+  struct Curl_llist_element conn_queue; /* list per connectdata */
+
+  CURLMstate mstate;  /* the handle's state */
+  CURLcode result;   /* previous result */
+
+  struct Curl_message msg; /* A single posted message. */
+
+  /* Array with the plain socket numbers this handle takes care of, in no
+     particular order. Note that all sockets are added to the sockhash, where
+     the state etc are also kept. This array is mostly used to detect when a
+     socket is to be removed from the hash. See singlesocket(). */
+  struct easy_pollset last_poll;
+
+  struct Names dns;
+  struct Curl_multi *multi;    /* if non-NULL, points to the multi handle
+                                  struct to which this "belongs" when used by
+                                  the multi interface */
+  struct Curl_multi *multi_easy; /* if non-NULL, points to the multi handle
+                                    struct to which this "belongs" when used
+                                    by the easy interface */
+  struct Curl_share *share;    /* Share, handles global variable mutexing */
+#ifdef USE_LIBPSL
+  struct PslCache *psl;        /* The associated PSL cache. */
+#endif
+  struct SingleRequest req;    /* Request-specific data */
+  struct UserDefined set;      /* values set by the libcurl user */
+#ifndef CURL_DISABLE_COOKIES
+  struct CookieInfo *cookies;  /* the cookies, read from files and servers.
+                                  NOTE that the 'cookie' field in the
+                                  UserDefined struct defines if the "engine"
+                                  is to be used or not. */
+#endif
+#ifndef CURL_DISABLE_HSTS
+  struct hsts *hsts;
+#endif
+#ifndef CURL_DISABLE_ALTSVC
+  struct altsvcinfo *asi;      /* the alt-svc cache */
+#endif
+  struct Progress progress;    /* for all the progress meter data */
+  struct UrlState state;       /* struct for fields used for state info and
+                                  other dynamic purposes */
+#ifndef CURL_DISABLE_FTP
+  struct WildcardData *wildcard; /* wildcard download state info */
+#endif
+  struct PureInfo info;        /* stats, reports and info data */
+  struct curl_tlssessioninfo tsi; /* Information about the TLS session, only
+                                     valid after a client has asked for it */
+#ifdef USE_HYPER
+  struct hyptransfer hyp;
+#endif
+};
+
+#define LIBCURL_NAME "libcurl"
+
+#endif /* HEADER_CURL_URLDATA_H */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/cleartext.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/cleartext.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/cleartext.c	(revision 104083)
@@ -0,0 +1,138 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC4616 PLAIN authentication
+ * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) ||       \
+  !defined(CURL_DISABLE_POP3) || \
+  (!defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP))
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#include "vauth/vauth.h"
+#include "warnless.h"
+#include "strtok.h"
+#include "sendf.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_create_plain_message()
+ *
+ * This is used to generate an already encoded PLAIN message ready
+ * for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * authzid [in]     - The authorization identity.
+ * authcid [in]     - The authentication identity.
+ * passwd  [in]     - The password.
+ * out     [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_plain_message(const char *authzid,
+                                        const char *authcid,
+                                        const char *passwd,
+                                        struct bufref *out)
+{
+  char *plainauth;
+  size_t plainlen;
+  size_t zlen;
+  size_t clen;
+  size_t plen;
+
+  zlen = (authzid == NULL ? 0 : strlen(authzid));
+  clen = strlen(authcid);
+  plen = strlen(passwd);
+
+  /* Compute binary message length. Check for overflows. */
+  if((zlen > SIZE_T_MAX/4) || (clen > SIZE_T_MAX/4) ||
+     (plen > (SIZE_T_MAX/2 - 2)))
+    return CURLE_OUT_OF_MEMORY;
+  plainlen = zlen + clen + plen + 2;
+
+  plainauth = malloc(plainlen + 1);
+  if(!plainauth)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Calculate the reply */
+  if(zlen)
+    memcpy(plainauth, authzid, zlen);
+  plainauth[zlen] = '\0';
+  memcpy(plainauth + zlen + 1, authcid, clen);
+  plainauth[zlen + clen + 1] = '\0';
+  memcpy(plainauth + zlen + clen + 2, passwd, plen);
+  plainauth[plainlen] = '\0';
+  Curl_bufref_set(out, plainauth, plainlen, curl_free);
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_create_login_message()
+ *
+ * This is used to generate an already encoded LOGIN message containing the
+ * user name or password ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * valuep  [in]     - The user name or user's password.
+ * out     [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_login_message(const char *valuep, struct bufref *out)
+{
+  Curl_bufref_set(out, valuep, strlen(valuep), NULL);
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_create_external_message()
+ *
+ * This is used to generate an already encoded EXTERNAL message containing
+ * the user name ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * user    [in]     - The user name.
+ * out     [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_external_message(const char *user,
+                                           struct bufref *out)
+{
+  /* This is the same formatting as the login message */
+  return Curl_auth_create_login_message(user, out);
+}
+
+#endif /* if no users */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/cram.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/cram.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/cram.c	(revision 104083)
@@ -0,0 +1,97 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC2195 CRAM-MD5 authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_DIGEST_AUTH
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#include "vauth/vauth.h"
+#include "curl_hmac.h"
+#include "curl_md5.h"
+#include "warnless.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+/*
+ * Curl_auth_create_cram_md5_message()
+ *
+ * This is used to generate a CRAM-MD5 response message ready for sending to
+ * the recipient.
+ *
+ * Parameters:
+ *
+ * chlg    [in]     - The challenge.
+ * userp   [in]     - The user name.
+ * passwdp [in]     - The user's password.
+ * out     [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
+                                           const char *userp,
+                                           const char *passwdp,
+                                           struct bufref *out)
+{
+  struct HMAC_context *ctxt;
+  unsigned char digest[MD5_DIGEST_LEN];
+  char *response;
+
+  /* Compute the digest using the password as the key */
+  ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
+                        (const unsigned char *) passwdp,
+                        curlx_uztoui(strlen(passwdp)));
+  if(!ctxt)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Update the digest with the given challenge */
+  if(Curl_bufref_len(chlg))
+    Curl_HMAC_update(ctxt, Curl_bufref_ptr(chlg),
+                     curlx_uztoui(Curl_bufref_len(chlg)));
+
+  /* Finalise the digest */
+  Curl_HMAC_final(ctxt, digest);
+
+  /* Generate the response */
+  response = aprintf(
+    "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+    userp, digest[0], digest[1], digest[2], digest[3], digest[4],
+    digest[5], digest[6], digest[7], digest[8], digest[9], digest[10],
+    digest[11], digest[12], digest[13], digest[14], digest[15]);
+  if(!response)
+    return CURLE_OUT_OF_MEMORY;
+
+  Curl_bufref_set(out, response, strlen(response), curl_free);
+  return CURLE_OK;
+}
+
+#endif /* !CURL_DISABLE_DIGEST_AUTH */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/digest.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/digest.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/digest.c	(revision 104083)
@@ -0,0 +1,1031 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC7616 DIGEST-SHA256, DIGEST-SHA512-256 authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_DIGEST_AUTH
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "vauth/digest.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "curl_hmac.h"
+#include "curl_md5.h"
+#include "curl_sha256.h"
+#include "curl_sha512_256.h"
+#include "vtls/vtls.h"
+#include "warnless.h"
+#include "strtok.h"
+#include "strcase.h"
+#include "curl_printf.h"
+#include "rand.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define SESSION_ALGO 1 /* for algos with this bit set */
+
+#define ALGO_MD5 0
+#define ALGO_MD5SESS (ALGO_MD5 | SESSION_ALGO)
+#define ALGO_SHA256 2
+#define ALGO_SHA256SESS (ALGO_SHA256 | SESSION_ALGO)
+#define ALGO_SHA512_256 4
+#define ALGO_SHA512_256SESS (ALGO_SHA512_256 | SESSION_ALGO)
+
+#if !defined(USE_WINDOWS_SSPI)
+#define DIGEST_QOP_VALUE_AUTH             (1 << 0)
+#define DIGEST_QOP_VALUE_AUTH_INT         (1 << 1)
+#define DIGEST_QOP_VALUE_AUTH_CONF        (1 << 2)
+
+#define DIGEST_QOP_VALUE_STRING_AUTH      "auth"
+#define DIGEST_QOP_VALUE_STRING_AUTH_INT  "auth-int"
+#define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf"
+#endif
+
+bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
+                               const char **endptr)
+{
+  int c;
+  bool starts_with_quote = FALSE;
+  bool escape = FALSE;
+
+  for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--);)
+    *value++ = *str++;
+  *value = 0;
+
+  if('=' != *str++)
+    /* eek, no match */
+    return FALSE;
+
+  if('\"' == *str) {
+    /* This starts with a quote so it must end with one as well! */
+    str++;
+    starts_with_quote = TRUE;
+  }
+
+  for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) {
+    if(!escape) {
+      switch(*str) {
+      case '\\':
+        if(starts_with_quote) {
+          /* the start of an escaped quote */
+          escape = TRUE;
+          continue;
+        }
+        break;
+
+      case ',':
+        if(!starts_with_quote) {
+          /* This signals the end of the content if we didn't get a starting
+             quote and then we do "sloppy" parsing */
+          c = 0; /* the end */
+          continue;
+        }
+        break;
+
+      case '\r':
+      case '\n':
+        /* end of string */
+        if(starts_with_quote)
+          return FALSE; /* No closing quote */
+        c = 0;
+        continue;
+
+      case '\"':
+        if(starts_with_quote) {
+          /* end of string */
+          c = 0;
+          continue;
+        }
+        else
+          return FALSE;
+      }
+    }
+
+    escape = FALSE;
+    *content++ = *str;
+  }
+  if(escape)
+    return FALSE; /* No character after backslash */
+
+  *content = 0;
+  *endptr = str;
+
+  return TRUE;
+}
+
+#if !defined(USE_WINDOWS_SSPI)
+/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string */
+static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
+                                     unsigned char *dest) /* 33 bytes */
+{
+  int i;
+  for(i = 0; i < 16; i++)
+    msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
+}
+
+/* Convert sha256 or SHA-512/256 chunk to RFC7616 -suitable ascii string */
+static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */
+                                     unsigned char *dest) /* 65 bytes */
+{
+  int i;
+  for(i = 0; i < 32; i++)
+    msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
+}
+
+/* Perform quoted-string escaping as described in RFC2616 and its errata */
+static char *auth_digest_string_quoted(const char *source)
+{
+  char *dest;
+  const char *s = source;
+  size_t n = 1; /* null terminator */
+
+  /* Calculate size needed */
+  while(*s) {
+    ++n;
+    if(*s == '"' || *s == '\\') {
+      ++n;
+    }
+    ++s;
+  }
+
+  dest = malloc(n);
+  if(dest) {
+    char *d = dest;
+    s = source;
+    while(*s) {
+      if(*s == '"' || *s == '\\') {
+        *d++ = '\\';
+      }
+      *d++ = *s++;
+    }
+    *d = '\0';
+  }
+
+  return dest;
+}
+
+/* Retrieves the value for a corresponding key from the challenge string
+ * returns TRUE if the key could be found, FALSE if it does not exists
+ */
+static bool auth_digest_get_key_value(const char *chlg,
+                                      const char *key,
+                                      char *value,
+                                      size_t max_val_len,
+                                      char end_char)
+{
+  char *find_pos;
+  size_t i;
+
+  find_pos = strstr(chlg, key);
+  if(!find_pos)
+    return FALSE;
+
+  find_pos += strlen(key);
+
+  for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i)
+    value[i] = *find_pos++;
+  value[i] = '\0';
+
+  return TRUE;
+}
+
+static CURLcode auth_digest_get_qop_values(const char *options, int *value)
+{
+  char *tmp;
+  char *token;
+  char *tok_buf = NULL;
+
+  /* Initialise the output */
+  *value = 0;
+
+  /* Tokenise the list of qop values. Use a temporary clone of the buffer since
+     strtok_r() ruins it. */
+  tmp = strdup(options);
+  if(!tmp)
+    return CURLE_OUT_OF_MEMORY;
+
+  token = strtok_r(tmp, ",", &tok_buf);
+  while(token) {
+    if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH))
+      *value |= DIGEST_QOP_VALUE_AUTH;
+    else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT))
+      *value |= DIGEST_QOP_VALUE_AUTH_INT;
+    else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF))
+      *value |= DIGEST_QOP_VALUE_AUTH_CONF;
+
+    token = strtok_r(NULL, ",", &tok_buf);
+  }
+
+  free(tmp);
+
+  return CURLE_OK;
+}
+
+/*
+ * auth_decode_digest_md5_message()
+ *
+ * This is used internally to decode an already encoded DIGEST-MD5 challenge
+ * message into the separate attributes.
+ *
+ * Parameters:
+ *
+ * chlgref [in]     - The challenge message.
+ * nonce   [in/out] - The buffer where the nonce will be stored.
+ * nlen    [in]     - The length of the nonce buffer.
+ * realm   [in/out] - The buffer where the realm will be stored.
+ * rlen    [in]     - The length of the realm buffer.
+ * alg     [in/out] - The buffer where the algorithm will be stored.
+ * alen    [in]     - The length of the algorithm buffer.
+ * qop     [in/out] - The buffer where the qop-options will be stored.
+ * qlen    [in]     - The length of the qop buffer.
+ *
+ * Returns CURLE_OK on success.
+ */
+static CURLcode auth_decode_digest_md5_message(const struct bufref *chlgref,
+                                               char *nonce, size_t nlen,
+                                               char *realm, size_t rlen,
+                                               char *alg, size_t alen,
+                                               char *qop, size_t qlen)
+{
+  const char *chlg = (const char *) Curl_bufref_ptr(chlgref);
+
+  /* Ensure we have a valid challenge message */
+  if(!Curl_bufref_len(chlgref))
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* Retrieve nonce string from the challenge */
+  if(!auth_digest_get_key_value(chlg, "nonce=\"", nonce, nlen, '\"'))
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* Retrieve realm string from the challenge */
+  if(!auth_digest_get_key_value(chlg, "realm=\"", realm, rlen, '\"')) {
+    /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
+    strcpy(realm, "");
+  }
+
+  /* Retrieve algorithm string from the challenge */
+  if(!auth_digest_get_key_value(chlg, "algorithm=", alg, alen, ','))
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* Retrieve qop-options string from the challenge */
+  if(!auth_digest_get_key_value(chlg, "qop=\"", qop, qlen, '\"'))
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_is_digest_supported()
+ *
+ * This is used to evaluate if DIGEST is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE as DIGEST as handled by libcurl.
+ */
+bool Curl_auth_is_digest_supported(void)
+{
+  return TRUE;
+}
+
+/*
+ * Curl_auth_create_digest_md5_message()
+ *
+ * This is used to generate an already encoded DIGEST-MD5 response message
+ * ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * chlg    [in]     - The challenge message.
+ * userp   [in]     - The user name.
+ * passwdp [in]     - The user's password.
+ * service [in]     - The service type such as http, smtp, pop or imap.
+ * out     [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
+                                             const struct bufref *chlg,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             const char *service,
+                                             struct bufref *out)
+{
+  size_t i;
+  struct MD5_context *ctxt;
+  char *response = NULL;
+  unsigned char digest[MD5_DIGEST_LEN];
+  char HA1_hex[2 * MD5_DIGEST_LEN + 1];
+  char HA2_hex[2 * MD5_DIGEST_LEN + 1];
+  char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];
+  char nonce[64];
+  char realm[128];
+  char algorithm[64];
+  char qop_options[64];
+  int qop_values;
+  char cnonce[33];
+  char nonceCount[] = "00000001";
+  char method[]     = "AUTHENTICATE";
+  char qop[]        = DIGEST_QOP_VALUE_STRING_AUTH;
+  char *spn         = NULL;
+
+  /* Decode the challenge message */
+  CURLcode result = auth_decode_digest_md5_message(chlg,
+                                                   nonce, sizeof(nonce),
+                                                   realm, sizeof(realm),
+                                                   algorithm,
+                                                   sizeof(algorithm),
+                                                   qop_options,
+                                                   sizeof(qop_options));
+  if(result)
+    return result;
+
+  /* We only support md5 sessions */
+  if(strcmp(algorithm, "md5-sess") != 0)
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* Get the qop-values from the qop-options */
+  result = auth_digest_get_qop_values(qop_options, &qop_values);
+  if(result)
+    return result;
+
+  /* We only support auth quality-of-protection */
+  if(!(qop_values & DIGEST_QOP_VALUE_AUTH))
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* Generate 32 random hex chars, 32 bytes + 1 null-termination */
+  result = Curl_rand_hex(data, (unsigned char *)cnonce, sizeof(cnonce));
+  if(result)
+    return result;
+
+  /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
+  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  if(!ctxt)
+    return CURLE_OUT_OF_MEMORY;
+
+  Curl_MD5_update(ctxt, (const unsigned char *) userp,
+                  curlx_uztoui(strlen(userp)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) realm,
+                  curlx_uztoui(strlen(realm)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) passwdp,
+                  curlx_uztoui(strlen(passwdp)));
+  Curl_MD5_final(ctxt, digest);
+
+  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  if(!ctxt)
+    return CURLE_OUT_OF_MEMORY;
+
+  Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN);
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) nonce,
+                  curlx_uztoui(strlen(nonce)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
+                  curlx_uztoui(strlen(cnonce)));
+  Curl_MD5_final(ctxt, digest);
+
+  /* Convert calculated 16 octet hex into 32 bytes string */
+  for(i = 0; i < MD5_DIGEST_LEN; i++)
+    msnprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
+
+  /* Generate our SPN */
+  spn = Curl_auth_build_spn(service, data->conn->host.name, NULL);
+  if(!spn)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Calculate H(A2) */
+  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  if(!ctxt) {
+    free(spn);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  Curl_MD5_update(ctxt, (const unsigned char *) method,
+                  curlx_uztoui(strlen(method)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) spn,
+                  curlx_uztoui(strlen(spn)));
+  Curl_MD5_final(ctxt, digest);
+
+  for(i = 0; i < MD5_DIGEST_LEN; i++)
+    msnprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
+
+  /* Now calculate the response hash */
+  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  if(!ctxt) {
+    free(spn);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN);
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) nonce,
+                  curlx_uztoui(strlen(nonce)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+
+  Curl_MD5_update(ctxt, (const unsigned char *) nonceCount,
+                  curlx_uztoui(strlen(nonceCount)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
+                  curlx_uztoui(strlen(cnonce)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) qop,
+                  curlx_uztoui(strlen(qop)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+
+  Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN);
+  Curl_MD5_final(ctxt, digest);
+
+  for(i = 0; i < MD5_DIGEST_LEN; i++)
+    msnprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
+
+  /* Generate the response */
+  response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\","
+                     "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s,"
+                     "qop=%s",
+                     userp, realm, nonce,
+                     cnonce, nonceCount, spn, resp_hash_hex, qop);
+  free(spn);
+  if(!response)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Return the response. */
+  Curl_bufref_set(out, response, strlen(response), curl_free);
+  return result;
+}
+
+/*
+ * Curl_auth_decode_digest_http_message()
+ *
+ * This is used to decode an HTTP DIGEST challenge message into the separate
+ * attributes.
+ *
+ * Parameters:
+ *
+ * chlg    [in]     - The challenge message.
+ * digest  [in/out] - The digest data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
+                                              struct digestdata *digest)
+{
+  bool before = FALSE; /* got a nonce before */
+  bool foundAuth = FALSE;
+  bool foundAuthInt = FALSE;
+  char *token = NULL;
+  char *tmp = NULL;
+
+  /* If we already have received a nonce, keep that in mind */
+  if(digest->nonce)
+    before = TRUE;
+
+  /* Clean up any former leftovers and initialise to defaults */
+  Curl_auth_digest_cleanup(digest);
+
+  for(;;) {
+    char value[DIGEST_MAX_VALUE_LENGTH];
+    char content[DIGEST_MAX_CONTENT_LENGTH];
+
+    /* Pass all additional spaces here */
+    while(*chlg && ISBLANK(*chlg))
+      chlg++;
+
+    /* Extract a value=content pair */
+    if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) {
+      if(strcasecompare(value, "nonce")) {
+        free(digest->nonce);
+        digest->nonce = strdup(content);
+        if(!digest->nonce)
+          return CURLE_OUT_OF_MEMORY;
+      }
+      else if(strcasecompare(value, "stale")) {
+        if(strcasecompare(content, "true")) {
+          digest->stale = TRUE;
+          digest->nc = 1; /* we make a new nonce now */
+        }
+      }
+      else if(strcasecompare(value, "realm")) {
+        free(digest->realm);
+        digest->realm = strdup(content);
+        if(!digest->realm)
+          return CURLE_OUT_OF_MEMORY;
+      }
+      else if(strcasecompare(value, "opaque")) {
+        free(digest->opaque);
+        digest->opaque = strdup(content);
+        if(!digest->opaque)
+          return CURLE_OUT_OF_MEMORY;
+      }
+      else if(strcasecompare(value, "qop")) {
+        char *tok_buf = NULL;
+        /* Tokenize the list and choose auth if possible, use a temporary
+           clone of the buffer since strtok_r() ruins it */
+        tmp = strdup(content);
+        if(!tmp)
+          return CURLE_OUT_OF_MEMORY;
+
+        token = strtok_r(tmp, ",", &tok_buf);
+        while(token) {
+          /* Pass additional spaces here */
+          while(*token && ISBLANK(*token))
+            token++;
+          if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) {
+            foundAuth = TRUE;
+          }
+          else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) {
+            foundAuthInt = TRUE;
+          }
+          token = strtok_r(NULL, ",", &tok_buf);
+        }
+
+        free(tmp);
+
+        /* Select only auth or auth-int. Otherwise, ignore */
+        if(foundAuth) {
+          free(digest->qop);
+          digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH);
+          if(!digest->qop)
+            return CURLE_OUT_OF_MEMORY;
+        }
+        else if(foundAuthInt) {
+          free(digest->qop);
+          digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT);
+          if(!digest->qop)
+            return CURLE_OUT_OF_MEMORY;
+        }
+      }
+      else if(strcasecompare(value, "algorithm")) {
+        free(digest->algorithm);
+        digest->algorithm = strdup(content);
+        if(!digest->algorithm)
+          return CURLE_OUT_OF_MEMORY;
+
+        if(strcasecompare(content, "MD5-sess"))
+          digest->algo = ALGO_MD5SESS;
+        else if(strcasecompare(content, "MD5"))
+          digest->algo = ALGO_MD5;
+        else if(strcasecompare(content, "SHA-256"))
+          digest->algo = ALGO_SHA256;
+        else if(strcasecompare(content, "SHA-256-SESS"))
+          digest->algo = ALGO_SHA256SESS;
+        else if(strcasecompare(content, "SHA-512-256")) {
+#ifdef CURL_HAVE_SHA512_256
+          digest->algo = ALGO_SHA512_256;
+#else  /* ! CURL_HAVE_SHA512_256 */
+          return CURLE_NOT_BUILT_IN;
+#endif /* ! CURL_HAVE_SHA512_256 */
+        }
+        else if(strcasecompare(content, "SHA-512-256-SESS")) {
+#ifdef CURL_HAVE_SHA512_256
+          digest->algo = ALGO_SHA512_256SESS;
+#else  /* ! CURL_HAVE_SHA512_256 */
+          return CURLE_NOT_BUILT_IN;
+#endif /* ! CURL_HAVE_SHA512_256 */
+        }
+        else
+          return CURLE_BAD_CONTENT_ENCODING;
+      }
+      else if(strcasecompare(value, "userhash")) {
+        if(strcasecompare(content, "true")) {
+          digest->userhash = TRUE;
+        }
+      }
+      else {
+        /* Unknown specifier, ignore it! */
+      }
+    }
+    else
+      break; /* We're done here */
+
+    /* Pass all additional spaces here */
+    while(*chlg && ISBLANK(*chlg))
+      chlg++;
+
+    /* Allow the list to be comma-separated */
+    if(',' == *chlg)
+      chlg++;
+  }
+
+  /* We had a nonce since before, and we got another one now without
+     'stale=true'. This means we provided bad credentials in the previous
+     request */
+  if(before && !digest->stale)
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* We got this header without a nonce, that's a bad Digest line! */
+  if(!digest->nonce)
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* "<algo>-sess" protocol versions require "auth" or "auth-int" qop */
+  if(!digest->qop && (digest->algo & SESSION_ALGO))
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  return CURLE_OK;
+}
+
+/*
+ * auth_create_digest_http_message()
+ *
+ * This is used to generate an HTTP DIGEST response message ready for sending
+ * to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * userp   [in]     - The user name.
+ * passwdp [in]     - The user's password.
+ * request [in]     - The HTTP request.
+ * uripath [in]     - The path of the HTTP uri.
+ * digest  [in/out] - The digest data struct being used and modified.
+ * outptr  [in/out] - The address where a pointer to newly allocated memory
+ *                    holding the result will be stored upon completion.
+ * outlen  [out]    - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+static CURLcode auth_create_digest_http_message(
+                  struct Curl_easy *data,
+                  const char *userp,
+                  const char *passwdp,
+                  const unsigned char *request,
+                  const unsigned char *uripath,
+                  struct digestdata *digest,
+                  char **outptr, size_t *outlen,
+                  void (*convert_to_ascii)(unsigned char *, unsigned char *),
+                  CURLcode (*hash)(unsigned char *, const unsigned char *,
+                                   const size_t))
+{
+  CURLcode result;
+  unsigned char hashbuf[32]; /* 32 bytes/256 bits */
+  unsigned char request_digest[65];
+  unsigned char ha1[65];    /* 64 digits and 1 zero byte */
+  unsigned char ha2[65];    /* 64 digits and 1 zero byte */
+  char userh[65];
+  char *cnonce = NULL;
+  size_t cnonce_sz = 0;
+  char *userp_quoted;
+  char *realm_quoted;
+  char *nonce_quoted;
+  char *response = NULL;
+  char *hashthis = NULL;
+  char *tmp = NULL;
+
+  memset(hashbuf, 0, sizeof(hashbuf));
+  if(!digest->nc)
+    digest->nc = 1;
+
+  if(!digest->cnonce) {
+    char cnoncebuf[33];
+    result = Curl_rand_hex(data, (unsigned char *)cnoncebuf,
+                           sizeof(cnoncebuf));
+    if(result)
+      return result;
+
+    result = Curl_base64_encode(cnoncebuf, strlen(cnoncebuf),
+                                &cnonce, &cnonce_sz);
+    if(result)
+      return result;
+
+    digest->cnonce = cnonce;
+  }
+
+  if(digest->userhash) {
+    hashthis = aprintf("%s:%s", userp, digest->realm ? digest->realm : "");
+    if(!hashthis)
+      return CURLE_OUT_OF_MEMORY;
+
+    result = hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
+    free(hashthis);
+    if(result)
+      return result;
+    convert_to_ascii(hashbuf, (unsigned char *)userh);
+  }
+
+  /*
+    If the algorithm is "MD5" or unspecified (which then defaults to MD5):
+
+      A1 = unq(username-value) ":" unq(realm-value) ":" passwd
+
+    If the algorithm is "MD5-sess" then:
+
+      A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd) ":"
+           unq(nonce-value) ":" unq(cnonce-value)
+  */
+
+  hashthis = aprintf("%s:%s:%s", userp, digest->realm ? digest->realm : "",
+                     passwdp);
+  if(!hashthis)
+    return CURLE_OUT_OF_MEMORY;
+
+  result = hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
+  free(hashthis);
+  if(result)
+    return result;
+  convert_to_ascii(hashbuf, ha1);
+
+  if(digest->algo & SESSION_ALGO) {
+    /* nonce and cnonce are OUTSIDE the hash */
+    tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce);
+    if(!tmp)
+      return CURLE_OUT_OF_MEMORY;
+
+    result = hash(hashbuf, (unsigned char *) tmp, strlen(tmp));
+    free(tmp);
+    if(result)
+      return result;
+    convert_to_ascii(hashbuf, ha1);
+  }
+
+  /*
+    If the "qop" directive's value is "auth" or is unspecified, then A2 is:
+
+      A2 = Method ":" digest-uri-value
+
+    If the "qop" value is "auth-int", then A2 is:
+
+      A2 = Method ":" digest-uri-value ":" H(entity-body)
+
+    (The "Method" value is the HTTP request method as specified in section
+    5.1.1 of RFC 2616)
+  */
+
+  hashthis = aprintf("%s:%s", request, uripath);
+  if(!hashthis)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
+    /* We don't support auth-int for PUT or POST */
+    char hashed[65];
+    char *hashthis2;
+
+    result = hash(hashbuf, (const unsigned char *)"", 0);
+    if(result) {
+      free(hashthis);
+      return result;
+    }
+    convert_to_ascii(hashbuf, (unsigned char *)hashed);
+
+    hashthis2 = aprintf("%s:%s", hashthis, hashed);
+    free(hashthis);
+    hashthis = hashthis2;
+  }
+
+  if(!hashthis)
+    return CURLE_OUT_OF_MEMORY;
+
+  result = hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
+  free(hashthis);
+  if(result)
+    return result;
+  convert_to_ascii(hashbuf, ha2);
+
+  if(digest->qop) {
+    hashthis = aprintf("%s:%s:%08x:%s:%s:%s", ha1, digest->nonce, digest->nc,
+                       digest->cnonce, digest->qop, ha2);
+  }
+  else {
+    hashthis = aprintf("%s:%s:%s", ha1, digest->nonce, ha2);
+  }
+
+  if(!hashthis)
+    return CURLE_OUT_OF_MEMORY;
+
+  result = hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
+  free(hashthis);
+  if(result)
+    return result;
+  convert_to_ascii(hashbuf, request_digest);
+
+  /* For test case 64 (snooped from a Mozilla 1.3a request)
+
+     Authorization: Digest username="testuser", realm="testrealm", \
+     nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
+
+     Digest parameters are all quoted strings.  Username which is provided by
+     the user will need double quotes and backslashes within it escaped.
+     realm, nonce, and opaque will need backslashes as well as they were
+     de-escaped when copied from request header.  cnonce is generated with
+     web-safe characters.  uri is already percent encoded.  nc is 8 hex
+     characters.  algorithm and qop with standard values only contain web-safe
+     characters.
+  */
+  userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp);
+  if(!userp_quoted)
+    return CURLE_OUT_OF_MEMORY;
+  if(digest->realm)
+    realm_quoted = auth_digest_string_quoted(digest->realm);
+  else {
+    realm_quoted = malloc(1);
+    if(realm_quoted)
+      realm_quoted[0] = 0;
+  }
+  if(!realm_quoted) {
+    free(userp_quoted);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  nonce_quoted = auth_digest_string_quoted(digest->nonce);
+  if(!nonce_quoted) {
+    free(realm_quoted);
+    free(userp_quoted);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(digest->qop) {
+    response = aprintf("username=\"%s\", "
+                       "realm=\"%s\", "
+                       "nonce=\"%s\", "
+                       "uri=\"%s\", "
+                       "cnonce=\"%s\", "
+                       "nc=%08x, "
+                       "qop=%s, "
+                       "response=\"%s\"",
+                       userp_quoted,
+                       realm_quoted,
+                       nonce_quoted,
+                       uripath,
+                       digest->cnonce,
+                       digest->nc,
+                       digest->qop,
+                       request_digest);
+
+    /* Increment nonce-count to use another nc value for the next request */
+    digest->nc++;
+  }
+  else {
+    response = aprintf("username=\"%s\", "
+                       "realm=\"%s\", "
+                       "nonce=\"%s\", "
+                       "uri=\"%s\", "
+                       "response=\"%s\"",
+                       userp_quoted,
+                       realm_quoted,
+                       nonce_quoted,
+                       uripath,
+                       request_digest);
+  }
+  free(nonce_quoted);
+  free(realm_quoted);
+  free(userp_quoted);
+  if(!response)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Add the optional fields */
+  if(digest->opaque) {
+    char *opaque_quoted;
+    /* Append the opaque */
+    opaque_quoted = auth_digest_string_quoted(digest->opaque);
+    if(!opaque_quoted) {
+      free(response);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    tmp = aprintf("%s, opaque=\"%s\"", response, opaque_quoted);
+    free(response);
+    free(opaque_quoted);
+    if(!tmp)
+      return CURLE_OUT_OF_MEMORY;
+
+    response = tmp;
+  }
+
+  if(digest->algorithm) {
+    /* Append the algorithm */
+    tmp = aprintf("%s, algorithm=%s", response, digest->algorithm);
+    free(response);
+    if(!tmp)
+      return CURLE_OUT_OF_MEMORY;
+
+    response = tmp;
+  }
+
+  if(digest->userhash) {
+    /* Append the userhash */
+    tmp = aprintf("%s, userhash=true", response);
+    free(response);
+    if(!tmp)
+      return CURLE_OUT_OF_MEMORY;
+
+    response = tmp;
+  }
+
+  /* Return the output */
+  *outptr = response;
+  *outlen = strlen(response);
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_create_digest_http_message()
+ *
+ * This is used to generate an HTTP DIGEST response message ready for sending
+ * to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * userp   [in]     - The user name.
+ * passwdp [in]     - The user's password.
+ * request [in]     - The HTTP request.
+ * uripath [in]     - The path of the HTTP uri.
+ * digest  [in/out] - The digest data struct being used and modified.
+ * outptr  [in/out] - The address where a pointer to newly allocated memory
+ *                    holding the result will be stored upon completion.
+ * outlen  [out]    - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
+                                              const char *userp,
+                                              const char *passwdp,
+                                              const unsigned char *request,
+                                              const unsigned char *uripath,
+                                              struct digestdata *digest,
+                                              char **outptr, size_t *outlen)
+{
+  if(digest->algo <= ALGO_MD5SESS)
+    return auth_create_digest_http_message(data, userp, passwdp,
+                                           request, uripath, digest,
+                                           outptr, outlen,
+                                           auth_digest_md5_to_ascii,
+                                           Curl_md5it);
+
+  if(digest->algo <= ALGO_SHA256SESS)
+    return auth_create_digest_http_message(data, userp, passwdp,
+                                           request, uripath, digest,
+                                           outptr, outlen,
+                                           auth_digest_sha256_to_ascii,
+                                           Curl_sha256it);
+#ifdef CURL_HAVE_SHA512_256
+  if(digest->algo <= ALGO_SHA512_256SESS)
+    return auth_create_digest_http_message(data, userp, passwdp,
+                                           request, uripath, digest,
+                                           outptr, outlen,
+                                           auth_digest_sha256_to_ascii,
+                                           Curl_sha512_256it);
+#endif /* CURL_HAVE_SHA512_256 */
+
+  /* Should be unreachable */
+  return CURLE_BAD_CONTENT_ENCODING;
+}
+
+/*
+ * Curl_auth_digest_cleanup()
+ *
+ * This is used to clean up the digest specific data.
+ *
+ * Parameters:
+ *
+ * digest    [in/out] - The digest data struct being cleaned up.
+ *
+ */
+void Curl_auth_digest_cleanup(struct digestdata *digest)
+{
+  Curl_safefree(digest->nonce);
+  Curl_safefree(digest->cnonce);
+  Curl_safefree(digest->realm);
+  Curl_safefree(digest->opaque);
+  Curl_safefree(digest->qop);
+  Curl_safefree(digest->algorithm);
+
+  digest->nc = 0;
+  digest->algo = ALGO_MD5; /* default algorithm */
+  digest->stale = FALSE; /* default means normal, not stale */
+  digest->userhash = FALSE;
+}
+#endif  /* !USE_WINDOWS_SSPI */
+
+#endif  /* !CURL_DISABLE_DIGEST_AUTH */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/digest.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/digest.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/digest.h	(revision 104083)
@@ -0,0 +1,40 @@
+#ifndef HEADER_CURL_DIGEST_H
+#define HEADER_CURL_DIGEST_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+#ifndef CURL_DISABLE_DIGEST_AUTH
+
+#define DIGEST_MAX_VALUE_LENGTH           256
+#define DIGEST_MAX_CONTENT_LENGTH         1024
+
+/* This is used to extract the realm from a challenge message */
+bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
+                               const char **endptr);
+
+#endif
+
+#endif /* HEADER_CURL_DIGEST_H */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/digest_sspi.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/digest_sspi.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/digest_sspi.c	(revision 104083)
@@ -0,0 +1,672 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC2831 DIGEST-MD5 authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_DIGEST_AUTH)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "vauth/digest.h"
+#include "urldata.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+#include "strdup.h"
+#include "strcase.h"
+#include "strerror.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+* Curl_auth_is_digest_supported()
+*
+* This is used to evaluate if DIGEST is supported.
+*
+* Parameters: None
+*
+* Returns TRUE if DIGEST is supported by Windows SSPI.
+*/
+bool Curl_auth_is_digest_supported(void)
+{
+  PSecPkgInfo SecurityPackage;
+  SECURITY_STATUS status;
+
+  /* Query the security package for Digest */
+  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
+                                              &SecurityPackage);
+
+  /* Release the package buffer as it is not required anymore */
+  if(status == SEC_E_OK) {
+    s_pSecFn->FreeContextBuffer(SecurityPackage);
+  }
+
+  return (status == SEC_E_OK ? TRUE : FALSE);
+}
+
+/*
+ * Curl_auth_create_digest_md5_message()
+ *
+ * This is used to generate an already encoded DIGEST-MD5 response message
+ * ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * chlg    [in]     - The challenge message.
+ * userp   [in]     - The user name in the format User or Domain\User.
+ * passwdp [in]     - The user's password.
+ * service [in]     - The service type such as http, smtp, pop or imap.
+ * out     [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
+                                             const struct bufref *chlg,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             const char *service,
+                                             struct bufref *out)
+{
+  CURLcode result = CURLE_OK;
+  TCHAR *spn = NULL;
+  size_t token_max = 0;
+  unsigned char *output_token = NULL;
+  CredHandle credentials;
+  CtxtHandle context;
+  PSecPkgInfo SecurityPackage;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  SecBuffer chlg_buf;
+  SecBuffer resp_buf;
+  SecBufferDesc chlg_desc;
+  SecBufferDesc resp_desc;
+  SECURITY_STATUS status;
+  unsigned long attrs;
+  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+  /* Ensure we have a valid challenge message */
+  if(!Curl_bufref_len(chlg)) {
+    infof(data, "DIGEST-MD5 handshake failure (empty challenge message)");
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Query the security package for DigestSSP */
+  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
+                                              &SecurityPackage);
+  if(status != SEC_E_OK) {
+    failf(data, "SSPI: couldn't get auth info");
+    return CURLE_AUTH_ERROR;
+  }
+
+  token_max = SecurityPackage->cbMaxToken;
+
+  /* Release the package buffer as it is not required anymore */
+  s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+  /* Allocate our response buffer */
+  output_token = malloc(token_max);
+  if(!output_token)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Generate our SPN */
+  spn = Curl_auth_build_spn(service, data->conn->host.name, NULL);
+  if(!spn) {
+    free(output_token);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(userp && *userp) {
+    /* Populate our identity structure */
+    result = Curl_create_sspi_identity(userp, passwdp, &identity);
+    if(result) {
+      free(spn);
+      free(output_token);
+      return result;
+    }
+
+    /* Allow proper cleanup of the identity structure */
+    p_identity = &identity;
+  }
+  else
+    /* Use the current Windows user */
+    p_identity = NULL;
+
+  /* Acquire our credentials handle */
+  status = s_pSecFn->AcquireCredentialsHandle(NULL,
+                                              (TCHAR *) TEXT(SP_NAME_DIGEST),
+                                              SECPKG_CRED_OUTBOUND, NULL,
+                                              p_identity, NULL, NULL,
+                                              &credentials, &expiry);
+
+  if(status != SEC_E_OK) {
+    Curl_sspi_free_identity(p_identity);
+    free(spn);
+    free(output_token);
+    return CURLE_LOGIN_DENIED;
+  }
+
+  /* Setup the challenge "input" security buffer */
+  chlg_desc.ulVersion = SECBUFFER_VERSION;
+  chlg_desc.cBuffers  = 1;
+  chlg_desc.pBuffers  = &chlg_buf;
+  chlg_buf.BufferType = SECBUFFER_TOKEN;
+  chlg_buf.pvBuffer   = (void *) Curl_bufref_ptr(chlg);
+  chlg_buf.cbBuffer   = curlx_uztoul(Curl_bufref_len(chlg));
+
+  /* Setup the response "output" security buffer */
+  resp_desc.ulVersion = SECBUFFER_VERSION;
+  resp_desc.cBuffers  = 1;
+  resp_desc.pBuffers  = &resp_buf;
+  resp_buf.BufferType = SECBUFFER_TOKEN;
+  resp_buf.pvBuffer   = output_token;
+  resp_buf.cbBuffer   = curlx_uztoul(token_max);
+
+  /* Generate our response message */
+  status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn,
+                                               0, 0, 0, &chlg_desc, 0,
+                                               &context, &resp_desc, &attrs,
+                                               &expiry);
+
+  if(status == SEC_I_COMPLETE_NEEDED ||
+     status == SEC_I_COMPLETE_AND_CONTINUE)
+    s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
+  else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+    char buffer[STRERROR_LEN];
+#endif
+
+    s_pSecFn->FreeCredentialsHandle(&credentials);
+    Curl_sspi_free_identity(p_identity);
+    free(spn);
+    free(output_token);
+
+    if(status == SEC_E_INSUFFICIENT_MEMORY)
+      return CURLE_OUT_OF_MEMORY;
+
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+    infof(data, "schannel: InitializeSecurityContext failed: %s",
+          Curl_sspi_strerror(status, buffer, sizeof(buffer)));
+#endif
+
+    return CURLE_AUTH_ERROR;
+  }
+
+  /* Return the response. */
+  Curl_bufref_set(out, output_token, resp_buf.cbBuffer, curl_free);
+
+  /* Free our handles */
+  s_pSecFn->DeleteSecurityContext(&context);
+  s_pSecFn->FreeCredentialsHandle(&credentials);
+
+  /* Free the identity structure */
+  Curl_sspi_free_identity(p_identity);
+
+  /* Free the SPN */
+  free(spn);
+
+  return result;
+}
+
+/*
+ * Curl_override_sspi_http_realm()
+ *
+ * This is used to populate the domain in a SSPI identity structure
+ * The realm is extracted from the challenge message and used as the
+ * domain if it is not already explicitly set.
+ *
+ * Parameters:
+ *
+ * chlg     [in]     - The challenge message.
+ * identity [in/out] - The identity structure.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_override_sspi_http_realm(const char *chlg,
+                                       SEC_WINNT_AUTH_IDENTITY *identity)
+{
+  xcharp_u domain, dup_domain;
+
+  /* If domain is blank or unset, check challenge message for realm */
+  if(!identity->Domain || !identity->DomainLength) {
+    for(;;) {
+      char value[DIGEST_MAX_VALUE_LENGTH];
+      char content[DIGEST_MAX_CONTENT_LENGTH];
+
+      /* Pass all additional spaces here */
+      while(*chlg && ISBLANK(*chlg))
+        chlg++;
+
+      /* Extract a value=content pair */
+      if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) {
+        if(strcasecompare(value, "realm")) {
+
+          /* Setup identity's domain and length */
+          domain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *) content);
+          if(!domain.tchar_ptr)
+            return CURLE_OUT_OF_MEMORY;
+
+          dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr);
+          if(!dup_domain.tchar_ptr) {
+            curlx_unicodefree(domain.tchar_ptr);
+            return CURLE_OUT_OF_MEMORY;
+          }
+
+          free(identity->Domain);
+          identity->Domain = dup_domain.tbyte_ptr;
+          identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr));
+          dup_domain.tchar_ptr = NULL;
+
+          curlx_unicodefree(domain.tchar_ptr);
+        }
+        else {
+          /* Unknown specifier, ignore it! */
+        }
+      }
+      else
+        break; /* We're done here */
+
+      /* Pass all additional spaces here */
+      while(*chlg && ISBLANK(*chlg))
+        chlg++;
+
+      /* Allow the list to be comma-separated */
+      if(',' == *chlg)
+        chlg++;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_decode_digest_http_message()
+ *
+ * This is used to decode an HTTP DIGEST challenge message into the separate
+ * attributes.
+ *
+ * Parameters:
+ *
+ * chlg    [in]     - The challenge message.
+ * digest  [in/out] - The digest data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
+                                              struct digestdata *digest)
+{
+  size_t chlglen = strlen(chlg);
+
+  /* We had an input token before so if there's another one now that means we
+     provided bad credentials in the previous request or it's stale. */
+  if(digest->input_token) {
+    bool stale = false;
+    const char *p = chlg;
+
+    /* Check for the 'stale' directive */
+    for(;;) {
+      char value[DIGEST_MAX_VALUE_LENGTH];
+      char content[DIGEST_MAX_CONTENT_LENGTH];
+
+      while(*p && ISBLANK(*p))
+        p++;
+
+      if(!Curl_auth_digest_get_pair(p, value, content, &p))
+        break;
+
+      if(strcasecompare(value, "stale") &&
+         strcasecompare(content, "true")) {
+        stale = true;
+        break;
+      }
+
+      while(*p && ISBLANK(*p))
+        p++;
+
+      if(',' == *p)
+        p++;
+    }
+
+    if(stale)
+      Curl_auth_digest_cleanup(digest);
+    else
+      return CURLE_LOGIN_DENIED;
+  }
+
+  /* Store the challenge for use later */
+  digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen + 1);
+  if(!digest->input_token)
+    return CURLE_OUT_OF_MEMORY;
+
+  digest->input_token_len = chlglen;
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_create_digest_http_message()
+ *
+ * This is used to generate an HTTP DIGEST response message ready for sending
+ * to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * userp   [in]     - The user name in the format User or Domain\User.
+ * passwdp [in]     - The user's password.
+ * request [in]     - The HTTP request.
+ * uripath [in]     - The path of the HTTP uri.
+ * digest  [in/out] - The digest data struct being used and modified.
+ * outptr  [in/out] - The address where a pointer to newly allocated memory
+ *                    holding the result will be stored upon completion.
+ * outlen  [out]    - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
+                                              const char *userp,
+                                              const char *passwdp,
+                                              const unsigned char *request,
+                                              const unsigned char *uripath,
+                                              struct digestdata *digest,
+                                              char **outptr, size_t *outlen)
+{
+  size_t token_max;
+  char *resp;
+  BYTE *output_token;
+  size_t output_token_len = 0;
+  PSecPkgInfo SecurityPackage;
+  SecBuffer chlg_buf[5];
+  SecBufferDesc chlg_desc;
+  SECURITY_STATUS status;
+
+  (void) data;
+
+  /* Query the security package for DigestSSP */
+  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
+                                              &SecurityPackage);
+  if(status != SEC_E_OK) {
+    failf(data, "SSPI: couldn't get auth info");
+    return CURLE_AUTH_ERROR;
+  }
+
+  token_max = SecurityPackage->cbMaxToken;
+
+  /* Release the package buffer as it is not required anymore */
+  s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+  /* Allocate the output buffer according to the max token size as indicated
+     by the security package */
+  output_token = malloc(token_max);
+  if(!output_token) {
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* If the user/passwd that was used to make the identity for http_context
+     has changed then delete that context. */
+  if((userp && !digest->user) || (!userp && digest->user) ||
+     (passwdp && !digest->passwd) || (!passwdp && digest->passwd) ||
+     (userp && digest->user && Curl_timestrcmp(userp, digest->user)) ||
+     (passwdp && digest->passwd && Curl_timestrcmp(passwdp, digest->passwd))) {
+    if(digest->http_context) {
+      s_pSecFn->DeleteSecurityContext(digest->http_context);
+      Curl_safefree(digest->http_context);
+    }
+    Curl_safefree(digest->user);
+    Curl_safefree(digest->passwd);
+  }
+
+  if(digest->http_context) {
+    chlg_desc.ulVersion    = SECBUFFER_VERSION;
+    chlg_desc.cBuffers     = 5;
+    chlg_desc.pBuffers     = chlg_buf;
+    chlg_buf[0].BufferType = SECBUFFER_TOKEN;
+    chlg_buf[0].pvBuffer   = NULL;
+    chlg_buf[0].cbBuffer   = 0;
+    chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
+    chlg_buf[1].pvBuffer   = (void *) request;
+    chlg_buf[1].cbBuffer   = curlx_uztoul(strlen((const char *) request));
+    chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
+    chlg_buf[2].pvBuffer   = (void *) uripath;
+    chlg_buf[2].cbBuffer   = curlx_uztoul(strlen((const char *) uripath));
+    chlg_buf[3].BufferType = SECBUFFER_PKG_PARAMS;
+    chlg_buf[3].pvBuffer   = NULL;
+    chlg_buf[3].cbBuffer   = 0;
+    chlg_buf[4].BufferType = SECBUFFER_PADDING;
+    chlg_buf[4].pvBuffer   = output_token;
+    chlg_buf[4].cbBuffer   = curlx_uztoul(token_max);
+
+    status = s_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc, 0);
+    if(status == SEC_E_OK)
+      output_token_len = chlg_buf[4].cbBuffer;
+    else { /* delete the context so a new one can be made */
+      infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx",
+            (long)status);
+      s_pSecFn->DeleteSecurityContext(digest->http_context);
+      Curl_safefree(digest->http_context);
+    }
+  }
+
+  if(!digest->http_context) {
+    CredHandle credentials;
+    SEC_WINNT_AUTH_IDENTITY identity;
+    SEC_WINNT_AUTH_IDENTITY *p_identity;
+    SecBuffer resp_buf;
+    SecBufferDesc resp_desc;
+    unsigned long attrs;
+    TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+    TCHAR *spn;
+
+    /* free the copy of user/passwd used to make the previous identity */
+    Curl_safefree(digest->user);
+    Curl_safefree(digest->passwd);
+
+    if(userp && *userp) {
+      /* Populate our identity structure */
+      if(Curl_create_sspi_identity(userp, passwdp, &identity)) {
+        free(output_token);
+        return CURLE_OUT_OF_MEMORY;
+      }
+
+      /* Populate our identity domain */
+      if(Curl_override_sspi_http_realm((const char *) digest->input_token,
+                                       &identity)) {
+        free(output_token);
+        return CURLE_OUT_OF_MEMORY;
+      }
+
+      /* Allow proper cleanup of the identity structure */
+      p_identity = &identity;
+    }
+    else
+      /* Use the current Windows user */
+      p_identity = NULL;
+
+    if(userp) {
+      digest->user = strdup(userp);
+
+      if(!digest->user) {
+        free(output_token);
+        return CURLE_OUT_OF_MEMORY;
+      }
+    }
+
+    if(passwdp) {
+      digest->passwd = strdup(passwdp);
+
+      if(!digest->passwd) {
+        free(output_token);
+        Curl_safefree(digest->user);
+        return CURLE_OUT_OF_MEMORY;
+      }
+    }
+
+    /* Acquire our credentials handle */
+    status = s_pSecFn->AcquireCredentialsHandle(NULL,
+                                                (TCHAR *) TEXT(SP_NAME_DIGEST),
+                                                SECPKG_CRED_OUTBOUND, NULL,
+                                                p_identity, NULL, NULL,
+                                                &credentials, &expiry);
+    if(status != SEC_E_OK) {
+      Curl_sspi_free_identity(p_identity);
+      free(output_token);
+
+      return CURLE_LOGIN_DENIED;
+    }
+
+    /* Setup the challenge "input" security buffer if present */
+    chlg_desc.ulVersion    = SECBUFFER_VERSION;
+    chlg_desc.cBuffers     = 3;
+    chlg_desc.pBuffers     = chlg_buf;
+    chlg_buf[0].BufferType = SECBUFFER_TOKEN;
+    chlg_buf[0].pvBuffer   = digest->input_token;
+    chlg_buf[0].cbBuffer   = curlx_uztoul(digest->input_token_len);
+    chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
+    chlg_buf[1].pvBuffer   = (void *) request;
+    chlg_buf[1].cbBuffer   = curlx_uztoul(strlen((const char *) request));
+    chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
+    chlg_buf[2].pvBuffer   = NULL;
+    chlg_buf[2].cbBuffer   = 0;
+
+    /* Setup the response "output" security buffer */
+    resp_desc.ulVersion = SECBUFFER_VERSION;
+    resp_desc.cBuffers  = 1;
+    resp_desc.pBuffers  = &resp_buf;
+    resp_buf.BufferType = SECBUFFER_TOKEN;
+    resp_buf.pvBuffer   = output_token;
+    resp_buf.cbBuffer   = curlx_uztoul(token_max);
+
+    spn = curlx_convert_UTF8_to_tchar((char *) uripath);
+    if(!spn) {
+      s_pSecFn->FreeCredentialsHandle(&credentials);
+
+      Curl_sspi_free_identity(p_identity);
+      free(output_token);
+
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    /* Allocate our new context handle */
+    digest->http_context = calloc(1, sizeof(CtxtHandle));
+    if(!digest->http_context)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* Generate our response message */
+    status = s_pSecFn->InitializeSecurityContext(&credentials, NULL,
+                                                 spn,
+                                                 ISC_REQ_USE_HTTP_STYLE, 0, 0,
+                                                 &chlg_desc, 0,
+                                                 digest->http_context,
+                                                 &resp_desc, &attrs, &expiry);
+    curlx_unicodefree(spn);
+
+    if(status == SEC_I_COMPLETE_NEEDED ||
+       status == SEC_I_COMPLETE_AND_CONTINUE)
+      s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
+    else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+      char buffer[STRERROR_LEN];
+#endif
+
+      s_pSecFn->FreeCredentialsHandle(&credentials);
+
+      Curl_sspi_free_identity(p_identity);
+      free(output_token);
+
+      Curl_safefree(digest->http_context);
+
+      if(status == SEC_E_INSUFFICIENT_MEMORY)
+        return CURLE_OUT_OF_MEMORY;
+
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+      infof(data, "schannel: InitializeSecurityContext failed: %s",
+            Curl_sspi_strerror(status, buffer, sizeof(buffer)));
+#endif
+
+      return CURLE_AUTH_ERROR;
+    }
+
+    output_token_len = resp_buf.cbBuffer;
+
+    s_pSecFn->FreeCredentialsHandle(&credentials);
+    Curl_sspi_free_identity(p_identity);
+  }
+
+  resp = malloc(output_token_len + 1);
+  if(!resp) {
+    free(output_token);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Copy the generated response */
+  memcpy(resp, output_token, output_token_len);
+  resp[output_token_len] = 0;
+
+  /* Return the response */
+  *outptr = resp;
+  *outlen = output_token_len;
+
+  /* Free the response buffer */
+  free(output_token);
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_digest_cleanup()
+ *
+ * This is used to clean up the digest specific data.
+ *
+ * Parameters:
+ *
+ * digest    [in/out] - The digest data struct being cleaned up.
+ *
+ */
+void Curl_auth_digest_cleanup(struct digestdata *digest)
+{
+  /* Free the input token */
+  Curl_safefree(digest->input_token);
+
+  /* Reset any variables */
+  digest->input_token_len = 0;
+
+  /* Delete security context */
+  if(digest->http_context) {
+    s_pSecFn->DeleteSecurityContext(digest->http_context);
+    Curl_safefree(digest->http_context);
+  }
+
+  /* Free the copy of user/passwd used to make the identity for http_context */
+  Curl_safefree(digest->user);
+  Curl_safefree(digest->passwd);
+}
+
+#endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_DIGEST_AUTH */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/gsasl.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/gsasl.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/gsasl.c	(revision 104083)
@@ -0,0 +1,127 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Simon Josefsson, <simon@josefsson.org>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC5802 SCRAM-SHA-1 authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_GSASL
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "sendf.h"
+
+#include <gsasl.h>
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+bool Curl_auth_gsasl_is_supported(struct Curl_easy *data,
+                                  const char *mech,
+                                  struct gsasldata *gsasl)
+{
+  int res;
+
+  res = gsasl_init(&gsasl->ctx);
+  if(res != GSASL_OK) {
+    failf(data, "gsasl init: %s\n", gsasl_strerror(res));
+    return FALSE;
+  }
+
+  res = gsasl_client_start(gsasl->ctx, mech, &gsasl->client);
+  if(res != GSASL_OK) {
+    gsasl_done(gsasl->ctx);
+    return FALSE;
+  }
+
+  return true;
+}
+
+CURLcode Curl_auth_gsasl_start(struct Curl_easy *data,
+                               const char *userp,
+                               const char *passwdp,
+                               struct gsasldata *gsasl)
+{
+#if GSASL_VERSION_NUMBER >= 0x010b00
+  int res;
+  res =
+#endif
+    gsasl_property_set(gsasl->client, GSASL_AUTHID, userp);
+#if GSASL_VERSION_NUMBER >= 0x010b00
+  if(res != GSASL_OK) {
+    failf(data, "setting AUTHID failed: %s\n", gsasl_strerror(res));
+    return CURLE_OUT_OF_MEMORY;
+  }
+#endif
+
+#if GSASL_VERSION_NUMBER >= 0x010b00
+  res =
+#endif
+    gsasl_property_set(gsasl->client, GSASL_PASSWORD, passwdp);
+#if GSASL_VERSION_NUMBER >= 0x010b00
+  if(res != GSASL_OK) {
+    failf(data, "setting PASSWORD failed: %s\n", gsasl_strerror(res));
+    return CURLE_OUT_OF_MEMORY;
+  }
+#endif
+
+  (void)data;
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_auth_gsasl_token(struct Curl_easy *data,
+                               const struct bufref *chlg,
+                               struct gsasldata *gsasl,
+                               struct bufref *out)
+{
+  int res;
+  char *response;
+  size_t outlen;
+
+  res = gsasl_step(gsasl->client,
+                   (const char *) Curl_bufref_ptr(chlg), Curl_bufref_len(chlg),
+                   &response, &outlen);
+  if(res != GSASL_OK && res != GSASL_NEEDS_MORE) {
+    failf(data, "GSASL step: %s\n", gsasl_strerror(res));
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  Curl_bufref_set(out, response, outlen, gsasl_free);
+  return CURLE_OK;
+}
+
+void Curl_auth_gsasl_cleanup(struct gsasldata *gsasl)
+{
+  gsasl_finish(gsasl->client);
+  gsasl->client = NULL;
+
+  gsasl_done(gsasl->ctx);
+  gsasl->ctx = NULL;
+}
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/vauth/krb5_gssapi.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/krb5_gssapi.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/krb5_gssapi.c	(revision 104083)
@@ -0,0 +1,324 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(HAVE_GSSAPI) && defined(USE_KERBEROS5)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "curl_sasl.h"
+#include "urldata.h"
+#include "curl_gssapi.h"
+#include "sendf.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_is_gssapi_supported()
+ *
+ * This is used to evaluate if GSSAPI (Kerberos V5) is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE if Kerberos V5 is supported by the GSS-API library.
+ */
+bool Curl_auth_is_gssapi_supported(void)
+{
+  return TRUE;
+}
+
+/*
+ * Curl_auth_create_gssapi_user_message()
+ *
+ * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
+ * message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data        [in]     - The session handle.
+ * userp       [in]     - The user name.
+ * passwdp     [in]     - The user's password.
+ * service     [in]     - The service type such as http, smtp, pop or imap.
+ * host        [in[     - The host name.
+ * mutual_auth [in]     - Flag specifying whether or not mutual authentication
+ *                        is enabled.
+ * chlg        [in]     - Optional challenge message.
+ * krb5        [in/out] - The Kerberos 5 data struct being used and modified.
+ * out         [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
+                                              const char *userp,
+                                              const char *passwdp,
+                                              const char *service,
+                                              const char *host,
+                                              const bool mutual_auth,
+                                              const struct bufref *chlg,
+                                              struct kerberos5data *krb5,
+                                              struct bufref *out)
+{
+  CURLcode result = CURLE_OK;
+  OM_uint32 major_status;
+  OM_uint32 minor_status;
+  OM_uint32 unused_status;
+  gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+
+  (void) userp;
+  (void) passwdp;
+
+  if(!krb5->spn) {
+    /* Generate our SPN */
+    char *spn = Curl_auth_build_spn(service, NULL, host);
+    if(!spn)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* Populate the SPN structure */
+    spn_token.value = spn;
+    spn_token.length = strlen(spn);
+
+    /* Import the SPN */
+    major_status = gss_import_name(&minor_status, &spn_token,
+                                   GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn);
+    if(GSS_ERROR(major_status)) {
+      Curl_gss_log_error(data, "gss_import_name() failed: ",
+                         major_status, minor_status);
+
+      free(spn);
+
+      return CURLE_AUTH_ERROR;
+    }
+
+    free(spn);
+  }
+
+  if(chlg) {
+    if(!Curl_bufref_len(chlg)) {
+      infof(data, "GSSAPI handshake failure (empty challenge message)");
+      return CURLE_BAD_CONTENT_ENCODING;
+    }
+    input_token.value = (void *) Curl_bufref_ptr(chlg);
+    input_token.length = Curl_bufref_len(chlg);
+  }
+
+  major_status = Curl_gss_init_sec_context(data,
+                                           &minor_status,
+                                           &krb5->context,
+                                           krb5->spn,
+                                           &Curl_krb5_mech_oid,
+                                           GSS_C_NO_CHANNEL_BINDINGS,
+                                           &input_token,
+                                           &output_token,
+                                           mutual_auth,
+                                           NULL);
+
+  if(GSS_ERROR(major_status)) {
+    if(output_token.value)
+      gss_release_buffer(&unused_status, &output_token);
+
+    Curl_gss_log_error(data, "gss_init_sec_context() failed: ",
+                       major_status, minor_status);
+
+    return CURLE_AUTH_ERROR;
+  }
+
+  if(output_token.value && output_token.length) {
+    result = Curl_bufref_memdup(out, output_token.value, output_token.length);
+    gss_release_buffer(&unused_status, &output_token);
+  }
+  else
+    Curl_bufref_set(out, mutual_auth? "": NULL, 0, NULL);
+
+  return result;
+}
+
+/*
+ * Curl_auth_create_gssapi_security_message()
+ *
+ * This is used to generate an already encoded GSSAPI (Kerberos V5) security
+ * token message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * authzid [in]     - The authorization identity if some.
+ * chlg    [in]     - Optional challenge message.
+ * krb5    [in/out] - The Kerberos 5 data struct being used and modified.
+ * out     [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
+                                                  const char *authzid,
+                                                  const struct bufref *chlg,
+                                                  struct kerberos5data *krb5,
+                                                  struct bufref *out)
+{
+  CURLcode result = CURLE_OK;
+  size_t messagelen = 0;
+  unsigned char *message = NULL;
+  OM_uint32 major_status;
+  OM_uint32 minor_status;
+  OM_uint32 unused_status;
+  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+  unsigned char *indata;
+  gss_qop_t qop = GSS_C_QOP_DEFAULT;
+  unsigned int sec_layer = 0;
+  unsigned int max_size = 0;
+
+  /* Ensure we have a valid challenge message */
+  if(!Curl_bufref_len(chlg)) {
+    infof(data, "GSSAPI handshake failure (empty security message)");
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Setup the challenge "input" security buffer */
+  input_token.value = (void *) Curl_bufref_ptr(chlg);
+  input_token.length = Curl_bufref_len(chlg);
+
+  /* Decrypt the inbound challenge and obtain the qop */
+  major_status = gss_unwrap(&minor_status, krb5->context, &input_token,
+                            &output_token, NULL, &qop);
+  if(GSS_ERROR(major_status)) {
+    Curl_gss_log_error(data, "gss_unwrap() failed: ",
+                       major_status, minor_status);
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
+  if(output_token.length != 4) {
+    infof(data, "GSSAPI handshake failure (invalid security data)");
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Extract the security layer and the maximum message size */
+  indata = output_token.value;
+  sec_layer = indata[0];
+  max_size = ((unsigned int)indata[1] << 16) |
+             ((unsigned int)indata[2] << 8) | indata[3];
+
+  /* Free the challenge as it is not required anymore */
+  gss_release_buffer(&unused_status, &output_token);
+
+  /* Process the security layer */
+  if(!(sec_layer & GSSAUTH_P_NONE)) {
+    infof(data, "GSSAPI handshake failure (invalid security layer)");
+
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+  sec_layer &= GSSAUTH_P_NONE;  /* We do not support a security layer */
+
+  /* Process the maximum message size the server can receive */
+  if(max_size > 0) {
+    /* The server has told us it supports a maximum receive buffer, however, as
+       we don't require one unless we are encrypting data, we tell the server
+       our receive buffer is zero. */
+    max_size = 0;
+  }
+
+  /* Allocate our message */
+  messagelen = 4;
+  if(authzid)
+    messagelen += strlen(authzid);
+  message = malloc(messagelen);
+  if(!message)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Populate the message with the security layer and client supported receive
+     message size. */
+  message[0] = sec_layer & 0xFF;
+  message[1] = (max_size >> 16) & 0xFF;
+  message[2] = (max_size >> 8) & 0xFF;
+  message[3] = max_size & 0xFF;
+
+  /* If given, append the authorization identity. */
+
+  if(authzid && *authzid)
+    memcpy(message + 4, authzid, messagelen - 4);
+
+  /* Setup the "authentication data" security buffer */
+  input_token.value = message;
+  input_token.length = messagelen;
+
+  /* Encrypt the data */
+  major_status = gss_wrap(&minor_status, krb5->context, 0,
+                          GSS_C_QOP_DEFAULT, &input_token, NULL,
+                          &output_token);
+  if(GSS_ERROR(major_status)) {
+    Curl_gss_log_error(data, "gss_wrap() failed: ",
+                       major_status, minor_status);
+    free(message);
+    return CURLE_AUTH_ERROR;
+  }
+
+  /* Return the response. */
+  result = Curl_bufref_memdup(out, output_token.value, output_token.length);
+  /* Free the output buffer */
+  gss_release_buffer(&unused_status, &output_token);
+
+  /* Free the message buffer */
+  free(message);
+
+  return result;
+}
+
+/*
+ * Curl_auth_cleanup_gssapi()
+ *
+ * This is used to clean up the GSSAPI (Kerberos V5) specific data.
+ *
+ * Parameters:
+ *
+ * krb5     [in/out] - The Kerberos 5 data struct being cleaned up.
+ *
+ */
+void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5)
+{
+  OM_uint32 minor_status;
+
+  /* Free our security context */
+  if(krb5->context != GSS_C_NO_CONTEXT) {
+    gss_delete_sec_context(&minor_status, &krb5->context, GSS_C_NO_BUFFER);
+    krb5->context = GSS_C_NO_CONTEXT;
+  }
+
+  /* Free the SPN */
+  if(krb5->spn != GSS_C_NO_NAME) {
+    gss_release_name(&minor_status, &krb5->spn);
+    krb5->spn = GSS_C_NO_NAME;
+  }
+}
+
+#endif /* HAVE_GSSAPI && USE_KERBEROS5 */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/krb5_sspi.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/krb5_sspi.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/krb5_sspi.c	(revision 104083)
@@ -0,0 +1,475 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && defined(USE_KERBEROS5)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_is_gssapi_supported()
+ *
+ * This is used to evaluate if GSSAPI (Kerberos V5) is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE if Kerberos V5 is supported by Windows SSPI.
+ */
+bool Curl_auth_is_gssapi_supported(void)
+{
+  PSecPkgInfo SecurityPackage;
+  SECURITY_STATUS status;
+
+  /* Query the security package for Kerberos */
+  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+                                              TEXT(SP_NAME_KERBEROS),
+                                              &SecurityPackage);
+
+  /* Release the package buffer as it is not required anymore */
+  if(status == SEC_E_OK) {
+    s_pSecFn->FreeContextBuffer(SecurityPackage);
+  }
+
+  return (status == SEC_E_OK ? TRUE : FALSE);
+}
+
+/*
+ * Curl_auth_create_gssapi_user_message()
+ *
+ * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
+ * message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data        [in]     - The session handle.
+ * userp       [in]     - The user name in the format User or Domain\User.
+ * passwdp     [in]     - The user's password.
+ * service     [in]     - The service type such as http, smtp, pop or imap.
+ * host        [in]     - The host name.
+ * mutual_auth [in]     - Flag specifying whether or not mutual authentication
+ *                        is enabled.
+ * chlg        [in]     - Optional challenge message.
+ * krb5        [in/out] - The Kerberos 5 data struct being used and modified.
+ * out         [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
+                                              const char *userp,
+                                              const char *passwdp,
+                                              const char *service,
+                                              const char *host,
+                                              const bool mutual_auth,
+                                              const struct bufref *chlg,
+                                              struct kerberos5data *krb5,
+                                              struct bufref *out)
+{
+  CURLcode result = CURLE_OK;
+  CtxtHandle context;
+  PSecPkgInfo SecurityPackage;
+  SecBuffer chlg_buf;
+  SecBuffer resp_buf;
+  SecBufferDesc chlg_desc;
+  SecBufferDesc resp_desc;
+  SECURITY_STATUS status;
+  unsigned long attrs;
+  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+  if(!krb5->spn) {
+    /* Generate our SPN */
+    krb5->spn = Curl_auth_build_spn(service, host, NULL);
+    if(!krb5->spn)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(!krb5->output_token) {
+    /* Query the security package for Kerberos */
+    status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+                                                TEXT(SP_NAME_KERBEROS),
+                                                &SecurityPackage);
+    if(status != SEC_E_OK) {
+      failf(data, "SSPI: couldn't get auth info");
+      return CURLE_AUTH_ERROR;
+    }
+
+    krb5->token_max = SecurityPackage->cbMaxToken;
+
+    /* Release the package buffer as it is not required anymore */
+    s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+    /* Allocate our response buffer */
+    krb5->output_token = malloc(krb5->token_max);
+    if(!krb5->output_token)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(!krb5->credentials) {
+    /* Do we have credentials to use or are we using single sign-on? */
+    if(userp && *userp) {
+      /* Populate our identity structure */
+      result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity);
+      if(result)
+        return result;
+
+      /* Allow proper cleanup of the identity structure */
+      krb5->p_identity = &krb5->identity;
+    }
+    else
+      /* Use the current Windows user */
+      krb5->p_identity = NULL;
+
+    /* Allocate our credentials handle */
+    krb5->credentials = calloc(1, sizeof(CredHandle));
+    if(!krb5->credentials)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* Acquire our credentials handle */
+    status = s_pSecFn->AcquireCredentialsHandle(NULL,
+                                                (TCHAR *)
+                                                TEXT(SP_NAME_KERBEROS),
+                                                SECPKG_CRED_OUTBOUND, NULL,
+                                                krb5->p_identity, NULL, NULL,
+                                                krb5->credentials, &expiry);
+    if(status != SEC_E_OK)
+      return CURLE_LOGIN_DENIED;
+
+    /* Allocate our new context handle */
+    krb5->context = calloc(1, sizeof(CtxtHandle));
+    if(!krb5->context)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(chlg) {
+    if(!Curl_bufref_len(chlg)) {
+      infof(data, "GSSAPI handshake failure (empty challenge message)");
+      return CURLE_BAD_CONTENT_ENCODING;
+    }
+
+    /* Setup the challenge "input" security buffer */
+    chlg_desc.ulVersion = SECBUFFER_VERSION;
+    chlg_desc.cBuffers  = 1;
+    chlg_desc.pBuffers  = &chlg_buf;
+    chlg_buf.BufferType = SECBUFFER_TOKEN;
+    chlg_buf.pvBuffer   = (void *) Curl_bufref_ptr(chlg);
+    chlg_buf.cbBuffer   = curlx_uztoul(Curl_bufref_len(chlg));
+  }
+
+  /* Setup the response "output" security buffer */
+  resp_desc.ulVersion = SECBUFFER_VERSION;
+  resp_desc.cBuffers  = 1;
+  resp_desc.pBuffers  = &resp_buf;
+  resp_buf.BufferType = SECBUFFER_TOKEN;
+  resp_buf.pvBuffer   = krb5->output_token;
+  resp_buf.cbBuffer   = curlx_uztoul(krb5->token_max);
+
+  /* Generate our challenge-response message */
+  status = s_pSecFn->InitializeSecurityContext(krb5->credentials,
+                                               chlg ? krb5->context : NULL,
+                                               krb5->spn,
+                                               (mutual_auth ?
+                                                ISC_REQ_MUTUAL_AUTH : 0),
+                                               0, SECURITY_NATIVE_DREP,
+                                               chlg ? &chlg_desc : NULL, 0,
+                                               &context,
+                                               &resp_desc, &attrs,
+                                               &expiry);
+
+  if(status == SEC_E_INSUFFICIENT_MEMORY)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
+    return CURLE_AUTH_ERROR;
+
+  if(memcmp(&context, krb5->context, sizeof(context))) {
+    s_pSecFn->DeleteSecurityContext(krb5->context);
+
+    memcpy(krb5->context, &context, sizeof(context));
+  }
+
+  if(resp_buf.cbBuffer) {
+    result = Curl_bufref_memdup(out, resp_buf.pvBuffer, resp_buf.cbBuffer);
+  }
+  else if(mutual_auth)
+    Curl_bufref_set(out, "", 0, NULL);
+  else
+    Curl_bufref_set(out, NULL, 0, NULL);
+
+  return result;
+}
+
+/*
+ * Curl_auth_create_gssapi_security_message()
+ *
+ * This is used to generate an already encoded GSSAPI (Kerberos V5) security
+ * token message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * authzid [in]     - The authorization identity if some.
+ * chlg    [in]     - The optional challenge message.
+ * krb5    [in/out] - The Kerberos 5 data struct being used and modified.
+ * out     [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
+                                                  const char *authzid,
+                                                  const struct bufref *chlg,
+                                                  struct kerberos5data *krb5,
+                                                  struct bufref *out)
+{
+  size_t offset = 0;
+  size_t messagelen = 0;
+  size_t appdatalen = 0;
+  unsigned char *trailer = NULL;
+  unsigned char *message = NULL;
+  unsigned char *padding = NULL;
+  unsigned char *appdata = NULL;
+  SecBuffer input_buf[2];
+  SecBuffer wrap_buf[3];
+  SecBufferDesc input_desc;
+  SecBufferDesc wrap_desc;
+  unsigned char *indata;
+  unsigned long qop = 0;
+  unsigned long sec_layer = 0;
+  unsigned long max_size = 0;
+  SecPkgContext_Sizes sizes;
+  SECURITY_STATUS status;
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) data;
+#endif
+
+  /* Ensure we have a valid challenge message */
+  if(!Curl_bufref_len(chlg)) {
+    infof(data, "GSSAPI handshake failure (empty security message)");
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Get our response size information */
+  status = s_pSecFn->QueryContextAttributes(krb5->context,
+                                            SECPKG_ATTR_SIZES,
+                                            &sizes);
+
+  if(status == SEC_E_INSUFFICIENT_MEMORY)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(status != SEC_E_OK)
+    return CURLE_AUTH_ERROR;
+
+  /* Setup the "input" security buffer */
+  input_desc.ulVersion = SECBUFFER_VERSION;
+  input_desc.cBuffers = 2;
+  input_desc.pBuffers = input_buf;
+  input_buf[0].BufferType = SECBUFFER_STREAM;
+  input_buf[0].pvBuffer = (void *) Curl_bufref_ptr(chlg);
+  input_buf[0].cbBuffer = curlx_uztoul(Curl_bufref_len(chlg));
+  input_buf[1].BufferType = SECBUFFER_DATA;
+  input_buf[1].pvBuffer = NULL;
+  input_buf[1].cbBuffer = 0;
+
+  /* Decrypt the inbound challenge and obtain the qop */
+  status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop);
+  if(status != SEC_E_OK) {
+    infof(data, "GSSAPI handshake failure (empty security message)");
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
+  if(input_buf[1].cbBuffer != 4) {
+    infof(data, "GSSAPI handshake failure (invalid security data)");
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Extract the security layer and the maximum message size */
+  indata = input_buf[1].pvBuffer;
+  sec_layer = indata[0];
+  max_size = ((unsigned long)indata[1] << 16) |
+             ((unsigned long)indata[2] << 8) | indata[3];
+
+  /* Free the challenge as it is not required anymore */
+  s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer);
+
+  /* Process the security layer */
+  if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) {
+    infof(data, "GSSAPI handshake failure (invalid security layer)");
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+  sec_layer &= KERB_WRAP_NO_ENCRYPT;  /* We do not support a security layer */
+
+  /* Process the maximum message size the server can receive */
+  if(max_size > 0) {
+    /* The server has told us it supports a maximum receive buffer, however, as
+       we don't require one unless we are encrypting data, we tell the server
+       our receive buffer is zero. */
+    max_size = 0;
+  }
+
+  /* Allocate the trailer */
+  trailer = malloc(sizes.cbSecurityTrailer);
+  if(!trailer)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Allocate our message */
+  messagelen = 4;
+  if(authzid)
+    messagelen += strlen(authzid);
+  message = malloc(messagelen);
+  if(!message) {
+    free(trailer);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Populate the message with the security layer and client supported receive
+     message size. */
+  message[0] = sec_layer & 0xFF;
+  message[1] = (max_size >> 16) & 0xFF;
+  message[2] = (max_size >> 8) & 0xFF;
+  message[3] = max_size & 0xFF;
+
+  /* If given, append the authorization identity. */
+
+  if(authzid && *authzid)
+    memcpy(message + 4, authzid, messagelen - 4);
+
+  /* Allocate the padding */
+  padding = malloc(sizes.cbBlockSize);
+  if(!padding) {
+    free(message);
+    free(trailer);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Setup the "authentication data" security buffer */
+  wrap_desc.ulVersion    = SECBUFFER_VERSION;
+  wrap_desc.cBuffers     = 3;
+  wrap_desc.pBuffers     = wrap_buf;
+  wrap_buf[0].BufferType = SECBUFFER_TOKEN;
+  wrap_buf[0].pvBuffer   = trailer;
+  wrap_buf[0].cbBuffer   = sizes.cbSecurityTrailer;
+  wrap_buf[1].BufferType = SECBUFFER_DATA;
+  wrap_buf[1].pvBuffer   = message;
+  wrap_buf[1].cbBuffer   = curlx_uztoul(messagelen);
+  wrap_buf[2].BufferType = SECBUFFER_PADDING;
+  wrap_buf[2].pvBuffer   = padding;
+  wrap_buf[2].cbBuffer   = sizes.cbBlockSize;
+
+  /* Encrypt the data */
+  status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT,
+                                    &wrap_desc, 0);
+  if(status != SEC_E_OK) {
+    free(padding);
+    free(message);
+    free(trailer);
+
+    if(status == SEC_E_INSUFFICIENT_MEMORY)
+      return CURLE_OUT_OF_MEMORY;
+
+    return CURLE_AUTH_ERROR;
+  }
+
+  /* Allocate the encryption (wrap) buffer */
+  appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer +
+               wrap_buf[2].cbBuffer;
+  appdata = malloc(appdatalen);
+  if(!appdata) {
+    free(padding);
+    free(message);
+    free(trailer);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Populate the encryption buffer */
+  memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer);
+  offset += wrap_buf[0].cbBuffer;
+  memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer);
+  offset += wrap_buf[1].cbBuffer;
+  memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer);
+
+  /* Free all of our local buffers */
+  free(padding);
+  free(message);
+  free(trailer);
+
+  /* Return the response. */
+  Curl_bufref_set(out, appdata, appdatalen, curl_free);
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_cleanup_gssapi()
+ *
+ * This is used to clean up the GSSAPI (Kerberos V5) specific data.
+ *
+ * Parameters:
+ *
+ * krb5     [in/out] - The Kerberos 5 data struct being cleaned up.
+ *
+ */
+void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5)
+{
+  /* Free our security context */
+  if(krb5->context) {
+    s_pSecFn->DeleteSecurityContext(krb5->context);
+    free(krb5->context);
+    krb5->context = NULL;
+  }
+
+  /* Free our credentials handle */
+  if(krb5->credentials) {
+    s_pSecFn->FreeCredentialsHandle(krb5->credentials);
+    free(krb5->credentials);
+    krb5->credentials = NULL;
+  }
+
+  /* Free our identity */
+  Curl_sspi_free_identity(krb5->p_identity);
+  krb5->p_identity = NULL;
+
+  /* Free the SPN and output token */
+  Curl_safefree(krb5->spn);
+  Curl_safefree(krb5->output_token);
+
+  /* Reset any variables */
+  krb5->token_max = 0;
+}
+
+#endif /* USE_WINDOWS_SSPI && USE_KERBEROS5 */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/ntlm.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/ntlm.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/ntlm.c	(revision 104083)
@@ -0,0 +1,780 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI)
+
+/*
+ * NTLM details:
+ *
+ * https://davenport.sourceforge.net/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
+ */
+
+#define DEBUG_ME 0
+
+#include "urldata.h"
+#include "sendf.h"
+#include "curl_ntlm_core.h"
+#include "curl_gethostname.h"
+#include "curl_multibyte.h"
+#include "curl_md5.h"
+#include "warnless.h"
+#include "rand.h"
+#include "vtls/vtls.h"
+#include "strdup.h"
+
+#define BUILDING_CURL_NTLM_MSGS_C
+#include "vauth/vauth.h"
+#include "vauth/ntlm.h"
+#include "curl_endian.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* "NTLMSSP" signature is always in ASCII regardless of the platform */
+#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
+
+/* The fixed host name we provide, in order to not leak our real local host
+   name. Copy the name used by Firefox. */
+#define NTLM_HOSTNAME "WORKSTATION"
+
+#if DEBUG_ME
+# define DEBUG_OUT(x) x
+static void ntlm_print_flags(FILE *handle, unsigned long flags)
+{
+  if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
+  if(flags & NTLMFLAG_NEGOTIATE_OEM)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
+  if(flags & NTLMFLAG_REQUEST_TARGET)
+    fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
+  if(flags & (1<<3))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
+  if(flags & NTLMFLAG_NEGOTIATE_SIGN)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
+  if(flags & NTLMFLAG_NEGOTIATE_SEAL)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
+  if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
+  if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
+  if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
+  if(flags & (1<<10))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
+  if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
+  if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
+  if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
+  if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
+  if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
+  if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
+    fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
+  if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
+    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
+  if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
+    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
+  if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
+  if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
+    fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
+  if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
+    fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
+  if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
+    fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
+  if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
+  if(flags & (1<<24))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
+  if(flags & (1<<25))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
+  if(flags & (1<<26))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
+  if(flags & (1<<27))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
+  if(flags & (1<<28))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
+  if(flags & NTLMFLAG_NEGOTIATE_128)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
+  if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
+  if(flags & NTLMFLAG_NEGOTIATE_56)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
+}
+
+static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
+{
+  const char *p = buf;
+
+  (void) handle;
+
+  fprintf(stderr, "0x");
+  while(len-- > 0)
+    fprintf(stderr, "%02.2x", (unsigned int)*p++);
+}
+#else
+# define DEBUG_OUT(x) Curl_nop_stmt
+#endif
+
+/*
+ * ntlm_decode_type2_target()
+ *
+ * This is used to decode the "target info" in the NTLM type-2 message
+ * received.
+ *
+ * Parameters:
+ *
+ * data      [in]     - The session handle.
+ * type2ref  [in]     - The type-2 message.
+ * ntlm      [in/out] - The NTLM data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
+                                         const struct bufref *type2ref,
+                                         struct ntlmdata *ntlm)
+{
+  unsigned short target_info_len = 0;
+  unsigned int target_info_offset = 0;
+  const unsigned char *type2 = Curl_bufref_ptr(type2ref);
+  size_t type2len = Curl_bufref_len(type2ref);
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) data;
+#endif
+
+  if(type2len >= 48) {
+    target_info_len = Curl_read16_le(&type2[40]);
+    target_info_offset = Curl_read32_le(&type2[44]);
+    if(target_info_len > 0) {
+      if((target_info_offset > type2len) ||
+         (target_info_offset + target_info_len) > type2len ||
+         target_info_offset < 48) {
+        infof(data, "NTLM handshake failure (bad type-2 message). "
+              "Target Info Offset Len is set incorrect by the peer");
+        return CURLE_BAD_CONTENT_ENCODING;
+      }
+
+      free(ntlm->target_info); /* replace any previous data */
+      ntlm->target_info = Curl_memdup(&type2[target_info_offset],
+                                      target_info_len);
+      if(!ntlm->target_info)
+        return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  ntlm->target_info_len = target_info_len;
+
+  return CURLE_OK;
+}
+
+/*
+  NTLM message structure notes:
+
+  A 'short' is a 'network short', a little-endian 16-bit unsigned value.
+
+  A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
+
+  A 'security buffer' represents a triplet used to point to a buffer,
+  consisting of two shorts and one long:
+
+    1. A 'short' containing the length of the buffer content in bytes.
+    2. A 'short' containing the allocated space for the buffer in bytes.
+    3. A 'long' containing the offset to the start of the buffer in bytes,
+       from the beginning of the NTLM message.
+*/
+
+/*
+ * Curl_auth_is_ntlm_supported()
+ *
+ * This is used to evaluate if NTLM is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE as NTLM as handled by libcurl.
+ */
+bool Curl_auth_is_ntlm_supported(void)
+{
+  return TRUE;
+}
+
+/*
+ * Curl_auth_decode_ntlm_type2_message()
+ *
+ * This is used to decode an NTLM type-2 message. The raw NTLM message is
+ * checked * for validity before the appropriate data for creating a type-3
+ * message is * written to the given NTLM data structure.
+ *
+ * Parameters:
+ *
+ * data     [in]     - The session handle.
+ * type2ref [in]     - The type-2 message.
+ * ntlm     [in/out] - The NTLM data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
+                                             const struct bufref *type2ref,
+                                             struct ntlmdata *ntlm)
+{
+  static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
+
+  /* NTLM type-2 message structure:
+
+          Index  Description            Content
+            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
+                                        (0x4e544c4d53535000)
+            8    NTLM Message Type      long (0x02000000)
+           12    Target Name            security buffer
+           20    Flags                  long
+           24    Challenge              8 bytes
+          (32)   Context                8 bytes (two consecutive longs) (*)
+          (40)   Target Information     security buffer (*)
+          (48)   OS Version Structure   8 bytes (*)
+  32 (48) (56)   Start of data block    (*)
+                                        (*) -> Optional
+  */
+
+  CURLcode result = CURLE_OK;
+  const unsigned char *type2 = Curl_bufref_ptr(type2ref);
+  size_t type2len = Curl_bufref_len(type2ref);
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void)data;
+#endif
+
+  ntlm->flags = 0;
+
+  if((type2len < 32) ||
+     (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) ||
+     (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) {
+    /* This was not a good enough type-2 message */
+    infof(data, "NTLM handshake failure (bad type-2 message)");
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  ntlm->flags = Curl_read32_le(&type2[20]);
+  memcpy(ntlm->nonce, &type2[24], 8);
+
+  if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) {
+    result = ntlm_decode_type2_target(data, type2ref, ntlm);
+    if(result) {
+      infof(data, "NTLM handshake failure (bad type-2 message)");
+      return result;
+    }
+  }
+
+  DEBUG_OUT({
+    fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
+    ntlm_print_flags(stderr, ntlm->flags);
+    fprintf(stderr, "\n                  nonce=");
+    ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
+    fprintf(stderr, "\n****\n");
+    fprintf(stderr, "**** Header %s\n ", header);
+  });
+
+  return result;
+}
+
+/* copy the source to the destination and fill in zeroes in every
+   other destination byte! */
+static void unicodecpy(unsigned char *dest, const char *src, size_t length)
+{
+  size_t i;
+  for(i = 0; i < length; i++) {
+    dest[2 * i] = (unsigned char)src[i];
+    dest[2 * i + 1] = '\0';
+  }
+}
+
+/*
+ * Curl_auth_create_ntlm_type1_message()
+ *
+ * This is used to generate an NTLM type-1 message ready for sending to the
+ * recipient using the appropriate compile time crypto API.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * userp   [in]     - The user name in the format User or Domain\User.
+ * passwdp [in]     - The user's password.
+ * service [in]     - The service type such as http, smtp, pop or imap.
+ * host    [in]     - The host name.
+ * ntlm    [in/out] - The NTLM data struct being used and modified.
+ * out     [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             const char *service,
+                                             const char *hostname,
+                                             struct ntlmdata *ntlm,
+                                             struct bufref *out)
+{
+  /* NTLM type-1 message structure:
+
+       Index  Description            Content
+         0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
+                                     (0x4e544c4d53535000)
+         8    NTLM Message Type      long (0x01000000)
+        12    Flags                  long
+       (16)   Supplied Domain        security buffer (*)
+       (24)   Supplied Workstation   security buffer (*)
+       (32)   OS Version Structure   8 bytes (*)
+  (32) (40)   Start of data block    (*)
+                                     (*) -> Optional
+  */
+
+  size_t size;
+
+  char *ntlmbuf;
+  const char *host = "";              /* empty */
+  const char *domain = "";            /* empty */
+  size_t hostlen = 0;
+  size_t domlen = 0;
+  size_t hostoff = 0;
+  size_t domoff = hostoff + hostlen;  /* This is 0: remember that host and
+                                         domain are empty */
+  (void)data;
+  (void)userp;
+  (void)passwdp;
+  (void)service;
+  (void)hostname;
+
+  /* Clean up any former leftovers and initialise to defaults */
+  Curl_auth_cleanup_ntlm(ntlm);
+
+  ntlmbuf = aprintf(NTLMSSP_SIGNATURE "%c"
+                    "\x01%c%c%c" /* 32-bit type = 1 */
+                    "%c%c%c%c"   /* 32-bit NTLM flag field */
+                    "%c%c"       /* domain length */
+                    "%c%c"       /* domain allocated space */
+                    "%c%c"       /* domain name offset */
+                    "%c%c"       /* 2 zeroes */
+                    "%c%c"       /* host length */
+                    "%c%c"       /* host allocated space */
+                    "%c%c"       /* host name offset */
+                    "%c%c"       /* 2 zeroes */
+                    "%s"         /* host name */
+                    "%s",        /* domain string */
+                    0,           /* trailing zero */
+                    0, 0, 0,     /* part of type-1 long */
+
+                    LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
+                                NTLMFLAG_REQUEST_TARGET |
+                                NTLMFLAG_NEGOTIATE_NTLM_KEY |
+                                NTLMFLAG_NEGOTIATE_NTLM2_KEY |
+                                NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
+                    SHORTPAIR(domlen),
+                    SHORTPAIR(domlen),
+                    SHORTPAIR(domoff),
+                    0, 0,
+                    SHORTPAIR(hostlen),
+                    SHORTPAIR(hostlen),
+                    SHORTPAIR(hostoff),
+                    0, 0,
+                    host,  /* this is empty */
+                    domain /* this is empty */);
+
+  if(!ntlmbuf)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Initial packet length */
+  size = 32 + hostlen + domlen;
+
+  DEBUG_OUT({
+    fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
+            "0x%08.8x ",
+            LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
+                        NTLMFLAG_REQUEST_TARGET |
+                        NTLMFLAG_NEGOTIATE_NTLM_KEY |
+                        NTLMFLAG_NEGOTIATE_NTLM2_KEY |
+                        NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
+            NTLMFLAG_NEGOTIATE_OEM |
+            NTLMFLAG_REQUEST_TARGET |
+            NTLMFLAG_NEGOTIATE_NTLM_KEY |
+            NTLMFLAG_NEGOTIATE_NTLM2_KEY |
+            NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
+    ntlm_print_flags(stderr,
+                     NTLMFLAG_NEGOTIATE_OEM |
+                     NTLMFLAG_REQUEST_TARGET |
+                     NTLMFLAG_NEGOTIATE_NTLM_KEY |
+                     NTLMFLAG_NEGOTIATE_NTLM2_KEY |
+                     NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
+    fprintf(stderr, "\n****\n");
+  });
+
+  Curl_bufref_set(out, ntlmbuf, size, curl_free);
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_create_ntlm_type3_message()
+ *
+ * This is used to generate an already encoded NTLM type-3 message ready for
+ * sending to the recipient using the appropriate compile time crypto API.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * userp   [in]     - The user name in the format User or Domain\User.
+ * passwdp [in]     - The user's password.
+ * ntlm    [in/out] - The NTLM data struct being used and modified.
+ * out     [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             struct ntlmdata *ntlm,
+                                             struct bufref *out)
+{
+  /* NTLM type-3 message structure:
+
+          Index  Description            Content
+            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
+                                        (0x4e544c4d53535000)
+            8    NTLM Message Type      long (0x03000000)
+           12    LM/LMv2 Response       security buffer
+           20    NTLM/NTLMv2 Response   security buffer
+           28    Target Name            security buffer
+           36    User Name              security buffer
+           44    Workstation Name       security buffer
+          (52)   Session Key            security buffer (*)
+          (60)   Flags                  long (*)
+          (64)   OS Version Structure   8 bytes (*)
+  52 (64) (72)   Start of data block
+                                          (*) -> Optional
+  */
+
+  CURLcode result = CURLE_OK;
+  size_t size;
+  unsigned char ntlmbuf[NTLM_BUFSIZE];
+  int lmrespoff;
+  unsigned char lmresp[24]; /* fixed-size */
+  int ntrespoff;
+  unsigned int ntresplen = 24;
+  unsigned char ntresp[24]; /* fixed-size */
+  unsigned char *ptr_ntresp = &ntresp[0];
+  unsigned char *ntlmv2resp = NULL;
+  bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
+  char host[HOSTNAME_MAX + 1] = "";
+  const char *user;
+  const char *domain = "";
+  size_t hostoff = 0;
+  size_t useroff = 0;
+  size_t domoff = 0;
+  size_t hostlen = 0;
+  size_t userlen = 0;
+  size_t domlen = 0;
+
+  memset(lmresp, 0, sizeof(lmresp));
+  memset(ntresp, 0, sizeof(ntresp));
+  user = strchr(userp, '\\');
+  if(!user)
+    user = strchr(userp, '/');
+
+  if(user) {
+    domain = userp;
+    domlen = (user - domain);
+    user++;
+  }
+  else
+    user = userp;
+
+  userlen = strlen(user);
+
+#ifndef NTLM_HOSTNAME
+  /* Get the machine's un-qualified host name as NTLM doesn't like the fully
+     qualified domain name */
+  if(Curl_gethostname(host, sizeof(host))) {
+    infof(data, "gethostname() failed, continuing without");
+    hostlen = 0;
+  }
+  else {
+    hostlen = strlen(host);
+  }
+#else
+  (void)msnprintf(host, sizeof(host), "%s", NTLM_HOSTNAME);
+  hostlen = sizeof(NTLM_HOSTNAME)-1;
+#endif
+
+  if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
+    unsigned char ntbuffer[0x18];
+    unsigned char entropy[8];
+    unsigned char ntlmv2hash[0x18];
+
+    /* Full NTLM version 2
+       Although this cannot be negotiated, it is used here if available, as
+       servers featuring extended security are likely supporting also
+       NTLMv2. */
+    result = Curl_rand(data, entropy, 8);
+    if(result)
+      return result;
+
+    result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer);
+    if(result)
+      return result;
+
+    result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen,
+                                           ntbuffer, ntlmv2hash);
+    if(result)
+      return result;
+
+    /* LMv2 response */
+    result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy,
+                                         &ntlm->nonce[0], lmresp);
+    if(result)
+      return result;
+
+    /* NTLMv2 response */
+    result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy,
+                                           ntlm, &ntlmv2resp, &ntresplen);
+    if(result)
+      return result;
+
+    ptr_ntresp = ntlmv2resp;
+  }
+  else {
+
+    unsigned char ntbuffer[0x18];
+    unsigned char lmbuffer[0x18];
+
+    /* NTLM version 1 */
+
+    result = Curl_ntlm_core_mk_nt_hash(passwdp, ntbuffer);
+    if(result)
+      return result;
+
+    Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
+
+    result = Curl_ntlm_core_mk_lm_hash(passwdp, lmbuffer);
+    if(result)
+      return result;
+
+    Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
+    ntlm->flags &= ~NTLMFLAG_NEGOTIATE_NTLM2_KEY;
+
+    /* A safer but less compatible alternative is:
+     *   Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
+     * See https://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
+  }
+
+  if(unicode) {
+    domlen = domlen * 2;
+    userlen = userlen * 2;
+    hostlen = hostlen * 2;
+  }
+
+  lmrespoff = 64; /* size of the message header */
+  ntrespoff = lmrespoff + 0x18;
+  domoff = ntrespoff + ntresplen;
+  useroff = domoff + domlen;
+  hostoff = useroff + userlen;
+
+  /* Create the big type-3 message binary blob */
+  size = msnprintf((char *)ntlmbuf, NTLM_BUFSIZE,
+                   NTLMSSP_SIGNATURE "%c"
+                   "\x03%c%c%c"  /* 32-bit type = 3 */
+
+                   "%c%c"  /* LanManager length */
+                   "%c%c"  /* LanManager allocated space */
+                   "%c%c"  /* LanManager offset */
+                   "%c%c"  /* 2 zeroes */
+
+                   "%c%c"  /* NT-response length */
+                   "%c%c"  /* NT-response allocated space */
+                   "%c%c"  /* NT-response offset */
+                   "%c%c"  /* 2 zeroes */
+
+                   "%c%c"  /* domain length */
+                   "%c%c"  /* domain allocated space */
+                   "%c%c"  /* domain name offset */
+                   "%c%c"  /* 2 zeroes */
+
+                   "%c%c"  /* user length */
+                   "%c%c"  /* user allocated space */
+                   "%c%c"  /* user offset */
+                   "%c%c"  /* 2 zeroes */
+
+                   "%c%c"  /* host length */
+                   "%c%c"  /* host allocated space */
+                   "%c%c"  /* host offset */
+                   "%c%c"  /* 2 zeroes */
+
+                   "%c%c"  /* session key length (unknown purpose) */
+                   "%c%c"  /* session key allocated space (unknown purpose) */
+                   "%c%c"  /* session key offset (unknown purpose) */
+                   "%c%c"  /* 2 zeroes */
+
+                   "%c%c%c%c",  /* flags */
+
+                   /* domain string */
+                   /* user string */
+                   /* host string */
+                   /* LanManager response */
+                   /* NT response */
+
+                   0,                /* null-termination */
+                   0, 0, 0,          /* type-3 long, the 24 upper bits */
+
+                   SHORTPAIR(0x18),  /* LanManager response length, twice */
+                   SHORTPAIR(0x18),
+                   SHORTPAIR(lmrespoff),
+                   0x0, 0x0,
+
+                   SHORTPAIR(ntresplen),  /* NT-response length, twice */
+                   SHORTPAIR(ntresplen),
+                   SHORTPAIR(ntrespoff),
+                   0x0, 0x0,
+
+                   SHORTPAIR(domlen),
+                   SHORTPAIR(domlen),
+                   SHORTPAIR(domoff),
+                   0x0, 0x0,
+
+                   SHORTPAIR(userlen),
+                   SHORTPAIR(userlen),
+                   SHORTPAIR(useroff),
+                   0x0, 0x0,
+
+                   SHORTPAIR(hostlen),
+                   SHORTPAIR(hostlen),
+                   SHORTPAIR(hostoff),
+                   0x0, 0x0,
+
+                   0x0, 0x0,
+                   0x0, 0x0,
+                   0x0, 0x0,
+                   0x0, 0x0,
+
+                   LONGQUARTET(ntlm->flags));
+
+  DEBUGASSERT(size == 64);
+  DEBUGASSERT(size == (size_t)lmrespoff);
+
+  /* We append the binary hashes */
+  if(size < (NTLM_BUFSIZE - 0x18)) {
+    memcpy(&ntlmbuf[size], lmresp, 0x18);
+    size += 0x18;
+  }
+
+  DEBUG_OUT({
+    fprintf(stderr, "**** TYPE3 header lmresp=");
+    ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
+  });
+
+  /* ntresplen + size should not be risking an integer overflow here */
+  if(ntresplen + size > sizeof(ntlmbuf)) {
+    failf(data, "incoming NTLM message too big");
+    return CURLE_OUT_OF_MEMORY;
+  }
+  DEBUGASSERT(size == (size_t)ntrespoff);
+  memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
+  size += ntresplen;
+
+  DEBUG_OUT({
+    fprintf(stderr, "\n   ntresp=");
+    ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen);
+  });
+
+  free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */
+
+  DEBUG_OUT({
+    fprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
+            LONGQUARTET(ntlm->flags), ntlm->flags);
+    ntlm_print_flags(stderr, ntlm->flags);
+    fprintf(stderr, "\n****\n");
+  });
+
+  /* Make sure that the domain, user and host strings fit in the
+     buffer before we copy them there. */
+  if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
+    failf(data, "user + domain + host name too big");
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  DEBUGASSERT(size == domoff);
+  if(unicode)
+    unicodecpy(&ntlmbuf[size], domain, domlen / 2);
+  else
+    memcpy(&ntlmbuf[size], domain, domlen);
+
+  size += domlen;
+
+  DEBUGASSERT(size == useroff);
+  if(unicode)
+    unicodecpy(&ntlmbuf[size], user, userlen / 2);
+  else
+    memcpy(&ntlmbuf[size], user, userlen);
+
+  size += userlen;
+
+  DEBUGASSERT(size == hostoff);
+  if(unicode)
+    unicodecpy(&ntlmbuf[size], host, hostlen / 2);
+  else
+    memcpy(&ntlmbuf[size], host, hostlen);
+
+  size += hostlen;
+
+  /* Return the binary blob. */
+  result = Curl_bufref_memdup(out, ntlmbuf, size);
+
+  Curl_auth_cleanup_ntlm(ntlm);
+
+  return result;
+}
+
+/*
+ * Curl_auth_cleanup_ntlm()
+ *
+ * This is used to clean up the NTLM specific data.
+ *
+ * Parameters:
+ *
+ * ntlm    [in/out] - The NTLM data struct being cleaned up.
+ *
+ */
+void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm)
+{
+  /* Free the target info */
+  Curl_safefree(ntlm->target_info);
+
+  /* Reset any variables */
+  ntlm->target_info_len = 0;
+}
+
+#endif /* USE_NTLM && !USE_WINDOWS_SSPI */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/ntlm.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/ntlm.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/ntlm.h	(revision 104083)
@@ -0,0 +1,143 @@
+#ifndef HEADER_VAUTH_NTLM_H
+#define HEADER_VAUTH_NTLM_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_NTLM
+
+/* NTLM buffer fixed size, large enough for long user + host + domain */
+#define NTLM_BUFSIZE 1024
+
+/* Stuff only required for curl_ntlm_msgs.c */
+#ifdef BUILDING_CURL_NTLM_MSGS_C
+
+/* Flag bits definitions based on
+   https://davenport.sourceforge.net/ntlm.html */
+
+#define NTLMFLAG_NEGOTIATE_UNICODE               (1<<0)
+/* Indicates that Unicode strings are supported for use in security buffer
+   data. */
+
+#define NTLMFLAG_NEGOTIATE_OEM                   (1<<1)
+/* Indicates that OEM strings are supported for use in security buffer data. */
+
+#define NTLMFLAG_REQUEST_TARGET                  (1<<2)
+/* Requests that the server's authentication realm be included in the Type 2
+   message. */
+
+/* unknown (1<<3) */
+#define NTLMFLAG_NEGOTIATE_SIGN                  (1<<4)
+/* Specifies that authenticated communication between the client and server
+   should carry a digital signature (message integrity). */
+
+#define NTLMFLAG_NEGOTIATE_SEAL                  (1<<5)
+/* Specifies that authenticated communication between the client and server
+   should be encrypted (message confidentiality). */
+
+#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE        (1<<6)
+/* Indicates that datagram authentication is being used. */
+
+#define NTLMFLAG_NEGOTIATE_LM_KEY                (1<<7)
+/* Indicates that the LAN Manager session key should be used for signing and
+   sealing authenticated communications. */
+
+#define NTLMFLAG_NEGOTIATE_NTLM_KEY              (1<<9)
+/* Indicates that NTLM authentication is being used. */
+
+/* unknown (1<<10) */
+
+#define NTLMFLAG_NEGOTIATE_ANONYMOUS             (1<<11)
+/* Sent by the client in the Type 3 message to indicate that an anonymous
+   context has been established. This also affects the response fields. */
+
+#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED       (1<<12)
+/* Sent by the client in the Type 1 message to indicate that a desired
+   authentication realm is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED  (1<<13)
+/* Sent by the client in the Type 1 message to indicate that the client
+   workstation's name is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_LOCAL_CALL            (1<<14)
+/* Sent by the server to indicate that the server and client are on the same
+   machine. Implies that the client may use a pre-established local security
+   context rather than responding to the challenge. */
+
+#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN           (1<<15)
+/* Indicates that authenticated communication between the client and server
+   should be signed with a "dummy" signature. */
+
+#define NTLMFLAG_TARGET_TYPE_DOMAIN              (1<<16)
+/* Sent by the server in the Type 2 message to indicate that the target
+   authentication realm is a domain. */
+
+#define NTLMFLAG_TARGET_TYPE_SERVER              (1<<17)
+/* Sent by the server in the Type 2 message to indicate that the target
+   authentication realm is a server. */
+
+#define NTLMFLAG_TARGET_TYPE_SHARE               (1<<18)
+/* Sent by the server in the Type 2 message to indicate that the target
+   authentication realm is a share. Presumably, this is for share-level
+   authentication. Usage is unclear. */
+
+#define NTLMFLAG_NEGOTIATE_NTLM2_KEY             (1<<19)
+/* Indicates that the NTLM2 signing and sealing scheme should be used for
+   protecting authenticated communications. */
+
+#define NTLMFLAG_REQUEST_INIT_RESPONSE           (1<<20)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE         (1<<21)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY       (1<<22)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_TARGET_INFO           (1<<23)
+/* Sent by the server in the Type 2 message to indicate that it is including a
+   Target Information block in the message. */
+
+/* unknown (1<24) */
+/* unknown (1<25) */
+/* unknown (1<26) */
+/* unknown (1<27) */
+/* unknown (1<28) */
+
+#define NTLMFLAG_NEGOTIATE_128                   (1<<29)
+/* Indicates that 128-bit encryption is supported. */
+
+#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE          (1<<30)
+/* Indicates that the client will provide an encrypted master key in
+   the "Session Key" field of the Type 3 message. */
+
+#define NTLMFLAG_NEGOTIATE_56                    (1<<31)
+/* Indicates that 56-bit encryption is supported. */
+
+#endif /* BUILDING_CURL_NTLM_MSGS_C */
+
+#endif /* USE_NTLM */
+
+#endif /* HEADER_VAUTH_NTLM_H */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/ntlm_sspi.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/ntlm_sspi.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/ntlm_sspi.c	(revision 104083)
@@ -0,0 +1,372 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && defined(USE_NTLM)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "curl_ntlm_core.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+#include "strdup.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_is_ntlm_supported()
+ *
+ * This is used to evaluate if NTLM is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE if NTLM is supported by Windows SSPI.
+ */
+bool Curl_auth_is_ntlm_supported(void)
+{
+  PSecPkgInfo SecurityPackage;
+  SECURITY_STATUS status;
+
+  /* Query the security package for NTLM */
+  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
+                                              &SecurityPackage);
+
+  /* Release the package buffer as it is not required anymore */
+  if(status == SEC_E_OK) {
+    s_pSecFn->FreeContextBuffer(SecurityPackage);
+  }
+
+  return (status == SEC_E_OK ? TRUE : FALSE);
+}
+
+/*
+ * Curl_auth_create_ntlm_type1_message()
+ *
+ * This is used to generate an already encoded NTLM type-1 message ready for
+ * sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * userp   [in]     - The user name in the format User or Domain\User.
+ * passwdp [in]     - The user's password.
+ * service [in]     - The service type such as http, smtp, pop or imap.
+ * host    [in]     - The host name.
+ * ntlm    [in/out] - The NTLM data struct being used and modified.
+ * out     [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             const char *service,
+                                             const char *host,
+                                             struct ntlmdata *ntlm,
+                                             struct bufref *out)
+{
+  PSecPkgInfo SecurityPackage;
+  SecBuffer type_1_buf;
+  SecBufferDesc type_1_desc;
+  SECURITY_STATUS status;
+  unsigned long attrs;
+  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+  /* Clean up any former leftovers and initialise to defaults */
+  Curl_auth_cleanup_ntlm(ntlm);
+
+  /* Query the security package for NTLM */
+  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
+                                              &SecurityPackage);
+  if(status != SEC_E_OK) {
+    failf(data, "SSPI: couldn't get auth info");
+    return CURLE_AUTH_ERROR;
+  }
+
+  ntlm->token_max = SecurityPackage->cbMaxToken;
+
+  /* Release the package buffer as it is not required anymore */
+  s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+  /* Allocate our output buffer */
+  ntlm->output_token = malloc(ntlm->token_max);
+  if(!ntlm->output_token)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(userp && *userp) {
+    CURLcode result;
+
+    /* Populate our identity structure */
+    result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity);
+    if(result)
+      return result;
+
+    /* Allow proper cleanup of the identity structure */
+    ntlm->p_identity = &ntlm->identity;
+  }
+  else
+    /* Use the current Windows user */
+    ntlm->p_identity = NULL;
+
+  /* Allocate our credentials handle */
+  ntlm->credentials = calloc(1, sizeof(CredHandle));
+  if(!ntlm->credentials)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Acquire our credentials handle */
+  status = s_pSecFn->AcquireCredentialsHandle(NULL,
+                                              (TCHAR *) TEXT(SP_NAME_NTLM),
+                                              SECPKG_CRED_OUTBOUND, NULL,
+                                              ntlm->p_identity, NULL, NULL,
+                                              ntlm->credentials, &expiry);
+  if(status != SEC_E_OK)
+    return CURLE_LOGIN_DENIED;
+
+  /* Allocate our new context handle */
+  ntlm->context = calloc(1, sizeof(CtxtHandle));
+  if(!ntlm->context)
+    return CURLE_OUT_OF_MEMORY;
+
+  ntlm->spn = Curl_auth_build_spn(service, host, NULL);
+  if(!ntlm->spn)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Setup the type-1 "output" security buffer */
+  type_1_desc.ulVersion = SECBUFFER_VERSION;
+  type_1_desc.cBuffers  = 1;
+  type_1_desc.pBuffers  = &type_1_buf;
+  type_1_buf.BufferType = SECBUFFER_TOKEN;
+  type_1_buf.pvBuffer   = ntlm->output_token;
+  type_1_buf.cbBuffer   = curlx_uztoul(ntlm->token_max);
+
+  /* Generate our type-1 message */
+  status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL,
+                                               ntlm->spn,
+                                               0, 0, SECURITY_NETWORK_DREP,
+                                               NULL, 0,
+                                               ntlm->context, &type_1_desc,
+                                               &attrs, &expiry);
+  if(status == SEC_I_COMPLETE_NEEDED ||
+    status == SEC_I_COMPLETE_AND_CONTINUE)
+    s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc);
+  else if(status == SEC_E_INSUFFICIENT_MEMORY)
+    return CURLE_OUT_OF_MEMORY;
+  else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
+    return CURLE_AUTH_ERROR;
+
+  /* Return the response. */
+  Curl_bufref_set(out, ntlm->output_token, type_1_buf.cbBuffer, NULL);
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_decode_ntlm_type2_message()
+ *
+ * This is used to decode an already encoded NTLM type-2 message.
+ *
+ * Parameters:
+ *
+ * data     [in]     - The session handle.
+ * type2    [in]     - The type-2 message.
+ * ntlm     [in/out] - The NTLM data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
+                                             const struct bufref *type2,
+                                             struct ntlmdata *ntlm)
+{
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) data;
+#endif
+
+  /* Ensure we have a valid type-2 message */
+  if(!Curl_bufref_len(type2)) {
+    infof(data, "NTLM handshake failure (empty type-2 message)");
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Store the challenge for later use */
+  ntlm->input_token = Curl_memdup0((const char *)Curl_bufref_ptr(type2),
+                                   Curl_bufref_len(type2));
+  if(!ntlm->input_token)
+    return CURLE_OUT_OF_MEMORY;
+  ntlm->input_token_len = Curl_bufref_len(type2);
+
+  return CURLE_OK;
+}
+
+/*
+* Curl_auth_create_ntlm_type3_message()
+ * Curl_auth_create_ntlm_type3_message()
+ *
+ * This is used to generate an already encoded NTLM type-3 message ready for
+ * sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * userp   [in]     - The user name in the format User or Domain\User.
+ * passwdp [in]     - The user's password.
+ * ntlm    [in/out] - The NTLM data struct being used and modified.
+ * out     [out]    - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             struct ntlmdata *ntlm,
+                                             struct bufref *out)
+{
+  CURLcode result = CURLE_OK;
+  SecBuffer type_2_bufs[2];
+  SecBuffer type_3_buf;
+  SecBufferDesc type_2_desc;
+  SecBufferDesc type_3_desc;
+  SECURITY_STATUS status;
+  unsigned long attrs;
+  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) data;
+#endif
+  (void) passwdp;
+  (void) userp;
+
+  /* Setup the type-2 "input" security buffer */
+  type_2_desc.ulVersion     = SECBUFFER_VERSION;
+  type_2_desc.cBuffers      = 1;
+  type_2_desc.pBuffers      = &type_2_bufs[0];
+  type_2_bufs[0].BufferType = SECBUFFER_TOKEN;
+  type_2_bufs[0].pvBuffer   = ntlm->input_token;
+  type_2_bufs[0].cbBuffer   = curlx_uztoul(ntlm->input_token_len);
+
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+  /* ssl context comes from schannel.
+  * When extended protection is used in IIS server,
+  * we have to pass a second SecBuffer to the SecBufferDesc
+  * otherwise IIS will not pass the authentication (401 response).
+  * Minimum supported version is Windows 7.
+  * https://docs.microsoft.com/en-us/security-updates
+  * /SecurityAdvisories/2009/973811
+  */
+  if(ntlm->sslContext) {
+    SEC_CHANNEL_BINDINGS channelBindings;
+    SecPkgContext_Bindings pkgBindings;
+    pkgBindings.Bindings = &channelBindings;
+    status = s_pSecFn->QueryContextAttributes(
+      ntlm->sslContext,
+      SECPKG_ATTR_ENDPOINT_BINDINGS,
+      &pkgBindings
+    );
+    if(status == SEC_E_OK) {
+      type_2_desc.cBuffers++;
+      type_2_bufs[1].BufferType = SECBUFFER_CHANNEL_BINDINGS;
+      type_2_bufs[1].cbBuffer = pkgBindings.BindingsLength;
+      type_2_bufs[1].pvBuffer = pkgBindings.Bindings;
+    }
+  }
+#endif
+
+  /* Setup the type-3 "output" security buffer */
+  type_3_desc.ulVersion = SECBUFFER_VERSION;
+  type_3_desc.cBuffers  = 1;
+  type_3_desc.pBuffers  = &type_3_buf;
+  type_3_buf.BufferType = SECBUFFER_TOKEN;
+  type_3_buf.pvBuffer   = ntlm->output_token;
+  type_3_buf.cbBuffer   = curlx_uztoul(ntlm->token_max);
+
+  /* Generate our type-3 message */
+  status = s_pSecFn->InitializeSecurityContext(ntlm->credentials,
+                                               ntlm->context,
+                                               ntlm->spn,
+                                               0, 0, SECURITY_NETWORK_DREP,
+                                               &type_2_desc,
+                                               0, ntlm->context,
+                                               &type_3_desc,
+                                               &attrs, &expiry);
+  if(status != SEC_E_OK) {
+    infof(data, "NTLM handshake failure (type-3 message): Status=%lx",
+          status);
+
+    if(status == SEC_E_INSUFFICIENT_MEMORY)
+      return CURLE_OUT_OF_MEMORY;
+
+    return CURLE_AUTH_ERROR;
+  }
+
+  /* Return the response. */
+  result = Curl_bufref_memdup(out, ntlm->output_token, type_3_buf.cbBuffer);
+  Curl_auth_cleanup_ntlm(ntlm);
+  return result;
+}
+
+/*
+ * Curl_auth_cleanup_ntlm()
+ *
+ * This is used to clean up the NTLM specific data.
+ *
+ * Parameters:
+ *
+ * ntlm    [in/out] - The NTLM data struct being cleaned up.
+ *
+ */
+void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm)
+{
+  /* Free our security context */
+  if(ntlm->context) {
+    s_pSecFn->DeleteSecurityContext(ntlm->context);
+    free(ntlm->context);
+    ntlm->context = NULL;
+  }
+
+  /* Free our credentials handle */
+  if(ntlm->credentials) {
+    s_pSecFn->FreeCredentialsHandle(ntlm->credentials);
+    free(ntlm->credentials);
+    ntlm->credentials = NULL;
+  }
+
+  /* Free our identity */
+  Curl_sspi_free_identity(ntlm->p_identity);
+  ntlm->p_identity = NULL;
+
+  /* Free the input and output tokens */
+  Curl_safefree(ntlm->input_token);
+  Curl_safefree(ntlm->output_token);
+
+  /* Reset any variables */
+  ntlm->token_max = 0;
+
+  Curl_safefree(ntlm->spn);
+}
+
+#endif /* USE_WINDOWS_SSPI && USE_NTLM */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/oauth2.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/oauth2.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/oauth2.c	(revision 104083)
@@ -0,0 +1,108 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC6749 OAuth 2.0 Authorization Framework
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \
+  !defined(CURL_DISABLE_POP3) || \
+  (!defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP))
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#include "vauth/vauth.h"
+#include "warnless.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_create_oauth_bearer_message()
+ *
+ * This is used to generate an OAuth 2.0 message ready for sending to the
+ * recipient.
+ *
+ * Parameters:
+ *
+ * user[in]         - The user name.
+ * host[in]         - The host name.
+ * port[in]         - The port(when not Port 80).
+ * bearer[in]       - The bearer token.
+ * out[out]         - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_oauth_bearer_message(const char *user,
+                                               const char *host,
+                                               const long port,
+                                               const char *bearer,
+                                               struct bufref *out)
+{
+  char *oauth;
+
+  /* Generate the message */
+  if(port == 0 || port == 80)
+    oauth = aprintf("n,a=%s,\1host=%s\1auth=Bearer %s\1\1", user, host,
+                    bearer);
+  else
+    oauth = aprintf("n,a=%s,\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user,
+                    host, port, bearer);
+  if(!oauth)
+    return CURLE_OUT_OF_MEMORY;
+
+  Curl_bufref_set(out, oauth, strlen(oauth), curl_free);
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_create_xoauth_bearer_message()
+ *
+ * This is used to generate a XOAuth 2.0 message ready for * sending to the
+ * recipient.
+ *
+ * Parameters:
+ *
+ * user[in]         - The user name.
+ * bearer[in]       - The bearer token.
+ * out[out]         - The result storage.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_xoauth_bearer_message(const char *user,
+                                               const char *bearer,
+                                               struct bufref *out)
+{
+  /* Generate the message */
+  char *xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer);
+  if(!xoauth)
+    return CURLE_OUT_OF_MEMORY;
+
+  Curl_bufref_set(out, xoauth, strlen(xoauth), curl_free);
+  return CURLE_OK;
+}
+#endif /* disabled, no users */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/spnego_gssapi.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/spnego_gssapi.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/spnego_gssapi.c	(revision 104083)
@@ -0,0 +1,281 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC4178 Simple and Protected GSS-API Negotiation Mechanism
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(HAVE_GSSAPI) && defined(USE_SPNEGO)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "curl_gssapi.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_is_spnego_supported()
+ *
+ * This is used to evaluate if SPNEGO (Negotiate) is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE if Negotiate supported by the GSS-API library.
+ */
+bool Curl_auth_is_spnego_supported(void)
+{
+  return TRUE;
+}
+
+/*
+ * Curl_auth_decode_spnego_message()
+ *
+ * This is used to decode an already encoded SPNEGO (Negotiate) challenge
+ * message.
+ *
+ * Parameters:
+ *
+ * data        [in]     - The session handle.
+ * userp       [in]     - The user name in the format User or Domain\User.
+ * passwdp     [in]     - The user's password.
+ * service     [in]     - The service type such as http, smtp, pop or imap.
+ * host        [in]     - The host name.
+ * chlg64      [in]     - The optional base64 encoded challenge message.
+ * nego        [in/out] - The Negotiate data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
+                                         const char *user,
+                                         const char *password,
+                                         const char *service,
+                                         const char *host,
+                                         const char *chlg64,
+                                         struct negotiatedata *nego)
+{
+  CURLcode result = CURLE_OK;
+  size_t chlglen = 0;
+  unsigned char *chlg = NULL;
+  OM_uint32 major_status;
+  OM_uint32 minor_status;
+  OM_uint32 unused_status;
+  gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+
+  (void) user;
+  (void) password;
+
+  if(nego->context && nego->status == GSS_S_COMPLETE) {
+    /* We finished successfully our part of authentication, but server
+     * rejected it (since we're again here). Exit with an error since we
+     * can't invent anything better */
+    Curl_auth_cleanup_spnego(nego);
+    return CURLE_LOGIN_DENIED;
+  }
+
+  if(!nego->spn) {
+    /* Generate our SPN */
+    char *spn = Curl_auth_build_spn(service, NULL, host);
+    if(!spn)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* Populate the SPN structure */
+    spn_token.value = spn;
+    spn_token.length = strlen(spn);
+
+    /* Import the SPN */
+    major_status = gss_import_name(&minor_status, &spn_token,
+                                   GSS_C_NT_HOSTBASED_SERVICE,
+                                   &nego->spn);
+    if(GSS_ERROR(major_status)) {
+      Curl_gss_log_error(data, "gss_import_name() failed: ",
+                         major_status, minor_status);
+
+      free(spn);
+
+      return CURLE_AUTH_ERROR;
+    }
+
+    free(spn);
+  }
+
+  if(chlg64 && *chlg64) {
+    /* Decode the base-64 encoded challenge message */
+    if(*chlg64 != '=') {
+      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+      if(result)
+        return result;
+    }
+
+    /* Ensure we have a valid challenge message */
+    if(!chlg) {
+      infof(data, "SPNEGO handshake failure (empty challenge message)");
+      return CURLE_BAD_CONTENT_ENCODING;
+    }
+
+    /* Setup the challenge "input" security buffer */
+    input_token.value = chlg;
+    input_token.length = chlglen;
+  }
+
+  /* Generate our challenge-response message */
+  major_status = Curl_gss_init_sec_context(data,
+                                           &minor_status,
+                                           &nego->context,
+                                           nego->spn,
+                                           &Curl_spnego_mech_oid,
+                                           GSS_C_NO_CHANNEL_BINDINGS,
+                                           &input_token,
+                                           &output_token,
+                                           TRUE,
+                                           NULL);
+
+  /* Free the decoded challenge as it is not required anymore */
+  Curl_safefree(input_token.value);
+
+  nego->status = major_status;
+  if(GSS_ERROR(major_status)) {
+    if(output_token.value)
+      gss_release_buffer(&unused_status, &output_token);
+
+    Curl_gss_log_error(data, "gss_init_sec_context() failed: ",
+                       major_status, minor_status);
+
+    return CURLE_AUTH_ERROR;
+  }
+
+  if(!output_token.value || !output_token.length) {
+    if(output_token.value)
+      gss_release_buffer(&unused_status, &output_token);
+
+    return CURLE_AUTH_ERROR;
+  }
+
+  /* Free previous token */
+  if(nego->output_token.length && nego->output_token.value)
+    gss_release_buffer(&unused_status, &nego->output_token);
+
+  nego->output_token = output_token;
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_create_spnego_message()
+ *
+ * This is used to generate an already encoded SPNEGO (Negotiate) response
+ * message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data        [in]     - The session handle.
+ * nego        [in/out] - The Negotiate data struct being used and modified.
+ * outptr      [in/out] - The address where a pointer to newly allocated memory
+ *                        holding the result will be stored upon completion.
+ * outlen      [out]    - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_spnego_message(struct negotiatedata *nego,
+                                         char **outptr, size_t *outlen)
+{
+  CURLcode result;
+  OM_uint32 minor_status;
+
+  /* Base64 encode the already generated response */
+  result = Curl_base64_encode(nego->output_token.value,
+                              nego->output_token.length,
+                              outptr, outlen);
+
+  if(result) {
+    gss_release_buffer(&minor_status, &nego->output_token);
+    nego->output_token.value = NULL;
+    nego->output_token.length = 0;
+
+    return result;
+  }
+
+  if(!*outptr || !*outlen) {
+    gss_release_buffer(&minor_status, &nego->output_token);
+    nego->output_token.value = NULL;
+    nego->output_token.length = 0;
+
+    return CURLE_REMOTE_ACCESS_DENIED;
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_cleanup_spnego()
+ *
+ * This is used to clean up the SPNEGO (Negotiate) specific data.
+ *
+ * Parameters:
+ *
+ * nego     [in/out] - The Negotiate data struct being cleaned up.
+ *
+ */
+void Curl_auth_cleanup_spnego(struct negotiatedata *nego)
+{
+  OM_uint32 minor_status;
+
+  /* Free our security context */
+  if(nego->context != GSS_C_NO_CONTEXT) {
+    gss_delete_sec_context(&minor_status, &nego->context, GSS_C_NO_BUFFER);
+    nego->context = GSS_C_NO_CONTEXT;
+  }
+
+  /* Free the output token */
+  if(nego->output_token.value) {
+    gss_release_buffer(&minor_status, &nego->output_token);
+    nego->output_token.value = NULL;
+    nego->output_token.length = 0;
+
+  }
+
+  /* Free the SPN */
+  if(nego->spn != GSS_C_NO_NAME) {
+    gss_release_name(&minor_status, &nego->spn);
+    nego->spn = GSS_C_NO_NAME;
+  }
+
+  /* Reset any variables */
+  nego->status = 0;
+  nego->noauthpersist = FALSE;
+  nego->havenoauthpersist = FALSE;
+  nego->havenegdata = FALSE;
+  nego->havemultiplerequests = FALSE;
+}
+
+#endif /* HAVE_GSSAPI && USE_SPNEGO */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/spnego_sspi.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/spnego_sspi.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/spnego_sspi.c	(revision 104083)
@@ -0,0 +1,364 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * RFC4178 Simple and Protected GSS-API Negotiation Mechanism
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && defined(USE_SPNEGO)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+#include "strerror.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_is_spnego_supported()
+ *
+ * This is used to evaluate if SPNEGO (Negotiate) is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE if Negotiate is supported by Windows SSPI.
+ */
+bool Curl_auth_is_spnego_supported(void)
+{
+  PSecPkgInfo SecurityPackage;
+  SECURITY_STATUS status;
+
+  /* Query the security package for Negotiate */
+  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+                                              TEXT(SP_NAME_NEGOTIATE),
+                                              &SecurityPackage);
+
+  /* Release the package buffer as it is not required anymore */
+  if(status == SEC_E_OK) {
+    s_pSecFn->FreeContextBuffer(SecurityPackage);
+  }
+
+
+  return (status == SEC_E_OK ? TRUE : FALSE);
+}
+
+/*
+ * Curl_auth_decode_spnego_message()
+ *
+ * This is used to decode an already encoded SPNEGO (Negotiate) challenge
+ * message.
+ *
+ * Parameters:
+ *
+ * data        [in]     - The session handle.
+ * user        [in]     - The user name in the format User or Domain\User.
+ * password    [in]     - The user's password.
+ * service     [in]     - The service type such as http, smtp, pop or imap.
+ * host        [in]     - The host name.
+ * chlg64      [in]     - The optional base64 encoded challenge message.
+ * nego        [in/out] - The Negotiate data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
+                                         const char *user,
+                                         const char *password,
+                                         const char *service,
+                                         const char *host,
+                                         const char *chlg64,
+                                         struct negotiatedata *nego)
+{
+  CURLcode result = CURLE_OK;
+  size_t chlglen = 0;
+  unsigned char *chlg = NULL;
+  PSecPkgInfo SecurityPackage;
+  SecBuffer chlg_buf[2];
+  SecBuffer resp_buf;
+  SecBufferDesc chlg_desc;
+  SecBufferDesc resp_desc;
+  unsigned long attrs;
+  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) data;
+#endif
+
+  if(nego->context && nego->status == SEC_E_OK) {
+    /* We finished successfully our part of authentication, but server
+     * rejected it (since we're again here). Exit with an error since we
+     * can't invent anything better */
+    Curl_auth_cleanup_spnego(nego);
+    return CURLE_LOGIN_DENIED;
+  }
+
+  if(!nego->spn) {
+    /* Generate our SPN */
+    nego->spn = Curl_auth_build_spn(service, host, NULL);
+    if(!nego->spn)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(!nego->output_token) {
+    /* Query the security package for Negotiate */
+    nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+                                                      TEXT(SP_NAME_NEGOTIATE),
+                                                      &SecurityPackage);
+    if(nego->status != SEC_E_OK) {
+      failf(data, "SSPI: couldn't get auth info");
+      return CURLE_AUTH_ERROR;
+    }
+
+    nego->token_max = SecurityPackage->cbMaxToken;
+
+    /* Release the package buffer as it is not required anymore */
+    s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+    /* Allocate our output buffer */
+    nego->output_token = malloc(nego->token_max);
+    if(!nego->output_token)
+      return CURLE_OUT_OF_MEMORY;
+ }
+
+  if(!nego->credentials) {
+    /* Do we have credentials to use or are we using single sign-on? */
+    if(user && *user) {
+      /* Populate our identity structure */
+      result = Curl_create_sspi_identity(user, password, &nego->identity);
+      if(result)
+        return result;
+
+      /* Allow proper cleanup of the identity structure */
+      nego->p_identity = &nego->identity;
+    }
+    else
+      /* Use the current Windows user */
+      nego->p_identity = NULL;
+
+    /* Allocate our credentials handle */
+    nego->credentials = calloc(1, sizeof(CredHandle));
+    if(!nego->credentials)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* Acquire our credentials handle */
+    nego->status =
+      s_pSecFn->AcquireCredentialsHandle(NULL,
+                                         (TCHAR *)TEXT(SP_NAME_NEGOTIATE),
+                                         SECPKG_CRED_OUTBOUND, NULL,
+                                         nego->p_identity, NULL, NULL,
+                                         nego->credentials, &expiry);
+    if(nego->status != SEC_E_OK)
+      return CURLE_AUTH_ERROR;
+
+    /* Allocate our new context handle */
+    nego->context = calloc(1, sizeof(CtxtHandle));
+    if(!nego->context)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(chlg64 && *chlg64) {
+    /* Decode the base-64 encoded challenge message */
+    if(*chlg64 != '=') {
+      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+      if(result)
+        return result;
+    }
+
+    /* Ensure we have a valid challenge message */
+    if(!chlg) {
+      infof(data, "SPNEGO handshake failure (empty challenge message)");
+      return CURLE_BAD_CONTENT_ENCODING;
+    }
+
+    /* Setup the challenge "input" security buffer */
+    chlg_desc.ulVersion    = SECBUFFER_VERSION;
+    chlg_desc.cBuffers     = 1;
+    chlg_desc.pBuffers     = &chlg_buf[0];
+    chlg_buf[0].BufferType = SECBUFFER_TOKEN;
+    chlg_buf[0].pvBuffer   = chlg;
+    chlg_buf[0].cbBuffer   = curlx_uztoul(chlglen);
+
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+    /* ssl context comes from Schannel.
+    * When extended protection is used in IIS server,
+    * we have to pass a second SecBuffer to the SecBufferDesc
+    * otherwise IIS will not pass the authentication (401 response).
+    * Minimum supported version is Windows 7.
+    * https://docs.microsoft.com/en-us/security-updates
+    * /SecurityAdvisories/2009/973811
+    */
+    if(nego->sslContext) {
+      SEC_CHANNEL_BINDINGS channelBindings;
+      SecPkgContext_Bindings pkgBindings;
+      pkgBindings.Bindings = &channelBindings;
+      nego->status = s_pSecFn->QueryContextAttributes(
+          nego->sslContext,
+          SECPKG_ATTR_ENDPOINT_BINDINGS,
+          &pkgBindings
+      );
+      if(nego->status == SEC_E_OK) {
+        chlg_desc.cBuffers++;
+        chlg_buf[1].BufferType = SECBUFFER_CHANNEL_BINDINGS;
+        chlg_buf[1].cbBuffer   = pkgBindings.BindingsLength;
+        chlg_buf[1].pvBuffer   = pkgBindings.Bindings;
+      }
+    }
+#endif
+  }
+
+  /* Setup the response "output" security buffer */
+  resp_desc.ulVersion = SECBUFFER_VERSION;
+  resp_desc.cBuffers  = 1;
+  resp_desc.pBuffers  = &resp_buf;
+  resp_buf.BufferType = SECBUFFER_TOKEN;
+  resp_buf.pvBuffer   = nego->output_token;
+  resp_buf.cbBuffer   = curlx_uztoul(nego->token_max);
+
+  /* Generate our challenge-response message */
+  nego->status = s_pSecFn->InitializeSecurityContext(nego->credentials,
+                                                     chlg ? nego->context :
+                                                            NULL,
+                                                     nego->spn,
+                                                     ISC_REQ_CONFIDENTIALITY,
+                                                     0, SECURITY_NATIVE_DREP,
+                                                     chlg ? &chlg_desc : NULL,
+                                                     0, nego->context,
+                                                     &resp_desc, &attrs,
+                                                     &expiry);
+
+  /* Free the decoded challenge as it is not required anymore */
+  free(chlg);
+
+  if(GSS_ERROR(nego->status)) {
+    char buffer[STRERROR_LEN];
+    failf(data, "InitializeSecurityContext failed: %s",
+          Curl_sspi_strerror(nego->status, buffer, sizeof(buffer)));
+
+    if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY)
+      return CURLE_OUT_OF_MEMORY;
+
+    return CURLE_AUTH_ERROR;
+  }
+
+  if(nego->status == SEC_I_COMPLETE_NEEDED ||
+     nego->status == SEC_I_COMPLETE_AND_CONTINUE) {
+    nego->status = s_pSecFn->CompleteAuthToken(nego->context, &resp_desc);
+    if(GSS_ERROR(nego->status)) {
+      char buffer[STRERROR_LEN];
+      failf(data, "CompleteAuthToken failed: %s",
+            Curl_sspi_strerror(nego->status, buffer, sizeof(buffer)));
+
+      if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY)
+        return CURLE_OUT_OF_MEMORY;
+
+      return CURLE_AUTH_ERROR;
+    }
+  }
+
+  nego->output_token_length = resp_buf.cbBuffer;
+
+  return result;
+}
+
+/*
+ * Curl_auth_create_spnego_message()
+ *
+ * This is used to generate an already encoded SPNEGO (Negotiate) response
+ * message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data        [in]     - The session handle.
+ * nego        [in/out] - The Negotiate data struct being used and modified.
+ * outptr      [in/out] - The address where a pointer to newly allocated memory
+ *                        holding the result will be stored upon completion.
+ * outlen      [out]    - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_spnego_message(struct negotiatedata *nego,
+                                         char **outptr, size_t *outlen)
+{
+  /* Base64 encode the already generated response */
+  CURLcode result = Curl_base64_encode((const char *) nego->output_token,
+                                       nego->output_token_length, outptr,
+                                       outlen);
+  if(!result && (!*outptr || !*outlen)) {
+    free(*outptr);
+    result = CURLE_REMOTE_ACCESS_DENIED;
+  }
+
+  return result;
+}
+
+/*
+ * Curl_auth_cleanup_spnego()
+ *
+ * This is used to clean up the SPNEGO (Negotiate) specific data.
+ *
+ * Parameters:
+ *
+ * nego     [in/out] - The Negotiate data struct being cleaned up.
+ *
+ */
+void Curl_auth_cleanup_spnego(struct negotiatedata *nego)
+{
+  /* Free our security context */
+  if(nego->context) {
+    s_pSecFn->DeleteSecurityContext(nego->context);
+    free(nego->context);
+    nego->context = NULL;
+  }
+
+  /* Free our credentials handle */
+  if(nego->credentials) {
+    s_pSecFn->FreeCredentialsHandle(nego->credentials);
+    free(nego->credentials);
+    nego->credentials = NULL;
+  }
+
+  /* Free our identity */
+  Curl_sspi_free_identity(nego->p_identity);
+  nego->p_identity = NULL;
+
+  /* Free the SPN and output token */
+  Curl_safefree(nego->spn);
+  Curl_safefree(nego->output_token);
+
+  /* Reset any variables */
+  nego->status = 0;
+  nego->token_max = 0;
+  nego->noauthpersist = FALSE;
+  nego->havenoauthpersist = FALSE;
+  nego->havenegdata = FALSE;
+  nego->havemultiplerequests = FALSE;
+}
+
+#endif /* USE_WINDOWS_SSPI && USE_SPNEGO */
Index: trunk/src/libs/curl-8.7.1/lib/vauth/vauth.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/vauth.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/vauth.c	(revision 104083)
@@ -0,0 +1,163 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "vauth.h"
+#include "urldata.h"
+#include "strcase.h"
+#include "curl_multibyte.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_build_spn()
+ *
+ * This is used to build a SPN string in the following formats:
+ *
+ * service/host@realm (Not currently used)
+ * service/host       (Not used by GSS-API)
+ * service@realm      (Not used by Windows SSPI)
+ *
+ * Parameters:
+ *
+ * service  [in] - The service type such as http, smtp, pop or imap.
+ * host     [in] - The host name.
+ * realm    [in] - The realm.
+ *
+ * Returns a pointer to the newly allocated SPN.
+ */
+#if !defined(USE_WINDOWS_SSPI)
+char *Curl_auth_build_spn(const char *service, const char *host,
+                          const char *realm)
+{
+  char *spn = NULL;
+
+  /* Generate our SPN */
+  if(host && realm)
+    spn = aprintf("%s/%s@%s", service, host, realm);
+  else if(host)
+    spn = aprintf("%s/%s", service, host);
+  else if(realm)
+    spn = aprintf("%s@%s", service, realm);
+
+  /* Return our newly allocated SPN */
+  return spn;
+}
+#else
+TCHAR *Curl_auth_build_spn(const char *service, const char *host,
+                           const char *realm)
+{
+  char *utf8_spn = NULL;
+  TCHAR *tchar_spn = NULL;
+  TCHAR *dupe_tchar_spn = NULL;
+
+  (void) realm;
+
+  /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather
+     than doing this ourselves but the first is only available in Windows XP
+     and Windows Server 2003 and the latter is only available in Windows 2000
+     but not Windows95/98/ME or Windows NT4.0 unless the Active Directory
+     Client Extensions are installed. As such it is far simpler for us to
+     formulate the SPN instead. */
+
+  /* Generate our UTF8 based SPN */
+  utf8_spn = aprintf("%s/%s", service, host);
+  if(!utf8_spn)
+    return NULL;
+
+  /* Allocate and return a TCHAR based SPN. Since curlx_convert_UTF8_to_tchar
+     must be freed by curlx_unicodefree we'll dupe the result so that the
+     pointer this function returns can be normally free'd. */
+  tchar_spn = curlx_convert_UTF8_to_tchar(utf8_spn);
+  free(utf8_spn);
+  if(!tchar_spn)
+    return NULL;
+  dupe_tchar_spn = _tcsdup(tchar_spn);
+  curlx_unicodefree(tchar_spn);
+  return dupe_tchar_spn;
+}
+#endif /* USE_WINDOWS_SSPI */
+
+/*
+ * Curl_auth_user_contains_domain()
+ *
+ * This is used to test if the specified user contains a Windows domain name as
+ * follows:
+ *
+ * Domain\User (Down-level Logon Name)
+ * Domain/User (curl Down-level format - for compatibility with existing code)
+ * User@Domain (User Principal Name)
+ *
+ * Note: The user name may be empty when using a GSS-API library or Windows
+ * SSPI as the user and domain are either obtained from the credentials cache
+ * when using GSS-API or via the currently logged in user's credentials when
+ * using Windows SSPI.
+ *
+ * Parameters:
+ *
+ * user  [in] - The user name.
+ *
+ * Returns TRUE on success; otherwise FALSE.
+ */
+bool Curl_auth_user_contains_domain(const char *user)
+{
+  bool valid = FALSE;
+
+  if(user && *user) {
+    /* Check we have a domain name or UPN present */
+    char *p = strpbrk(user, "\\/@");
+
+    valid = (p != NULL && p > user && p < user + strlen(user) - 1 ? TRUE :
+                                                                    FALSE);
+  }
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  else
+    /* User and domain are obtained from the GSS-API credentials cache or the
+       currently logged in user from Windows */
+    valid = TRUE;
+#endif
+
+  return valid;
+}
+
+/*
+ * Curl_auth_ollowed_to_host() tells if authentication, cookies or other
+ * "sensitive data" can (still) be sent to this host.
+ */
+bool Curl_auth_allowed_to_host(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+  return (!data->state.this_is_a_follow ||
+          data->set.allow_auth_to_other_hosts ||
+          (data->state.first_host &&
+           strcasecompare(data->state.first_host, conn->host.name) &&
+           (data->state.first_remote_port == conn->remote_port) &&
+           (data->state.first_remote_protocol == conn->handler->protocol)));
+}
Index: trunk/src/libs/curl-8.7.1/lib/vauth/vauth.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vauth/vauth.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vauth/vauth.h	(revision 104083)
@@ -0,0 +1,238 @@
+#ifndef HEADER_CURL_VAUTH_H
+#define HEADER_CURL_VAUTH_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+#include "bufref.h"
+
+struct Curl_easy;
+
+#if !defined(CURL_DISABLE_DIGEST_AUTH)
+struct digestdata;
+#endif
+
+#if defined(USE_NTLM)
+struct ntlmdata;
+#endif
+
+#if defined(USE_KERBEROS5)
+struct kerberos5data;
+#endif
+
+#if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO)
+struct negotiatedata;
+#endif
+
+#if defined(USE_GSASL)
+struct gsasldata;
+#endif
+
+#if defined(USE_WINDOWS_SSPI)
+#define GSS_ERROR(status) ((status) & 0x80000000)
+#endif
+
+/*
+ * Curl_auth_allowed_to_host() tells if authentication, cookies or other
+ * "sensitive data" can (still) be sent to this host.
+ */
+bool Curl_auth_allowed_to_host(struct Curl_easy *data);
+
+/* This is used to build a SPN string */
+#if !defined(USE_WINDOWS_SSPI)
+char *Curl_auth_build_spn(const char *service, const char *host,
+                          const char *realm);
+#else
+TCHAR *Curl_auth_build_spn(const char *service, const char *host,
+                           const char *realm);
+#endif
+
+/* This is used to test if the user contains a Windows domain name */
+bool Curl_auth_user_contains_domain(const char *user);
+
+/* This is used to generate a PLAIN cleartext message */
+CURLcode Curl_auth_create_plain_message(const char *authzid,
+                                        const char *authcid,
+                                        const char *passwd,
+                                        struct bufref *out);
+
+/* This is used to generate a LOGIN cleartext message */
+CURLcode Curl_auth_create_login_message(const char *value,
+                                        struct bufref *out);
+
+/* This is used to generate an EXTERNAL cleartext message */
+CURLcode Curl_auth_create_external_message(const char *user,
+                                           struct bufref *out);
+
+#ifndef CURL_DISABLE_DIGEST_AUTH
+/* This is used to generate a CRAM-MD5 response message */
+CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
+                                           const char *userp,
+                                           const char *passwdp,
+                                           struct bufref *out);
+
+/* This is used to evaluate if DIGEST is supported */
+bool Curl_auth_is_digest_supported(void);
+
+/* This is used to generate a base64 encoded DIGEST-MD5 response message */
+CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
+                                             const struct bufref *chlg,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             const char *service,
+                                             struct bufref *out);
+
+/* This is used to decode an HTTP DIGEST challenge message */
+CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
+                                              struct digestdata *digest);
+
+/* This is used to generate an HTTP DIGEST response message */
+CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
+                                              const char *userp,
+                                              const char *passwdp,
+                                              const unsigned char *request,
+                                              const unsigned char *uri,
+                                              struct digestdata *digest,
+                                              char **outptr, size_t *outlen);
+
+/* This is used to clean up the digest specific data */
+void Curl_auth_digest_cleanup(struct digestdata *digest);
+#endif /* !CURL_DISABLE_DIGEST_AUTH */
+
+#ifdef USE_GSASL
+/* This is used to evaluate if MECH is supported by gsasl */
+bool Curl_auth_gsasl_is_supported(struct Curl_easy *data,
+                                  const char *mech,
+                                  struct gsasldata *gsasl);
+/* This is used to start a gsasl method */
+CURLcode Curl_auth_gsasl_start(struct Curl_easy *data,
+                               const char *userp,
+                               const char *passwdp,
+                               struct gsasldata *gsasl);
+
+/* This is used to process and generate a new SASL token */
+CURLcode Curl_auth_gsasl_token(struct Curl_easy *data,
+                               const struct bufref *chlg,
+                               struct gsasldata *gsasl,
+                               struct bufref *out);
+
+/* This is used to clean up the gsasl specific data */
+void Curl_auth_gsasl_cleanup(struct gsasldata *digest);
+#endif
+
+#if defined(USE_NTLM)
+/* This is used to evaluate if NTLM is supported */
+bool Curl_auth_is_ntlm_supported(void);
+
+/* This is used to generate a base64 encoded NTLM type-1 message */
+CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             const char *service,
+                                             const char *host,
+                                             struct ntlmdata *ntlm,
+                                             struct bufref *out);
+
+/* This is used to decode a base64 encoded NTLM type-2 message */
+CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
+                                             const struct bufref *type2,
+                                             struct ntlmdata *ntlm);
+
+/* This is used to generate a base64 encoded NTLM type-3 message */
+CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             struct ntlmdata *ntlm,
+                                             struct bufref *out);
+
+/* This is used to clean up the NTLM specific data */
+void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm);
+#endif /* USE_NTLM */
+
+/* This is used to generate a base64 encoded OAuth 2.0 message */
+CURLcode Curl_auth_create_oauth_bearer_message(const char *user,
+                                               const char *host,
+                                               const long port,
+                                               const char *bearer,
+                                               struct bufref *out);
+
+/* This is used to generate a base64 encoded XOAuth 2.0 message */
+CURLcode Curl_auth_create_xoauth_bearer_message(const char *user,
+                                                const char *bearer,
+                                                struct bufref *out);
+
+#if defined(USE_KERBEROS5)
+/* This is used to evaluate if GSSAPI (Kerberos V5) is supported */
+bool Curl_auth_is_gssapi_supported(void);
+
+/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token
+   message */
+CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
+                                              const char *userp,
+                                              const char *passwdp,
+                                              const char *service,
+                                              const char *host,
+                                              const bool mutual,
+                                              const struct bufref *chlg,
+                                              struct kerberos5data *krb5,
+                                              struct bufref *out);
+
+/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security
+   token message */
+CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
+                                                  const char *authzid,
+                                                  const struct bufref *chlg,
+                                                  struct kerberos5data *krb5,
+                                                  struct bufref *out);
+
+/* This is used to clean up the GSSAPI specific data */
+void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5);
+#endif /* USE_KERBEROS5 */
+
+#if defined(USE_SPNEGO)
+/* This is used to evaluate if SPNEGO (Negotiate) is supported */
+bool Curl_auth_is_spnego_supported(void);
+
+/* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge
+   message */
+CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
+                                         const char *user,
+                                         const char *password,
+                                         const char *service,
+                                         const char *host,
+                                         const char *chlg64,
+                                         struct negotiatedata *nego);
+
+/* This is used to generate a base64 encoded SPNEGO (Negotiate) response
+   message */
+CURLcode Curl_auth_create_spnego_message(struct negotiatedata *nego,
+                                         char **outptr, size_t *outlen);
+
+/* This is used to clean up the SPNEGO specific data */
+void Curl_auth_cleanup_spnego(struct negotiatedata *nego);
+
+#endif /* USE_SPNEGO */
+
+#endif /* HEADER_CURL_VAUTH_H */
Index: trunk/src/libs/curl-8.7.1/lib/version.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/version.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/version.c	(revision 104083)
@@ -0,0 +1,684 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_NGHTTP2
+#include <nghttp2/nghttp2.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "vtls/vtls.h"
+#include "http2.h"
+#include "vssh/ssh.h"
+#include "vquic/vquic.h"
+#include "curl_printf.h"
+#include "easy_lock.h"
+
+#ifdef USE_ARES
+#  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) &&   \
+  defined(_WIN32)
+#    define CARES_STATICLIB
+#  endif
+#  include <ares.h>
+#endif
+
+#ifdef USE_LIBIDN2
+#include <idn2.h>
+#endif
+
+#ifdef USE_LIBPSL
+#include <libpsl.h>
+#endif
+
+#ifdef USE_LIBRTMP
+#include <librtmp/rtmp.h>
+#endif
+
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+#ifdef HAVE_BROTLI
+#if defined(__GNUC__)
+/* Ignore -Wvla warnings in brotli headers */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wvla"
+#endif
+#include <brotli/decode.h>
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+#endif
+
+#ifdef HAVE_ZSTD
+#include <zstd.h>
+#endif
+
+#ifdef USE_GSASL
+#include <gsasl.h>
+#endif
+
+#ifdef USE_OPENLDAP
+#include <ldap.h>
+#endif
+
+#ifdef HAVE_BROTLI
+static void brotli_version(char *buf, size_t bufsz)
+{
+  uint32_t brotli_version = BrotliDecoderVersion();
+  unsigned int major = brotli_version >> 24;
+  unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12;
+  unsigned int patch = brotli_version & 0x00000FFF;
+  (void)msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
+}
+#endif
+
+#ifdef HAVE_ZSTD
+static void zstd_version(char *buf, size_t bufsz)
+{
+  unsigned long zstd_version = (unsigned long)ZSTD_versionNumber();
+  unsigned int major = (unsigned int)(zstd_version / (100 * 100));
+  unsigned int minor = (unsigned int)((zstd_version -
+                                       (major * 100 * 100)) / 100);
+  unsigned int patch = (unsigned int)(zstd_version -
+                                      (major * 100 * 100) - (minor * 100));
+  (void)msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
+}
+#endif
+
+/*
+ * curl_version() returns a pointer to a static buffer.
+ *
+ * It is implemented to work multi-threaded by making sure repeated invokes
+ * generate the exact same string and never write any temporary data like
+ * zeros in the data.
+ */
+
+#define VERSION_PARTS 16 /* number of substrings we can concatenate */
+
+char *curl_version(void)
+{
+  static char out[300];
+  char *outp;
+  size_t outlen;
+  const char *src[VERSION_PARTS];
+#ifdef USE_SSL
+  char ssl_version[200];
+#endif
+#ifdef HAVE_LIBZ
+  char z_version[40];
+#endif
+#ifdef HAVE_BROTLI
+  char br_version[40] = "brotli/";
+#endif
+#ifdef HAVE_ZSTD
+  char zst_version[40] = "zstd/";
+#endif
+#ifdef USE_ARES
+  char cares_version[40];
+#endif
+#if defined(USE_LIBIDN2)
+  char idn_version[40];
+#endif
+#ifdef USE_LIBPSL
+  char psl_version[40];
+#endif
+#ifdef USE_SSH
+  char ssh_version[40];
+#endif
+#ifdef USE_NGHTTP2
+  char h2_version[40];
+#endif
+#ifdef ENABLE_QUIC
+  char h3_version[40];
+#endif
+#ifdef USE_LIBRTMP
+  char rtmp_version[40];
+#endif
+#ifdef USE_HYPER
+  char hyper_buf[30];
+#endif
+#ifdef USE_GSASL
+  char gsasl_buf[30];
+#endif
+#ifdef USE_OPENLDAP
+  char ldap_buf[30];
+#endif
+  int i = 0;
+  int j;
+
+#ifdef DEBUGBUILD
+  /* Override version string when environment variable CURL_VERSION is set */
+  const char *debugversion = getenv("CURL_VERSION");
+  if(debugversion) {
+    strncpy(out, debugversion, sizeof(out)-1);
+    out[sizeof(out)-1] = '\0';
+    return out;
+  }
+#endif
+
+  src[i++] = LIBCURL_NAME "/" LIBCURL_VERSION;
+#ifdef USE_SSL
+  Curl_ssl_version(ssl_version, sizeof(ssl_version));
+  src[i++] = ssl_version;
+#endif
+#ifdef HAVE_LIBZ
+  msnprintf(z_version, sizeof(z_version), "zlib/%s", zlibVersion());
+  src[i++] = z_version;
+#endif
+#ifdef HAVE_BROTLI
+  brotli_version(&br_version[7], sizeof(br_version) - 7);
+  src[i++] = br_version;
+#endif
+#ifdef HAVE_ZSTD
+  zstd_version(&zst_version[5], sizeof(zst_version) - 5);
+  src[i++] = zst_version;
+#endif
+#ifdef USE_ARES
+  msnprintf(cares_version, sizeof(cares_version),
+            "c-ares/%s", ares_version(NULL));
+  src[i++] = cares_version;
+#endif
+#ifdef USE_LIBIDN2
+  msnprintf(idn_version, sizeof(idn_version),
+            "libidn2/%s", idn2_check_version(NULL));
+  src[i++] = idn_version;
+#elif defined(USE_WIN32_IDN)
+  src[i++] = (char *)"WinIDN";
+#endif
+
+#ifdef USE_LIBPSL
+  {
+#if defined(PSL_VERSION_MAJOR) && (PSL_VERSION_MAJOR > 0 ||     \
+                                   PSL_VERSION_MINOR >= 11)
+    int num = psl_check_version_number(0);
+    msnprintf(psl_version, sizeof(psl_version), "libpsl/%d.%d.%d",
+              num >> 16, (num >> 8) & 0xff, num & 0xff);
+#else
+    msnprintf(psl_version, sizeof(psl_version), "libpsl/%s",
+              psl_get_version());
+#endif
+    src[i++] = psl_version;
+  }
+#endif
+
+#ifdef USE_SSH
+  Curl_ssh_version(ssh_version, sizeof(ssh_version));
+  src[i++] = ssh_version;
+#endif
+#ifdef USE_NGHTTP2
+  Curl_http2_ver(h2_version, sizeof(h2_version));
+  src[i++] = h2_version;
+#endif
+#ifdef ENABLE_QUIC
+  Curl_quic_ver(h3_version, sizeof(h3_version));
+  src[i++] = h3_version;
+#endif
+#ifdef USE_LIBRTMP
+  {
+    char suff[2];
+    if(RTMP_LIB_VERSION & 0xff) {
+      suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1;
+      suff[1] = '\0';
+    }
+    else
+      suff[0] = '\0';
+
+    msnprintf(rtmp_version, sizeof(rtmp_version), "librtmp/%d.%d%s",
+              RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff,
+              suff);
+    src[i++] = rtmp_version;
+  }
+#endif
+#ifdef USE_HYPER
+  msnprintf(hyper_buf, sizeof(hyper_buf), "Hyper/%s", hyper_version());
+  src[i++] = hyper_buf;
+#endif
+#ifdef USE_GSASL
+  msnprintf(gsasl_buf, sizeof(gsasl_buf), "libgsasl/%s",
+            gsasl_check_version(NULL));
+  src[i++] = gsasl_buf;
+#endif
+#ifdef USE_OPENLDAP
+  {
+    LDAPAPIInfo api;
+    api.ldapai_info_version = LDAP_API_INFO_VERSION;
+
+    if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) == LDAP_OPT_SUCCESS) {
+      unsigned int patch = api.ldapai_vendor_version % 100;
+      unsigned int major = api.ldapai_vendor_version / 10000;
+      unsigned int minor =
+        ((api.ldapai_vendor_version - major * 10000) - patch) / 100;
+      msnprintf(ldap_buf, sizeof(ldap_buf), "%s/%u.%u.%u",
+                api.ldapai_vendor_name, major, minor, patch);
+      src[i++] = ldap_buf;
+      ldap_memfree(api.ldapai_vendor_name);
+      ber_memvfree((void **)api.ldapai_extensions);
+    }
+  }
+#endif
+
+  DEBUGASSERT(i <= VERSION_PARTS);
+
+  outp = &out[0];
+  outlen = sizeof(out);
+  for(j = 0; j < i; j++) {
+    size_t n = strlen(src[j]);
+    /* we need room for a space, the string and the final zero */
+    if(outlen <= (n + 2))
+      break;
+    if(j) {
+      /* prepend a space if not the first */
+      *outp++ = ' ';
+      outlen--;
+    }
+    memcpy(outp, src[j], n);
+    outp += n;
+    outlen -= n;
+  }
+  *outp = 0;
+
+  return out;
+}
+
+/* data for curl_version_info
+
+   Keep the list sorted alphabetically. It is also written so that each
+   protocol line has its own #if line to make things easier on the eye.
+ */
+
+static const char * const supported_protocols[] = {
+#ifndef CURL_DISABLE_DICT
+  "dict",
+#endif
+#ifndef CURL_DISABLE_FILE
+  "file",
+#endif
+#ifndef CURL_DISABLE_FTP
+  "ftp",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
+  "ftps",
+#endif
+#ifndef CURL_DISABLE_GOPHER
+  "gopher",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)
+  "gophers",
+#endif
+#ifndef CURL_DISABLE_HTTP
+  "http",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+  "https",
+#endif
+#ifndef CURL_DISABLE_IMAP
+  "imap",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
+  "imaps",
+#endif
+#ifndef CURL_DISABLE_LDAP
+  "ldap",
+#if !defined(CURL_DISABLE_LDAPS) && \
+    ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
+     (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
+  "ldaps",
+#endif
+#endif
+#ifndef CURL_DISABLE_MQTT
+  "mqtt",
+#endif
+#ifndef CURL_DISABLE_POP3
+  "pop3",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
+  "pop3s",
+#endif
+#ifdef USE_LIBRTMP
+  "rtmp",
+  "rtmpe",
+  "rtmps",
+  "rtmpt",
+  "rtmpte",
+  "rtmpts",
+#endif
+#ifndef CURL_DISABLE_RTSP
+  "rtsp",
+#endif
+#if defined(USE_SSH) && !defined(USE_WOLFSSH)
+  "scp",
+#endif
+#ifdef USE_SSH
+  "sftp",
+#endif
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE)
+  "smb",
+#  ifdef USE_SSL
+  "smbs",
+#  endif
+#endif
+#ifndef CURL_DISABLE_SMTP
+  "smtp",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
+  "smtps",
+#endif
+#ifndef CURL_DISABLE_TELNET
+  "telnet",
+#endif
+#ifndef CURL_DISABLE_TFTP
+  "tftp",
+#endif
+#ifdef USE_WEBSOCKETS
+  "ws",
+#endif
+#if defined(USE_SSL) && defined(USE_WEBSOCKETS)
+  "wss",
+#endif
+
+  NULL
+};
+
+/*
+ * Feature presence run-time check functions.
+ *
+ * Warning: the value returned by these should not change between
+ * curl_global_init() and curl_global_cleanup() calls.
+ */
+
+#if defined(USE_LIBIDN2)
+static int idn_present(curl_version_info_data *info)
+{
+  return info->libidn != NULL;
+}
+#else
+#define idn_present     NULL
+#endif
+
+#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) && \
+  !defined(CURL_DISABLE_HTTP)
+static int https_proxy_present(curl_version_info_data *info)
+{
+  (void) info;
+  return Curl_ssl_supports(NULL, SSLSUPP_HTTPS_PROXY);
+}
+#endif
+
+/*
+ * Features table.
+ *
+ * Keep the features alphabetically sorted.
+ * Use FEATURE() macro to define an entry: this allows documentation check.
+ */
+
+#define FEATURE(name, present, bitmask) {(name), (present), (bitmask)}
+
+struct feat {
+  const char *name;
+  int        (*present)(curl_version_info_data *info);
+  int        bitmask;
+};
+
+static const struct feat features_table[] = {
+#ifndef CURL_DISABLE_ALTSVC
+  FEATURE("alt-svc",     NULL,                CURL_VERSION_ALTSVC),
+#endif
+#ifdef CURLRES_ASYNCH
+  FEATURE("AsynchDNS",   NULL,                CURL_VERSION_ASYNCHDNS),
+#endif
+#ifdef HAVE_BROTLI
+  FEATURE("brotli",      NULL,                CURL_VERSION_BROTLI),
+#endif
+#ifdef DEBUGBUILD
+  FEATURE("Debug",       NULL,                CURL_VERSION_DEBUG),
+#endif
+#ifdef USE_GSASL
+  FEATURE("gsasl",       NULL,                CURL_VERSION_GSASL),
+#endif
+#ifdef HAVE_GSSAPI
+  FEATURE("GSS-API",     NULL,                CURL_VERSION_GSSAPI),
+#endif
+#ifndef CURL_DISABLE_HSTS
+  FEATURE("HSTS",        NULL,                CURL_VERSION_HSTS),
+#endif
+#if defined(USE_NGHTTP2)
+  FEATURE("HTTP2",       NULL,                CURL_VERSION_HTTP2),
+#endif
+#if defined(ENABLE_QUIC)
+  FEATURE("HTTP3",       NULL,                CURL_VERSION_HTTP3),
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) && \
+  !defined(CURL_DISABLE_HTTP)
+  FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY),
+#endif
+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
+  FEATURE("IDN",         idn_present,         CURL_VERSION_IDN),
+#endif
+#ifdef ENABLE_IPV6
+  FEATURE("IPv6",        NULL,                CURL_VERSION_IPV6),
+#endif
+#ifdef USE_KERBEROS5
+  FEATURE("Kerberos",    NULL,                CURL_VERSION_KERBEROS5),
+#endif
+#if (SIZEOF_CURL_OFF_T > 4) && \
+    ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) )
+  FEATURE("Largefile",   NULL,                CURL_VERSION_LARGEFILE),
+#endif
+#ifdef HAVE_LIBZ
+  FEATURE("libz",        NULL,                CURL_VERSION_LIBZ),
+#endif
+#ifdef CURL_WITH_MULTI_SSL
+  FEATURE("MultiSSL",    NULL,                CURL_VERSION_MULTI_SSL),
+#endif
+#ifdef USE_NTLM
+  FEATURE("NTLM",        NULL,                CURL_VERSION_NTLM),
+#endif
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+  defined(NTLM_WB_ENABLED)
+  FEATURE("NTLM_WB",     NULL,                CURL_VERSION_NTLM_WB),
+#endif
+#if defined(USE_LIBPSL)
+  FEATURE("PSL",         NULL,                CURL_VERSION_PSL),
+#endif
+#ifdef USE_SPNEGO
+  FEATURE("SPNEGO",      NULL,                CURL_VERSION_SPNEGO),
+#endif
+#ifdef USE_SSL
+  FEATURE("SSL",         NULL,                CURL_VERSION_SSL),
+#endif
+#ifdef USE_WINDOWS_SSPI
+  FEATURE("SSPI",        NULL,                CURL_VERSION_SSPI),
+#endif
+#ifdef GLOBAL_INIT_IS_THREADSAFE
+  FEATURE("threadsafe",  NULL,                CURL_VERSION_THREADSAFE),
+#endif
+#ifdef USE_TLS_SRP
+  FEATURE("TLS-SRP",     NULL,                CURL_VERSION_TLSAUTH_SRP),
+#endif
+#ifdef CURLDEBUG
+  FEATURE("TrackMemory", NULL,                CURL_VERSION_CURLDEBUG),
+#endif
+#if defined(_WIN32) && defined(UNICODE) && defined(_UNICODE)
+  FEATURE("Unicode",     NULL,                CURL_VERSION_UNICODE),
+#endif
+#ifdef USE_UNIX_SOCKETS
+  FEATURE("UnixSockets", NULL,                CURL_VERSION_UNIX_SOCKETS),
+#endif
+#ifdef HAVE_ZSTD
+  FEATURE("zstd",        NULL,                CURL_VERSION_ZSTD),
+#endif
+  {NULL,             NULL,                0}
+};
+
+static const char *feature_names[sizeof(features_table) /
+                                 sizeof(features_table[0])] = {NULL};
+
+
+static curl_version_info_data version_info = {
+  CURLVERSION_NOW,
+  LIBCURL_VERSION,
+  LIBCURL_VERSION_NUM,
+  OS,   /* as found by configure or set by hand at build-time */
+  0,    /* features bitmask is built at run-time */
+  NULL, /* ssl_version */
+  0,    /* ssl_version_num, this is kept at zero */
+  NULL, /* zlib_version */
+  supported_protocols,
+  NULL, /* c-ares version */
+  0,    /* c-ares version numerical */
+  NULL, /* libidn version */
+  0,    /* iconv version */
+  NULL, /* ssh lib version */
+  0,    /* brotli_ver_num */
+  NULL, /* brotli version */
+  0,    /* nghttp2 version number */
+  NULL, /* nghttp2 version string */
+  NULL, /* quic library string */
+#ifdef CURL_CA_BUNDLE
+  CURL_CA_BUNDLE, /* cainfo */
+#else
+  NULL,
+#endif
+#ifdef CURL_CA_PATH
+  CURL_CA_PATH,  /* capath */
+#else
+  NULL,
+#endif
+  0,    /* zstd_ver_num */
+  NULL, /* zstd version */
+  NULL, /* Hyper version */
+  NULL, /* gsasl version */
+  feature_names
+};
+
+curl_version_info_data *curl_version_info(CURLversion stamp)
+{
+  size_t n;
+  const struct feat *p;
+  int features = 0;
+
+#if defined(USE_SSH)
+  static char ssh_buffer[80];
+#endif
+#ifdef USE_SSL
+#ifdef CURL_WITH_MULTI_SSL
+  static char ssl_buffer[200];
+#else
+  static char ssl_buffer[80];
+#endif
+#endif
+#ifdef HAVE_BROTLI
+  static char brotli_buffer[80];
+#endif
+#ifdef HAVE_ZSTD
+  static char zstd_buffer[80];
+#endif
+
+  (void)stamp; /* avoid compiler warnings, we don't use this */
+
+#ifdef USE_SSL
+  Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
+  version_info.ssl_version = ssl_buffer;
+#endif
+
+#ifdef HAVE_LIBZ
+  version_info.libz_version = zlibVersion();
+  /* libz left NULL if non-existing */
+#endif
+#ifdef USE_ARES
+  {
+    int aresnum;
+    version_info.ares = ares_version(&aresnum);
+    version_info.ares_num = aresnum;
+  }
+#endif
+#ifdef USE_LIBIDN2
+  /* This returns a version string if we use the given version or later,
+     otherwise it returns NULL */
+  version_info.libidn = idn2_check_version(IDN2_VERSION);
+#endif
+
+#if defined(USE_SSH)
+  Curl_ssh_version(ssh_buffer, sizeof(ssh_buffer));
+  version_info.libssh_version = ssh_buffer;
+#endif
+
+#ifdef HAVE_BROTLI
+  version_info.brotli_ver_num = BrotliDecoderVersion();
+  brotli_version(brotli_buffer, sizeof(brotli_buffer));
+  version_info.brotli_version = brotli_buffer;
+#endif
+
+#ifdef HAVE_ZSTD
+  version_info.zstd_ver_num = (unsigned int)ZSTD_versionNumber();
+  zstd_version(zstd_buffer, sizeof(zstd_buffer));
+  version_info.zstd_version = zstd_buffer;
+#endif
+
+#ifdef USE_NGHTTP2
+  {
+    nghttp2_info *h2 = nghttp2_version(0);
+    version_info.nghttp2_ver_num = h2->version_num;
+    version_info.nghttp2_version = h2->version_str;
+  }
+#endif
+
+#ifdef ENABLE_QUIC
+  {
+    static char quicbuffer[80];
+    Curl_quic_ver(quicbuffer, sizeof(quicbuffer));
+    version_info.quic_version = quicbuffer;
+  }
+#endif
+
+#ifdef USE_HYPER
+  {
+    static char hyper_buffer[30];
+    msnprintf(hyper_buffer, sizeof(hyper_buffer), "Hyper/%s", hyper_version());
+    version_info.hyper_version = hyper_buffer;
+  }
+#endif
+
+#ifdef USE_GSASL
+  {
+    version_info.gsasl_version = gsasl_check_version(NULL);
+  }
+#endif
+
+  /* Get available features, build bitmask and names array. */
+  n = 0;
+  for(p = features_table; p->name; p++)
+    if(!p->present || p->present(&version_info)) {
+      features |= p->bitmask;
+      feature_names[n++] = p->name;
+    }
+
+  feature_names[n] = NULL;  /* Terminate array. */
+  version_info.features = features;
+
+  return &version_info;
+}
Index: trunk/src/libs/curl-8.7.1/lib/version_win32.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/version_win32.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/version_win32.c	(revision 104083)
@@ -0,0 +1,319 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(_WIN32)
+
+#include <curl/curl.h>
+#include "version_win32.h"
+#include "warnless.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
+   and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */
+struct OUR_OSVERSIONINFOEXW {
+  ULONG  dwOSVersionInfoSize;
+  ULONG  dwMajorVersion;
+  ULONG  dwMinorVersion;
+  ULONG  dwBuildNumber;
+  ULONG  dwPlatformId;
+  WCHAR  szCSDVersion[128];
+  USHORT wServicePackMajor;
+  USHORT wServicePackMinor;
+  USHORT wSuiteMask;
+  UCHAR  wProductType;
+  UCHAR  wReserved;
+};
+
+/*
+ * curlx_verify_windows_version()
+ *
+ * This is used to verify if we are running on a specific windows version.
+ *
+ * Parameters:
+ *
+ * majorVersion [in] - The major version number.
+ * minorVersion [in] - The minor version number.
+ * buildVersion [in] - The build version number. If 0, this parameter is
+ *                     ignored.
+ * platform     [in] - The optional platform identifier.
+ * condition    [in] - The test condition used to specifier whether we are
+ *                     checking a version less then, equal to or greater than
+ *                     what is specified in the major and minor version
+ *                     numbers.
+ *
+ * Returns TRUE if matched; otherwise FALSE.
+ */
+bool curlx_verify_windows_version(const unsigned int majorVersion,
+                                  const unsigned int minorVersion,
+                                  const unsigned int buildVersion,
+                                  const PlatformIdentifier platform,
+                                  const VersionCondition condition)
+{
+  bool matched = FALSE;
+
+#if defined(CURL_WINDOWS_APP)
+  (void)buildVersion;
+
+  /* We have no way to determine the Windows version from Windows apps,
+     so let's assume we're running on the target Windows version. */
+  const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
+  const WORD targetVersion = (WORD)_WIN32_WINNT;
+
+  switch(condition) {
+  case VERSION_LESS_THAN:
+    matched = targetVersion < fullVersion;
+    break;
+
+  case VERSION_LESS_THAN_EQUAL:
+    matched = targetVersion <= fullVersion;
+    break;
+
+  case VERSION_EQUAL:
+    matched = targetVersion == fullVersion;
+    break;
+
+  case VERSION_GREATER_THAN_EQUAL:
+    matched = targetVersion >= fullVersion;
+    break;
+
+  case VERSION_GREATER_THAN:
+    matched = targetVersion > fullVersion;
+    break;
+  }
+
+  if(matched && (platform == PLATFORM_WINDOWS)) {
+    /* we're always running on PLATFORM_WINNT */
+    matched = FALSE;
+  }
+#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
+    (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
+  OSVERSIONINFO osver;
+
+  memset(&osver, 0, sizeof(osver));
+  osver.dwOSVersionInfoSize = sizeof(osver);
+
+  /* Find out Windows version */
+  if(GetVersionEx(&osver)) {
+    /* Verify the Operating System version number */
+    switch(condition) {
+    case VERSION_LESS_THAN:
+      if(osver.dwMajorVersion < majorVersion ||
+        (osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion < minorVersion) ||
+        (buildVersion != 0 &&
+         (osver.dwMajorVersion == majorVersion &&
+          osver.dwMinorVersion == minorVersion &&
+          osver.dwBuildNumber < buildVersion)))
+        matched = TRUE;
+      break;
+
+    case VERSION_LESS_THAN_EQUAL:
+      if(osver.dwMajorVersion < majorVersion ||
+        (osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion < minorVersion) ||
+        (osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion == minorVersion &&
+         (buildVersion == 0 ||
+          osver.dwBuildNumber <= buildVersion)))
+        matched = TRUE;
+      break;
+
+    case VERSION_EQUAL:
+      if(osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion == minorVersion &&
+        (buildVersion == 0 ||
+         osver.dwBuildNumber == buildVersion))
+        matched = TRUE;
+      break;
+
+    case VERSION_GREATER_THAN_EQUAL:
+      if(osver.dwMajorVersion > majorVersion ||
+        (osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion > minorVersion) ||
+        (osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion == minorVersion &&
+         (buildVersion == 0 ||
+          osver.dwBuildNumber >= buildVersion)))
+        matched = TRUE;
+      break;
+
+    case VERSION_GREATER_THAN:
+      if(osver.dwMajorVersion > majorVersion ||
+        (osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion > minorVersion) ||
+        (buildVersion != 0 &&
+         (osver.dwMajorVersion == majorVersion &&
+          osver.dwMinorVersion == minorVersion &&
+          osver.dwBuildNumber > buildVersion)))
+        matched = TRUE;
+      break;
+    }
+
+    /* Verify the platform identifier (if necessary) */
+    if(matched) {
+      switch(platform) {
+      case PLATFORM_WINDOWS:
+        if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
+          matched = FALSE;
+        break;
+
+      case PLATFORM_WINNT:
+        if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
+          matched = FALSE;
+        break;
+
+      default: /* like platform == PLATFORM_DONT_CARE */
+        break;
+      }
+    }
+  }
+#else
+  ULONGLONG cm = 0;
+  struct OUR_OSVERSIONINFOEXW osver;
+  BYTE majorCondition;
+  BYTE minorCondition;
+  BYTE buildCondition;
+  BYTE spMajorCondition;
+  BYTE spMinorCondition;
+  DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION |
+                     VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR;
+
+  typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN)
+    (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG);
+  static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo;
+  static bool onetime = true; /* safe because first call is during init */
+
+  if(onetime) {
+    pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN,
+      (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo")));
+    onetime = false;
+  }
+
+  switch(condition) {
+  case VERSION_LESS_THAN:
+    majorCondition = VER_LESS;
+    minorCondition = VER_LESS;
+    buildCondition = VER_LESS;
+    spMajorCondition = VER_LESS_EQUAL;
+    spMinorCondition = VER_LESS_EQUAL;
+    break;
+
+  case VERSION_LESS_THAN_EQUAL:
+    majorCondition = VER_LESS_EQUAL;
+    minorCondition = VER_LESS_EQUAL;
+    buildCondition = VER_LESS_EQUAL;
+    spMajorCondition = VER_LESS_EQUAL;
+    spMinorCondition = VER_LESS_EQUAL;
+    break;
+
+  case VERSION_EQUAL:
+    majorCondition = VER_EQUAL;
+    minorCondition = VER_EQUAL;
+    buildCondition = VER_EQUAL;
+    spMajorCondition = VER_GREATER_EQUAL;
+    spMinorCondition = VER_GREATER_EQUAL;
+    break;
+
+  case VERSION_GREATER_THAN_EQUAL:
+    majorCondition = VER_GREATER_EQUAL;
+    minorCondition = VER_GREATER_EQUAL;
+    buildCondition = VER_GREATER_EQUAL;
+    spMajorCondition = VER_GREATER_EQUAL;
+    spMinorCondition = VER_GREATER_EQUAL;
+    break;
+
+  case VERSION_GREATER_THAN:
+    majorCondition = VER_GREATER;
+    minorCondition = VER_GREATER;
+    buildCondition = VER_GREATER;
+    spMajorCondition = VER_GREATER_EQUAL;
+    spMinorCondition = VER_GREATER_EQUAL;
+    break;
+
+  default:
+    return FALSE;
+  }
+
+  memset(&osver, 0, sizeof(osver));
+  osver.dwOSVersionInfoSize = sizeof(osver);
+  osver.dwMajorVersion = majorVersion;
+  osver.dwMinorVersion = minorVersion;
+  osver.dwBuildNumber = buildVersion;
+  if(platform == PLATFORM_WINDOWS)
+    osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
+  else if(platform == PLATFORM_WINNT)
+    osver.dwPlatformId = VER_PLATFORM_WIN32_NT;
+
+  cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition);
+  cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
+  cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
+  cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
+
+  if(platform != PLATFORM_DONT_CARE) {
+    cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
+    dwTypeMask |= VER_PLATFORMID;
+  }
+
+  /* Later versions of Windows have version functions that may not return the
+     real version of Windows unless the application is so manifested. We prefer
+     the real version always, so we use the Rtl variant of the function when
+     possible. Note though the function signatures have underlying fundamental
+     types that are the same, the return values are different. */
+  if(pRtlVerifyVersionInfo)
+    matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
+  else
+    matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm);
+
+  /* Compare the build number separately. VerifyVersionInfo normally compares
+     major.minor in hierarchical order (eg 1.9 is less than 2.0) but does not
+     do the same for build (eg 1.9 build 222 is not less than 2.0 build 111).
+     Build comparison is only needed when build numbers are equal (eg 1.9 is
+     always less than 2.0 so build comparison is not needed). */
+  if(matched && buildVersion &&
+     (condition == VERSION_EQUAL ||
+      ((condition == VERSION_GREATER_THAN_EQUAL ||
+        condition == VERSION_LESS_THAN_EQUAL) &&
+        curlx_verify_windows_version(majorVersion, minorVersion, 0,
+                                     platform, VERSION_EQUAL)))) {
+
+    cm = VerSetConditionMask(0, VER_BUILDNUMBER, buildCondition);
+    dwTypeMask = VER_BUILDNUMBER;
+    if(pRtlVerifyVersionInfo)
+      matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
+    else
+      matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver,
+                                      dwTypeMask, cm);
+  }
+
+#endif
+
+  return matched;
+}
+
+#endif /* _WIN32 */
Index: trunk/src/libs/curl-8.7.1/lib/version_win32.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/version_win32.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/version_win32.h	(revision 104083)
@@ -0,0 +1,56 @@
+#ifndef HEADER_CURL_VERSION_WIN32_H
+#define HEADER_CURL_VERSION_WIN32_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(_WIN32)
+
+/* Version condition */
+typedef enum {
+  VERSION_LESS_THAN,
+  VERSION_LESS_THAN_EQUAL,
+  VERSION_EQUAL,
+  VERSION_GREATER_THAN_EQUAL,
+  VERSION_GREATER_THAN
+} VersionCondition;
+
+/* Platform identifier */
+typedef enum {
+  PLATFORM_DONT_CARE,
+  PLATFORM_WINDOWS,
+  PLATFORM_WINNT
+} PlatformIdentifier;
+
+/* This is used to verify if we are running on a specific windows version */
+bool curlx_verify_windows_version(const unsigned int majorVersion,
+                                  const unsigned int minorVersion,
+                                  const unsigned int buildVersion,
+                                  const PlatformIdentifier platform,
+                                  const VersionCondition condition);
+
+#endif /* _WIN32 */
+
+#endif /* HEADER_CURL_VERSION_WIN32_H */
Index: trunk/src/libs/curl-8.7.1/lib/vquic/curl_msh3.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vquic/curl_msh3.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vquic/curl_msh3.c	(revision 104083)
@@ -0,0 +1,1071 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_MSH3
+
+#include "urldata.h"
+#include "timeval.h"
+#include "multiif.h"
+#include "sendf.h"
+#include "curl_trc.h"
+#include "cfilters.h"
+#include "cf-socket.h"
+#include "connect.h"
+#include "progress.h"
+#include "http1.h"
+#include "curl_msh3.h"
+#include "socketpair.h"
+#include "vtls/vtls.h"
+#include "vquic/vquic.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef CURL_DISABLE_SOCKETPAIR
+#error "MSH3 cannot be build with CURL_DISABLE_SOCKETPAIR set"
+#endif
+
+#define H3_STREAM_WINDOW_SIZE (128 * 1024)
+#define H3_STREAM_CHUNK_SIZE   (16 * 1024)
+#define H3_STREAM_RECV_CHUNKS \
+          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
+
+#ifdef _WIN32
+#define msh3_lock CRITICAL_SECTION
+#define msh3_lock_initialize(lock) InitializeCriticalSection(lock)
+#define msh3_lock_uninitialize(lock) DeleteCriticalSection(lock)
+#define msh3_lock_acquire(lock) EnterCriticalSection(lock)
+#define msh3_lock_release(lock) LeaveCriticalSection(lock)
+#else /* !_WIN32 */
+#include <pthread.h>
+#define msh3_lock pthread_mutex_t
+#define msh3_lock_initialize(lock) do { \
+  pthread_mutexattr_t attr; \
+  pthread_mutexattr_init(&attr); \
+  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
+  pthread_mutex_init(lock, &attr); \
+  pthread_mutexattr_destroy(&attr); \
+}while(0)
+#define msh3_lock_uninitialize(lock) pthread_mutex_destroy(lock)
+#define msh3_lock_acquire(lock) pthread_mutex_lock(lock)
+#define msh3_lock_release(lock) pthread_mutex_unlock(lock)
+#endif /* _WIN32 */
+
+
+static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection,
+                                          void *IfContext);
+static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection,
+                                          void *IfContext);
+static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection,
+                                          void *IfContext,
+                                          MSH3_REQUEST *Request);
+static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
+                                           void *IfContext,
+                                           const MSH3_HEADER *Header);
+static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
+                                        void *IfContext, uint32_t *Length,
+                                        const uint8_t *Data);
+static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
+                                    bool Aborted, uint64_t AbortError);
+static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request,
+                                             void *IfContext);
+static void MSH3_CALL msh3_data_sent(MSH3_REQUEST *Request,
+                                     void *IfContext, void *SendContext);
+
+
+void Curl_msh3_ver(char *p, size_t len)
+{
+  uint32_t v[4];
+  MsH3Version(v);
+  (void)msnprintf(p, len, "msh3/%d.%d.%d.%d", v[0], v[1], v[2], v[3]);
+}
+
+#define SP_LOCAL   0
+#define SP_REMOTE  1
+
+struct cf_msh3_ctx {
+  MSH3_API *api;
+  MSH3_CONNECTION *qconn;
+  struct Curl_sockaddr_ex addr;
+  curl_socket_t sock[2]; /* fake socket pair until we get support in msh3 */
+  char l_ip[MAX_IPADR_LEN];          /* local IP as string */
+  int l_port;                        /* local port number */
+  struct cf_call_data call_data;
+  struct curltime connect_started;   /* time the current attempt started */
+  struct curltime handshake_at;      /* time connect handshake finished */
+  /* Flags written by msh3/msquic thread */
+  bool handshake_complete;
+  bool handshake_succeeded;
+  bool connected;
+  /* Flags written by curl thread */
+  BIT(verbose);
+  BIT(active);
+};
+
+/* How to access `call_data` from a cf_msh3 filter */
+#undef CF_CTX_CALL_DATA
+#define CF_CTX_CALL_DATA(cf)  \
+  ((struct cf_msh3_ctx *)(cf)->ctx)->call_data
+
+/**
+ * All about the H3 internals of a stream
+ */
+struct stream_ctx {
+  struct MSH3_REQUEST *req;
+  struct bufq recvbuf;   /* h3 response */
+#ifdef _WIN32
+  CRITICAL_SECTION recv_lock;
+#else /* !_WIN32 */
+  pthread_mutex_t recv_lock;
+#endif /* _WIN32 */
+  uint64_t error3; /* HTTP/3 stream error code */
+  int status_code; /* HTTP status code */
+  CURLcode recv_error;
+  bool closed;
+  bool reset;
+  bool upload_done;
+  bool firstheader;  /* FALSE until headers arrive */
+  bool recv_header_complete;
+};
+
+#define H3_STREAM_CTX(d)    ((struct stream_ctx *)(((d) && (d)->req.p.http)? \
+                             ((struct HTTP *)(d)->req.p.http)->h3_ctx \
+                               : NULL))
+#define H3_STREAM_LCTX(d)   ((struct HTTP *)(d)->req.p.http)->h3_ctx
+#define H3_STREAM_ID(d)     (H3_STREAM_CTX(d)? \
+                             H3_STREAM_CTX(d)->id : -2)
+
+
+static CURLcode h3_data_setup(struct Curl_cfilter *cf,
+                              struct Curl_easy *data)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+
+  if(stream)
+    return CURLE_OK;
+
+  stream = calloc(1, sizeof(*stream));
+  if(!stream)
+    return CURLE_OUT_OF_MEMORY;
+
+  H3_STREAM_LCTX(data) = stream;
+  stream->req = ZERO_NULL;
+  msh3_lock_initialize(&stream->recv_lock);
+  Curl_bufq_init2(&stream->recvbuf, H3_STREAM_CHUNK_SIZE,
+                  H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
+  CURL_TRC_CF(data, cf, "data setup");
+  return CURLE_OK;
+}
+
+static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+
+  (void)cf;
+  if(stream) {
+    CURL_TRC_CF(data, cf, "easy handle is done");
+    Curl_bufq_free(&stream->recvbuf);
+    free(stream);
+    H3_STREAM_LCTX(data) = NULL;
+  }
+}
+
+static void drain_stream_from_other_thread(struct Curl_easy *data,
+                                           struct stream_ctx *stream)
+{
+  unsigned char bits;
+
+  /* risky */
+  bits = CURL_CSELECT_IN;
+  if(stream && !stream->upload_done)
+    bits |= CURL_CSELECT_OUT;
+  if(data->state.select_bits != bits) {
+    data->state.select_bits = bits;
+    /* cannot expire from other thread */
+  }
+}
+
+static void drain_stream(struct Curl_cfilter *cf,
+                         struct Curl_easy *data)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  unsigned char bits;
+
+  (void)cf;
+  bits = CURL_CSELECT_IN;
+  if(stream && !stream->upload_done)
+    bits |= CURL_CSELECT_OUT;
+  if(data->state.select_bits != bits) {
+    data->state.select_bits = bits;
+    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+  }
+}
+
+static const MSH3_CONNECTION_IF msh3_conn_if = {
+  msh3_conn_connected,
+  msh3_conn_shutdown_complete,
+  msh3_conn_new_request
+};
+
+static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection,
+                                          void *IfContext)
+{
+  struct Curl_cfilter *cf = IfContext;
+  struct cf_msh3_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  (void)Connection;
+
+  CURL_TRC_CF(data, cf, "[MSH3] connected");
+  ctx->handshake_succeeded = true;
+  ctx->connected = true;
+  ctx->handshake_complete = true;
+}
+
+static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection,
+                                          void *IfContext)
+{
+  struct Curl_cfilter *cf = IfContext;
+  struct cf_msh3_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+
+  (void)Connection;
+  CURL_TRC_CF(data, cf, "[MSH3] shutdown complete");
+  ctx->connected = false;
+  ctx->handshake_complete = true;
+}
+
+static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection,
+                                          void *IfContext,
+                                          MSH3_REQUEST *Request)
+{
+  (void)Connection;
+  (void)IfContext;
+  (void)Request;
+}
+
+static const MSH3_REQUEST_IF msh3_request_if = {
+  msh3_header_received,
+  msh3_data_received,
+  msh3_complete,
+  msh3_shutdown_complete,
+  msh3_data_sent
+};
+
+/* Decode HTTP status code.  Returns -1 if no valid status code was
+   decoded. (duplicate from http2.c) */
+static int decode_status_code(const char *value, size_t len)
+{
+  int i;
+  int res;
+
+  if(len != 3) {
+    return -1;
+  }
+
+  res = 0;
+
+  for(i = 0; i < 3; ++i) {
+    char c = value[i];
+
+    if(c < '0' || c > '9') {
+      return -1;
+    }
+
+    res *= 10;
+    res += c - '0';
+  }
+
+  return res;
+}
+
+/*
+ * write_resp_raw() copies response data in raw format to the `data`'s
+  * receive buffer. If not enough space is available, it appends to the
+ * `data`'s overflow buffer.
+ */
+static CURLcode write_resp_raw(struct Curl_easy *data,
+                               const void *mem, size_t memlen)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  CURLcode result = CURLE_OK;
+  ssize_t nwritten;
+
+  if(!stream)
+    return CURLE_RECV_ERROR;
+
+  nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
+  if(nwritten < 0) {
+    return result;
+  }
+
+  if((size_t)nwritten < memlen) {
+    /* This MUST not happen. Our recbuf is dimensioned to hold the
+     * full max_stream_window and then some for this very reason. */
+    DEBUGASSERT(0);
+    return CURLE_RECV_ERROR;
+  }
+  return result;
+}
+
+static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
+                                           void *userp,
+                                           const MSH3_HEADER *hd)
+{
+  struct Curl_easy *data = userp;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  CURLcode result;
+  (void)Request;
+
+  if(!stream || stream->recv_header_complete) {
+    return;
+  }
+
+  msh3_lock_acquire(&stream->recv_lock);
+
+  if((hd->NameLength == 7) &&
+     !strncmp(HTTP_PSEUDO_STATUS, (char *)hd->Name, 7)) {
+    char line[14]; /* status line is always 13 characters long */
+    size_t ncopy;
+
+    DEBUGASSERT(!stream->firstheader);
+    stream->status_code = decode_status_code(hd->Value, hd->ValueLength);
+    DEBUGASSERT(stream->status_code != -1);
+    ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
+                      stream->status_code);
+    result = write_resp_raw(data, line, ncopy);
+    if(result)
+      stream->recv_error = result;
+    stream->firstheader = TRUE;
+  }
+  else {
+    /* store as an HTTP1-style header */
+    DEBUGASSERT(stream->firstheader);
+    result = write_resp_raw(data, hd->Name, hd->NameLength);
+    if(!result)
+      result = write_resp_raw(data, ": ", 2);
+    if(!result)
+      result = write_resp_raw(data, hd->Value, hd->ValueLength);
+    if(!result)
+      result = write_resp_raw(data, "\r\n", 2);
+    if(result) {
+      stream->recv_error = result;
+    }
+  }
+
+  drain_stream_from_other_thread(data, stream);
+  msh3_lock_release(&stream->recv_lock);
+}
+
+static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
+                                         void *IfContext, uint32_t *buflen,
+                                         const uint8_t *buf)
+{
+  struct Curl_easy *data = IfContext;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  CURLcode result;
+  bool rv = FALSE;
+
+  /* TODO: we would like to limit the amount of data we are buffer here.
+   * There seems to be no mechanism in msh3 to adjust flow control and
+   * it is undocumented what happens if we return FALSE here or less
+   * length (buflen is an inout parameter).
+   */
+  (void)Request;
+  if(!stream)
+    return FALSE;
+
+  msh3_lock_acquire(&stream->recv_lock);
+
+  if(!stream->recv_header_complete) {
+    result = write_resp_raw(data, "\r\n", 2);
+    if(result) {
+      stream->recv_error = result;
+      goto out;
+    }
+    stream->recv_header_complete = true;
+  }
+
+  result = write_resp_raw(data, buf, *buflen);
+  if(result) {
+    stream->recv_error = result;
+  }
+  rv = TRUE;
+
+out:
+  msh3_lock_release(&stream->recv_lock);
+  return rv;
+}
+
+static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
+                                    bool aborted, uint64_t error)
+{
+  struct Curl_easy *data = IfContext;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+
+  (void)Request;
+  if(!stream)
+    return;
+  msh3_lock_acquire(&stream->recv_lock);
+  stream->closed = TRUE;
+  stream->recv_header_complete = true;
+  if(error)
+    stream->error3 = error;
+  if(aborted)
+    stream->reset = TRUE;
+  msh3_lock_release(&stream->recv_lock);
+}
+
+static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request,
+                                             void *IfContext)
+{
+  struct Curl_easy *data = IfContext;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+
+  if(!stream)
+    return;
+  (void)Request;
+  (void)stream;
+}
+
+static void MSH3_CALL msh3_data_sent(MSH3_REQUEST *Request,
+                                     void *IfContext, void *SendContext)
+{
+  struct Curl_easy *data = IfContext;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  if(!stream)
+    return;
+  (void)Request;
+  (void)stream;
+  (void)SendContext;
+}
+
+static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  CURLcode *err)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  ssize_t nread = -1;
+
+  if(!stream) {
+    *err = CURLE_RECV_ERROR;
+    return -1;
+  }
+  (void)cf;
+  if(stream->reset) {
+    failf(data, "HTTP/3 stream reset by server");
+    *err = CURLE_PARTIAL_FILE;
+    CURL_TRC_CF(data, cf, "cf_recv, was reset -> %d", *err);
+    goto out;
+  }
+  else if(stream->error3) {
+    failf(data, "HTTP/3 stream was not closed cleanly: (error %zd)",
+          (ssize_t)stream->error3);
+    *err = CURLE_HTTP3;
+    CURL_TRC_CF(data, cf, "cf_recv, closed uncleanly -> %d", *err);
+    goto out;
+  }
+  else {
+    CURL_TRC_CF(data, cf, "cf_recv, closed ok -> %d", *err);
+  }
+  *err = CURLE_OK;
+  nread = 0;
+
+out:
+  return nread;
+}
+
+static void set_quic_expire(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+
+  /* we have no indication from msh3 when it would be a good time
+   * to juggle the connection again. So, we compromise by calling
+   * us again every some milliseconds. */
+  (void)cf;
+  if(stream && stream->req && !stream->closed) {
+    Curl_expire(data, 10, EXPIRE_QUIC);
+  }
+  else {
+    Curl_expire(data, 50, EXPIRE_QUIC);
+  }
+}
+
+static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                            char *buf, size_t len, CURLcode *err)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  ssize_t nread = -1;
+  struct cf_call_data save;
+
+  (void)cf;
+  if(!stream) {
+    *err = CURLE_RECV_ERROR;
+    return -1;
+  }
+  CF_DATA_SAVE(save, cf, data);
+  CURL_TRC_CF(data, cf, "req: recv with %zu byte buffer", len);
+
+  msh3_lock_acquire(&stream->recv_lock);
+
+  if(stream->recv_error) {
+    failf(data, "request aborted");
+    *err = stream->recv_error;
+    goto out;
+  }
+
+  *err = CURLE_OK;
+
+  if(!Curl_bufq_is_empty(&stream->recvbuf)) {
+    nread = Curl_bufq_read(&stream->recvbuf,
+                           (unsigned char *)buf, len, err);
+    CURL_TRC_CF(data, cf, "read recvbuf(len=%zu) -> %zd, %d",
+                len, nread, *err);
+    if(nread < 0)
+      goto out;
+    if(stream->closed)
+      drain_stream(cf, data);
+  }
+  else if(stream->closed) {
+    nread = recv_closed_stream(cf, data, err);
+    goto out;
+  }
+  else {
+    CURL_TRC_CF(data, cf, "req: nothing here, call again");
+    *err = CURLE_AGAIN;
+  }
+
+out:
+  msh3_lock_release(&stream->recv_lock);
+  set_quic_expire(cf, data);
+  CF_DATA_RESTORE(cf, save);
+  return nread;
+}
+
+static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                            const void *buf, size_t len, CURLcode *err)
+{
+  struct cf_msh3_ctx *ctx = cf->ctx;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  struct h1_req_parser h1;
+  struct dynhds h2_headers;
+  MSH3_HEADER *nva = NULL;
+  size_t nheader, i;
+  ssize_t nwritten = -1;
+  struct cf_call_data save;
+  bool eos;
+
+  CF_DATA_SAVE(save, cf, data);
+
+  Curl_h1_req_parse_init(&h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
+  Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
+
+  /* Sizes must match for cast below to work" */
+  DEBUGASSERT(stream);
+  CURL_TRC_CF(data, cf, "req: send %zu bytes", len);
+
+  if(!stream->req) {
+    /* The first send on the request contains the headers and possibly some
+       data. Parse out the headers and create the request, then if there is
+       any data left over go ahead and send it too. */
+    nwritten = Curl_h1_req_parse_read(&h1, buf, len, NULL, 0, err);
+    if(nwritten < 0)
+      goto out;
+    DEBUGASSERT(h1.done);
+    DEBUGASSERT(h1.req);
+
+    *err = Curl_http_req_to_h2(&h2_headers, h1.req, data);
+    if(*err) {
+      nwritten = -1;
+      goto out;
+    }
+
+    nheader = Curl_dynhds_count(&h2_headers);
+    nva = malloc(sizeof(MSH3_HEADER) * nheader);
+    if(!nva) {
+      *err = CURLE_OUT_OF_MEMORY;
+      nwritten = -1;
+      goto out;
+    }
+
+    for(i = 0; i < nheader; ++i) {
+      struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i);
+      nva[i].Name = e->name;
+      nva[i].NameLength = e->namelen;
+      nva[i].Value = e->value;
+      nva[i].ValueLength = e->valuelen;
+    }
+
+    switch(data->state.httpreq) {
+    case HTTPREQ_POST:
+    case HTTPREQ_POST_FORM:
+    case HTTPREQ_POST_MIME:
+    case HTTPREQ_PUT:
+      /* known request body size or -1 */
+      eos = FALSE;
+      break;
+    default:
+      /* there is not request body */
+      eos = TRUE;
+      stream->upload_done = TRUE;
+      break;
+    }
+
+    CURL_TRC_CF(data, cf, "req: send %zu headers", nheader);
+    stream->req = MsH3RequestOpen(ctx->qconn, &msh3_request_if, data,
+                                  nva, nheader,
+                                  eos ? MSH3_REQUEST_FLAG_FIN :
+                                  MSH3_REQUEST_FLAG_NONE);
+    if(!stream->req) {
+      failf(data, "request open failed");
+      *err = CURLE_SEND_ERROR;
+      goto out;
+    }
+    *err = CURLE_OK;
+    nwritten = len;
+    goto out;
+  }
+  else {
+    /* request is open */
+    CURL_TRC_CF(data, cf, "req: send %zu body bytes", len);
+    if(len > 0xFFFFFFFF) {
+      len = 0xFFFFFFFF;
+    }
+
+    if(!MsH3RequestSend(stream->req, MSH3_REQUEST_FLAG_NONE, buf,
+                        (uint32_t)len, stream)) {
+      *err = CURLE_SEND_ERROR;
+      goto out;
+    }
+
+    /* TODO - msh3/msquic will hold onto this memory until the send complete
+       event. How do we make sure curl doesn't free it until then? */
+    *err = CURLE_OK;
+    nwritten = len;
+  }
+
+out:
+  set_quic_expire(cf, data);
+  free(nva);
+  Curl_h1_req_parse_free(&h1);
+  Curl_dynhds_free(&h2_headers);
+  CF_DATA_RESTORE(cf, save);
+  return nwritten;
+}
+
+static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   struct easy_pollset *ps)
+{
+  struct cf_msh3_ctx *ctx = cf->ctx;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  struct cf_call_data save;
+
+  CF_DATA_SAVE(save, cf, data);
+  if(stream && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) {
+    if(stream->recv_error) {
+      Curl_pollset_add_in(data, ps, ctx->sock[SP_LOCAL]);
+      drain_stream(cf, data);
+    }
+    else if(stream->req) {
+      Curl_pollset_add_out(data, ps, ctx->sock[SP_LOCAL]);
+      drain_stream(cf, data);
+    }
+  }
+}
+
+static bool cf_msh3_data_pending(struct Curl_cfilter *cf,
+                                 const struct Curl_easy *data)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  struct cf_call_data save;
+  bool pending = FALSE;
+
+  CF_DATA_SAVE(save, cf, data);
+
+  (void)cf;
+  if(stream && stream->req) {
+    msh3_lock_acquire(&stream->recv_lock);
+    CURL_TRC_CF((struct Curl_easy *)data, cf, "data pending = %zu",
+                Curl_bufq_len(&stream->recvbuf));
+    pending = !Curl_bufq_is_empty(&stream->recvbuf);
+    msh3_lock_release(&stream->recv_lock);
+    if(pending)
+      drain_stream(cf, (struct Curl_easy *)data);
+  }
+
+  CF_DATA_RESTORE(cf, save);
+  return pending;
+}
+
+static CURLcode h3_data_pause(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              bool pause)
+{
+  if(!pause) {
+    drain_stream(cf, data);
+    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+  }
+  return CURLE_OK;
+}
+
+static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   int event, int arg1, void *arg2)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  struct cf_call_data save;
+  CURLcode result = CURLE_OK;
+
+  CF_DATA_SAVE(save, cf, data);
+
+  (void)arg1;
+  (void)arg2;
+  switch(event) {
+  case CF_CTRL_DATA_SETUP:
+    result = h3_data_setup(cf, data);
+    break;
+  case CF_CTRL_DATA_PAUSE:
+    result = h3_data_pause(cf, data, (arg1 != 0));
+    break;
+  case CF_CTRL_DATA_DONE:
+    h3_data_done(cf, data);
+    break;
+  case CF_CTRL_DATA_DONE_SEND:
+    CURL_TRC_CF(data, cf, "req: send done");
+    if(stream) {
+      stream->upload_done = TRUE;
+      if(stream->req) {
+        char buf[1];
+        if(!MsH3RequestSend(stream->req, MSH3_REQUEST_FLAG_FIN,
+                            buf, 0, data)) {
+          result = CURLE_SEND_ERROR;
+        }
+      }
+    }
+    break;
+  default:
+    break;
+  }
+
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
+static CURLcode cf_connect_start(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data)
+{
+  struct cf_msh3_ctx *ctx = cf->ctx;
+  struct ssl_primary_config *conn_config;
+  MSH3_ADDR addr = {0};
+  CURLcode result;
+  bool verify;
+
+  conn_config = Curl_ssl_cf_get_primary_config(cf);
+  if(!conn_config)
+    return CURLE_FAILED_INIT;
+  verify = !!conn_config->verifypeer;
+
+  memcpy(&addr, &ctx->addr.sa_addr, ctx->addr.addrlen);
+  MSH3_SET_PORT(&addr, (uint16_t)cf->conn->remote_port);
+
+  if(verify && (conn_config->CAfile || conn_config->CApath)) {
+    /* TODO: need a way to provide trust anchors to MSH3 */
+#ifdef DEBUGBUILD
+    /* we need this for our test cases to run */
+    CURL_TRC_CF(data, cf, "non-standard CA not supported, "
+                "switching off verifypeer in DEBUG mode");
+    verify = 0;
+#else
+    CURL_TRC_CF(data, cf, "non-standard CA not supported, "
+                "attempting with built-in verification");
+#endif
+  }
+
+  CURL_TRC_CF(data, cf, "connecting to %s:%d (verify=%d)",
+              cf->conn->host.name, (int)cf->conn->remote_port, verify);
+
+  ctx->api = MsH3ApiOpen();
+  if(!ctx->api) {
+    failf(data, "can't create msh3 api");
+    return CURLE_FAILED_INIT;
+  }
+
+  ctx->qconn = MsH3ConnectionOpen(ctx->api,
+                                  &msh3_conn_if,
+                                  cf,
+                                  cf->conn->host.name,
+                                  &addr,
+                                  !verify);
+  if(!ctx->qconn) {
+    failf(data, "can't create msh3 connection");
+    if(ctx->api) {
+      MsH3ApiClose(ctx->api);
+      ctx->api = NULL;
+    }
+    return CURLE_FAILED_INIT;
+  }
+
+  result = h3_data_setup(cf, data);
+  if(result)
+    return result;
+
+  return CURLE_OK;
+}
+
+static CURLcode cf_msh3_connect(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                bool blocking, bool *done)
+{
+  struct cf_msh3_ctx *ctx = cf->ctx;
+  struct cf_call_data save;
+  CURLcode result = CURLE_OK;
+
+  (void)blocking;
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  CF_DATA_SAVE(save, cf, data);
+
+  if(ctx->sock[SP_LOCAL] == CURL_SOCKET_BAD) {
+    if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx->sock[0]) < 0) {
+      ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
+      ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
+      return CURLE_COULDNT_CONNECT;
+    }
+  }
+
+  *done = FALSE;
+  if(!ctx->qconn) {
+    ctx->connect_started = Curl_now();
+    result = cf_connect_start(cf, data);
+    if(result)
+      goto out;
+  }
+
+  if(ctx->handshake_complete) {
+    ctx->handshake_at = Curl_now();
+    if(ctx->handshake_succeeded) {
+      CURL_TRC_CF(data, cf, "handshake succeeded");
+      cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+      cf->conn->httpversion = 30;
+      cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+      cf->connected = TRUE;
+      cf->conn->alpn = CURL_HTTP_VERSION_3;
+      *done = TRUE;
+      connkeep(cf->conn, "HTTP/3 default");
+      Curl_pgrsTime(data, TIMER_APPCONNECT);
+    }
+    else {
+      failf(data, "failed to connect, handshake failed");
+      result = CURLE_COULDNT_CONNECT;
+    }
+  }
+
+out:
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
+static void cf_msh3_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_msh3_ctx *ctx = cf->ctx;
+  struct cf_call_data save;
+
+  (void)data;
+  CF_DATA_SAVE(save, cf, data);
+
+  if(ctx) {
+    CURL_TRC_CF(data, cf, "destroying");
+    if(ctx->qconn) {
+      MsH3ConnectionClose(ctx->qconn);
+      ctx->qconn = NULL;
+    }
+    if(ctx->api) {
+      MsH3ApiClose(ctx->api);
+      ctx->api = NULL;
+    }
+
+    if(ctx->active) {
+      /* We share our socket at cf->conn->sock[cf->sockindex] when active.
+       * If it is no longer there, someone has stolen (and hopefully
+       * closed it) and we just forget about it.
+       */
+      ctx->active = FALSE;
+      if(ctx->sock[SP_LOCAL] == cf->conn->sock[cf->sockindex]) {
+        CURL_TRC_CF(data, cf, "cf_msh3_close(%d) active",
+                    (int)ctx->sock[SP_LOCAL]);
+        cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
+      }
+      else {
+        CURL_TRC_CF(data, cf, "cf_socket_close(%d) no longer at "
+                    "conn->sock[], discarding", (int)ctx->sock[SP_LOCAL]);
+        ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
+      }
+      if(cf->sockindex == FIRSTSOCKET)
+        cf->conn->remote_addr = NULL;
+    }
+    if(ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) {
+      sclose(ctx->sock[SP_LOCAL]);
+    }
+    if(ctx->sock[SP_REMOTE] != CURL_SOCKET_BAD) {
+      sclose(ctx->sock[SP_REMOTE]);
+    }
+    ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
+    ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
+  }
+  CF_DATA_RESTORE(cf, save);
+}
+
+static void cf_msh3_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_call_data save;
+
+  CF_DATA_SAVE(save, cf, data);
+  cf_msh3_close(cf, data);
+  free(cf->ctx);
+  cf->ctx = NULL;
+  /* no CF_DATA_RESTORE(cf, save); its gone */
+
+}
+
+static CURLcode cf_msh3_query(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              int query, int *pres1, void *pres2)
+{
+  struct cf_msh3_ctx *ctx = cf->ctx;
+
+  switch(query) {
+  case CF_QUERY_MAX_CONCURRENT: {
+    /* TODO: we do not have access to this so far, fake it */
+    (void)ctx;
+    *pres1 = 100;
+    return CURLE_OK;
+  }
+  case CF_QUERY_TIMER_CONNECT: {
+    struct curltime *when = pres2;
+    /* we do not know when the first byte arrived */
+    if(cf->connected)
+      *when = ctx->handshake_at;
+    return CURLE_OK;
+  }
+  case CF_QUERY_TIMER_APPCONNECT: {
+    struct curltime *when = pres2;
+    if(cf->connected)
+      *when = ctx->handshake_at;
+    return CURLE_OK;
+  }
+  default:
+    break;
+  }
+  return cf->next?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
+}
+
+static bool cf_msh3_conn_is_alive(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  bool *input_pending)
+{
+  struct cf_msh3_ctx *ctx = cf->ctx;
+
+  (void)data;
+  *input_pending = FALSE;
+  return ctx && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD && ctx->qconn &&
+         ctx->connected;
+}
+
+struct Curl_cftype Curl_cft_http3 = {
+  "HTTP/3",
+  CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
+  0,
+  cf_msh3_destroy,
+  cf_msh3_connect,
+  cf_msh3_close,
+  Curl_cf_def_get_host,
+  cf_msh3_adjust_pollset,
+  cf_msh3_data_pending,
+  cf_msh3_send,
+  cf_msh3_recv,
+  cf_msh3_data_event,
+  cf_msh3_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  cf_msh3_query,
+};
+
+CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf,
+                             struct Curl_easy *data,
+                             struct connectdata *conn,
+                             const struct Curl_addrinfo *ai)
+{
+  struct cf_msh3_ctx *ctx = NULL;
+  struct Curl_cfilter *cf = NULL;
+  CURLcode result;
+
+  (void)data;
+  (void)conn;
+  (void)ai; /* TODO: msh3 resolves itself? */
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  Curl_sock_assign_addr(&ctx->addr, ai, TRNSPRT_QUIC);
+  ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
+  ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
+
+  result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
+
+out:
+  *pcf = (!result)? cf : NULL;
+  if(result) {
+    Curl_safefree(cf);
+    Curl_safefree(ctx);
+  }
+
+  return result;
+}
+
+bool Curl_conn_is_msh3(const struct Curl_easy *data,
+                       const struct connectdata *conn,
+                       int sockindex)
+{
+  struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+
+  (void)data;
+  for(; cf; cf = cf->next) {
+    if(cf->cft == &Curl_cft_http3)
+      return TRUE;
+    if(cf->cft->flags & CF_TYPE_IP_CONNECT)
+      return FALSE;
+  }
+  return FALSE;
+}
+
+#endif /* USE_MSH3 */
Index: trunk/src/libs/curl-8.7.1/lib/vquic/curl_msh3.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vquic/curl_msh3.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vquic/curl_msh3.h	(revision 104083)
@@ -0,0 +1,46 @@
+#ifndef HEADER_CURL_VQUIC_CURL_MSH3_H
+#define HEADER_CURL_VQUIC_CURL_MSH3_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_MSH3
+
+#include <msh3.h>
+
+void Curl_msh3_ver(char *p, size_t len);
+
+CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf,
+                             struct Curl_easy *data,
+                             struct connectdata *conn,
+                             const struct Curl_addrinfo *ai);
+
+bool Curl_conn_is_msh3(const struct Curl_easy *data,
+                       const struct connectdata *conn,
+                       int sockindex);
+
+#endif /* USE_MSQUIC */
+
+#endif /* HEADER_CURL_VQUIC_CURL_MSH3_H */
Index: trunk/src/libs/curl-8.7.1/lib/vquic/curl_ngtcp2.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vquic/curl_ngtcp2.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vquic/curl_ngtcp2.c	(revision 104083)
@@ -0,0 +1,2291 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
+#include <ngtcp2/ngtcp2.h>
+#include <nghttp3/nghttp3.h>
+
+#ifdef USE_OPENSSL
+#include <openssl/err.h>
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+#include <ngtcp2/ngtcp2_crypto_boringssl.h>
+#else
+#include <ngtcp2/ngtcp2_crypto_quictls.h>
+#endif
+#include "vtls/openssl.h"
+#elif defined(USE_GNUTLS)
+#include <ngtcp2/ngtcp2_crypto_gnutls.h>
+#include "vtls/gtls.h"
+#elif defined(USE_WOLFSSL)
+#include <ngtcp2/ngtcp2_crypto_wolfssl.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "strdup.h"
+#include "rand.h"
+#include "multiif.h"
+#include "strcase.h"
+#include "cfilters.h"
+#include "cf-socket.h"
+#include "connect.h"
+#include "progress.h"
+#include "strerror.h"
+#include "dynbuf.h"
+#include "http1.h"
+#include "select.h"
+#include "inet_pton.h"
+#include "transfer.h"
+#include "vquic.h"
+#include "vquic_int.h"
+#include "vquic-tls.h"
+#include "vtls/keylog.h"
+#include "vtls/vtls.h"
+#include "curl_ngtcp2.h"
+
+#include "warnless.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+#define QUIC_MAX_STREAMS (256*1024)
+#define QUIC_MAX_DATA (1*1024*1024)
+#define QUIC_HANDSHAKE_TIMEOUT (10*NGTCP2_SECONDS)
+
+/* A stream window is the maximum amount we need to buffer for
+ * each active transfer. We use HTTP/3 flow control and only ACK
+ * when we take things out of the buffer.
+ * Chunk size is large enough to take a full DATA frame */
+#define H3_STREAM_WINDOW_SIZE (128 * 1024)
+#define H3_STREAM_CHUNK_SIZE   (16 * 1024)
+/* The pool keeps spares around and half of a full stream windows
+ * seems good. More does not seem to improve performance.
+ * The benefit of the pool is that stream buffer to not keep
+ * spares. So memory consumption goes down when streams run empty,
+ * have a large upload done, etc. */
+#define H3_STREAM_POOL_SPARES \
+          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
+/* Receive and Send max number of chunks just follows from the
+ * chunk size and window size */
+#define H3_STREAM_RECV_CHUNKS \
+          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
+#define H3_STREAM_SEND_CHUNKS \
+          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
+
+
+/*
+ * Store ngtcp2 version info in this buffer.
+ */
+void Curl_ngtcp2_ver(char *p, size_t len)
+{
+  const ngtcp2_info *ng2 = ngtcp2_version(0);
+  const nghttp3_info *ht3 = nghttp3_version(0);
+  (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
+                  ng2->version_str, ht3->version_str);
+}
+
+struct cf_ngtcp2_ctx {
+  struct cf_quic_ctx q;
+  struct ssl_peer peer;
+  struct quic_tls_ctx tls;
+  ngtcp2_path connected_path;
+  ngtcp2_conn *qconn;
+  ngtcp2_cid dcid;
+  ngtcp2_cid scid;
+  uint32_t version;
+  ngtcp2_settings settings;
+  ngtcp2_transport_params transport_params;
+  ngtcp2_ccerr last_error;
+  ngtcp2_crypto_conn_ref conn_ref;
+  struct cf_call_data call_data;
+  nghttp3_conn *h3conn;
+  nghttp3_settings h3settings;
+  struct curltime started_at;        /* time the current attempt started */
+  struct curltime handshake_at;      /* time connect handshake finished */
+  struct curltime reconnect_at;      /* time the next attempt should start */
+  struct bufc_pool stream_bufcp;     /* chunk pool for streams */
+  size_t max_stream_window;          /* max flow window for one stream */
+  uint64_t max_idle_ms;              /* max idle time for QUIC connection */
+  int qlogfd;
+};
+
+/* How to access `call_data` from a cf_ngtcp2 filter */
+#undef CF_CTX_CALL_DATA
+#define CF_CTX_CALL_DATA(cf)  \
+  ((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data
+
+/**
+ * All about the H3 internals of a stream
+ */
+struct h3_stream_ctx {
+  int64_t id; /* HTTP/3 protocol identifier */
+  struct bufq sendbuf;   /* h3 request body */
+  struct h1_req_parser h1; /* h1 request parsing */
+  size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
+  size_t upload_blocked_len; /* the amount written last and EGAINed */
+  uint64_t error3; /* HTTP/3 stream error code */
+  curl_off_t upload_left; /* number of request bytes left to upload */
+  int status_code; /* HTTP status code */
+  bool resp_hds_complete; /* we have a complete, final response */
+  bool closed; /* TRUE on stream close */
+  bool reset;  /* TRUE on stream reset */
+  bool send_closed; /* stream is local closed */
+  BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
+};
+
+#define H3_STREAM_CTX(d)  ((struct h3_stream_ctx *)(((d) && (d)->req.p.http)? \
+                           ((struct HTTP *)(d)->req.p.http)->h3_ctx \
+                             : NULL))
+#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx
+#define H3_STREAM_ID(d)   (H3_STREAM_CTX(d)? \
+                           H3_STREAM_CTX(d)->id : -2)
+
+static CURLcode h3_data_setup(struct Curl_cfilter *cf,
+                              struct Curl_easy *data)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+
+  if(!data || !data->req.p.http) {
+    failf(data, "initialization failure, transfer not http initialized");
+    return CURLE_FAILED_INIT;
+  }
+
+  if(stream)
+    return CURLE_OK;
+
+  stream = calloc(1, sizeof(*stream));
+  if(!stream)
+    return CURLE_OUT_OF_MEMORY;
+
+  stream->id = -1;
+  /* on send, we control how much we put into the buffer */
+  Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
+                  H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
+  stream->sendbuf_len_in_flight = 0;
+  Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
+
+  H3_STREAM_LCTX(data) = stream;
+  return CURLE_OK;
+}
+
+static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+
+  (void)cf;
+  if(stream) {
+    CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->id);
+    if(ctx->h3conn && !stream->closed) {
+      nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream->id);
+      nghttp3_conn_close_stream(ctx->h3conn, stream->id,
+                                NGHTTP3_H3_REQUEST_CANCELLED);
+      nghttp3_conn_set_stream_user_data(ctx->h3conn, stream->id, NULL);
+      ngtcp2_conn_set_stream_user_data(ctx->qconn, stream->id, NULL);
+      stream->closed = TRUE;
+    }
+
+    Curl_bufq_free(&stream->sendbuf);
+    Curl_h1_req_parse_free(&stream->h1);
+    free(stream);
+    H3_STREAM_LCTX(data) = NULL;
+  }
+}
+
+static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
+                                         struct Curl_easy *data,
+                                         int64_t stream_id)
+{
+  struct Curl_easy *sdata;
+
+  (void)cf;
+  if(H3_STREAM_ID(data) == stream_id) {
+    return data;
+  }
+  else {
+    DEBUGASSERT(data->multi);
+    for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+      if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream_id) {
+        return sdata;
+      }
+    }
+  }
+  return NULL;
+}
+
+static void h3_drain_stream(struct Curl_cfilter *cf,
+                            struct Curl_easy *data)
+{
+  struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+  unsigned char bits;
+
+  (void)cf;
+  bits = CURL_CSELECT_IN;
+  if(stream && stream->upload_left && !stream->send_closed)
+    bits |= CURL_CSELECT_OUT;
+  if(data->state.select_bits != bits) {
+    data->state.select_bits = bits;
+    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+  }
+}
+
+/* ngtcp2 default congestion controller does not perform pacing. Limit
+   the maximum packet burst to MAX_PKT_BURST packets. */
+#define MAX_PKT_BURST 10
+
+struct pkt_io_ctx {
+  struct Curl_cfilter *cf;
+  struct Curl_easy *data;
+  ngtcp2_tstamp ts;
+  size_t pkt_count;
+  ngtcp2_path_storage ps;
+};
+
+static void pktx_update_time(struct pkt_io_ctx *pktx,
+                             struct Curl_cfilter *cf)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+
+  vquic_ctx_update_time(&ctx->q);
+  pktx->ts = ctx->q.last_op.tv_sec * NGTCP2_SECONDS +
+             ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS;
+}
+
+static void pktx_init(struct pkt_io_ctx *pktx,
+                      struct Curl_cfilter *cf,
+                      struct Curl_easy *data)
+{
+  pktx->cf = cf;
+  pktx->data = data;
+  pktx->pkt_count = 0;
+  ngtcp2_path_storage_zero(&pktx->ps);
+  pktx_update_time(pktx, cf);
+}
+
+static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    struct pkt_io_ctx *pktx);
+static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   struct pkt_io_ctx *pktx);
+static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
+                                   uint64_t datalen, void *user_data,
+                                   void *stream_user_data);
+
+static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref)
+{
+  struct Curl_cfilter *cf = conn_ref->user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  return ctx->qconn;
+}
+
+#ifdef DEBUG_NGTCP2
+static void quic_printf(void *user_data, const char *fmt, ...)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+
+  (void)ctx;  /* TODO: need an easy handle to infof() message */
+  va_list ap;
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+  fprintf(stderr, "\n");
+}
+#endif
+
+static void qlog_callback(void *user_data, uint32_t flags,
+                          const void *data, size_t datalen)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  (void)flags;
+  if(ctx->qlogfd != -1) {
+    ssize_t rc = write(ctx->qlogfd, data, datalen);
+    if(rc == -1) {
+      /* on write error, stop further write attempts */
+      close(ctx->qlogfd);
+      ctx->qlogfd = -1;
+    }
+  }
+
+}
+
+static void quic_settings(struct cf_ngtcp2_ctx *ctx,
+                          struct Curl_easy *data,
+                          struct pkt_io_ctx *pktx)
+{
+  ngtcp2_settings *s = &ctx->settings;
+  ngtcp2_transport_params *t = &ctx->transport_params;
+
+  ngtcp2_settings_default(s);
+  ngtcp2_transport_params_default(t);
+#ifdef DEBUG_NGTCP2
+  s->log_printf = quic_printf;
+#else
+  s->log_printf = NULL;
+#endif
+
+  (void)data;
+  s->initial_ts = pktx->ts;
+  s->handshake_timeout = QUIC_HANDSHAKE_TIMEOUT;
+  s->max_window = 100 * ctx->max_stream_window;
+  s->max_stream_window = ctx->max_stream_window;
+
+  t->initial_max_data = 10 * ctx->max_stream_window;
+  t->initial_max_stream_data_bidi_local = ctx->max_stream_window;
+  t->initial_max_stream_data_bidi_remote = ctx->max_stream_window;
+  t->initial_max_stream_data_uni = ctx->max_stream_window;
+  t->initial_max_streams_bidi = QUIC_MAX_STREAMS;
+  t->initial_max_streams_uni = QUIC_MAX_STREAMS;
+  t->max_idle_timeout = (ctx->max_idle_ms * NGTCP2_MILLISECONDS);
+  if(ctx->qlogfd != -1) {
+    s->qlog_write = qlog_callback;
+  }
+}
+
+static int init_ngh3_conn(struct Curl_cfilter *cf);
+
+static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
+{
+  (void)user_data;
+  (void)tconn;
+  return 0;
+}
+
+static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
+                               int64_t stream_id, uint64_t offset,
+                               const uint8_t *buf, size_t buflen,
+                               void *user_data, void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  nghttp3_ssize nconsumed;
+  int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0;
+  struct Curl_easy *data = stream_user_data;
+  (void)offset;
+  (void)data;
+
+  nconsumed =
+    nghttp3_conn_read_stream(ctx->h3conn, stream_id, buf, buflen, fin);
+  CURL_TRC_CF(data, cf, "[%" PRId64 "] read_stream(len=%zu) -> %zd",
+              stream_id, buflen, nconsumed);
+  if(nconsumed < 0) {
+    if(!data) {
+      struct Curl_easy *cdata = CF_DATA_CURRENT(cf);
+      CURL_TRC_CF(cdata, cf, "[%" PRId64 "] nghttp3 error on stream not "
+                  "used by us, ignored", stream_id);
+      return 0;
+    }
+    ngtcp2_ccerr_set_application_error(
+      &ctx->last_error,
+      nghttp3_err_infer_quic_app_error_code((int)nconsumed), NULL, 0);
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  /* number of bytes inside buflen which consists of framing overhead
+   * including QPACK HEADERS. In other words, it does not consume payload of
+   * DATA frame. */
+  ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, nconsumed);
+  ngtcp2_conn_extend_max_offset(tconn, nconsumed);
+
+  return 0;
+}
+
+static int
+cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
+                            uint64_t offset, uint64_t datalen, void *user_data,
+                            void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  int rv;
+  (void)stream_id;
+  (void)tconn;
+  (void)offset;
+  (void)datalen;
+  (void)stream_user_data;
+
+  rv = nghttp3_conn_add_ack_offset(ctx->h3conn, stream_id, datalen);
+  if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+
+static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags,
+                           int64_t stream3_id, uint64_t app_error_code,
+                           void *user_data, void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct Curl_easy *data = stream_user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  int rv;
+
+  (void)tconn;
+  (void)data;
+  /* stream is closed... */
+
+  if(!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
+    app_error_code = NGHTTP3_H3_NO_ERROR;
+  }
+
+  rv = nghttp3_conn_close_stream(ctx->h3conn, stream3_id,
+                                 app_error_code);
+  CURL_TRC_CF(data, cf, "[%" PRId64 "] quic close(err=%"
+              PRIu64 ") -> %d", stream3_id, app_error_code, rv);
+  if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
+    ngtcp2_ccerr_set_application_error(
+      &ctx->last_error, nghttp3_err_infer_quic_app_error_code(rv), NULL, 0);
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+
+static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
+                           uint64_t final_size, uint64_t app_error_code,
+                           void *user_data, void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = stream_user_data;
+  int rv;
+  (void)tconn;
+  (void)final_size;
+  (void)app_error_code;
+  (void)data;
+
+  rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
+  CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv);
+  if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+
+static int cb_stream_stop_sending(ngtcp2_conn *tconn, int64_t stream_id,
+                                  uint64_t app_error_code, void *user_data,
+                                  void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  int rv;
+  (void)tconn;
+  (void)app_error_code;
+  (void)stream_user_data;
+
+  rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
+  if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+
+static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
+                                            uint64_t max_streams,
+                                            void *user_data)
+{
+  (void)tconn;
+  (void)max_streams;
+  (void)user_data;
+
+  return 0;
+}
+
+static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
+                                     uint64_t max_data, void *user_data,
+                                     void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  struct Curl_easy *s_data;
+  struct h3_stream_ctx *stream;
+  int rv;
+  (void)tconn;
+  (void)max_data;
+  (void)stream_user_data;
+
+  rv = nghttp3_conn_unblock_stream(ctx->h3conn, stream_id);
+  if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+  s_data = get_stream_easy(cf, data, stream_id);
+  stream = H3_STREAM_CTX(s_data);
+  if(stream && stream->quic_flow_blocked) {
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] unblock quic flow", stream_id);
+    stream->quic_flow_blocked = FALSE;
+    h3_drain_stream(cf, data);
+  }
+  return 0;
+}
+
+static void cb_rand(uint8_t *dest, size_t destlen,
+                    const ngtcp2_rand_ctx *rand_ctx)
+{
+  CURLcode result;
+  (void)rand_ctx;
+
+  result = Curl_rand(NULL, dest, destlen);
+  if(result) {
+    /* cb_rand is only used for non-cryptographic context.  If Curl_rand
+       failed, just fill 0 and call it *random*. */
+    memset(dest, 0, destlen);
+  }
+}
+
+static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
+                                    uint8_t *token, size_t cidlen,
+                                    void *user_data)
+{
+  CURLcode result;
+  (void)tconn;
+  (void)user_data;
+
+  result = Curl_rand(NULL, cid->data, cidlen);
+  if(result)
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  cid->datalen = cidlen;
+
+  result = Curl_rand(NULL, token, NGTCP2_STATELESS_RESET_TOKENLEN);
+  if(result)
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+
+  return 0;
+}
+
+static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_encryption_level level,
+                          void *user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  (void)tconn;
+
+  if(level != NGTCP2_ENCRYPTION_LEVEL_1RTT) {
+    return 0;
+  }
+
+  if(init_ngh3_conn(cf) != CURLE_OK) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+
+static ngtcp2_callbacks ng_callbacks = {
+  ngtcp2_crypto_client_initial_cb,
+  NULL, /* recv_client_initial */
+  ngtcp2_crypto_recv_crypto_data_cb,
+  cb_handshake_completed,
+  NULL, /* recv_version_negotiation */
+  ngtcp2_crypto_encrypt_cb,
+  ngtcp2_crypto_decrypt_cb,
+  ngtcp2_crypto_hp_mask_cb,
+  cb_recv_stream_data,
+  cb_acked_stream_data_offset,
+  NULL, /* stream_open */
+  cb_stream_close,
+  NULL, /* recv_stateless_reset */
+  ngtcp2_crypto_recv_retry_cb,
+  cb_extend_max_local_streams_bidi,
+  NULL, /* extend_max_local_streams_uni */
+  cb_rand,
+  cb_get_new_connection_id,
+  NULL, /* remove_connection_id */
+  ngtcp2_crypto_update_key_cb, /* update_key */
+  NULL, /* path_validation */
+  NULL, /* select_preferred_addr */
+  cb_stream_reset,
+  NULL, /* extend_max_remote_streams_bidi */
+  NULL, /* extend_max_remote_streams_uni */
+  cb_extend_max_stream_data,
+  NULL, /* dcid_status */
+  NULL, /* handshake_confirmed */
+  NULL, /* recv_new_token */
+  ngtcp2_crypto_delete_crypto_aead_ctx_cb,
+  ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
+  NULL, /* recv_datagram */
+  NULL, /* ack_datagram */
+  NULL, /* lost_datagram */
+  ngtcp2_crypto_get_path_challenge_data_cb,
+  cb_stream_stop_sending,
+  NULL, /* version_negotiation */
+  cb_recv_rx_key,
+  NULL, /* recv_tx_key */
+  NULL, /* early_data_rejected */
+};
+
+/**
+ * Connection maintenance like timeouts on packet ACKs etc. are done by us, not
+ * the OS like for TCP. POLL events on the socket therefore are not
+ * sufficient.
+ * ngtcp2 tells us when it wants to be invoked again. We handle that via
+ * the `Curl_expire()` mechanisms.
+ */
+static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data,
+                                     struct pkt_io_ctx *pktx)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct pkt_io_ctx local_pktx;
+  ngtcp2_tstamp expiry;
+
+  if(!pktx) {
+    pktx_init(&local_pktx, cf, data);
+    pktx = &local_pktx;
+  }
+  else {
+    pktx_update_time(pktx, cf);
+  }
+
+  expiry = ngtcp2_conn_get_expiry(ctx->qconn);
+  if(expiry != UINT64_MAX) {
+    if(expiry <= pktx->ts) {
+      CURLcode result;
+      int rv = ngtcp2_conn_handle_expiry(ctx->qconn, pktx->ts);
+      if(rv) {
+        failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
+              ngtcp2_strerror(rv));
+        ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0);
+        return CURLE_SEND_ERROR;
+      }
+      result = cf_progress_ingress(cf, data, pktx);
+      if(result)
+        return result;
+      result = cf_progress_egress(cf, data, pktx);
+      if(result)
+        return result;
+      /* ask again, things might have changed */
+      expiry = ngtcp2_conn_get_expiry(ctx->qconn);
+    }
+
+    if(expiry > pktx->ts) {
+      ngtcp2_duration timeout = expiry - pktx->ts;
+      if(timeout % NGTCP2_MILLISECONDS) {
+        timeout += NGTCP2_MILLISECONDS;
+      }
+      Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);
+    }
+  }
+  return CURLE_OK;
+}
+
+static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data,
+                                      struct easy_pollset *ps)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  bool want_recv, want_send;
+
+  if(!ctx->qconn)
+    return;
+
+  Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
+  if(want_recv || want_send) {
+    struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+    struct cf_call_data save;
+    bool c_exhaust, s_exhaust;
+
+    CF_DATA_SAVE(save, cf, data);
+    c_exhaust = want_send && (!ngtcp2_conn_get_cwnd_left(ctx->qconn) ||
+                !ngtcp2_conn_get_max_data_left(ctx->qconn));
+    s_exhaust = want_send && stream && stream->id >= 0 &&
+                stream->quic_flow_blocked;
+    want_recv = (want_recv || c_exhaust || s_exhaust);
+    want_send = (!s_exhaust && want_send) ||
+                 !Curl_bufq_is_empty(&ctx->q.sendbuf);
+
+    Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send);
+    CF_DATA_RESTORE(cf, save);
+  }
+}
+
+static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
+                              uint64_t app_error_code, void *user_data,
+                              void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct Curl_easy *data = stream_user_data;
+  struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+  (void)conn;
+  (void)stream_id;
+
+  /* we might be called by nghttp3 after we already cleaned up */
+  if(!stream)
+    return 0;
+
+  stream->closed = TRUE;
+  stream->error3 = app_error_code;
+  if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
+    stream->reset = TRUE;
+    stream->send_closed = TRUE;
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] RESET: error %" PRId64,
+                stream->id, stream->error3);
+  }
+  else {
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] CLOSED", stream->id);
+  }
+  h3_drain_stream(cf, data);
+  return 0;
+}
+
+static CURLcode write_resp_hds(struct Curl_easy *data,
+                               const char *buf, size_t blen)
+{
+  return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
+}
+
+static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
+                           const uint8_t *buf, size_t blen,
+                           void *user_data, void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = stream_user_data;
+  struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+  CURLcode result;
+
+  (void)conn;
+  (void)stream3_id;
+
+  if(!stream)
+    return NGHTTP3_ERR_CALLBACK_FAILURE;
+
+  result = Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
+  if(result) {
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, ERROR receiving %d",
+                stream->id, blen, result);
+    return NGHTTP3_ERR_CALLBACK_FAILURE;
+  }
+  if(blen) {
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] ACK %zu bytes of DATA",
+                stream->id, blen);
+    ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream->id, blen);
+    ngtcp2_conn_extend_max_offset(ctx->qconn, blen);
+  }
+  CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu", stream->id, blen);
+  return 0;
+}
+
+static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream3_id,
+                                  size_t consumed, void *user_data,
+                                  void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  (void)conn;
+  (void)stream_user_data;
+
+  /* nghttp3 has consumed bytes on the QUIC stream and we need to
+   * tell the QUIC connection to increase its flow control */
+  ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream3_id, consumed);
+  ngtcp2_conn_extend_max_offset(ctx->qconn, consumed);
+  return 0;
+}
+
+static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
+                             int fin, void *user_data, void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct Curl_easy *data = stream_user_data;
+  struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+  CURLcode result = CURLE_OK;
+  (void)conn;
+  (void)stream_id;
+  (void)fin;
+  (void)cf;
+
+  if(!stream)
+    return 0;
+  /* add a CRLF only if we've received some headers */
+  result = write_resp_hds(data, "\r\n", 2);
+  if(result) {
+    return -1;
+  }
+
+  CURL_TRC_CF(data, cf, "[%" PRId64 "] end_headers, status=%d",
+              stream_id, stream->status_code);
+  if(stream->status_code / 100 != 1) {
+    stream->resp_hds_complete = TRUE;
+  }
+  h3_drain_stream(cf, data);
+  return 0;
+}
+
+static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
+                             int32_t token, nghttp3_rcbuf *name,
+                             nghttp3_rcbuf *value, uint8_t flags,
+                             void *user_data, void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
+  nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
+  struct Curl_easy *data = stream_user_data;
+  struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+  CURLcode result = CURLE_OK;
+  (void)conn;
+  (void)stream_id;
+  (void)token;
+  (void)flags;
+  (void)cf;
+
+  /* we might have cleaned up this transfer already */
+  if(!stream)
+    return 0;
+
+  if(token == NGHTTP3_QPACK_TOKEN__STATUS) {
+    char line[14]; /* status line is always 13 characters long */
+    size_t ncopy;
+
+    result = Curl_http_decode_status(&stream->status_code,
+                                     (const char *)h3val.base, h3val.len);
+    if(result)
+      return -1;
+    ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
+                      stream->status_code);
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] status: %s", stream_id, line);
+    result = write_resp_hds(data, line, ncopy);
+    if(result) {
+      return -1;
+    }
+  }
+  else {
+    /* store as an HTTP1-style header */
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] header: %.*s: %.*s",
+                stream_id, (int)h3name.len, h3name.base,
+                (int)h3val.len, h3val.base);
+    result = write_resp_hds(data, (const char *)h3name.base, h3name.len);
+    if(result) {
+      return -1;
+    }
+    result = write_resp_hds(data, ": ", 2);
+    if(result) {
+      return -1;
+    }
+    result = write_resp_hds(data, (const char *)h3val.base, h3val.len);
+    if(result) {
+      return -1;
+    }
+    result = write_resp_hds(data, "\r\n", 2);
+    if(result) {
+      return -1;
+    }
+  }
+  return 0;
+}
+
+static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id,
+                              uint64_t app_error_code, void *user_data,
+                              void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  int rv;
+  (void)conn;
+  (void)stream_user_data;
+
+  rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, 0, stream_id,
+                                        app_error_code);
+  if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+
+static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id,
+                              uint64_t app_error_code, void *user_data,
+                              void *stream_user_data) {
+  struct Curl_cfilter *cf = user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = stream_user_data;
+  int rv;
+  (void)conn;
+  (void)data;
+
+  rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, 0, stream_id,
+                                         app_error_code);
+  CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv);
+  if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+
+static nghttp3_callbacks ngh3_callbacks = {
+  cb_h3_acked_req_body, /* acked_stream_data */
+  cb_h3_stream_close,
+  cb_h3_recv_data,
+  cb_h3_deferred_consume,
+  NULL, /* begin_headers */
+  cb_h3_recv_header,
+  cb_h3_end_headers,
+  NULL, /* begin_trailers */
+  cb_h3_recv_header,
+  NULL, /* end_trailers */
+  cb_h3_stop_sending,
+  NULL, /* end_stream */
+  cb_h3_reset_stream,
+  NULL, /* shutdown */
+  NULL /* recv_settings */
+};
+
+static int init_ngh3_conn(struct Curl_cfilter *cf)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  CURLcode result;
+  int rc;
+  int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;
+
+  if(ngtcp2_conn_get_streams_uni_left(ctx->qconn) < 3) {
+    return CURLE_QUIC_CONNECT_ERROR;
+  }
+
+  nghttp3_settings_default(&ctx->h3settings);
+
+  rc = nghttp3_conn_client_new(&ctx->h3conn,
+                               &ngh3_callbacks,
+                               &ctx->h3settings,
+                               nghttp3_mem_default(),
+                               cf);
+  if(rc) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto fail;
+  }
+
+  rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &ctrl_stream_id, NULL);
+  if(rc) {
+    result = CURLE_QUIC_CONNECT_ERROR;
+    goto fail;
+  }
+
+  rc = nghttp3_conn_bind_control_stream(ctx->h3conn, ctrl_stream_id);
+  if(rc) {
+    result = CURLE_QUIC_CONNECT_ERROR;
+    goto fail;
+  }
+
+  rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_enc_stream_id, NULL);
+  if(rc) {
+    result = CURLE_QUIC_CONNECT_ERROR;
+    goto fail;
+  }
+
+  rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_dec_stream_id, NULL);
+  if(rc) {
+    result = CURLE_QUIC_CONNECT_ERROR;
+    goto fail;
+  }
+
+  rc = nghttp3_conn_bind_qpack_streams(ctx->h3conn, qpack_enc_stream_id,
+                                       qpack_dec_stream_id);
+  if(rc) {
+    result = CURLE_QUIC_CONNECT_ERROR;
+    goto fail;
+  }
+
+  return CURLE_OK;
+fail:
+
+  return result;
+}
+
+static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  struct h3_stream_ctx *stream,
+                                  CURLcode *err)
+{
+  ssize_t nread = -1;
+
+  (void)cf;
+  if(stream->reset) {
+    failf(data,
+          "HTTP/3 stream %" PRId64 " reset by server", stream->id);
+    *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+    goto out;
+  }
+  else if(!stream->resp_hds_complete) {
+    failf(data,
+          "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting"
+          " all response header fields, treated as error",
+          stream->id);
+    *err = CURLE_HTTP3;
+    goto out;
+  }
+  *err = CURLE_OK;
+  nread = 0;
+
+out:
+  return nread;
+}
+
+/* incoming data frames on the h3 stream */
+static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              char *buf, size_t blen, CURLcode *err)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+  ssize_t nread = -1;
+  struct cf_call_data save;
+  struct pkt_io_ctx pktx;
+
+  (void)ctx;
+  (void)buf;
+
+  CF_DATA_SAVE(save, cf, data);
+  DEBUGASSERT(cf->connected);
+  DEBUGASSERT(ctx);
+  DEBUGASSERT(ctx->qconn);
+  DEBUGASSERT(ctx->h3conn);
+  *err = CURLE_OK;
+
+  pktx_init(&pktx, cf, data);
+
+  if(!stream) {
+    *err = CURLE_RECV_ERROR;
+    goto out;
+  }
+
+  if(cf_progress_ingress(cf, data, &pktx)) {
+    *err = CURLE_RECV_ERROR;
+    nread = -1;
+    goto out;
+  }
+
+  if(stream->closed) {
+    nread = recv_closed_stream(cf, data, stream, err);
+    goto out;
+  }
+  *err = CURLE_AGAIN;
+  nread = -1;
+
+out:
+  if(cf_progress_egress(cf, data, &pktx)) {
+    *err = CURLE_SEND_ERROR;
+    nread = -1;
+  }
+  else {
+    CURLcode result2 = check_and_set_expiry(cf, data, &pktx);
+    if(result2) {
+      *err = result2;
+      nread = -1;
+    }
+  }
+  CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv(blen=%zu) -> %zd, %d",
+              stream? stream->id : -1, blen, nread, *err);
+  CF_DATA_RESTORE(cf, save);
+  return nread;
+}
+
+static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
+                                uint64_t datalen, void *user_data,
+                                void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct Curl_easy *data = stream_user_data;
+  struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+  size_t skiplen;
+
+  (void)cf;
+  if(!stream)
+    return 0;
+  /* The server acknowledged `datalen` of bytes from our request body.
+   * This is a delta. We have kept this data in `sendbuf` for
+   * re-transmissions and can free it now. */
+  if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
+    skiplen = stream->sendbuf_len_in_flight;
+  else
+    skiplen = (size_t)datalen;
+  Curl_bufq_skip(&stream->sendbuf, skiplen);
+  stream->sendbuf_len_in_flight -= skiplen;
+
+  /* Everything ACKed, we resume upload processing */
+  if(!stream->sendbuf_len_in_flight) {
+    int rv = nghttp3_conn_resume_stream(conn, stream_id);
+    if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
+      return NGTCP2_ERR_CALLBACK_FAILURE;
+    }
+  }
+  return 0;
+}
+
+static nghttp3_ssize
+cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
+                    nghttp3_vec *vec, size_t veccnt,
+                    uint32_t *pflags, void *user_data,
+                    void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct Curl_easy *data = stream_user_data;
+  struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+  ssize_t nwritten = 0;
+  size_t nvecs = 0;
+  (void)cf;
+  (void)conn;
+  (void)stream_id;
+  (void)user_data;
+  (void)veccnt;
+
+  if(!stream)
+    return NGHTTP3_ERR_CALLBACK_FAILURE;
+  /* nghttp3 keeps references to the sendbuf data until it is ACKed
+   * by the server (see `cb_h3_acked_req_body()` for updates).
+   * `sendbuf_len_in_flight` is the amount of bytes in `sendbuf`
+   * that we have already passed to nghttp3, but which have not been
+   * ACKed yet.
+   * Any amount beyond `sendbuf_len_in_flight` we need still to pass
+   * to nghttp3. Do that now, if we can. */
+  if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
+    nvecs = 0;
+    while(nvecs < veccnt &&
+          Curl_bufq_peek_at(&stream->sendbuf,
+                            stream->sendbuf_len_in_flight,
+                            (const unsigned char **)&vec[nvecs].base,
+                            &vec[nvecs].len)) {
+      stream->sendbuf_len_in_flight += vec[nvecs].len;
+      nwritten += vec[nvecs].len;
+      ++nvecs;
+    }
+    DEBUGASSERT(nvecs > 0); /* we SHOULD have been be able to peek */
+  }
+
+  if(nwritten > 0 && stream->upload_left != -1)
+    stream->upload_left -= nwritten;
+
+  /* When we stopped sending and everything in `sendbuf` is "in flight",
+   * we are at the end of the request body. */
+  if(stream->upload_left == 0) {
+    *pflags = NGHTTP3_DATA_FLAG_EOF;
+    stream->send_closed = TRUE;
+  }
+  else if(!nwritten) {
+    /* Not EOF, and nothing to give, we signal WOULDBLOCK. */
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> AGAIN",
+                stream->id);
+    return NGHTTP3_ERR_WOULDBLOCK;
+  }
+
+  CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> "
+              "%d vecs%s with %zu (buffered=%zu, left=%"
+              CURL_FORMAT_CURL_OFF_T ")",
+              stream->id, (int)nvecs,
+              *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
+              nwritten, Curl_bufq_len(&stream->sendbuf),
+              stream->upload_left);
+  return (nghttp3_ssize)nvecs;
+}
+
+/* Index where :authority header field will appear in request header
+   field list. */
+#define AUTHORITY_DST_IDX 3
+
+static ssize_t h3_stream_open(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              const void *buf, size_t len,
+                              CURLcode *err)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct h3_stream_ctx *stream = NULL;
+  struct dynhds h2_headers;
+  size_t nheader;
+  nghttp3_nv *nva = NULL;
+  int rc = 0;
+  unsigned int i;
+  ssize_t nwritten = -1;
+  nghttp3_data_reader reader;
+  nghttp3_data_reader *preader = NULL;
+
+  Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
+
+  *err = h3_data_setup(cf, data);
+  if(*err)
+    goto out;
+  stream = H3_STREAM_CTX(data);
+  DEBUGASSERT(stream);
+  if(!stream) {
+    *err = CURLE_FAILED_INIT;
+    goto out;
+  }
+
+  nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
+  if(nwritten < 0)
+    goto out;
+  if(!stream->h1.done) {
+    /* need more data */
+    goto out;
+  }
+  DEBUGASSERT(stream->h1.req);
+
+  *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
+  if(*err) {
+    nwritten = -1;
+    goto out;
+  }
+  /* no longer needed */
+  Curl_h1_req_parse_free(&stream->h1);
+
+  nheader = Curl_dynhds_count(&h2_headers);
+  nva = malloc(sizeof(nghttp3_nv) * nheader);
+  if(!nva) {
+    *err = CURLE_OUT_OF_MEMORY;
+    nwritten = -1;
+    goto out;
+  }
+
+  for(i = 0; i < nheader; ++i) {
+    struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i);
+    nva[i].name = (unsigned char *)e->name;
+    nva[i].namelen = e->namelen;
+    nva[i].value = (unsigned char *)e->value;
+    nva[i].valuelen = e->valuelen;
+    nva[i].flags = NGHTTP3_NV_FLAG_NONE;
+  }
+
+  rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &stream->id, data);
+  if(rc) {
+    failf(data, "can get bidi streams");
+    *err = CURLE_SEND_ERROR;
+    goto out;
+  }
+
+  switch(data->state.httpreq) {
+  case HTTPREQ_POST:
+  case HTTPREQ_POST_FORM:
+  case HTTPREQ_POST_MIME:
+  case HTTPREQ_PUT:
+    /* known request body size or -1 */
+    if(data->state.infilesize != -1)
+      stream->upload_left = data->state.infilesize;
+    else
+      /* data sending without specifying the data amount up front */
+      stream->upload_left = -1; /* unknown */
+    break;
+  default:
+    /* there is not request body */
+    stream->upload_left = 0; /* no request body */
+    break;
+  }
+
+  stream->send_closed = (stream->upload_left == 0);
+  if(!stream->send_closed) {
+    reader.read_data = cb_h3_read_req_body;
+    preader = &reader;
+  }
+
+  rc = nghttp3_conn_submit_request(ctx->h3conn, stream->id,
+                                   nva, nheader, preader, data);
+  if(rc) {
+    switch(rc) {
+    case NGHTTP3_ERR_CONN_CLOSING:
+      CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send, "
+                  "connection is closing", stream->id);
+      break;
+    default:
+      CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send -> %d (%s)",
+                  stream->id, rc, ngtcp2_strerror(rc));
+      break;
+    }
+    *err = CURLE_SEND_ERROR;
+    nwritten = -1;
+    goto out;
+  }
+
+  if(Curl_trc_is_verbose(data)) {
+    infof(data, "[HTTP/3] [%" PRId64 "] OPENED stream for %s",
+          stream->id, data->state.url);
+    for(i = 0; i < nheader; ++i) {
+      infof(data, "[HTTP/3] [%" PRId64 "] [%.*s: %.*s]", stream->id,
+            (int)nva[i].namelen, nva[i].name,
+            (int)nva[i].valuelen, nva[i].value);
+    }
+  }
+
+out:
+  free(nva);
+  Curl_dynhds_free(&h2_headers);
+  return nwritten;
+}
+
+static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              const void *buf, size_t len, CURLcode *err)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+  ssize_t sent = 0;
+  struct cf_call_data save;
+  struct pkt_io_ctx pktx;
+  CURLcode result;
+
+  CF_DATA_SAVE(save, cf, data);
+  DEBUGASSERT(cf->connected);
+  DEBUGASSERT(ctx->qconn);
+  DEBUGASSERT(ctx->h3conn);
+  pktx_init(&pktx, cf, data);
+  *err = CURLE_OK;
+
+  result = cf_progress_ingress(cf, data, &pktx);
+  if(result) {
+    *err = result;
+    sent = -1;
+  }
+
+  if(!stream || stream->id < 0) {
+    sent = h3_stream_open(cf, data, buf, len, err);
+    if(sent < 0) {
+      CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
+      goto out;
+    }
+    stream = H3_STREAM_CTX(data);
+  }
+  else if(stream->upload_blocked_len) {
+    /* the data in `buf` has already been submitted or added to the
+     * buffers, but have been EAGAINed on the last invocation. */
+    DEBUGASSERT(len >= stream->upload_blocked_len);
+    if(len < stream->upload_blocked_len) {
+      /* Did we get called again with a smaller `len`? This should not
+       * happen. We are not prepared to handle that. */
+      failf(data, "HTTP/3 send again with decreased length");
+      *err = CURLE_HTTP3;
+      sent = -1;
+      goto out;
+    }
+    sent = (ssize_t)stream->upload_blocked_len;
+    stream->upload_blocked_len = 0;
+  }
+  else if(stream->closed) {
+    if(stream->resp_hds_complete) {
+      /* Server decided to close the stream after having sent us a final
+       * response. This is valid if it is not interested in the request
+       * body. This happens on 30x or 40x responses.
+       * We silently discard the data sent, since this is not a transport
+       * error situation. */
+      CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
+                  "on closed stream with response", stream->id);
+      *err = CURLE_OK;
+      sent = (ssize_t)len;
+      goto out;
+    }
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+                "-> stream closed", stream->id, len);
+    *err = CURLE_HTTP3;
+    sent = -1;
+    goto out;
+  }
+  else {
+    sent = Curl_bufq_write(&stream->sendbuf, buf, len, err);
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send, add to "
+                "sendbuf(len=%zu) -> %zd, %d",
+                stream->id, len, sent, *err);
+    if(sent < 0) {
+      goto out;
+    }
+
+    (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
+  }
+
+  result = cf_progress_egress(cf, data, &pktx);
+  if(result) {
+    *err = result;
+    sent = -1;
+  }
+
+  if(stream && sent > 0 && stream->sendbuf_len_in_flight) {
+    /* We have unacknowledged DATA and cannot report success to our
+     * caller. Instead we EAGAIN and remember how much we have already
+     * "written" into our various internal connection buffers. */
+    stream->upload_blocked_len = sent;
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu), "
+                "%zu bytes in flight -> EGAIN", stream->id, len,
+                stream->sendbuf_len_in_flight);
+    *err = CURLE_AGAIN;
+    sent = -1;
+  }
+
+out:
+  result = check_and_set_expiry(cf, data, &pktx);
+  if(result) {
+    *err = result;
+    sent = -1;
+  }
+  CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d",
+              stream? stream->id : -1, len, sent, *err);
+  CF_DATA_RESTORE(cf, save);
+  return sent;
+}
+
+static CURLcode qng_verify_peer(struct Curl_cfilter *cf,
+                                struct Curl_easy *data)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+
+  cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+  cf->conn->httpversion = 30;
+  cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+
+  return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
+}
+
+static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
+                         struct sockaddr_storage *remote_addr,
+                         socklen_t remote_addrlen, int ecn,
+                         void *userp)
+{
+  struct pkt_io_ctx *pktx = userp;
+  struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx;
+  ngtcp2_pkt_info pi;
+  ngtcp2_path path;
+  int rv;
+
+  ++pktx->pkt_count;
+  ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr,
+                   ctx->q.local_addrlen);
+  ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr,
+                   remote_addrlen);
+  pi.ecn = (uint8_t)ecn;
+
+  rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts);
+  if(rv) {
+    CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)",
+                ngtcp2_strerror(rv), rv);
+    if(!ctx->last_error.error_code) {
+      if(rv == NGTCP2_ERR_CRYPTO) {
+        ngtcp2_ccerr_set_tls_alert(&ctx->last_error,
+                                   ngtcp2_conn_get_tls_alert(ctx->qconn),
+                                   NULL, 0);
+      }
+      else {
+        ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0);
+      }
+    }
+
+    if(rv == NGTCP2_ERR_CRYPTO)
+      /* this is a "TLS problem", but a failed certificate verification
+         is a common reason for this */
+      return CURLE_PEER_FAILED_VERIFICATION;
+    return CURLE_RECV_ERROR;
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    struct pkt_io_ctx *pktx)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct pkt_io_ctx local_pktx;
+  size_t pkts_chunk = 128, i;
+  CURLcode result = CURLE_OK;
+
+  if(!pktx) {
+    pktx_init(&local_pktx, cf, data);
+    pktx = &local_pktx;
+  }
+  else {
+    pktx_update_time(pktx, cf);
+  }
+
+  result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
+  if(result)
+    return result;
+
+  for(i = 0; i < 4; ++i) {
+    if(i)
+      pktx_update_time(pktx, cf);
+    pktx->pkt_count = 0;
+    result = vquic_recv_packets(cf, data, &ctx->q, pkts_chunk,
+                                recv_pkt, pktx);
+    if(result || !pktx->pkt_count) /* error or got nothing */
+      break;
+  }
+  return result;
+}
+
+/**
+ * Read a network packet to send from ngtcp2 into `buf`.
+ * Return number of bytes written or -1 with *err set.
+ */
+static ssize_t read_pkt_to_send(void *userp,
+                                unsigned char *buf, size_t buflen,
+                                CURLcode *err)
+{
+  struct pkt_io_ctx *x = userp;
+  struct cf_ngtcp2_ctx *ctx = x->cf->ctx;
+  nghttp3_vec vec[16];
+  nghttp3_ssize veccnt;
+  ngtcp2_ssize ndatalen;
+  uint32_t flags;
+  int64_t stream_id;
+  int fin;
+  ssize_t nwritten, n;
+  veccnt = 0;
+  stream_id = -1;
+  fin = 0;
+
+  /* ngtcp2 may want to put several frames from different streams into
+   * this packet. `NGTCP2_WRITE_STREAM_FLAG_MORE` tells it to do so.
+   * When `NGTCP2_ERR_WRITE_MORE` is returned, we *need* to make
+   * another iteration.
+   * When ngtcp2 is happy (because it has no other frame that would fit
+   * or it has nothing more to send), it returns the total length
+   * of the assembled packet. This may be 0 if there was nothing to send. */
+  nwritten = 0;
+  *err = CURLE_OK;
+  for(;;) {
+
+    if(ctx->h3conn && ngtcp2_conn_get_max_data_left(ctx->qconn)) {
+      veccnt = nghttp3_conn_writev_stream(ctx->h3conn, &stream_id, &fin, vec,
+                                          sizeof(vec) / sizeof(vec[0]));
+      if(veccnt < 0) {
+        failf(x->data, "nghttp3_conn_writev_stream returned error: %s",
+              nghttp3_strerror((int)veccnt));
+        ngtcp2_ccerr_set_application_error(
+          &ctx->last_error,
+          nghttp3_err_infer_quic_app_error_code((int)veccnt), NULL, 0);
+        *err = CURLE_SEND_ERROR;
+        return -1;
+      }
+    }
+
+    flags = NGTCP2_WRITE_STREAM_FLAG_MORE |
+            (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0);
+    n = ngtcp2_conn_writev_stream(ctx->qconn, &x->ps.path,
+                                  NULL, buf, buflen,
+                                  &ndatalen, flags, stream_id,
+                                  (const ngtcp2_vec *)vec, veccnt, x->ts);
+    if(n == 0) {
+      /* nothing to send */
+      *err = CURLE_AGAIN;
+      nwritten = -1;
+      goto out;
+    }
+    else if(n < 0) {
+      switch(n) {
+      case NGTCP2_ERR_STREAM_DATA_BLOCKED: {
+        struct h3_stream_ctx *stream = H3_STREAM_CTX(x->data);
+        DEBUGASSERT(ndatalen == -1);
+        nghttp3_conn_block_stream(ctx->h3conn, stream_id);
+        CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] block quic flow",
+                    stream_id);
+        DEBUGASSERT(stream);
+        if(stream)
+          stream->quic_flow_blocked = TRUE;
+        n = 0;
+        break;
+      }
+      case NGTCP2_ERR_STREAM_SHUT_WR:
+        DEBUGASSERT(ndatalen == -1);
+        nghttp3_conn_shutdown_stream_write(ctx->h3conn, stream_id);
+        n = 0;
+        break;
+      case NGTCP2_ERR_WRITE_MORE:
+        /* ngtcp2 wants to send more. update the flow of the stream whose data
+         * is in the buffer and continue */
+        DEBUGASSERT(ndatalen >= 0);
+        n = 0;
+        break;
+      default:
+        DEBUGASSERT(ndatalen == -1);
+        failf(x->data, "ngtcp2_conn_writev_stream returned error: %s",
+              ngtcp2_strerror((int)n));
+        ngtcp2_ccerr_set_liberr(&ctx->last_error, (int)n, NULL, 0);
+        *err = CURLE_SEND_ERROR;
+        nwritten = -1;
+        goto out;
+      }
+    }
+
+    if(ndatalen >= 0) {
+      /* we add the amount of data bytes to the flow windows */
+      int rv = nghttp3_conn_add_write_offset(ctx->h3conn, stream_id, ndatalen);
+      if(rv) {
+        failf(x->data, "nghttp3_conn_add_write_offset returned error: %s\n",
+              nghttp3_strerror(rv));
+        return CURLE_SEND_ERROR;
+      }
+    }
+
+    if(n > 0) {
+      /* packet assembled, leave */
+      nwritten = n;
+      goto out;
+    }
+  }
+out:
+  return nwritten;
+}
+
+static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   struct pkt_io_ctx *pktx)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  ssize_t nread;
+  size_t max_payload_size, path_max_payload_size, max_pktcnt;
+  size_t pktcnt = 0;
+  size_t gsolen = 0;  /* this disables gso until we have a clue */
+  CURLcode curlcode;
+  struct pkt_io_ctx local_pktx;
+
+  if(!pktx) {
+    pktx_init(&local_pktx, cf, data);
+    pktx = &local_pktx;
+  }
+  else {
+    pktx_update_time(pktx, cf);
+    ngtcp2_path_storage_zero(&pktx->ps);
+  }
+
+  curlcode = vquic_flush(cf, data, &ctx->q);
+  if(curlcode) {
+    if(curlcode == CURLE_AGAIN) {
+      Curl_expire(data, 1, EXPIRE_QUIC);
+      return CURLE_OK;
+    }
+    return curlcode;
+  }
+
+  /* In UDP, there is a maximum theoretical packet paload length and
+   * a minimum payload length that is "guaranteed" to work.
+   * To detect if this minimum payload can be increased, ngtcp2 sends
+   * now and then a packet payload larger than the minimum. It that
+   * is ACKed by the peer, both parties know that it works and
+   * the subsequent packets can use a larger one.
+   * This is called PMTUD (Path Maximum Transmission Unit Discovery).
+   * Since a PMTUD might be rejected right on send, we do not want it
+   * be followed by other packets of lesser size. Because those would
+   * also fail then. So, if we detect a PMTUD while buffering, we flush.
+   */
+  max_payload_size = ngtcp2_conn_get_max_tx_udp_payload_size(ctx->qconn);
+  path_max_payload_size =
+      ngtcp2_conn_get_path_max_tx_udp_payload_size(ctx->qconn);
+  /* maximum number of packets buffered before we flush to the socket */
+  max_pktcnt = CURLMIN(MAX_PKT_BURST,
+                       ctx->q.sendbuf.chunk_size / max_payload_size);
+
+  for(;;) {
+    /* add the next packet to send, if any, to our buffer */
+    nread = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size,
+                           read_pkt_to_send, pktx, &curlcode);
+    if(nread < 0) {
+      if(curlcode != CURLE_AGAIN)
+        return curlcode;
+      /* Nothing more to add, flush and leave */
+      curlcode = vquic_send(cf, data, &ctx->q, gsolen);
+      if(curlcode) {
+        if(curlcode == CURLE_AGAIN) {
+          Curl_expire(data, 1, EXPIRE_QUIC);
+          return CURLE_OK;
+        }
+        return curlcode;
+      }
+      goto out;
+    }
+
+    DEBUGASSERT(nread > 0);
+    if(pktcnt == 0) {
+      /* first packet in buffer. This is either of a known, "good"
+       * payload size or it is a PMTUD. We'll see. */
+      gsolen = (size_t)nread;
+    }
+    else if((size_t)nread > gsolen ||
+            (gsolen > path_max_payload_size && (size_t)nread != gsolen)) {
+      /* The just added packet is a PMTUD *or* the one(s) before the
+       * just added were PMTUD and the last one is smaller.
+       * Flush the buffer before the last add. */
+      curlcode = vquic_send_tail_split(cf, data, &ctx->q,
+                                       gsolen, nread, nread);
+      if(curlcode) {
+        if(curlcode == CURLE_AGAIN) {
+          Curl_expire(data, 1, EXPIRE_QUIC);
+          return CURLE_OK;
+        }
+        return curlcode;
+      }
+      pktcnt = 0;
+      continue;
+    }
+
+    if(++pktcnt >= max_pktcnt || (size_t)nread < gsolen) {
+      /* Reached MAX_PKT_BURST *or*
+       * the capacity of our buffer *or*
+       * last add was shorter than the previous ones, flush */
+      curlcode = vquic_send(cf, data, &ctx->q, gsolen);
+      if(curlcode) {
+        if(curlcode == CURLE_AGAIN) {
+          Curl_expire(data, 1, EXPIRE_QUIC);
+          return CURLE_OK;
+        }
+        return curlcode;
+      }
+      /* pktbuf has been completely sent */
+      pktcnt = 0;
+    }
+  }
+
+out:
+  return CURLE_OK;
+}
+
+/*
+ * Called from transfer.c:data_pending to know if we should keep looping
+ * to receive more data from the connection.
+ */
+static bool cf_ngtcp2_data_pending(struct Curl_cfilter *cf,
+                                   const struct Curl_easy *data)
+{
+  (void)cf;
+  (void)data;
+  return FALSE;
+}
+
+static CURLcode h3_data_pause(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              bool pause)
+{
+  /* TODO: there seems right now no API in ngtcp2 to shrink/enlarge
+   * the streams windows. As we do in HTTP/2. */
+  if(!pause) {
+    h3_drain_stream(cf, data);
+    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+  }
+  return CURLE_OK;
+}
+
+static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data,
+                                     int event, int arg1, void *arg2)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
+  struct cf_call_data save;
+
+  CF_DATA_SAVE(save, cf, data);
+  (void)arg1;
+  (void)arg2;
+  switch(event) {
+  case CF_CTRL_DATA_SETUP:
+    break;
+  case CF_CTRL_DATA_PAUSE:
+    result = h3_data_pause(cf, data, (arg1 != 0));
+    break;
+  case CF_CTRL_DATA_DETACH:
+    h3_data_done(cf, data);
+    break;
+  case CF_CTRL_DATA_DONE:
+    h3_data_done(cf, data);
+    break;
+  case CF_CTRL_DATA_DONE_SEND: {
+    struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+    if(stream && !stream->send_closed) {
+      stream->send_closed = TRUE;
+      stream->upload_left = Curl_bufq_len(&stream->sendbuf);
+      (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
+    }
+    break;
+  }
+  case CF_CTRL_DATA_IDLE: {
+    struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+    CURL_TRC_CF(data, cf, "data idle");
+    if(stream && !stream->closed) {
+      result = check_and_set_expiry(cf, data, NULL);
+      if(result)
+        CURL_TRC_CF(data, cf, "data idle, check_and_set_expiry -> %d", result);
+    }
+    break;
+  }
+  default:
+    break;
+  }
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
+static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
+{
+  struct cf_call_data save = ctx->call_data;
+
+  if(ctx->qlogfd != -1) {
+    close(ctx->qlogfd);
+  }
+  Curl_vquic_tls_cleanup(&ctx->tls);
+  vquic_ctx_free(&ctx->q);
+  if(ctx->h3conn)
+    nghttp3_conn_del(ctx->h3conn);
+  if(ctx->qconn)
+    ngtcp2_conn_del(ctx->qconn);
+  Curl_bufcp_free(&ctx->stream_bufcp);
+  Curl_ssl_peer_cleanup(&ctx->peer);
+
+  memset(ctx, 0, sizeof(*ctx));
+  ctx->qlogfd = -1;
+  ctx->call_data = save;
+}
+
+static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct cf_call_data save;
+
+  CF_DATA_SAVE(save, cf, data);
+  if(ctx && ctx->qconn) {
+    char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE];
+    struct pkt_io_ctx pktx;
+    ngtcp2_ssize rc;
+
+    CURL_TRC_CF(data, cf, "close");
+    pktx_init(&pktx, cf, data);
+    rc = ngtcp2_conn_write_connection_close(ctx->qconn, NULL, /* path */
+                                            NULL, /* pkt_info */
+                                            (uint8_t *)buffer, sizeof(buffer),
+                                            &ctx->last_error, pktx.ts);
+    if(rc > 0) {
+      while((send(ctx->q.sockfd, buffer, (SEND_TYPE_ARG3)rc, 0) == -1) &&
+            SOCKERRNO == EINTR);
+    }
+
+    cf_ngtcp2_ctx_clear(ctx);
+  }
+
+  cf->connected = FALSE;
+  CF_DATA_RESTORE(cf, save);
+}
+
+static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct cf_call_data save;
+
+  CF_DATA_SAVE(save, cf, data);
+  CURL_TRC_CF(data, cf, "destroy");
+  if(ctx) {
+    cf_ngtcp2_ctx_clear(ctx);
+    free(ctx);
+  }
+  cf->ctx = NULL;
+  /* No CF_DATA_RESTORE(cf, save) possible */
+  (void)save;
+}
+
+static CURLcode tls_ctx_setup(struct quic_tls_ctx *ctx,
+                              struct Curl_cfilter *cf,
+                              struct Curl_easy *data)
+{
+  (void)cf;
+#ifdef USE_OPENSSL
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+  if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ssl_ctx) != 0) {
+    failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
+    return CURLE_FAILED_INIT;
+  }
+#else
+  if(ngtcp2_crypto_quictls_configure_client_context(ctx->ssl_ctx) != 0) {
+    failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
+    return CURLE_FAILED_INIT;
+  }
+#endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
+#elif defined(USE_GNUTLS)
+  if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls->session) != 0) {
+    failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
+    return CURLE_FAILED_INIT;
+  }
+#elif defined(USE_WOLFSSL)
+  if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->ssl_ctx) != 0) {
+    failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
+    return CURLE_FAILED_INIT;
+  }
+#endif
+  return CURLE_OK;
+}
+
+/*
+ * Might be called twice for happy eyeballs.
+ */
+static CURLcode cf_connect_start(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 struct pkt_io_ctx *pktx)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  int rc;
+  int rv;
+  CURLcode result;
+  const struct Curl_sockaddr_ex *sockaddr = NULL;
+  int qfd;
+
+  ctx->version = NGTCP2_PROTO_VER_MAX;
+  ctx->max_stream_window = H3_STREAM_WINDOW_SIZE;
+  ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
+  Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
+                  H3_STREAM_POOL_SPARES);
+
+  result = Curl_ssl_peer_init(&ctx->peer, cf);
+  if(result)
+    return result;
+
+#define H3_ALPN "\x2h3\x5h3-29"
+  result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
+                               H3_ALPN, sizeof(H3_ALPN) - 1,
+                               tls_ctx_setup, &ctx->conn_ref);
+  if(result)
+    return result;
+
+  ctx->dcid.datalen = NGTCP2_MAX_CIDLEN;
+  result = Curl_rand(data, ctx->dcid.data, NGTCP2_MAX_CIDLEN);
+  if(result)
+    return result;
+
+  ctx->scid.datalen = NGTCP2_MAX_CIDLEN;
+  result = Curl_rand(data, ctx->scid.data, NGTCP2_MAX_CIDLEN);
+  if(result)
+    return result;
+
+  (void)Curl_qlogdir(data, ctx->scid.data, NGTCP2_MAX_CIDLEN, &qfd);
+  ctx->qlogfd = qfd; /* -1 if failure above */
+  quic_settings(ctx, data, pktx);
+
+  result = vquic_ctx_init(&ctx->q);
+  if(result)
+    return result;
+
+  Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL);
+  if(!sockaddr)
+    return CURLE_QUIC_CONNECT_ERROR;
+  ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
+  rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr,
+                   &ctx->q.local_addrlen);
+  if(rv == -1)
+    return CURLE_QUIC_CONNECT_ERROR;
+
+  ngtcp2_addr_init(&ctx->connected_path.local,
+                   (struct sockaddr *)&ctx->q.local_addr,
+                   ctx->q.local_addrlen);
+  ngtcp2_addr_init(&ctx->connected_path.remote,
+                   &sockaddr->sa_addr, sockaddr->addrlen);
+
+  rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid,
+                              &ctx->connected_path,
+                              NGTCP2_PROTO_VER_V1, &ng_callbacks,
+                              &ctx->settings, &ctx->transport_params,
+                              NULL, cf);
+  if(rc)
+    return CURLE_QUIC_CONNECT_ERROR;
+
+#ifdef USE_GNUTLS
+  ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls->session);
+#else
+  ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ssl);
+#endif
+
+  ngtcp2_ccerr_default(&ctx->last_error);
+
+  ctx->conn_ref.get_conn = get_conn;
+  ctx->conn_ref.user_data = cf;
+
+  return CURLE_OK;
+}
+
+static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  bool blocking, bool *done)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
+  struct cf_call_data save;
+  struct curltime now;
+  struct pkt_io_ctx pktx;
+
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  /* Connect the UDP filter first */
+  if(!cf->next->connected) {
+    result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+    if(result || !*done)
+      return result;
+  }
+
+  *done = FALSE;
+  now = Curl_now();
+  pktx_init(&pktx, cf, data);
+
+  CF_DATA_SAVE(save, cf, data);
+
+  if(ctx->reconnect_at.tv_sec && Curl_timediff(now, ctx->reconnect_at) < 0) {
+    /* Not time yet to attempt the next connect */
+    CURL_TRC_CF(data, cf, "waiting for reconnect time");
+    goto out;
+  }
+
+  if(!ctx->qconn) {
+    ctx->started_at = now;
+    result = cf_connect_start(cf, data, &pktx);
+    if(result)
+      goto out;
+    result = cf_progress_egress(cf, data, &pktx);
+    /* we do not expect to be able to recv anything yet */
+    goto out;
+  }
+
+  result = cf_progress_ingress(cf, data, &pktx);
+  if(result)
+    goto out;
+
+  result = cf_progress_egress(cf, data, &pktx);
+  if(result)
+    goto out;
+
+  if(ngtcp2_conn_get_handshake_completed(ctx->qconn)) {
+    ctx->handshake_at = now;
+    CURL_TRC_CF(data, cf, "handshake complete after %dms",
+               (int)Curl_timediff(now, ctx->started_at));
+    result = qng_verify_peer(cf, data);
+    if(!result) {
+      CURL_TRC_CF(data, cf, "peer verified");
+      cf->connected = TRUE;
+      cf->conn->alpn = CURL_HTTP_VERSION_3;
+      *done = TRUE;
+      connkeep(cf->conn, "HTTP/3 default");
+    }
+  }
+
+out:
+  if(result == CURLE_RECV_ERROR && ctx->qconn &&
+     ngtcp2_conn_in_draining_period(ctx->qconn)) {
+    /* When a QUIC server instance is shutting down, it may send us a
+     * CONNECTION_CLOSE right away. Our connection then enters the DRAINING
+     * state. The CONNECT may work in the near future again. Indicate
+     * that as a "weird" reply. */
+    result = CURLE_WEIRD_SERVER_REPLY;
+  }
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  if(result) {
+    struct ip_quadruple ip;
+
+    Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
+    infof(data, "QUIC connect to %s port %u failed: %s",
+          ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
+  }
+#endif
+  if(!result && ctx->qconn) {
+    result = check_and_set_expiry(cf, data, &pktx);
+  }
+  if(result || *done)
+    CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done);
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
+static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                int query, int *pres1, void *pres2)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct cf_call_data save;
+
+  switch(query) {
+  case CF_QUERY_MAX_CONCURRENT: {
+    const ngtcp2_transport_params *rp;
+    DEBUGASSERT(pres1);
+
+    CF_DATA_SAVE(save, cf, data);
+    rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
+    if(rp)
+      *pres1 = (rp->initial_max_streams_bidi > INT_MAX)?
+                 INT_MAX : (int)rp->initial_max_streams_bidi;
+    else  /* not arrived yet? */
+      *pres1 = Curl_multi_max_concurrent_streams(data->multi);
+    CURL_TRC_CF(data, cf, "query max_conncurrent -> %d", *pres1);
+    CF_DATA_RESTORE(cf, save);
+    return CURLE_OK;
+  }
+  case CF_QUERY_CONNECT_REPLY_MS:
+    if(ctx->q.got_first_byte) {
+      timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
+      *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
+    }
+    else
+      *pres1 = -1;
+    return CURLE_OK;
+  case CF_QUERY_TIMER_CONNECT: {
+    struct curltime *when = pres2;
+    if(ctx->q.got_first_byte)
+      *when = ctx->q.first_byte_at;
+    return CURLE_OK;
+  }
+  case CF_QUERY_TIMER_APPCONNECT: {
+    struct curltime *when = pres2;
+    if(cf->connected)
+      *when = ctx->handshake_at;
+    return CURLE_OK;
+  }
+  default:
+    break;
+  }
+  return cf->next?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
+}
+
+static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    bool *input_pending)
+{
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  bool alive = FALSE;
+  const ngtcp2_transport_params *rp;
+  struct cf_call_data save;
+
+    CF_DATA_SAVE(save, cf, data);
+  *input_pending = FALSE;
+  if(!ctx->qconn)
+    goto out;
+
+  /* Both sides of the QUIC connection announce they max idle times in
+   * the transport parameters. Look at the minimum of both and if
+   * we exceed this, regard the connection as dead. The other side
+   * may have completely purged it and will no longer respond
+   * to any packets from us. */
+  rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
+  if(rp) {
+    timediff_t idletime;
+    uint64_t idle_ms = ctx->max_idle_ms;
+
+    if(rp->max_idle_timeout &&
+      (rp->max_idle_timeout / NGTCP2_MILLISECONDS) < idle_ms)
+      idle_ms = (rp->max_idle_timeout / NGTCP2_MILLISECONDS);
+    idletime = Curl_timediff(Curl_now(), ctx->q.last_io);
+    if(idletime > 0 && (uint64_t)idletime > idle_ms)
+      goto out;
+  }
+
+  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
+    goto out;
+
+  alive = TRUE;
+  if(*input_pending) {
+    CURLcode result;
+    /* This happens before we've sent off a request and the connection is
+       not in use by any other transfer, there shouldn't be any data here,
+       only "protocol frames" */
+    *input_pending = FALSE;
+    result = cf_progress_ingress(cf, data, NULL);
+    CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
+    alive = result? FALSE : TRUE;
+  }
+
+out:
+  CF_DATA_RESTORE(cf, save);
+  return alive;
+}
+
+struct Curl_cftype Curl_cft_http3 = {
+  "HTTP/3",
+  CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
+  0,
+  cf_ngtcp2_destroy,
+  cf_ngtcp2_connect,
+  cf_ngtcp2_close,
+  Curl_cf_def_get_host,
+  cf_ngtcp2_adjust_pollset,
+  cf_ngtcp2_data_pending,
+  cf_ngtcp2_send,
+  cf_ngtcp2_recv,
+  cf_ngtcp2_data_event,
+  cf_ngtcp2_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  cf_ngtcp2_query,
+};
+
+CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
+                               struct Curl_easy *data,
+                               struct connectdata *conn,
+                               const struct Curl_addrinfo *ai)
+{
+  struct cf_ngtcp2_ctx *ctx = NULL;
+  struct Curl_cfilter *cf = NULL, *udp_cf = NULL;
+  CURLcode result;
+
+  (void)data;
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  ctx->qlogfd = -1;
+  cf_ngtcp2_ctx_clear(ctx);
+
+  result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
+  if(result)
+    goto out;
+
+  result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC);
+  if(result)
+    goto out;
+
+  cf->conn = conn;
+  udp_cf->conn = cf->conn;
+  udp_cf->sockindex = cf->sockindex;
+  cf->next = udp_cf;
+
+out:
+  *pcf = (!result)? cf : NULL;
+  if(result) {
+    if(udp_cf)
+      Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
+    Curl_safefree(cf);
+    Curl_safefree(ctx);
+  }
+  return result;
+}
+
+bool Curl_conn_is_ngtcp2(const struct Curl_easy *data,
+                         const struct connectdata *conn,
+                         int sockindex)
+{
+  struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+
+  (void)data;
+  for(; cf; cf = cf->next) {
+    if(cf->cft == &Curl_cft_http3)
+      return TRUE;
+    if(cf->cft->flags & CF_TYPE_IP_CONNECT)
+      return FALSE;
+  }
+  return FALSE;
+}
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/vquic/curl_ngtcp2.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vquic/curl_ngtcp2.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vquic/curl_ngtcp2.h	(revision 104083)
@@ -0,0 +1,61 @@
+#ifndef HEADER_CURL_VQUIC_CURL_NGTCP2_H
+#define HEADER_CURL_VQUIC_CURL_NGTCP2_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
+
+#ifdef HAVE_NETINET_UDP_H
+#include <netinet/udp.h>
+#endif
+
+#include <ngtcp2/ngtcp2_crypto.h>
+#include <nghttp3/nghttp3.h>
+#ifdef USE_OPENSSL
+#include <openssl/ssl.h>
+#elif defined(USE_WOLFSSL)
+#include <wolfssl/options.h>
+#include <wolfssl/ssl.h>
+#include <wolfssl/quic.h>
+#endif
+
+struct Curl_cfilter;
+
+#include "urldata.h"
+
+void Curl_ngtcp2_ver(char *p, size_t len);
+
+CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
+                             struct Curl_easy *data,
+                             struct connectdata *conn,
+                             const struct Curl_addrinfo *ai);
+
+bool Curl_conn_is_ngtcp2(const struct Curl_easy *data,
+                         const struct connectdata *conn,
+                         int sockindex);
+#endif
+
+#endif /* HEADER_CURL_VQUIC_CURL_NGTCP2_H */
Index: trunk/src/libs/curl-8.7.1/lib/vquic/curl_quiche.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vquic/curl_quiche.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vquic/curl_quiche.c	(revision 104083)
@@ -0,0 +1,1595 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_QUICHE
+#include <quiche.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include "bufq.h"
+#include "urldata.h"
+#include "cfilters.h"
+#include "cf-socket.h"
+#include "sendf.h"
+#include "strdup.h"
+#include "rand.h"
+#include "strcase.h"
+#include "multiif.h"
+#include "connect.h"
+#include "progress.h"
+#include "strerror.h"
+#include "http1.h"
+#include "vquic.h"
+#include "vquic_int.h"
+#include "vquic-tls.h"
+#include "curl_quiche.h"
+#include "transfer.h"
+#include "inet_pton.h"
+#include "vtls/openssl.h"
+#include "vtls/keylog.h"
+#include "vtls/vtls.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* HTTP/3 error values defined in RFC 9114, ch. 8.1 */
+#define CURL_H3_NO_ERROR  (0x0100)
+
+#define QUIC_MAX_STREAMS              (100)
+
+#define H3_STREAM_WINDOW_SIZE  (128 * 1024)
+#define H3_STREAM_CHUNK_SIZE    (16 * 1024)
+/* The pool keeps spares around and half of a full stream windows
+ * seems good. More does not seem to improve performance.
+ * The benefit of the pool is that stream buffer to not keep
+ * spares. So memory consumption goes down when streams run empty,
+ * have a large upload done, etc. */
+#define H3_STREAM_POOL_SPARES \
+          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
+/* Receive and Send max number of chunks just follows from the
+ * chunk size and window size */
+#define H3_STREAM_RECV_CHUNKS \
+          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
+#define H3_STREAM_SEND_CHUNKS \
+          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
+
+/*
+ * Store quiche version info in this buffer.
+ */
+void Curl_quiche_ver(char *p, size_t len)
+{
+  (void)msnprintf(p, len, "quiche/%s", quiche_version());
+}
+
+struct cf_quiche_ctx {
+  struct cf_quic_ctx q;
+  struct ssl_peer peer;
+  struct quic_tls_ctx tls;
+  quiche_conn *qconn;
+  quiche_config *cfg;
+  quiche_h3_conn *h3c;
+  quiche_h3_config *h3config;
+  uint8_t scid[QUICHE_MAX_CONN_ID_LEN];
+  struct curltime started_at;        /* time the current attempt started */
+  struct curltime handshake_at;      /* time connect handshake finished */
+  struct curltime reconnect_at;      /* time the next attempt should start */
+  struct bufc_pool stream_bufcp;     /* chunk pool for streams */
+  curl_off_t data_recvd;
+  uint64_t max_idle_ms;              /* max idle time for QUIC conn */
+  BIT(goaway);                       /* got GOAWAY from server */
+  BIT(x509_store_setup);             /* if x509 store has been set up */
+};
+
+#ifdef DEBUG_QUICHE
+static void quiche_debug_log(const char *line, void *argp)
+{
+  (void)argp;
+  fprintf(stderr, "%s\n", line);
+}
+#endif
+
+static void cf_quiche_ctx_clear(struct cf_quiche_ctx *ctx)
+{
+  if(ctx) {
+    if(ctx->h3c)
+      quiche_h3_conn_free(ctx->h3c);
+    if(ctx->h3config)
+      quiche_h3_config_free(ctx->h3config);
+    if(ctx->qconn)
+      quiche_conn_free(ctx->qconn);
+    if(ctx->cfg)
+      quiche_config_free(ctx->cfg);
+    /* quiche just freed ctx->tls.ssl */
+    ctx->tls.ssl = NULL;
+    Curl_vquic_tls_cleanup(&ctx->tls);
+    Curl_ssl_peer_cleanup(&ctx->peer);
+    vquic_ctx_free(&ctx->q);
+    Curl_bufcp_free(&ctx->stream_bufcp);
+
+    memset(ctx, 0, sizeof(*ctx));
+  }
+}
+
+/**
+ * All about the H3 internals of a stream
+ */
+struct stream_ctx {
+  int64_t id; /* HTTP/3 protocol stream identifier */
+  struct bufq recvbuf; /* h3 response */
+  struct h1_req_parser h1; /* h1 request parsing */
+  uint64_t error3; /* HTTP/3 stream error code */
+  curl_off_t upload_left; /* number of request bytes left to upload */
+  bool closed; /* TRUE on stream close */
+  bool reset;  /* TRUE on stream reset */
+  bool send_closed; /* stream is locally closed */
+  bool resp_hds_complete;  /* complete, final response has been received */
+  bool resp_got_header; /* TRUE when h3 stream has recvd some HEADER */
+  BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
+};
+
+#define H3_STREAM_CTX(d)    ((struct stream_ctx *)(((d) && (d)->req.p.http)? \
+                             ((struct HTTP *)(d)->req.p.http)->h3_ctx \
+                               : NULL))
+#define H3_STREAM_LCTX(d)   ((struct HTTP *)(d)->req.p.http)->h3_ctx
+#define H3_STREAM_ID(d)     (H3_STREAM_CTX(d)? \
+                             H3_STREAM_CTX(d)->id : -2)
+
+static void check_resumes(struct Curl_cfilter *cf,
+                          struct Curl_easy *data)
+{
+  struct Curl_easy *sdata;
+  struct stream_ctx *stream;
+
+  DEBUGASSERT(data->multi);
+  for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+    if(sdata->conn == data->conn) {
+      stream = H3_STREAM_CTX(sdata);
+      if(stream && stream->quic_flow_blocked) {
+        stream->quic_flow_blocked = FALSE;
+        Curl_expire(data, 0, EXPIRE_RUN_NOW);
+        CURL_TRC_CF(data, cf, "[%"PRId64"] unblock", stream->id);
+      }
+    }
+  }
+}
+
+static CURLcode h3_data_setup(struct Curl_cfilter *cf,
+                              struct Curl_easy *data)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+
+  if(stream)
+    return CURLE_OK;
+
+  stream = calloc(1, sizeof(*stream));
+  if(!stream)
+    return CURLE_OUT_OF_MEMORY;
+
+  H3_STREAM_LCTX(data) = stream;
+  stream->id = -1;
+  Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
+                  H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
+  Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
+  return CURLE_OK;
+}
+
+static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+
+  (void)cf;
+  if(stream) {
+    CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->id);
+    if(ctx->qconn && !stream->closed) {
+      quiche_conn_stream_shutdown(ctx->qconn, stream->id,
+                                  QUICHE_SHUTDOWN_READ, CURL_H3_NO_ERROR);
+      if(!stream->send_closed) {
+        quiche_conn_stream_shutdown(ctx->qconn, stream->id,
+                                    QUICHE_SHUTDOWN_WRITE, CURL_H3_NO_ERROR);
+        stream->send_closed = TRUE;
+      }
+      stream->closed = TRUE;
+    }
+    Curl_bufq_free(&stream->recvbuf);
+    Curl_h1_req_parse_free(&stream->h1);
+    free(stream);
+    H3_STREAM_LCTX(data) = NULL;
+  }
+}
+
+static void drain_stream(struct Curl_cfilter *cf,
+                         struct Curl_easy *data)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  unsigned char bits;
+
+  (void)cf;
+  bits = CURL_CSELECT_IN;
+  if(stream && !stream->send_closed && stream->upload_left)
+    bits |= CURL_CSELECT_OUT;
+  if(data->state.select_bits != bits) {
+    data->state.select_bits = bits;
+    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+  }
+}
+
+static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
+                                         struct Curl_easy *data,
+                                         int64_t stream3_id)
+{
+  struct Curl_easy *sdata;
+
+  (void)cf;
+  if(H3_STREAM_ID(data) == stream3_id) {
+    return data;
+  }
+  else {
+    DEBUGASSERT(data->multi);
+    for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+      if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream3_id) {
+        return sdata;
+      }
+    }
+  }
+  return NULL;
+}
+
+/*
+ * write_resp_raw() copies response data in raw format to the `data`'s
+  * receive buffer. If not enough space is available, it appends to the
+ * `data`'s overflow buffer.
+ */
+static CURLcode write_resp_raw(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               const void *mem, size_t memlen)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  CURLcode result = CURLE_OK;
+  ssize_t nwritten;
+
+  (void)cf;
+  if(!stream)
+    return CURLE_RECV_ERROR;
+  nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
+  if(nwritten < 0)
+    return result;
+
+  if((size_t)nwritten < memlen) {
+    /* This MUST not happen. Our recbuf is dimensioned to hold the
+     * full max_stream_window and then some for this very reason. */
+    DEBUGASSERT(0);
+    return CURLE_RECV_ERROR;
+  }
+  return result;
+}
+
+struct cb_ctx {
+  struct Curl_cfilter *cf;
+  struct Curl_easy *data;
+};
+
+static int cb_each_header(uint8_t *name, size_t name_len,
+                          uint8_t *value, size_t value_len,
+                          void *argp)
+{
+  struct cb_ctx *x = argp;
+  struct stream_ctx *stream = H3_STREAM_CTX(x->data);
+  CURLcode result;
+
+  if(!stream)
+    return CURLE_OK;
+
+  if((name_len == 7) && !strncmp(HTTP_PSEUDO_STATUS, (char *)name, 7)) {
+    CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] status: %.*s",
+                stream->id, (int)value_len, value);
+    result = write_resp_raw(x->cf, x->data, "HTTP/3 ", sizeof("HTTP/3 ") - 1);
+    if(!result)
+      result = write_resp_raw(x->cf, x->data, value, value_len);
+    if(!result)
+      result = write_resp_raw(x->cf, x->data, " \r\n", 3);
+  }
+  else {
+    CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] header: %.*s: %.*s",
+                stream->id, (int)name_len, name,
+                (int)value_len, value);
+    result = write_resp_raw(x->cf, x->data, name, name_len);
+    if(!result)
+      result = write_resp_raw(x->cf, x->data, ": ", 2);
+    if(!result)
+      result = write_resp_raw(x->cf, x->data, value, value_len);
+    if(!result)
+      result = write_resp_raw(x->cf, x->data, "\r\n", 2);
+  }
+  if(result) {
+    CURL_TRC_CF(x->data, x->cf, "[%"PRId64"] on header error %d",
+                stream->id, result);
+  }
+  return result;
+}
+
+static ssize_t stream_resp_read(void *reader_ctx,
+                                unsigned char *buf, size_t len,
+                                CURLcode *err)
+{
+  struct cb_ctx *x = reader_ctx;
+  struct cf_quiche_ctx *ctx = x->cf->ctx;
+  struct stream_ctx *stream = H3_STREAM_CTX(x->data);
+  ssize_t nread;
+
+  if(!stream) {
+    *err = CURLE_RECV_ERROR;
+    return -1;
+  }
+
+  nread = quiche_h3_recv_body(ctx->h3c, ctx->qconn, stream->id,
+                              buf, len);
+  if(nread >= 0) {
+    *err = CURLE_OK;
+    return nread;
+  }
+  else {
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+}
+
+static CURLcode cf_recv_body(struct Curl_cfilter *cf,
+                             struct Curl_easy *data)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  ssize_t nwritten;
+  struct cb_ctx cb_ctx;
+  CURLcode result = CURLE_OK;
+
+  if(!stream)
+    return CURLE_RECV_ERROR;
+
+  if(!stream->resp_hds_complete) {
+    result = write_resp_raw(cf, data, "\r\n", 2);
+    if(result)
+      return result;
+    stream->resp_hds_complete = TRUE;
+  }
+
+  cb_ctx.cf = cf;
+  cb_ctx.data = data;
+  nwritten = Curl_bufq_slurp(&stream->recvbuf,
+                             stream_resp_read, &cb_ctx, &result);
+
+  if(nwritten < 0 && result != CURLE_AGAIN) {
+    CURL_TRC_CF(data, cf, "[%"PRId64"] recv_body error %zd",
+                stream->id, nwritten);
+    failf(data, "Error %d in HTTP/3 response body for stream[%"PRId64"]",
+          result, stream->id);
+    stream->closed = TRUE;
+    stream->reset = TRUE;
+    stream->send_closed = TRUE;
+    streamclose(cf->conn, "Reset of stream");
+    return result;
+  }
+  return CURLE_OK;
+}
+
+#ifdef DEBUGBUILD
+static const char *cf_ev_name(quiche_h3_event *ev)
+{
+  switch(quiche_h3_event_type(ev)) {
+  case QUICHE_H3_EVENT_HEADERS:
+    return "HEADERS";
+  case QUICHE_H3_EVENT_DATA:
+    return "DATA";
+  case QUICHE_H3_EVENT_RESET:
+    return "RESET";
+  case QUICHE_H3_EVENT_FINISHED:
+    return "FINISHED";
+  case QUICHE_H3_EVENT_GOAWAY:
+    return "GOAWAY";
+  default:
+    return "Unknown";
+  }
+}
+#else
+#define cf_ev_name(x)   ""
+#endif
+
+static CURLcode h3_process_event(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 int64_t stream3_id,
+                                 quiche_h3_event *ev)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  struct cb_ctx cb_ctx;
+  CURLcode result = CURLE_OK;
+  int rc;
+
+  if(!stream)
+    return CURLE_OK;
+  DEBUGASSERT(stream3_id == stream->id);
+  switch(quiche_h3_event_type(ev)) {
+  case QUICHE_H3_EVENT_HEADERS:
+    stream->resp_got_header = TRUE;
+    cb_ctx.cf = cf;
+    cb_ctx.data = data;
+    rc = quiche_h3_event_for_each_header(ev, cb_each_header, &cb_ctx);
+    if(rc) {
+      failf(data, "Error %d in HTTP/3 response header for stream[%"PRId64"]",
+            rc, stream3_id);
+      return CURLE_RECV_ERROR;
+    }
+    CURL_TRC_CF(data, cf, "[%"PRId64"] <- [HEADERS]", stream3_id);
+    break;
+
+  case QUICHE_H3_EVENT_DATA:
+    if(!stream->closed) {
+      result = cf_recv_body(cf, data);
+    }
+    break;
+
+  case QUICHE_H3_EVENT_RESET:
+    CURL_TRC_CF(data, cf, "[%"PRId64"] RESET", stream3_id);
+    stream->closed = TRUE;
+    stream->reset = TRUE;
+    stream->send_closed = TRUE;
+    streamclose(cf->conn, "Reset of stream");
+    break;
+
+  case QUICHE_H3_EVENT_FINISHED:
+    CURL_TRC_CF(data, cf, "[%"PRId64"] CLOSED", stream3_id);
+    if(!stream->resp_hds_complete) {
+      result = write_resp_raw(cf, data, "\r\n", 2);
+      if(result)
+        return result;
+      stream->resp_hds_complete = TRUE;
+    }
+    stream->closed = TRUE;
+    streamclose(cf->conn, "End of stream");
+    break;
+
+  case QUICHE_H3_EVENT_GOAWAY:
+    CURL_TRC_CF(data, cf, "[%"PRId64"] <- [GOAWAY]", stream3_id);
+    break;
+
+  default:
+    CURL_TRC_CF(data, cf, "[%"PRId64"] recv, unhandled event %d",
+                stream3_id, quiche_h3_event_type(ev));
+    break;
+  }
+  return result;
+}
+
+static CURLcode cf_poll_events(struct Curl_cfilter *cf,
+                               struct Curl_easy *data)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  struct Curl_easy *sdata;
+  quiche_h3_event *ev;
+  CURLcode result;
+
+  /* Take in the events and distribute them to the transfers. */
+  while(ctx->h3c) {
+    int64_t stream3_id = quiche_h3_conn_poll(ctx->h3c, ctx->qconn, &ev);
+    if(stream3_id == QUICHE_H3_ERR_DONE) {
+      break;
+    }
+    else if(stream3_id < 0) {
+      CURL_TRC_CF(data, cf, "[%"PRId64"] error poll: %"PRId64,
+                  stream? stream->id : -1, stream3_id);
+      return CURLE_HTTP3;
+    }
+
+    sdata = get_stream_easy(cf, data, stream3_id);
+    if(!sdata) {
+      CURL_TRC_CF(data, cf, "[%"PRId64"] discard event %s for "
+                  "unknown [%"PRId64"]",
+                  stream? stream->id : -1, cf_ev_name(ev), stream3_id);
+    }
+    else {
+      result = h3_process_event(cf, sdata, stream3_id, ev);
+      drain_stream(cf, sdata);
+      if(result) {
+        CURL_TRC_CF(data, cf, "[%"PRId64"] error processing event %s "
+                    "for [%"PRId64"] -> %d",
+                    stream? stream->id : -1, cf_ev_name(ev),
+                    stream3_id, result);
+        if(data == sdata) {
+          /* Only report this error to the caller if it is about the
+           * transfer we were called with. Otherwise we fail a transfer
+           * due to a problem in another one. */
+          quiche_h3_event_free(ev);
+          return result;
+        }
+      }
+      quiche_h3_event_free(ev);
+    }
+  }
+  return CURLE_OK;
+}
+
+struct recv_ctx {
+  struct Curl_cfilter *cf;
+  struct Curl_easy *data;
+  int pkts;
+};
+
+static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
+                         struct sockaddr_storage *remote_addr,
+                         socklen_t remote_addrlen, int ecn,
+                         void *userp)
+{
+  struct recv_ctx *r = userp;
+  struct cf_quiche_ctx *ctx = r->cf->ctx;
+  quiche_recv_info recv_info;
+  ssize_t nread;
+
+  (void)ecn;
+  ++r->pkts;
+
+  recv_info.to = (struct sockaddr *)&ctx->q.local_addr;
+  recv_info.to_len = ctx->q.local_addrlen;
+  recv_info.from = (struct sockaddr *)remote_addr;
+  recv_info.from_len = remote_addrlen;
+
+  nread = quiche_conn_recv(ctx->qconn, (unsigned char *)pkt, pktlen,
+                           &recv_info);
+  if(nread < 0) {
+    if(QUICHE_ERR_DONE == nread) {
+      CURL_TRC_CF(r->data, r->cf, "ingress, quiche is DONE");
+      return CURLE_OK;
+    }
+    else if(QUICHE_ERR_TLS_FAIL == nread) {
+      long verify_ok = SSL_get_verify_result(ctx->tls.ssl);
+      if(verify_ok != X509_V_OK) {
+        failf(r->data, "SSL certificate problem: %s",
+              X509_verify_cert_error_string(verify_ok));
+        return CURLE_PEER_FAILED_VERIFICATION;
+      }
+    }
+    else {
+      failf(r->data, "quiche_conn_recv() == %zd", nread);
+      return CURLE_RECV_ERROR;
+    }
+  }
+  else if((size_t)nread < pktlen) {
+    CURL_TRC_CF(r->data, r->cf, "ingress, quiche only read %zd/%zu bytes",
+                nread, pktlen);
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode cf_process_ingress(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  struct recv_ctx rctx;
+  CURLcode result;
+
+  DEBUGASSERT(ctx->qconn);
+  result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
+  if(result)
+    return result;
+
+  rctx.cf = cf;
+  rctx.data = data;
+  rctx.pkts = 0;
+
+  result = vquic_recv_packets(cf, data, &ctx->q, 1000, recv_pkt, &rctx);
+  if(result)
+    return result;
+
+  if(rctx.pkts > 0) {
+    /* quiche digested ingress packets. It might have opened flow control
+     * windows again. */
+    check_resumes(cf, data);
+  }
+  return cf_poll_events(cf, data);
+}
+
+struct read_ctx {
+  struct Curl_cfilter *cf;
+  struct Curl_easy *data;
+  quiche_send_info send_info;
+};
+
+static ssize_t read_pkt_to_send(void *userp,
+                                unsigned char *buf, size_t buflen,
+                                CURLcode *err)
+{
+  struct read_ctx *x = userp;
+  struct cf_quiche_ctx *ctx = x->cf->ctx;
+  ssize_t nwritten;
+
+  nwritten = quiche_conn_send(ctx->qconn, buf, buflen, &x->send_info);
+  if(nwritten == QUICHE_ERR_DONE) {
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+
+  if(nwritten < 0) {
+    failf(x->data, "quiche_conn_send returned %zd", nwritten);
+    *err = CURLE_SEND_ERROR;
+    return -1;
+  }
+  *err = CURLE_OK;
+  return nwritten;
+}
+
+/*
+ * flush_egress drains the buffers and sends off data.
+ * Calls failf() on errors.
+ */
+static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
+                                struct Curl_easy *data)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  ssize_t nread;
+  CURLcode result;
+  int64_t expiry_ns;
+  int64_t timeout_ns;
+  struct read_ctx readx;
+  size_t pkt_count, gsolen;
+
+  expiry_ns = quiche_conn_timeout_as_nanos(ctx->qconn);
+  if(!expiry_ns) {
+    quiche_conn_on_timeout(ctx->qconn);
+    if(quiche_conn_is_closed(ctx->qconn)) {
+      failf(data, "quiche_conn_on_timeout closed the connection");
+      return CURLE_SEND_ERROR;
+    }
+  }
+
+  result = vquic_flush(cf, data, &ctx->q);
+  if(result) {
+    if(result == CURLE_AGAIN) {
+      Curl_expire(data, 1, EXPIRE_QUIC);
+      return CURLE_OK;
+    }
+    return result;
+  }
+
+  readx.cf = cf;
+  readx.data = data;
+  memset(&readx.send_info, 0, sizeof(readx.send_info));
+  pkt_count = 0;
+  gsolen = quiche_conn_max_send_udp_payload_size(ctx->qconn);
+  for(;;) {
+    /* add the next packet to send, if any, to our buffer */
+    nread = Curl_bufq_sipn(&ctx->q.sendbuf, 0,
+                           read_pkt_to_send, &readx, &result);
+    if(nread < 0) {
+      if(result != CURLE_AGAIN)
+        return result;
+      /* Nothing more to add, flush and leave */
+      result = vquic_send(cf, data, &ctx->q, gsolen);
+      if(result) {
+        if(result == CURLE_AGAIN) {
+          Curl_expire(data, 1, EXPIRE_QUIC);
+          return CURLE_OK;
+        }
+        return result;
+      }
+      goto out;
+    }
+
+    ++pkt_count;
+    if((size_t)nread < gsolen || pkt_count >= MAX_PKT_BURST) {
+      result = vquic_send(cf, data, &ctx->q, gsolen);
+      if(result) {
+        if(result == CURLE_AGAIN) {
+          Curl_expire(data, 1, EXPIRE_QUIC);
+          return CURLE_OK;
+        }
+        goto out;
+      }
+      pkt_count = 0;
+    }
+  }
+
+out:
+  timeout_ns = quiche_conn_timeout_as_nanos(ctx->qconn);
+  if(timeout_ns % 1000000)
+    timeout_ns += 1000000;
+    /* expire resolution is milliseconds */
+  Curl_expire(data, (timeout_ns / 1000000), EXPIRE_QUIC);
+  return result;
+}
+
+static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  CURLcode *err)
+{
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  ssize_t nread = -1;
+
+  DEBUGASSERT(stream);
+  if(stream->reset) {
+    failf(data,
+          "HTTP/3 stream %" PRId64 " reset by server", stream->id);
+    *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv, was reset -> %d",
+                stream->id, *err);
+  }
+  else if(!stream->resp_got_header) {
+    failf(data,
+          "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting"
+          " all response header fields, treated as error",
+          stream->id);
+    /* *err = CURLE_PARTIAL_FILE; */
+    *err = CURLE_HTTP3;
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv, closed incomplete"
+                " -> %d", stream->id, *err);
+  }
+  else {
+    *err = CURLE_OK;
+    nread = 0;
+  }
+  return nread;
+}
+
+static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              char *buf, size_t len, CURLcode *err)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  ssize_t nread = -1;
+  CURLcode result;
+
+  vquic_ctx_update_time(&ctx->q);
+
+  if(!stream) {
+    *err = CURLE_RECV_ERROR;
+    return -1;
+  }
+
+  if(!Curl_bufq_is_empty(&stream->recvbuf)) {
+    nread = Curl_bufq_read(&stream->recvbuf,
+                           (unsigned char *)buf, len, err);
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
+                "-> %zd, %d", stream->id, len, nread, *err);
+    if(nread < 0)
+      goto out;
+  }
+
+  if(cf_process_ingress(cf, data)) {
+    CURL_TRC_CF(data, cf, "cf_recv, error on ingress");
+    *err = CURLE_RECV_ERROR;
+    nread = -1;
+    goto out;
+  }
+
+  /* recvbuf had nothing before, maybe after progressing ingress? */
+  if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
+    nread = Curl_bufq_read(&stream->recvbuf,
+                           (unsigned char *)buf, len, err);
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
+                "-> %zd, %d", stream->id, len, nread, *err);
+    if(nread < 0)
+      goto out;
+  }
+
+  if(nread > 0) {
+    if(stream->closed)
+      drain_stream(cf, data);
+  }
+  else {
+    if(stream->closed) {
+      nread = recv_closed_stream(cf, data, err);
+      goto out;
+    }
+    else if(quiche_conn_is_draining(ctx->qconn)) {
+      failf(data, "QUIC connection is draining");
+      *err = CURLE_HTTP3;
+      nread = -1;
+      goto out;
+    }
+    *err = CURLE_AGAIN;
+    nread = -1;
+  }
+
+out:
+  result = cf_flush_egress(cf, data);
+  if(result) {
+    CURL_TRC_CF(data, cf, "cf_recv, flush egress failed");
+    *err = result;
+    nread = -1;
+  }
+  if(nread > 0)
+    ctx->data_recvd += nread;
+  CURL_TRC_CF(data, cf, "[%"PRId64"] cf_recv(total=%"
+              CURL_FORMAT_CURL_OFF_T ") -> %zd, %d",
+              stream->id, ctx->data_recvd, nread, *err);
+  return nread;
+}
+
+/* Index where :authority header field will appear in request header
+   field list. */
+#define AUTHORITY_DST_IDX 3
+
+static ssize_t h3_open_stream(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              const void *buf, size_t len,
+                              CURLcode *err)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  size_t nheader, i;
+  int64_t stream3_id;
+  struct dynhds h2_headers;
+  quiche_h3_header *nva = NULL;
+  ssize_t nwritten;
+
+  if(!stream) {
+    *err = h3_data_setup(cf, data);
+    if(*err) {
+      return -1;
+    }
+    stream = H3_STREAM_CTX(data);
+    DEBUGASSERT(stream);
+  }
+
+  Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
+
+  DEBUGASSERT(stream);
+  nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
+  if(nwritten < 0)
+    goto out;
+  if(!stream->h1.done) {
+    /* need more data */
+    goto out;
+  }
+  DEBUGASSERT(stream->h1.req);
+
+  *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
+  if(*err) {
+    nwritten = -1;
+    goto out;
+  }
+  /* no longer needed */
+  Curl_h1_req_parse_free(&stream->h1);
+
+  nheader = Curl_dynhds_count(&h2_headers);
+  nva = malloc(sizeof(quiche_h3_header) * nheader);
+  if(!nva) {
+    *err = CURLE_OUT_OF_MEMORY;
+    nwritten = -1;
+    goto out;
+  }
+
+  for(i = 0; i < nheader; ++i) {
+    struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i);
+    nva[i].name = (unsigned char *)e->name;
+    nva[i].name_len = e->namelen;
+    nva[i].value = (unsigned char *)e->value;
+    nva[i].value_len = e->valuelen;
+  }
+
+  switch(data->state.httpreq) {
+  case HTTPREQ_POST:
+  case HTTPREQ_POST_FORM:
+  case HTTPREQ_POST_MIME:
+  case HTTPREQ_PUT:
+    if(data->state.infilesize != -1)
+      stream->upload_left = data->state.infilesize;
+    else
+      /* data sending without specifying the data amount up front */
+      stream->upload_left = -1; /* unknown */
+    break;
+  default:
+    stream->upload_left = 0; /* no request body */
+    break;
+  }
+
+  if(stream->upload_left == 0)
+    stream->send_closed = TRUE;
+
+  stream3_id = quiche_h3_send_request(ctx->h3c, ctx->qconn, nva, nheader,
+                                      stream->send_closed);
+  if(stream3_id < 0) {
+    if(QUICHE_H3_ERR_STREAM_BLOCKED == stream3_id) {
+      /* quiche seems to report this error if the connection window is
+       * exhausted. Which happens frequently and intermittent. */
+      CURL_TRC_CF(data, cf, "[%"PRId64"] blocked", stream->id);
+      stream->quic_flow_blocked = TRUE;
+      *err = CURLE_AGAIN;
+      nwritten = -1;
+      goto out;
+    }
+    else {
+      CURL_TRC_CF(data, cf, "send_request(%s) -> %" PRId64,
+                  data->state.url, stream3_id);
+    }
+    *err = CURLE_SEND_ERROR;
+    nwritten = -1;
+    goto out;
+  }
+
+  DEBUGASSERT(stream->id == -1);
+  *err = CURLE_OK;
+  stream->id = stream3_id;
+  stream->closed = FALSE;
+  stream->reset = FALSE;
+
+  if(Curl_trc_is_verbose(data)) {
+    infof(data, "[HTTP/3] [%" PRId64 "] OPENED stream for %s",
+          stream->id, data->state.url);
+    for(i = 0; i < nheader; ++i) {
+      infof(data, "[HTTP/3] [%" PRId64 "] [%.*s: %.*s]", stream->id,
+            (int)nva[i].name_len, nva[i].name,
+            (int)nva[i].value_len, nva[i].value);
+    }
+  }
+
+out:
+  free(nva);
+  Curl_dynhds_free(&h2_headers);
+  return nwritten;
+}
+
+static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              const void *buf, size_t len, CURLcode *err)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+  CURLcode result;
+  ssize_t nwritten;
+
+  vquic_ctx_update_time(&ctx->q);
+
+  *err = cf_process_ingress(cf, data);
+  if(*err) {
+    nwritten = -1;
+    goto out;
+  }
+
+  if(!stream || stream->id < 0) {
+    nwritten = h3_open_stream(cf, data, buf, len, err);
+    if(nwritten < 0)
+      goto out;
+    stream = H3_STREAM_CTX(data);
+  }
+  else if(stream->closed) {
+    if(stream->resp_hds_complete) {
+      /* sending request body on a stream that has been closed by the
+       * server. If the server has send us a final response, we should
+       * silently discard the send data.
+       * This happens for example on redirects where the server, instead
+       * of reading the full request body just closed the stream after
+       * sending the 30x response.
+       * This is sort of a race: had the transfer loop called recv first,
+       * it would see the response and stop/discard sending on its own- */
+      CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
+                  "on closed stream with response", stream->id);
+      *err = CURLE_OK;
+      nwritten = (ssize_t)len;
+      goto out;
+    }
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+                "-> stream closed", stream->id, len);
+    *err = CURLE_HTTP3;
+    nwritten = -1;
+    goto out;
+  }
+  else {
+    bool eof = (stream->upload_left >= 0 &&
+                (curl_off_t)len >= stream->upload_left);
+    nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id,
+                                   (uint8_t *)buf, len, eof);
+    if(nwritten == QUICHE_H3_ERR_DONE || (nwritten == 0 && len > 0)) {
+      /* TODO: we seem to be blocked on flow control and should HOLD
+       * sending. But when do we open again? */
+      if(!quiche_conn_stream_writable(ctx->qconn, stream->id, len)) {
+        CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+                    "-> window exhausted", stream->id, len);
+        stream->quic_flow_blocked = TRUE;
+      }
+      *err = CURLE_AGAIN;
+      nwritten = -1;
+      goto out;
+    }
+    else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) {
+      CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+                  "-> invalid stream state", stream->id, len);
+      *err = CURLE_HTTP3;
+      nwritten = -1;
+      goto out;
+    }
+    else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) {
+      CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+                  "-> exceeds size", stream->id, len);
+      *err = CURLE_SEND_ERROR;
+      nwritten = -1;
+      goto out;
+    }
+    else if(nwritten < 0) {
+      CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+                  "-> quiche err %zd", stream->id, len, nwritten);
+      *err = CURLE_SEND_ERROR;
+      nwritten = -1;
+      goto out;
+    }
+    else {
+      /* quiche accepted all or at least a part of the buf */
+      if(stream->upload_left > 0) {
+        stream->upload_left = (nwritten < stream->upload_left)?
+                              (stream->upload_left - nwritten) : 0;
+      }
+      if(stream->upload_left == 0)
+        stream->send_closed = TRUE;
+
+      CURL_TRC_CF(data, cf, "[%" PRId64 "] send body(len=%zu, "
+                  "left=%" CURL_FORMAT_CURL_OFF_T ") -> %zd",
+                  stream->id, len, stream->upload_left, nwritten);
+      *err = CURLE_OK;
+    }
+  }
+
+out:
+  result = cf_flush_egress(cf, data);
+  if(result) {
+    *err = result;
+    nwritten = -1;
+  }
+  CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d",
+              stream? stream->id : -1, len, nwritten, *err);
+  return nwritten;
+}
+
+static bool stream_is_writeable(struct Curl_cfilter *cf,
+                                struct Curl_easy *data)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  struct stream_ctx *stream = H3_STREAM_CTX(data);
+
+  return stream && (quiche_conn_stream_writable(ctx->qconn,
+                                                (uint64_t)stream->id, 1) > 0);
+}
+
+static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data,
+                                     struct easy_pollset *ps)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  bool want_recv, want_send;
+
+  if(!ctx->qconn)
+    return;
+
+  Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
+  if(want_recv || want_send) {
+    struct stream_ctx *stream = H3_STREAM_CTX(data);
+    bool c_exhaust, s_exhaust;
+
+    c_exhaust = FALSE; /* Have not found any call in quiche that tells
+                          us if the connection itself is blocked */
+    s_exhaust = want_send && stream && stream->id >= 0 &&
+                (stream->quic_flow_blocked || !stream_is_writeable(cf, data));
+    want_recv = (want_recv || c_exhaust || s_exhaust);
+    want_send = (!s_exhaust && want_send) ||
+                 !Curl_bufq_is_empty(&ctx->q.sendbuf);
+
+    Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send);
+  }
+}
+
+/*
+ * Called from transfer.c:data_pending to know if we should keep looping
+ * to receive more data from the connection.
+ */
+static bool cf_quiche_data_pending(struct Curl_cfilter *cf,
+                                   const struct Curl_easy *data)
+{
+  const struct stream_ctx *stream = H3_STREAM_CTX(data);
+  (void)cf;
+  return stream && !Curl_bufq_is_empty(&stream->recvbuf);
+}
+
+static CURLcode h3_data_pause(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              bool pause)
+{
+  /* TODO: there seems right now no API in quiche to shrink/enlarge
+   * the streams windows. As we do in HTTP/2. */
+  if(!pause) {
+    drain_stream(cf, data);
+    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+  }
+  return CURLE_OK;
+}
+
+static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data,
+                                     int event, int arg1, void *arg2)
+{
+  CURLcode result = CURLE_OK;
+
+  (void)arg1;
+  (void)arg2;
+  switch(event) {
+  case CF_CTRL_DATA_SETUP:
+    break;
+  case CF_CTRL_DATA_PAUSE:
+    result = h3_data_pause(cf, data, (arg1 != 0));
+    break;
+  case CF_CTRL_DATA_DETACH:
+    h3_data_done(cf, data);
+    break;
+  case CF_CTRL_DATA_DONE:
+    h3_data_done(cf, data);
+    break;
+  case CF_CTRL_DATA_DONE_SEND: {
+    struct stream_ctx *stream = H3_STREAM_CTX(data);
+    if(stream && !stream->send_closed) {
+      unsigned char body[1];
+      ssize_t sent;
+
+      stream->send_closed = TRUE;
+      stream->upload_left = 0;
+      body[0] = 'X';
+      sent = cf_quiche_send(cf, data, body, 0, &result);
+      CURL_TRC_CF(data, cf, "[%"PRId64"] DONE_SEND -> %zd, %d",
+                  stream->id, sent, result);
+    }
+    break;
+  }
+  case CF_CTRL_DATA_IDLE: {
+    struct stream_ctx *stream = H3_STREAM_CTX(data);
+    if(stream && !stream->closed) {
+      result = cf_flush_egress(cf, data);
+      if(result)
+        CURL_TRC_CF(data, cf, "data idle, flush egress -> %d", result);
+    }
+    break;
+  }
+  default:
+    break;
+  }
+  return result;
+}
+
+static CURLcode cf_connect_start(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  int rv;
+  CURLcode result;
+  const struct Curl_sockaddr_ex *sockaddr;
+
+  DEBUGASSERT(ctx->q.sockfd != CURL_SOCKET_BAD);
+
+#ifdef DEBUG_QUICHE
+  /* initialize debug log callback only once */
+  static int debug_log_init = 0;
+  if(!debug_log_init) {
+    quiche_enable_debug_logging(quiche_debug_log, NULL);
+    debug_log_init = 1;
+  }
+#endif
+  ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
+  Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
+                  H3_STREAM_POOL_SPARES);
+  ctx->data_recvd = 0;
+
+  result = vquic_ctx_init(&ctx->q);
+  if(result)
+    return result;
+
+  result = Curl_ssl_peer_init(&ctx->peer, cf);
+  if(result)
+    return result;
+
+  ctx->cfg = quiche_config_new(QUICHE_PROTOCOL_VERSION);
+  if(!ctx->cfg) {
+    failf(data, "can't create quiche config");
+    return CURLE_FAILED_INIT;
+  }
+  quiche_config_enable_pacing(ctx->cfg, false);
+  quiche_config_set_max_idle_timeout(ctx->cfg, ctx->max_idle_ms * 1000);
+  quiche_config_set_initial_max_data(ctx->cfg, (1 * 1024 * 1024)
+    /* (QUIC_MAX_STREAMS/2) * H3_STREAM_WINDOW_SIZE */);
+  quiche_config_set_initial_max_streams_bidi(ctx->cfg, QUIC_MAX_STREAMS);
+  quiche_config_set_initial_max_streams_uni(ctx->cfg, QUIC_MAX_STREAMS);
+  quiche_config_set_initial_max_stream_data_bidi_local(ctx->cfg,
+    H3_STREAM_WINDOW_SIZE);
+  quiche_config_set_initial_max_stream_data_bidi_remote(ctx->cfg,
+    H3_STREAM_WINDOW_SIZE);
+  quiche_config_set_initial_max_stream_data_uni(ctx->cfg,
+    H3_STREAM_WINDOW_SIZE);
+  quiche_config_set_disable_active_migration(ctx->cfg, TRUE);
+
+  quiche_config_set_max_connection_window(ctx->cfg,
+    10 * QUIC_MAX_STREAMS * H3_STREAM_WINDOW_SIZE);
+  quiche_config_set_max_stream_window(ctx->cfg, 10 * H3_STREAM_WINDOW_SIZE);
+  quiche_config_set_application_protos(ctx->cfg,
+                                       (uint8_t *)
+                                       QUICHE_H3_APPLICATION_PROTOCOL,
+                                       sizeof(QUICHE_H3_APPLICATION_PROTOCOL)
+                                       - 1);
+
+  result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
+                               QUICHE_H3_APPLICATION_PROTOCOL,
+                               sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1,
+                               NULL, cf);
+  if(result)
+    return result;
+
+  result = Curl_rand(data, ctx->scid, sizeof(ctx->scid));
+  if(result)
+    return result;
+
+  Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL);
+  ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
+  rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr,
+                   &ctx->q.local_addrlen);
+  if(rv == -1)
+    return CURLE_QUIC_CONNECT_ERROR;
+
+  ctx->qconn = quiche_conn_new_with_tls((const uint8_t *)ctx->scid,
+                                      sizeof(ctx->scid), NULL, 0,
+                                      (struct sockaddr *)&ctx->q.local_addr,
+                                      ctx->q.local_addrlen,
+                                      &sockaddr->sa_addr, sockaddr->addrlen,
+                                      ctx->cfg, ctx->tls.ssl, false);
+  if(!ctx->qconn) {
+    failf(data, "can't create quiche connection");
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Known to not work on Windows */
+#if !defined(_WIN32) && defined(HAVE_QUICHE_CONN_SET_QLOG_FD)
+  {
+    int qfd;
+    (void)Curl_qlogdir(data, ctx->scid, sizeof(ctx->scid), &qfd);
+    if(qfd != -1)
+      quiche_conn_set_qlog_fd(ctx->qconn, qfd,
+                              "qlog title", "curl qlog");
+  }
+#endif
+
+  result = cf_flush_egress(cf, data);
+  if(result)
+    return result;
+
+  {
+    unsigned char alpn_protocols[] = QUICHE_H3_APPLICATION_PROTOCOL;
+    unsigned alpn_len, offset = 0;
+
+    /* Replace each ALPN length prefix by a comma. */
+    while(offset < sizeof(alpn_protocols) - 1) {
+      alpn_len = alpn_protocols[offset];
+      alpn_protocols[offset] = ',';
+      offset += 1 + alpn_len;
+    }
+
+    CURL_TRC_CF(data, cf, "Sent QUIC client Initial, ALPN: %s",
+                alpn_protocols + 1);
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode cf_quiche_verify_peer(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+
+  cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+  cf->conn->httpversion = 30;
+  cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+
+  return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
+}
+
+static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  bool blocking, bool *done)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
+
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  /* Connect the UDP filter first */
+  if(!cf->next->connected) {
+    result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+    if(result || !*done)
+      return result;
+  }
+
+  *done = FALSE;
+  vquic_ctx_update_time(&ctx->q);
+
+  if(ctx->reconnect_at.tv_sec &&
+     Curl_timediff(ctx->q.last_op, ctx->reconnect_at) < 0) {
+    /* Not time yet to attempt the next connect */
+    CURL_TRC_CF(data, cf, "waiting for reconnect time");
+    goto out;
+  }
+
+  if(!ctx->qconn) {
+    result = cf_connect_start(cf, data);
+    if(result)
+      goto out;
+    ctx->started_at = ctx->q.last_op;
+    result = cf_flush_egress(cf, data);
+    /* we do not expect to be able to recv anything yet */
+    goto out;
+  }
+
+  result = cf_process_ingress(cf, data);
+  if(result)
+    goto out;
+
+  result = cf_flush_egress(cf, data);
+  if(result)
+    goto out;
+
+  if(quiche_conn_is_established(ctx->qconn)) {
+    ctx->handshake_at = ctx->q.last_op;
+    CURL_TRC_CF(data, cf, "handshake complete after %dms",
+                (int)Curl_timediff(ctx->handshake_at, ctx->started_at));
+    result = cf_quiche_verify_peer(cf, data);
+    if(!result) {
+      CURL_TRC_CF(data, cf, "peer verified");
+      ctx->h3config = quiche_h3_config_new();
+      if(!ctx->h3config) {
+        result = CURLE_OUT_OF_MEMORY;
+        goto out;
+      }
+
+      /* Create a new HTTP/3 connection on the QUIC connection. */
+      ctx->h3c = quiche_h3_conn_new_with_transport(ctx->qconn, ctx->h3config);
+      if(!ctx->h3c) {
+        result = CURLE_OUT_OF_MEMORY;
+        goto out;
+      }
+      cf->connected = TRUE;
+      cf->conn->alpn = CURL_HTTP_VERSION_3;
+      *done = TRUE;
+      connkeep(cf->conn, "HTTP/3 default");
+    }
+  }
+  else if(quiche_conn_is_draining(ctx->qconn)) {
+    /* When a QUIC server instance is shutting down, it may send us a
+     * CONNECTION_CLOSE right away. Our connection then enters the DRAINING
+     * state. The CONNECT may work in the near future again. Indicate
+     * that as a "weird" reply. */
+    result = CURLE_WEIRD_SERVER_REPLY;
+  }
+
+out:
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  if(result && result != CURLE_AGAIN) {
+    struct ip_quadruple ip;
+
+    Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
+    infof(data, "connect to %s port %u failed: %s",
+          ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
+  }
+#endif
+  return result;
+}
+
+static void cf_quiche_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+
+  if(ctx) {
+    if(ctx->qconn) {
+      vquic_ctx_update_time(&ctx->q);
+      (void)quiche_conn_close(ctx->qconn, TRUE, 0, NULL, 0);
+      /* flushing the egress is not a failsafe way to deliver all the
+         outstanding packets, but we also don't want to get stuck here... */
+      (void)cf_flush_egress(cf, data);
+    }
+    cf_quiche_ctx_clear(ctx);
+  }
+}
+
+static void cf_quiche_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+
+  (void)data;
+  cf_quiche_ctx_clear(ctx);
+  free(ctx);
+  cf->ctx = NULL;
+}
+
+static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                int query, int *pres1, void *pres2)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+
+  switch(query) {
+  case CF_QUERY_MAX_CONCURRENT: {
+    uint64_t max_streams = CONN_INUSE(cf->conn);
+    if(!ctx->goaway) {
+      max_streams += quiche_conn_peer_streams_left_bidi(ctx->qconn);
+    }
+    *pres1 = (max_streams > INT_MAX)? INT_MAX : (int)max_streams;
+    CURL_TRC_CF(data, cf, "query: MAX_CONCURRENT -> %d", *pres1);
+    return CURLE_OK;
+  }
+  case CF_QUERY_CONNECT_REPLY_MS:
+    if(ctx->q.got_first_byte) {
+      timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
+      *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
+    }
+    else
+      *pres1 = -1;
+    return CURLE_OK;
+  case CF_QUERY_TIMER_CONNECT: {
+    struct curltime *when = pres2;
+    if(ctx->q.got_first_byte)
+      *when = ctx->q.first_byte_at;
+    return CURLE_OK;
+  }
+  case CF_QUERY_TIMER_APPCONNECT: {
+    struct curltime *when = pres2;
+    if(cf->connected)
+      *when = ctx->handshake_at;
+    return CURLE_OK;
+  }
+  default:
+    break;
+  }
+  return cf->next?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
+}
+
+static bool cf_quiche_conn_is_alive(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    bool *input_pending)
+{
+  struct cf_quiche_ctx *ctx = cf->ctx;
+  bool alive = TRUE;
+
+  *input_pending = FALSE;
+  if(!ctx->qconn)
+    return FALSE;
+
+  /* Both sides of the QUIC connection announce they max idle times in
+   * the transport parameters. Look at the minimum of both and if
+   * we exceed this, regard the connection as dead. The other side
+   * may have completely purged it and will no longer respond
+   * to any packets from us. */
+  {
+    quiche_transport_params qpeerparams;
+    timediff_t idletime;
+    uint64_t idle_ms = ctx->max_idle_ms;
+
+    if(quiche_conn_peer_transport_params(ctx->qconn, &qpeerparams) &&
+       qpeerparams.peer_max_idle_timeout &&
+       qpeerparams.peer_max_idle_timeout < idle_ms)
+      idle_ms = qpeerparams.peer_max_idle_timeout;
+    idletime = Curl_timediff(Curl_now(), cf->conn->lastused);
+    if(idletime > 0 && (uint64_t)idletime > idle_ms)
+      return FALSE;
+  }
+
+  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
+    return FALSE;
+
+  if(*input_pending) {
+    /* This happens before we've sent off a request and the connection is
+       not in use by any other transfer, there shouldn't be any data here,
+       only "protocol frames" */
+    *input_pending = FALSE;
+    if(cf_process_ingress(cf, data))
+      alive = FALSE;
+    else {
+      alive = TRUE;
+    }
+  }
+
+  return alive;
+}
+
+struct Curl_cftype Curl_cft_http3 = {
+  "HTTP/3",
+  CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
+  0,
+  cf_quiche_destroy,
+  cf_quiche_connect,
+  cf_quiche_close,
+  Curl_cf_def_get_host,
+  cf_quiche_adjust_pollset,
+  cf_quiche_data_pending,
+  cf_quiche_send,
+  cf_quiche_recv,
+  cf_quiche_data_event,
+  cf_quiche_conn_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  cf_quiche_query,
+};
+
+CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
+                               struct Curl_easy *data,
+                               struct connectdata *conn,
+                               const struct Curl_addrinfo *ai)
+{
+  struct cf_quiche_ctx *ctx = NULL;
+  struct Curl_cfilter *cf = NULL, *udp_cf = NULL;
+  CURLcode result;
+
+  (void)data;
+  (void)conn;
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+
+  result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
+  if(result)
+    goto out;
+
+  result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC);
+  if(result)
+    goto out;
+
+  udp_cf->conn = cf->conn;
+  udp_cf->sockindex = cf->sockindex;
+  cf->next = udp_cf;
+
+out:
+  *pcf = (!result)? cf : NULL;
+  if(result) {
+    if(udp_cf)
+      Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
+    Curl_safefree(cf);
+    Curl_safefree(ctx);
+  }
+
+  return result;
+}
+
+bool Curl_conn_is_quiche(const struct Curl_easy *data,
+                         const struct connectdata *conn,
+                         int sockindex)
+{
+  struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+
+  (void)data;
+  for(; cf; cf = cf->next) {
+    if(cf->cft == &Curl_cft_http3)
+      return TRUE;
+    if(cf->cft->flags & CF_TYPE_IP_CONNECT)
+      return FALSE;
+  }
+  return FALSE;
+}
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/vquic/curl_quiche.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vquic/curl_quiche.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vquic/curl_quiche.h	(revision 104083)
@@ -0,0 +1,50 @@
+#ifndef HEADER_CURL_VQUIC_CURL_QUICHE_H
+#define HEADER_CURL_VQUIC_CURL_QUICHE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_QUICHE
+
+#include <quiche.h>
+#include <openssl/ssl.h>
+
+struct Curl_cfilter;
+struct Curl_easy;
+
+void Curl_quiche_ver(char *p, size_t len);
+
+CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
+                               struct Curl_easy *data,
+                               struct connectdata *conn,
+                               const struct Curl_addrinfo *ai);
+
+bool Curl_conn_is_quiche(const struct Curl_easy *data,
+                         const struct connectdata *conn,
+                         int sockindex);
+
+#endif
+
+#endif /* HEADER_CURL_VQUIC_CURL_QUICHE_H */
Index: trunk/src/libs/curl-8.7.1/lib/vquic/vquic.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vquic/vquic.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vquic/vquic.c	(revision 104083)
@@ -0,0 +1,677 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* WIP, experimental: use recvmmsg() on linux
+ * we have no configure check, yet
+ * and also it is only available for _GNU_SOURCE, which
+ * we do not use otherwise.
+#define HAVE_SENDMMSG
+ */
+#if defined(HAVE_SENDMMSG)
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#undef _GNU_SOURCE
+#endif
+
+#include "curl_setup.h"
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include "urldata.h"
+#include "bufq.h"
+#include "dynbuf.h"
+#include "cfilters.h"
+#include "curl_trc.h"
+#include "curl_msh3.h"
+#include "curl_ngtcp2.h"
+#include "curl_osslq.h"
+#include "curl_quiche.h"
+#include "rand.h"
+#include "vquic.h"
+#include "vquic_int.h"
+#include "strerror.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+#ifdef ENABLE_QUIC
+
+#ifdef O_BINARY
+#define QLOGMODE O_WRONLY|O_CREAT|O_BINARY
+#else
+#define QLOGMODE O_WRONLY|O_CREAT
+#endif
+
+#define NW_CHUNK_SIZE     (64 * 1024)
+#define NW_SEND_CHUNKS    2
+
+
+void Curl_quic_ver(char *p, size_t len)
+{
+#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
+  Curl_ngtcp2_ver(p, len);
+#elif defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)
+  Curl_osslq_ver(p, len);
+#elif defined(USE_QUICHE)
+  Curl_quiche_ver(p, len);
+#elif defined(USE_MSH3)
+  Curl_msh3_ver(p, len);
+#endif
+}
+
+CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx)
+{
+  Curl_bufq_init2(&qctx->sendbuf, NW_CHUNK_SIZE, NW_SEND_CHUNKS,
+                  BUFQ_OPT_SOFT_LIMIT);
+#if defined(__linux__) && defined(UDP_SEGMENT) && defined(HAVE_SENDMSG)
+  qctx->no_gso = FALSE;
+#else
+  qctx->no_gso = TRUE;
+#endif
+#ifdef DEBUGBUILD
+  {
+    char *p = getenv("CURL_DBG_QUIC_WBLOCK");
+    if(p) {
+      long l = strtol(p, NULL, 10);
+      if(l >= 0 && l <= 100)
+        qctx->wblock_percent = (int)l;
+    }
+  }
+#endif
+  vquic_ctx_update_time(qctx);
+
+  return CURLE_OK;
+}
+
+void vquic_ctx_free(struct cf_quic_ctx *qctx)
+{
+  Curl_bufq_free(&qctx->sendbuf);
+}
+
+void vquic_ctx_update_time(struct cf_quic_ctx *qctx)
+{
+  qctx->last_op = Curl_now();
+}
+
+static CURLcode send_packet_no_gso(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   struct cf_quic_ctx *qctx,
+                                   const uint8_t *pkt, size_t pktlen,
+                                   size_t gsolen, size_t *psent);
+
+static CURLcode do_sendmsg(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           struct cf_quic_ctx *qctx,
+                           const uint8_t *pkt, size_t pktlen, size_t gsolen,
+                           size_t *psent)
+{
+#ifdef HAVE_SENDMSG
+  struct iovec msg_iov;
+  struct msghdr msg = {0};
+  ssize_t sent;
+#if defined(__linux__) && defined(UDP_SEGMENT)
+  uint8_t msg_ctrl[32];
+  struct cmsghdr *cm;
+#endif
+
+  *psent = 0;
+  msg_iov.iov_base = (uint8_t *)pkt;
+  msg_iov.iov_len = pktlen;
+  msg.msg_iov = &msg_iov;
+  msg.msg_iovlen = 1;
+
+#if defined(__linux__) && defined(UDP_SEGMENT)
+  if(pktlen > gsolen) {
+    /* Only set this, when we need it. macOS, for example,
+     * does not seem to like a msg_control of length 0. */
+    msg.msg_control = msg_ctrl;
+    assert(sizeof(msg_ctrl) >= CMSG_SPACE(sizeof(uint16_t)));
+    msg.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
+    cm = CMSG_FIRSTHDR(&msg);
+    cm->cmsg_level = SOL_UDP;
+    cm->cmsg_type = UDP_SEGMENT;
+    cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
+    *(uint16_t *)(void *)CMSG_DATA(cm) = gsolen & 0xffff;
+  }
+#endif
+
+
+  while((sent = sendmsg(qctx->sockfd, &msg, 0)) == -1 && SOCKERRNO == EINTR)
+    ;
+
+  if(sent == -1) {
+    switch(SOCKERRNO) {
+    case EAGAIN:
+#if EAGAIN != EWOULDBLOCK
+    case EWOULDBLOCK:
+#endif
+      return CURLE_AGAIN;
+    case EMSGSIZE:
+      /* UDP datagram is too large; caused by PMTUD. Just let it be lost. */
+      break;
+    case EIO:
+      if(pktlen > gsolen) {
+        /* GSO failure */
+        failf(data, "sendmsg() returned %zd (errno %d); disable GSO", sent,
+              SOCKERRNO);
+        qctx->no_gso = TRUE;
+        return send_packet_no_gso(cf, data, qctx, pkt, pktlen, gsolen, psent);
+      }
+      FALLTHROUGH();
+    default:
+      failf(data, "sendmsg() returned %zd (errno %d)", sent, SOCKERRNO);
+      return CURLE_SEND_ERROR;
+    }
+  }
+  else {
+    assert(pktlen == (size_t)sent);
+  }
+#else
+  ssize_t sent;
+  (void)gsolen;
+
+  *psent = 0;
+
+  while((sent = send(qctx->sockfd,
+                     (const char *)pkt, (SEND_TYPE_ARG3)pktlen, 0)) == -1 &&
+        SOCKERRNO == EINTR)
+    ;
+
+  if(sent == -1) {
+    if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
+      return CURLE_AGAIN;
+    }
+    else {
+      failf(data, "send() returned %zd (errno %d)", sent, SOCKERRNO);
+      if(SOCKERRNO != EMSGSIZE) {
+        return CURLE_SEND_ERROR;
+      }
+      /* UDP datagram is too large; caused by PMTUD. Just let it be
+         lost. */
+    }
+  }
+#endif
+  (void)cf;
+  *psent = pktlen;
+
+  return CURLE_OK;
+}
+
+static CURLcode send_packet_no_gso(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   struct cf_quic_ctx *qctx,
+                                   const uint8_t *pkt, size_t pktlen,
+                                   size_t gsolen, size_t *psent)
+{
+  const uint8_t *p, *end = pkt + pktlen;
+  size_t sent;
+
+  *psent = 0;
+
+  for(p = pkt; p < end; p += gsolen) {
+    size_t len = CURLMIN(gsolen, (size_t)(end - p));
+    CURLcode curlcode = do_sendmsg(cf, data, qctx, p, len, len, &sent);
+    if(curlcode != CURLE_OK) {
+      return curlcode;
+    }
+    *psent += sent;
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode vquic_send_packets(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   struct cf_quic_ctx *qctx,
+                                   const uint8_t *pkt, size_t pktlen,
+                                   size_t gsolen, size_t *psent)
+{
+  CURLcode result;
+#ifdef DEBUGBUILD
+  /* simulate network blocking/partial writes */
+  if(qctx->wblock_percent > 0) {
+    unsigned char c;
+    Curl_rand(data, &c, 1);
+    if(c >= ((100-qctx->wblock_percent)*256/100)) {
+      CURL_TRC_CF(data, cf, "vquic_flush() simulate EWOULDBLOCK");
+      return CURLE_AGAIN;
+    }
+  }
+#endif
+  if(qctx->no_gso && pktlen > gsolen) {
+    result = send_packet_no_gso(cf, data, qctx, pkt, pktlen, gsolen, psent);
+  }
+  else {
+    result = do_sendmsg(cf, data, qctx, pkt, pktlen, gsolen, psent);
+  }
+  if(!result)
+    qctx->last_io = qctx->last_op;
+  return result;
+}
+
+CURLcode vquic_flush(struct Curl_cfilter *cf, struct Curl_easy *data,
+                     struct cf_quic_ctx *qctx)
+{
+  const unsigned char *buf;
+  size_t blen, sent;
+  CURLcode result;
+  size_t gsolen;
+
+  while(Curl_bufq_peek(&qctx->sendbuf, &buf, &blen)) {
+    gsolen = qctx->gsolen;
+    if(qctx->split_len) {
+      gsolen = qctx->split_gsolen;
+      if(blen > qctx->split_len)
+        blen = qctx->split_len;
+    }
+
+    result = vquic_send_packets(cf, data, qctx, buf, blen, gsolen, &sent);
+    CURL_TRC_CF(data, cf, "vquic_send(len=%zu, gso=%zu) -> %d, sent=%zu",
+                blen, gsolen, result, sent);
+    if(result) {
+      if(result == CURLE_AGAIN) {
+        Curl_bufq_skip(&qctx->sendbuf, sent);
+        if(qctx->split_len)
+          qctx->split_len -= sent;
+      }
+      return result;
+    }
+    Curl_bufq_skip(&qctx->sendbuf, sent);
+    if(qctx->split_len)
+      qctx->split_len -= sent;
+  }
+  return CURLE_OK;
+}
+
+CURLcode vquic_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                        struct cf_quic_ctx *qctx, size_t gsolen)
+{
+  qctx->gsolen = gsolen;
+  return vquic_flush(cf, data, qctx);
+}
+
+CURLcode vquic_send_tail_split(struct Curl_cfilter *cf, struct Curl_easy *data,
+                               struct cf_quic_ctx *qctx, size_t gsolen,
+                               size_t tail_len, size_t tail_gsolen)
+{
+  DEBUGASSERT(Curl_bufq_len(&qctx->sendbuf) > tail_len);
+  qctx->split_len = Curl_bufq_len(&qctx->sendbuf) - tail_len;
+  qctx->split_gsolen = gsolen;
+  qctx->gsolen = tail_gsolen;
+  CURL_TRC_CF(data, cf, "vquic_send_tail_split: [%zu gso=%zu][%zu gso=%zu]",
+              qctx->split_len, qctx->split_gsolen,
+              tail_len, qctx->gsolen);
+  return vquic_flush(cf, data, qctx);
+}
+
+#ifdef HAVE_SENDMMSG
+static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 struct cf_quic_ctx *qctx,
+                                 size_t max_pkts,
+                                 vquic_recv_pkt_cb *recv_cb, void *userp)
+{
+#define MMSG_NUM  64
+  struct iovec msg_iov[MMSG_NUM];
+  struct mmsghdr mmsg[MMSG_NUM];
+  uint8_t bufs[MMSG_NUM][2*1024];
+  struct sockaddr_storage remote_addr[MMSG_NUM];
+  size_t total_nread, pkts;
+  int mcount, i, n;
+  char errstr[STRERROR_LEN];
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(max_pkts > 0);
+  pkts = 0;
+  total_nread = 0;
+  while(pkts < max_pkts) {
+    n = (int)CURLMIN(MMSG_NUM, max_pkts);
+    memset(&mmsg, 0, sizeof(mmsg));
+    for(i = 0; i < n; ++i) {
+      msg_iov[i].iov_base = bufs[i];
+      msg_iov[i].iov_len = (int)sizeof(bufs[i]);
+      mmsg[i].msg_hdr.msg_iov = &msg_iov[i];
+      mmsg[i].msg_hdr.msg_iovlen = 1;
+      mmsg[i].msg_hdr.msg_name = &remote_addr[i];
+      mmsg[i].msg_hdr.msg_namelen = sizeof(remote_addr[i]);
+    }
+
+    while((mcount = recvmmsg(qctx->sockfd, mmsg, n, 0, NULL)) == -1 &&
+          SOCKERRNO == EINTR)
+      ;
+    if(mcount == -1) {
+      if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
+        CURL_TRC_CF(data, cf, "ingress, recvmmsg -> EAGAIN");
+        goto out;
+      }
+      if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
+        struct ip_quadruple ip;
+        Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
+        failf(data, "QUIC: connection to %s port %u refused",
+              ip.remote_ip, ip.remote_port);
+        result = CURLE_COULDNT_CONNECT;
+        goto out;
+      }
+      Curl_strerror(SOCKERRNO, errstr, sizeof(errstr));
+      failf(data, "QUIC: recvmsg() unexpectedly returned %d (errno=%d; %s)",
+                  mcount, SOCKERRNO, errstr);
+      result = CURLE_RECV_ERROR;
+      goto out;
+    }
+
+    CURL_TRC_CF(data, cf, "recvmmsg() -> %d packets", mcount);
+    pkts += mcount;
+    for(i = 0; i < mcount; ++i) {
+      total_nread += mmsg[i].msg_len;
+      result = recv_cb(bufs[i], mmsg[i].msg_len,
+                       mmsg[i].msg_hdr.msg_name, mmsg[i].msg_hdr.msg_namelen,
+                       0, userp);
+      if(result)
+        goto out;
+    }
+  }
+
+out:
+  if(total_nread || result)
+    CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d",
+                pkts, total_nread, result);
+  return result;
+}
+
+#elif defined(HAVE_SENDMSG)
+static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                struct cf_quic_ctx *qctx,
+                                size_t max_pkts,
+                                vquic_recv_pkt_cb *recv_cb, void *userp)
+{
+  struct iovec msg_iov;
+  struct msghdr msg;
+  uint8_t buf[64*1024];
+  struct sockaddr_storage remote_addr;
+  size_t total_nread, pkts;
+  ssize_t nread;
+  char errstr[STRERROR_LEN];
+  CURLcode result = CURLE_OK;
+
+  msg_iov.iov_base = buf;
+  msg_iov.iov_len = (int)sizeof(buf);
+
+  memset(&msg, 0, sizeof(msg));
+  msg.msg_iov = &msg_iov;
+  msg.msg_iovlen = 1;
+
+  DEBUGASSERT(max_pkts > 0);
+  for(pkts = 0, total_nread = 0; pkts < max_pkts;) {
+    msg.msg_name = &remote_addr;
+    msg.msg_namelen = sizeof(remote_addr);
+    while((nread = recvmsg(qctx->sockfd, &msg, 0)) == -1 &&
+          SOCKERRNO == EINTR)
+      ;
+    if(nread == -1) {
+      if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
+        goto out;
+      }
+      if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
+        struct ip_quadruple ip;
+        Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
+        failf(data, "QUIC: connection to %s port %u refused",
+              ip.remote_ip, ip.remote_port);
+        result = CURLE_COULDNT_CONNECT;
+        goto out;
+      }
+      Curl_strerror(SOCKERRNO, errstr, sizeof(errstr));
+      failf(data, "QUIC: recvmsg() unexpectedly returned %zd (errno=%d; %s)",
+                  nread, SOCKERRNO, errstr);
+      result = CURLE_RECV_ERROR;
+      goto out;
+    }
+
+    ++pkts;
+    total_nread += (size_t)nread;
+    result = recv_cb(buf, (size_t)nread, msg.msg_name, msg.msg_namelen,
+                     0, userp);
+    if(result)
+      goto out;
+  }
+
+out:
+  if(total_nread || result)
+    CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d",
+                pkts, total_nread, result);
+  return result;
+}
+
+#else /* HAVE_SENDMMSG || HAVE_SENDMSG */
+static CURLcode recvfrom_packets(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 struct cf_quic_ctx *qctx,
+                                 size_t max_pkts,
+                                 vquic_recv_pkt_cb *recv_cb, void *userp)
+{
+  uint8_t buf[64*1024];
+  int bufsize = (int)sizeof(buf);
+  struct sockaddr_storage remote_addr;
+  socklen_t remote_addrlen = sizeof(remote_addr);
+  size_t total_nread, pkts;
+  ssize_t nread;
+  char errstr[STRERROR_LEN];
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(max_pkts > 0);
+  for(pkts = 0, total_nread = 0; pkts < max_pkts;) {
+    while((nread = recvfrom(qctx->sockfd, (char *)buf, bufsize, 0,
+                            (struct sockaddr *)&remote_addr,
+                            &remote_addrlen)) == -1 &&
+          SOCKERRNO == EINTR)
+      ;
+    if(nread == -1) {
+      if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
+        CURL_TRC_CF(data, cf, "ingress, recvfrom -> EAGAIN");
+        goto out;
+      }
+      if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
+        struct ip_quadruple ip;
+        Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
+        failf(data, "QUIC: connection to %s port %u refused",
+              ip.remote_ip, ip.remote_port);
+        result = CURLE_COULDNT_CONNECT;
+        goto out;
+      }
+      Curl_strerror(SOCKERRNO, errstr, sizeof(errstr));
+      failf(data, "QUIC: recvfrom() unexpectedly returned %zd (errno=%d; %s)",
+                  nread, SOCKERRNO, errstr);
+      result = CURLE_RECV_ERROR;
+      goto out;
+    }
+
+    ++pkts;
+    total_nread += (size_t)nread;
+    result = recv_cb(buf, (size_t)nread, &remote_addr, remote_addrlen,
+                     0, userp);
+    if(result)
+      goto out;
+  }
+
+out:
+  if(total_nread || result)
+    CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d",
+                pkts, total_nread, result);
+  return result;
+}
+#endif /* !HAVE_SENDMMSG && !HAVE_SENDMSG */
+
+CURLcode vquic_recv_packets(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            struct cf_quic_ctx *qctx,
+                            size_t max_pkts,
+                            vquic_recv_pkt_cb *recv_cb, void *userp)
+{
+  CURLcode result;
+#if defined(HAVE_SENDMMSG)
+  result = recvmmsg_packets(cf, data, qctx, max_pkts, recv_cb, userp);
+#elif defined(HAVE_SENDMSG)
+  result = recvmsg_packets(cf, data, qctx, max_pkts, recv_cb, userp);
+#else
+  result = recvfrom_packets(cf, data, qctx, max_pkts, recv_cb, userp);
+#endif
+  if(!result) {
+    if(!qctx->got_first_byte) {
+      qctx->got_first_byte = TRUE;
+      qctx->first_byte_at = qctx->last_op;
+    }
+    qctx->last_io = qctx->last_op;
+  }
+  return result;
+}
+
+/*
+ * If the QLOGDIR environment variable is set, open and return a file
+ * descriptor to write the log to.
+ *
+ * This function returns error if something failed outside of failing to
+ * create the file. Open file success is deemed by seeing if the returned fd
+ * is != -1.
+ */
+CURLcode Curl_qlogdir(struct Curl_easy *data,
+                      unsigned char *scid,
+                      size_t scidlen,
+                      int *qlogfdp)
+{
+  const char *qlog_dir = getenv("QLOGDIR");
+  *qlogfdp = -1;
+  if(qlog_dir) {
+    struct dynbuf fname;
+    CURLcode result;
+    unsigned int i;
+    Curl_dyn_init(&fname, DYN_QLOG_NAME);
+    result = Curl_dyn_add(&fname, qlog_dir);
+    if(!result)
+      result = Curl_dyn_add(&fname, "/");
+    for(i = 0; (i < scidlen) && !result; i++) {
+      char hex[3];
+      msnprintf(hex, 3, "%02x", scid[i]);
+      result = Curl_dyn_add(&fname, hex);
+    }
+    if(!result)
+      result = Curl_dyn_add(&fname, ".sqlog");
+
+    if(!result) {
+      int qlogfd = open(Curl_dyn_ptr(&fname), QLOGMODE,
+                        data->set.new_file_perms);
+      if(qlogfd != -1)
+        *qlogfdp = qlogfd;
+    }
+    Curl_dyn_free(&fname);
+    if(result)
+      return result;
+  }
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf,
+                             struct Curl_easy *data,
+                             struct connectdata *conn,
+                             const struct Curl_addrinfo *ai,
+                             int transport)
+{
+  (void)transport;
+  DEBUGASSERT(transport == TRNSPRT_QUIC);
+#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
+  return Curl_cf_ngtcp2_create(pcf, data, conn, ai);
+#elif defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)
+  return Curl_cf_osslq_create(pcf, data, conn, ai);
+#elif defined(USE_QUICHE)
+  return Curl_cf_quiche_create(pcf, data, conn, ai);
+#elif defined(USE_MSH3)
+  return Curl_cf_msh3_create(pcf, data, conn, ai);
+#else
+  *pcf = NULL;
+  (void)data;
+  (void)conn;
+  (void)ai;
+  return CURLE_NOT_BUILT_IN;
+#endif
+}
+
+bool Curl_conn_is_http3(const struct Curl_easy *data,
+                        const struct connectdata *conn,
+                        int sockindex)
+{
+#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
+  return Curl_conn_is_ngtcp2(data, conn, sockindex);
+#elif defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)
+  return Curl_conn_is_osslq(data, conn, sockindex);
+#elif defined(USE_QUICHE)
+  return Curl_conn_is_quiche(data, conn, sockindex);
+#elif defined(USE_MSH3)
+  return Curl_conn_is_msh3(data, conn, sockindex);
+#else
+  return ((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+          (conn->httpversion == 30));
+#endif
+}
+
+CURLcode Curl_conn_may_http3(struct Curl_easy *data,
+                             const struct connectdata *conn)
+{
+  if(conn->transport == TRNSPRT_UNIX) {
+    /* cannot do QUIC over a unix domain socket */
+    return CURLE_QUIC_CONNECT_ERROR;
+  }
+  if(!(conn->handler->flags & PROTOPT_SSL)) {
+    failf(data, "HTTP/3 requested for non-HTTPS URL");
+    return CURLE_URL_MALFORMAT;
+  }
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.socksproxy) {
+    failf(data, "HTTP/3 is not supported over a SOCKS proxy");
+    return CURLE_URL_MALFORMAT;
+  }
+  if(conn->bits.httpproxy && conn->bits.tunnel_proxy) {
+    failf(data, "HTTP/3 is not supported over a HTTP proxy");
+    return CURLE_URL_MALFORMAT;
+  }
+#endif
+
+  return CURLE_OK;
+}
+
+#else /* ENABLE_QUIC */
+
+CURLcode Curl_conn_may_http3(struct Curl_easy *data,
+                             const struct connectdata *conn)
+{
+  (void)conn;
+  (void)data;
+  DEBUGF(infof(data, "QUIC is not supported in this build"));
+  return CURLE_NOT_BUILT_IN;
+}
+
+#endif /* !ENABLE_QUIC */
Index: trunk/src/libs/curl-8.7.1/lib/vquic/vquic.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vquic/vquic.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vquic/vquic.h	(revision 104083)
@@ -0,0 +1,64 @@
+#ifndef HEADER_CURL_VQUIC_QUIC_H
+#define HEADER_CURL_VQUIC_QUIC_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef ENABLE_QUIC
+struct Curl_cfilter;
+struct Curl_easy;
+struct connectdata;
+struct Curl_addrinfo;
+
+void Curl_quic_ver(char *p, size_t len);
+
+CURLcode Curl_qlogdir(struct Curl_easy *data,
+                      unsigned char *scid,
+                      size_t scidlen,
+                      int *qlogfdp);
+
+
+CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf,
+                             struct Curl_easy *data,
+                             struct connectdata *conn,
+                             const struct Curl_addrinfo *ai,
+                             int transport);
+
+bool Curl_conn_is_http3(const struct Curl_easy *data,
+                        const struct connectdata *conn,
+                        int sockindex);
+
+extern struct Curl_cftype Curl_cft_http3;
+
+#else /* ENABLE_QUIC */
+
+#define Curl_conn_is_http3(a,b,c)   FALSE
+
+#endif /* !ENABLE_QUIC */
+
+CURLcode Curl_conn_may_http3(struct Curl_easy *data,
+                             const struct connectdata *conn);
+
+#endif /* HEADER_CURL_VQUIC_QUIC_H */
Index: trunk/src/libs/curl-8.7.1/lib/vquic/vquic_int.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vquic/vquic_int.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vquic/vquic_int.h	(revision 104083)
@@ -0,0 +1,93 @@
+#ifndef HEADER_CURL_VQUIC_QUIC_INT_H
+#define HEADER_CURL_VQUIC_QUIC_INT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "bufq.h"
+
+#ifdef ENABLE_QUIC
+
+#define MAX_PKT_BURST 10
+#define MAX_UDP_PAYLOAD_SIZE  1452
+/* Default QUIC connection timeout we announce from our side */
+#define CURL_QUIC_MAX_IDLE_MS   (120 * 1000)
+
+struct cf_quic_ctx {
+  curl_socket_t sockfd; /* connected UDP socket */
+  struct sockaddr_storage local_addr; /* address socket is bound to */
+  socklen_t local_addrlen; /* length of local address */
+
+  struct bufq sendbuf; /* buffer for sending one or more packets */
+  struct curltime first_byte_at;     /* when first byte was recvd */
+  struct curltime last_op; /* last (attempted) send/recv operation */
+  struct curltime last_io; /* last successful socket IO */
+  size_t gsolen; /* length of individual packets in send buf */
+  size_t split_len; /* if != 0, buffer length after which GSO differs */
+  size_t split_gsolen; /* length of individual packets after split_len */
+#ifdef DEBUGBUILD
+  int wblock_percent; /* percent of writes doing EAGAIN */
+#endif
+  BIT(got_first_byte); /* if first byte was received */
+  BIT(no_gso); /* do not use gso on sending */
+};
+
+CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx);
+void vquic_ctx_free(struct cf_quic_ctx *qctx);
+
+void vquic_ctx_update_time(struct cf_quic_ctx *qctx);
+
+void vquic_push_blocked_pkt(struct Curl_cfilter *cf,
+                            struct cf_quic_ctx *qctx,
+                            const uint8_t *pkt, size_t pktlen, size_t gsolen);
+
+CURLcode vquic_send_blocked_pkts(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 struct cf_quic_ctx *qctx);
+
+CURLcode vquic_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                        struct cf_quic_ctx *qctx, size_t gsolen);
+
+CURLcode vquic_send_tail_split(struct Curl_cfilter *cf, struct Curl_easy *data,
+                               struct cf_quic_ctx *qctx, size_t gsolen,
+                               size_t tail_len, size_t tail_gsolen);
+
+CURLcode vquic_flush(struct Curl_cfilter *cf, struct Curl_easy *data,
+                     struct cf_quic_ctx *qctx);
+
+
+typedef CURLcode vquic_recv_pkt_cb(const unsigned char *pkt, size_t pktlen,
+                                   struct sockaddr_storage *remote_addr,
+                                   socklen_t remote_addrlen, int ecn,
+                                   void *userp);
+
+CURLcode vquic_recv_packets(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            struct cf_quic_ctx *qctx,
+                            size_t max_pkts,
+                            vquic_recv_pkt_cb *recv_cb, void *userp);
+
+#endif /* !ENABLE_QUIC */
+
+#endif /* HEADER_CURL_VQUIC_QUIC_INT_H */
Index: trunk/src/libs/curl-8.7.1/lib/vssh/libssh.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vssh/libssh.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vssh/libssh.c	(revision 104083)
@@ -0,0 +1,2952 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Red Hat, Inc.
+ *
+ * Authors: Nikos Mavrogiannopoulos, Tomas Mraz, Stanislav Zidek,
+ *          Robert Kolcun, Andreas Schneider
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_LIBSSH
+
+#include <limits.h>
+
+/* in 0.10.0 or later, ignore deprecated warnings */
+#define SSH_SUPPRESS_DEPRECATED
+#include <libssh/libssh.h>
+#include <libssh/sftp.h>
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h"               /* for HTTP proxy tunnel stuff */
+#include "ssh.h"
+#include "url.h"
+#include "speedcheck.h"
+#include "getinfo.h"
+#include "strdup.h"
+#include "strcase.h"
+#include "vtls/vtls.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "inet_ntop.h"
+#include "parsedate.h"          /* for the week day and month names */
+#include "sockaddr.h"           /* required for Curl_sockaddr_storage */
+#include "strtoofft.h"
+#include "multiif.h"
+#include "select.h"
+#include "warnless.h"
+#include "curl_path.h"
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* A recent macro provided by libssh. Or make our own. */
+#ifndef SSH_STRING_FREE_CHAR
+#define SSH_STRING_FREE_CHAR(x)                 \
+  do {                                          \
+    if(x) {                                     \
+      ssh_string_free_char(x);                  \
+      x = NULL;                                 \
+    }                                           \
+  } while(0)
+#endif
+
+/* These stat values may not be the same as the user's S_IFMT / S_IFLNK */
+#ifndef SSH_S_IFMT
+#define SSH_S_IFMT   00170000
+#endif
+#ifndef SSH_S_IFLNK
+#define SSH_S_IFLNK  0120000
+#endif
+
+/* Local functions: */
+static CURLcode myssh_connect(struct Curl_easy *data, bool *done);
+static CURLcode myssh_multi_statemach(struct Curl_easy *data,
+                                      bool *done);
+static CURLcode myssh_do_it(struct Curl_easy *data, bool *done);
+
+static CURLcode scp_done(struct Curl_easy *data,
+                         CURLcode, bool premature);
+static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
+static CURLcode scp_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn,
+                               bool dead_connection);
+
+static CURLcode sftp_done(struct Curl_easy *data,
+                          CURLcode, bool premature);
+static CURLcode sftp_doing(struct Curl_easy *data,
+                           bool *dophase_done);
+static CURLcode sftp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                bool dead);
+static
+CURLcode sftp_perform(struct Curl_easy *data,
+                      bool *connected,
+                      bool *dophase_done);
+
+static void sftp_quote(struct Curl_easy *data);
+static void sftp_quote_stat(struct Curl_easy *data);
+static int myssh_getsock(struct Curl_easy *data,
+                         struct connectdata *conn, curl_socket_t *sock);
+
+static CURLcode myssh_setup_connection(struct Curl_easy *data,
+                                       struct connectdata *conn);
+
+/*
+ * SCP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_scp = {
+  "SCP",                        /* scheme */
+  myssh_setup_connection,       /* setup_connection */
+  myssh_do_it,                  /* do_it */
+  scp_done,                     /* done */
+  ZERO_NULL,                    /* do_more */
+  myssh_connect,                /* connect_it */
+  myssh_multi_statemach,        /* connecting */
+  scp_doing,                    /* doing */
+  myssh_getsock,                /* proto_getsock */
+  myssh_getsock,                /* doing_getsock */
+  ZERO_NULL,                    /* domore_getsock */
+  myssh_getsock,                /* perform_getsock */
+  scp_disconnect,               /* disconnect */
+  ZERO_NULL,                    /* write_resp */
+  ZERO_NULL,                    /* connection_check */
+  ZERO_NULL,                    /* attach connection */
+  PORT_SSH,                     /* defport */
+  CURLPROTO_SCP,                /* protocol */
+  CURLPROTO_SCP,                /* family */
+  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY    /* flags */
+};
+
+/*
+ * SFTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_sftp = {
+  "SFTP",                               /* scheme */
+  myssh_setup_connection,               /* setup_connection */
+  myssh_do_it,                          /* do_it */
+  sftp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  myssh_connect,                        /* connect_it */
+  myssh_multi_statemach,                /* connecting */
+  sftp_doing,                           /* doing */
+  myssh_getsock,                        /* proto_getsock */
+  myssh_getsock,                        /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  myssh_getsock,                        /* perform_getsock */
+  sftp_disconnect,                      /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_SSH,                             /* defport */
+  CURLPROTO_SFTP,                       /* protocol */
+  CURLPROTO_SFTP,                       /* family */
+  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+  | PROTOPT_NOURLQUERY                  /* flags */
+};
+
+static CURLcode sftp_error_to_CURLE(int err)
+{
+  switch(err) {
+    case SSH_FX_OK:
+      return CURLE_OK;
+
+    case SSH_FX_NO_SUCH_FILE:
+    case SSH_FX_NO_SUCH_PATH:
+      return CURLE_REMOTE_FILE_NOT_FOUND;
+
+    case SSH_FX_PERMISSION_DENIED:
+    case SSH_FX_WRITE_PROTECT:
+      return CURLE_REMOTE_ACCESS_DENIED;
+
+    case SSH_FX_FILE_ALREADY_EXISTS:
+      return CURLE_REMOTE_FILE_EXISTS;
+
+    default:
+      break;
+  }
+
+  return CURLE_SSH;
+}
+
+#ifndef DEBUGBUILD
+#define state(x,y) mystate(x,y)
+#else
+#define state(x,y) mystate(x,y, __LINE__)
+#endif
+
+/*
+ * SSH State machine related code
+ */
+/* This is the ONLY way to change SSH state! */
+static void mystate(struct Curl_easy *data, sshstate nowstate
+#ifdef DEBUGBUILD
+                    , int lineno
+#endif
+  )
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char *const names[] = {
+    "SSH_STOP",
+    "SSH_INIT",
+    "SSH_S_STARTUP",
+    "SSH_HOSTKEY",
+    "SSH_AUTHLIST",
+    "SSH_AUTH_PKEY_INIT",
+    "SSH_AUTH_PKEY",
+    "SSH_AUTH_PASS_INIT",
+    "SSH_AUTH_PASS",
+    "SSH_AUTH_AGENT_INIT",
+    "SSH_AUTH_AGENT_LIST",
+    "SSH_AUTH_AGENT",
+    "SSH_AUTH_HOST_INIT",
+    "SSH_AUTH_HOST",
+    "SSH_AUTH_KEY_INIT",
+    "SSH_AUTH_KEY",
+    "SSH_AUTH_GSSAPI",
+    "SSH_AUTH_DONE",
+    "SSH_SFTP_INIT",
+    "SSH_SFTP_REALPATH",
+    "SSH_SFTP_QUOTE_INIT",
+    "SSH_SFTP_POSTQUOTE_INIT",
+    "SSH_SFTP_QUOTE",
+    "SSH_SFTP_NEXT_QUOTE",
+    "SSH_SFTP_QUOTE_STAT",
+    "SSH_SFTP_QUOTE_SETSTAT",
+    "SSH_SFTP_QUOTE_SYMLINK",
+    "SSH_SFTP_QUOTE_MKDIR",
+    "SSH_SFTP_QUOTE_RENAME",
+    "SSH_SFTP_QUOTE_RMDIR",
+    "SSH_SFTP_QUOTE_UNLINK",
+    "SSH_SFTP_QUOTE_STATVFS",
+    "SSH_SFTP_GETINFO",
+    "SSH_SFTP_FILETIME",
+    "SSH_SFTP_TRANS_INIT",
+    "SSH_SFTP_UPLOAD_INIT",
+    "SSH_SFTP_CREATE_DIRS_INIT",
+    "SSH_SFTP_CREATE_DIRS",
+    "SSH_SFTP_CREATE_DIRS_MKDIR",
+    "SSH_SFTP_READDIR_INIT",
+    "SSH_SFTP_READDIR",
+    "SSH_SFTP_READDIR_LINK",
+    "SSH_SFTP_READDIR_BOTTOM",
+    "SSH_SFTP_READDIR_DONE",
+    "SSH_SFTP_DOWNLOAD_INIT",
+    "SSH_SFTP_DOWNLOAD_STAT",
+    "SSH_SFTP_CLOSE",
+    "SSH_SFTP_SHUTDOWN",
+    "SSH_SCP_TRANS_INIT",
+    "SSH_SCP_UPLOAD_INIT",
+    "SSH_SCP_DOWNLOAD_INIT",
+    "SSH_SCP_DOWNLOAD",
+    "SSH_SCP_DONE",
+    "SSH_SCP_SEND_EOF",
+    "SSH_SCP_WAIT_EOF",
+    "SSH_SCP_WAIT_CLOSE",
+    "SSH_SCP_CHANNEL_FREE",
+    "SSH_SESSION_DISCONNECT",
+    "SSH_SESSION_FREE",
+    "QUIT"
+  };
+
+
+  if(sshc->state != nowstate) {
+    infof(data, "SSH %p state change from %s to %s (line %d)",
+          (void *) sshc, names[sshc->state], names[nowstate],
+          lineno);
+  }
+#endif
+
+  sshc->state = nowstate;
+}
+
+/* Multiple options:
+ * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5
+ *    hash (90s style auth, not sure we should have it here)
+ * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first
+ *    use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE
+ *    is returned by it.
+ * 3. none of the above. We only accept if it is present on known hosts.
+ *
+ * Returns SSH_OK or SSH_ERROR.
+ */
+static int myssh_is_known(struct Curl_easy *data)
+{
+  int rc;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  ssh_key pubkey;
+  size_t hlen;
+  unsigned char *hash = NULL;
+  char *found_base64 = NULL;
+  char *known_base64 = NULL;
+  int vstate;
+  enum curl_khmatch keymatch;
+  struct curl_khkey foundkey;
+  struct curl_khkey *knownkeyp = NULL;
+  curl_sshkeycallback func =
+    data->set.ssh_keyfunc;
+
+#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
+  struct ssh_knownhosts_entry *knownhostsentry = NULL;
+  struct curl_khkey knownkey;
+#endif
+
+#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
+  rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey);
+#else
+  rc = ssh_get_publickey(sshc->ssh_session, &pubkey);
+#endif
+  if(rc != SSH_OK)
+    return rc;
+
+  if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
+    int i;
+    char md5buffer[33];
+    const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
+
+    rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5,
+                                &hash, &hlen);
+    if(rc != SSH_OK || hlen != 16) {
+      failf(data,
+            "Denied establishing ssh session: md5 fingerprint not available");
+      goto cleanup;
+    }
+
+    for(i = 0; i < 16; i++)
+      msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]);
+
+    infof(data, "SSH MD5 fingerprint: %s", md5buffer);
+
+    if(!strcasecompare(md5buffer, pubkey_md5)) {
+      failf(data,
+            "Denied establishing ssh session: mismatch md5 fingerprint. "
+            "Remote %s is not equal to %s", md5buffer, pubkey_md5);
+      rc = SSH_ERROR;
+      goto cleanup;
+    }
+
+    rc = SSH_OK;
+    goto cleanup;
+  }
+
+  if(data->set.ssl.primary.verifyhost != TRUE) {
+    rc = SSH_OK;
+    goto cleanup;
+  }
+
+#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
+  /* Get the known_key from the known hosts file */
+  vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
+                                             &knownhostsentry);
+
+  /* Case an entry was found in a known hosts file */
+  if(knownhostsentry) {
+    if(knownhostsentry->publickey) {
+      rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
+                                        &known_base64);
+      if(rc != SSH_OK) {
+        goto cleanup;
+      }
+      knownkey.key = known_base64;
+      knownkey.len = strlen(known_base64);
+
+      switch(ssh_key_type(knownhostsentry->publickey)) {
+        case SSH_KEYTYPE_RSA:
+          knownkey.keytype = CURLKHTYPE_RSA;
+          break;
+        case SSH_KEYTYPE_RSA1:
+          knownkey.keytype = CURLKHTYPE_RSA1;
+          break;
+        case SSH_KEYTYPE_ECDSA:
+        case SSH_KEYTYPE_ECDSA_P256:
+        case SSH_KEYTYPE_ECDSA_P384:
+        case SSH_KEYTYPE_ECDSA_P521:
+          knownkey.keytype = CURLKHTYPE_ECDSA;
+          break;
+        case SSH_KEYTYPE_ED25519:
+          knownkey.keytype = CURLKHTYPE_ED25519;
+          break;
+        case SSH_KEYTYPE_DSS:
+          knownkey.keytype = CURLKHTYPE_DSS;
+          break;
+        default:
+          rc = SSH_ERROR;
+          goto cleanup;
+      }
+      knownkeyp = &knownkey;
+    }
+  }
+
+  switch(vstate) {
+    case SSH_KNOWN_HOSTS_OK:
+      keymatch = CURLKHMATCH_OK;
+      break;
+    case SSH_KNOWN_HOSTS_OTHER:
+    case SSH_KNOWN_HOSTS_NOT_FOUND:
+    case SSH_KNOWN_HOSTS_UNKNOWN:
+    case SSH_KNOWN_HOSTS_ERROR:
+      keymatch = CURLKHMATCH_MISSING;
+      break;
+  default:
+      keymatch = CURLKHMATCH_MISMATCH;
+      break;
+  }
+
+#else
+  vstate = ssh_is_server_known(sshc->ssh_session);
+  switch(vstate) {
+    case SSH_SERVER_KNOWN_OK:
+      keymatch = CURLKHMATCH_OK;
+      break;
+    case SSH_SERVER_FILE_NOT_FOUND:
+    case SSH_SERVER_NOT_KNOWN:
+      keymatch = CURLKHMATCH_MISSING;
+      break;
+  default:
+      keymatch = CURLKHMATCH_MISMATCH;
+      break;
+  }
+#endif
+
+  if(func) { /* use callback to determine action */
+    rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
+    if(rc != SSH_OK)
+      goto cleanup;
+
+    foundkey.key = found_base64;
+    foundkey.len = strlen(found_base64);
+
+    switch(ssh_key_type(pubkey)) {
+      case SSH_KEYTYPE_RSA:
+        foundkey.keytype = CURLKHTYPE_RSA;
+        break;
+      case SSH_KEYTYPE_RSA1:
+        foundkey.keytype = CURLKHTYPE_RSA1;
+        break;
+      case SSH_KEYTYPE_ECDSA:
+#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
+      case SSH_KEYTYPE_ECDSA_P256:
+      case SSH_KEYTYPE_ECDSA_P384:
+      case SSH_KEYTYPE_ECDSA_P521:
+#endif
+        foundkey.keytype = CURLKHTYPE_ECDSA;
+        break;
+#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0)
+      case SSH_KEYTYPE_ED25519:
+        foundkey.keytype = CURLKHTYPE_ED25519;
+        break;
+#endif
+      case SSH_KEYTYPE_DSS:
+        foundkey.keytype = CURLKHTYPE_DSS;
+        break;
+      default:
+        rc = SSH_ERROR;
+        goto cleanup;
+    }
+
+    Curl_set_in_callback(data, true);
+    rc = func(data, knownkeyp, /* from the knownhosts file */
+              &foundkey, /* from the remote host */
+              keymatch, data->set.ssh_keyfunc_userp);
+    Curl_set_in_callback(data, false);
+
+    switch(rc) {
+      case CURLKHSTAT_FINE_ADD_TO_FILE:
+#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
+        rc = ssh_session_update_known_hosts(sshc->ssh_session);
+#else
+        rc = ssh_write_knownhost(sshc->ssh_session);
+#endif
+        if(rc != SSH_OK) {
+          goto cleanup;
+        }
+        break;
+      case CURLKHSTAT_FINE:
+        break;
+      default: /* REJECT/DEFER */
+        rc = SSH_ERROR;
+        goto cleanup;
+    }
+  }
+  else {
+    if(keymatch != CURLKHMATCH_OK) {
+      rc = SSH_ERROR;
+      goto cleanup;
+    }
+  }
+  rc = SSH_OK;
+
+cleanup:
+  if(found_base64) {
+    (free)(found_base64);
+  }
+  if(known_base64) {
+    (free)(known_base64);
+  }
+  if(hash)
+    ssh_clean_pubkey_hash(&hash);
+  ssh_key_free(pubkey);
+#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
+  if(knownhostsentry) {
+    ssh_knownhosts_entry_free(knownhostsentry);
+  }
+#endif
+  return rc;
+}
+
+#define MOVE_TO_ERROR_STATE(_r) do {            \
+    state(data, SSH_SESSION_DISCONNECT);        \
+    sshc->actualcode = _r;                      \
+    rc = SSH_ERROR;                             \
+  } while(0)
+
+#define MOVE_TO_SFTP_CLOSE_STATE() do {                         \
+    state(data, SSH_SFTP_CLOSE);                                \
+    sshc->actualcode =                                          \
+      sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session));  \
+    rc = SSH_ERROR;                                             \
+  } while(0)
+
+#define MOVE_TO_PASSWD_AUTH do {                        \
+    if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
+      rc = SSH_OK;                                      \
+      state(data, SSH_AUTH_PASS_INIT);                  \
+    }                                                   \
+    else {                                              \
+      MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);          \
+    }                                                   \
+  } while(0)
+
+#define MOVE_TO_KEY_AUTH do {                                   \
+    if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {      \
+      rc = SSH_OK;                                              \
+      state(data, SSH_AUTH_KEY_INIT);                           \
+    }                                                           \
+    else {                                                      \
+      MOVE_TO_PASSWD_AUTH;                                      \
+    }                                                           \
+  } while(0)
+
+#define MOVE_TO_GSSAPI_AUTH do {                                \
+    if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {       \
+      rc = SSH_OK;                                              \
+      state(data, SSH_AUTH_GSSAPI);                             \
+    }                                                           \
+    else {                                                      \
+      MOVE_TO_KEY_AUTH;                                         \
+    }                                                           \
+  } while(0)
+
+static
+int myssh_auth_interactive(struct connectdata *conn)
+{
+  int rc;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  int nprompts;
+
+restart:
+  switch(sshc->kbd_state) {
+    case 0:
+      rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
+      if(rc == SSH_AUTH_AGAIN)
+        return SSH_AGAIN;
+
+      if(rc != SSH_AUTH_INFO)
+        return SSH_ERROR;
+
+      nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
+      if(nprompts != 1)
+        return SSH_ERROR;
+
+      rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0, conn->passwd);
+      if(rc < 0)
+        return SSH_ERROR;
+
+      FALLTHROUGH();
+    case 1:
+      sshc->kbd_state = 1;
+
+      rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
+      if(rc == SSH_AUTH_AGAIN)
+        return SSH_AGAIN;
+      else if(rc == SSH_AUTH_SUCCESS)
+        rc = SSH_OK;
+      else if(rc == SSH_AUTH_INFO) {
+        nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
+        if(nprompts)
+          return SSH_ERROR;
+
+        sshc->kbd_state = 2;
+        goto restart;
+      }
+      else
+        rc = SSH_ERROR;
+      break;
+    case 2:
+      sshc->kbd_state = 2;
+
+      rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
+      if(rc == SSH_AUTH_AGAIN)
+        return SSH_AGAIN;
+      else if(rc == SSH_AUTH_SUCCESS)
+        rc = SSH_OK;
+      else
+        rc = SSH_ERROR;
+
+      break;
+    default:
+      return SSH_ERROR;
+  }
+
+  sshc->kbd_state = 0;
+  return rc;
+}
+
+/*
+ * ssh_statemach_act() runs the SSH state machine as far as it can without
+ * blocking and without reaching the end.  The data the pointer 'block' points
+ * to will be set to TRUE if the libssh function returns SSH_AGAIN
+ * meaning it wants to be called again when the socket is ready
+ */
+static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct SSHPROTO *protop = data->req.p.ssh;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  int rc = SSH_NO_ERROR, err;
+  int seekerr = CURL_SEEKFUNC_OK;
+  const char *err_msg;
+  *block = 0;                   /* we're not blocking by default */
+
+  do {
+
+    switch(sshc->state) {
+    case SSH_INIT:
+      sshc->secondCreateDirs = 0;
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_OK;
+
+#if 0
+      ssh_set_log_level(SSH_LOG_PROTOCOL);
+#endif
+
+      /* Set libssh to non-blocking, since everything internally is
+         non-blocking */
+      ssh_set_blocking(sshc->ssh_session, 0);
+
+      state(data, SSH_S_STARTUP);
+      FALLTHROUGH();
+
+    case SSH_S_STARTUP:
+      rc = ssh_connect(sshc->ssh_session);
+      if(rc == SSH_AGAIN)
+        break;
+
+      if(rc != SSH_OK) {
+        failf(data, "Failure establishing ssh session");
+        MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT);
+        break;
+      }
+
+      state(data, SSH_HOSTKEY);
+
+      FALLTHROUGH();
+    case SSH_HOSTKEY:
+
+      rc = myssh_is_known(data);
+      if(rc != SSH_OK) {
+        MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
+        break;
+      }
+
+      state(data, SSH_AUTHLIST);
+      FALLTHROUGH();
+    case SSH_AUTHLIST:{
+        sshc->authed = FALSE;
+
+        rc = ssh_userauth_none(sshc->ssh_session, NULL);
+        if(rc == SSH_AUTH_AGAIN) {
+          rc = SSH_AGAIN;
+          break;
+        }
+
+        if(rc == SSH_AUTH_SUCCESS) {
+          sshc->authed = TRUE;
+          infof(data, "Authenticated with none");
+          state(data, SSH_AUTH_DONE);
+          break;
+        }
+        else if(rc == SSH_AUTH_ERROR) {
+          MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+          break;
+        }
+
+        sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL);
+        if(sshc->auth_methods)
+          infof(data, "SSH authentication methods available: %s%s%s%s",
+                sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY ?
+                "public key, ": "",
+                sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC ?
+                "GSSAPI, " : "",
+                sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE ?
+                "keyboard-interactive, " : "",
+                sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ?
+                "password": "");
+        if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
+          state(data, SSH_AUTH_PKEY_INIT);
+          infof(data, "Authentication using SSH public key file");
+        }
+        else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
+          state(data, SSH_AUTH_GSSAPI);
+        }
+        else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
+          state(data, SSH_AUTH_KEY_INIT);
+        }
+        else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
+          state(data, SSH_AUTH_PASS_INIT);
+        }
+        else {                  /* unsupported authentication method */
+          MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+          break;
+        }
+
+        break;
+      }
+    case SSH_AUTH_PKEY_INIT:
+      if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
+        MOVE_TO_GSSAPI_AUTH;
+        break;
+      }
+
+      /* Two choices, (1) private key was given on CMD,
+       * (2) use the "default" keys. */
+      if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
+        if(sshc->pubkey && !data->set.ssl.key_passwd) {
+          rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL,
+                                          sshc->pubkey);
+          if(rc == SSH_AUTH_AGAIN) {
+            rc = SSH_AGAIN;
+            break;
+          }
+
+          if(rc != SSH_OK) {
+            MOVE_TO_GSSAPI_AUTH;
+            break;
+          }
+        }
+
+        rc = ssh_pki_import_privkey_file(data->
+                                         set.str[STRING_SSH_PRIVATE_KEY],
+                                         data->set.ssl.key_passwd, NULL,
+                                         NULL, &sshc->privkey);
+        if(rc != SSH_OK) {
+          failf(data, "Could not load private key file %s",
+                data->set.str[STRING_SSH_PRIVATE_KEY]);
+          MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+          break;
+        }
+
+        state(data, SSH_AUTH_PKEY);
+        break;
+
+      }
+      else {
+        rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL,
+                                         data->set.ssl.key_passwd);
+        if(rc == SSH_AUTH_AGAIN) {
+          rc = SSH_AGAIN;
+          break;
+        }
+        if(rc == SSH_AUTH_SUCCESS) {
+          rc = SSH_OK;
+          sshc->authed = TRUE;
+          infof(data, "Completed public key authentication");
+          state(data, SSH_AUTH_DONE);
+          break;
+        }
+
+        MOVE_TO_GSSAPI_AUTH;
+      }
+      break;
+    case SSH_AUTH_PKEY:
+      rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey);
+      if(rc == SSH_AUTH_AGAIN) {
+        rc = SSH_AGAIN;
+        break;
+      }
+
+      if(rc == SSH_AUTH_SUCCESS) {
+        sshc->authed = TRUE;
+        infof(data, "Completed public key authentication");
+        state(data, SSH_AUTH_DONE);
+        break;
+      }
+      else {
+        infof(data, "Failed public key authentication (rc: %d)", rc);
+        MOVE_TO_GSSAPI_AUTH;
+      }
+      break;
+
+    case SSH_AUTH_GSSAPI:
+      if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) {
+        MOVE_TO_KEY_AUTH;
+        break;
+      }
+
+      rc = ssh_userauth_gssapi(sshc->ssh_session);
+      if(rc == SSH_AUTH_AGAIN) {
+        rc = SSH_AGAIN;
+        break;
+      }
+
+      if(rc == SSH_AUTH_SUCCESS) {
+        rc = SSH_OK;
+        sshc->authed = TRUE;
+        infof(data, "Completed gssapi authentication");
+        state(data, SSH_AUTH_DONE);
+        break;
+      }
+
+      MOVE_TO_KEY_AUTH;
+      break;
+
+    case SSH_AUTH_KEY_INIT:
+      if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
+        state(data, SSH_AUTH_KEY);
+      }
+      else {
+        MOVE_TO_PASSWD_AUTH;
+      }
+      break;
+
+    case SSH_AUTH_KEY:
+      /* keyboard-interactive authentication */
+      rc = myssh_auth_interactive(conn);
+      if(rc == SSH_AGAIN) {
+        break;
+      }
+      if(rc == SSH_OK) {
+        sshc->authed = TRUE;
+        infof(data, "completed keyboard interactive authentication");
+        state(data, SSH_AUTH_DONE);
+      }
+      else {
+        MOVE_TO_PASSWD_AUTH;
+      }
+      break;
+
+    case SSH_AUTH_PASS_INIT:
+      if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) {
+        MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+        break;
+      }
+      state(data, SSH_AUTH_PASS);
+      FALLTHROUGH();
+
+    case SSH_AUTH_PASS:
+      rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd);
+      if(rc == SSH_AUTH_AGAIN) {
+        rc = SSH_AGAIN;
+        break;
+      }
+
+      if(rc == SSH_AUTH_SUCCESS) {
+        sshc->authed = TRUE;
+        infof(data, "Completed password authentication");
+        state(data, SSH_AUTH_DONE);
+      }
+      else {
+        MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+      }
+      break;
+
+    case SSH_AUTH_DONE:
+      if(!sshc->authed) {
+        failf(data, "Authentication failure");
+        MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+        break;
+      }
+
+      /*
+       * At this point we have an authenticated ssh session.
+       */
+      infof(data, "Authentication complete");
+
+      Curl_pgrsTime(data, TIMER_APPCONNECT);      /* SSH is connected */
+
+      conn->sockfd = sock;
+      conn->writesockfd = CURL_SOCKET_BAD;
+
+      if(conn->handler->protocol == CURLPROTO_SFTP) {
+        state(data, SSH_SFTP_INIT);
+        break;
+      }
+      infof(data, "SSH CONNECT phase done");
+      state(data, SSH_STOP);
+      break;
+
+    case SSH_SFTP_INIT:
+      ssh_set_blocking(sshc->ssh_session, 1);
+
+      sshc->sftp_session = sftp_new(sshc->ssh_session);
+      if(!sshc->sftp_session) {
+        failf(data, "Failure initializing sftp session: %s",
+              ssh_get_error(sshc->ssh_session));
+        MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
+        break;
+      }
+
+      rc = sftp_init(sshc->sftp_session);
+      if(rc != SSH_OK) {
+        failf(data, "Failure initializing sftp session: %s",
+              ssh_get_error(sshc->ssh_session));
+        MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE));
+        break;
+      }
+      state(data, SSH_SFTP_REALPATH);
+      FALLTHROUGH();
+    case SSH_SFTP_REALPATH:
+      /*
+       * Get the "home" directory
+       */
+      sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, ".");
+      if(!sshc->homedir) {
+        MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
+        break;
+      }
+      data->state.most_recent_ftp_entrypath = sshc->homedir;
+
+      /* This is the last step in the SFTP connect phase. Do note that while
+         we get the homedir here, we get the "workingpath" in the DO action
+         since the homedir will remain the same between request but the
+         working path will not. */
+      DEBUGF(infof(data, "SSH CONNECT phase done"));
+      state(data, SSH_STOP);
+      break;
+
+    case SSH_SFTP_QUOTE_INIT:
+      result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
+      if(result) {
+        sshc->actualcode = result;
+        state(data, SSH_STOP);
+        break;
+      }
+
+      if(data->set.quote) {
+        infof(data, "Sending quote commands");
+        sshc->quote_item = data->set.quote;
+        state(data, SSH_SFTP_QUOTE);
+      }
+      else {
+        state(data, SSH_SFTP_GETINFO);
+      }
+      break;
+
+    case SSH_SFTP_POSTQUOTE_INIT:
+      if(data->set.postquote) {
+        infof(data, "Sending quote commands");
+        sshc->quote_item = data->set.postquote;
+        state(data, SSH_SFTP_QUOTE);
+      }
+      else {
+        state(data, SSH_STOP);
+      }
+      break;
+
+    case SSH_SFTP_QUOTE:
+      /* Send any quote commands */
+      sftp_quote(data);
+      break;
+
+    case SSH_SFTP_NEXT_QUOTE:
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+
+      sshc->quote_item = sshc->quote_item->next;
+
+      if(sshc->quote_item) {
+        state(data, SSH_SFTP_QUOTE);
+      }
+      else {
+        if(sshc->nextstate != SSH_NO_STATE) {
+          state(data, sshc->nextstate);
+          sshc->nextstate = SSH_NO_STATE;
+        }
+        else {
+          state(data, SSH_SFTP_GETINFO);
+        }
+      }
+      break;
+
+    case SSH_SFTP_QUOTE_STAT:
+      sftp_quote_stat(data);
+      break;
+
+    case SSH_SFTP_QUOTE_SETSTAT:
+      rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2,
+                        sshc->quote_attrs);
+      if(rc && !sshc->acceptfail) {
+        Curl_safefree(sshc->quote_path1);
+        Curl_safefree(sshc->quote_path2);
+        failf(data, "Attempt to set SFTP stats failed: %s",
+              ssh_get_error(sshc->ssh_session));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        /* sshc->actualcode = sftp_error_to_CURLE(err);
+         * we do not send the actual error; we return
+         * the error the libssh2 backend is returning */
+        break;
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_SYMLINK:
+      rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2,
+                        sshc->quote_path1);
+      if(rc && !sshc->acceptfail) {
+        Curl_safefree(sshc->quote_path1);
+        Curl_safefree(sshc->quote_path2);
+        failf(data, "symlink command failed: %s",
+              ssh_get_error(sshc->ssh_session));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_MKDIR:
+      rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1,
+                      (mode_t)data->set.new_directory_perms);
+      if(rc && !sshc->acceptfail) {
+        Curl_safefree(sshc->quote_path1);
+        failf(data, "mkdir command failed: %s",
+              ssh_get_error(sshc->ssh_session));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_RENAME:
+      rc = sftp_rename(sshc->sftp_session, sshc->quote_path1,
+                       sshc->quote_path2);
+      if(rc && !sshc->acceptfail) {
+        Curl_safefree(sshc->quote_path1);
+        Curl_safefree(sshc->quote_path2);
+        failf(data, "rename command failed: %s",
+              ssh_get_error(sshc->ssh_session));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_RMDIR:
+      rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
+      if(rc && !sshc->acceptfail) {
+        Curl_safefree(sshc->quote_path1);
+        failf(data, "rmdir command failed: %s",
+              ssh_get_error(sshc->ssh_session));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_UNLINK:
+      rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1);
+      if(rc && !sshc->acceptfail) {
+        Curl_safefree(sshc->quote_path1);
+        failf(data, "rm command failed: %s",
+              ssh_get_error(sshc->ssh_session));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_STATVFS:
+    {
+      sftp_statvfs_t statvfs;
+
+      statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1);
+      if(!statvfs && !sshc->acceptfail) {
+        Curl_safefree(sshc->quote_path1);
+        failf(data, "statvfs command failed: %s",
+              ssh_get_error(sshc->ssh_session));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      else if(statvfs) {
+        #ifdef _MSC_VER
+        #define CURL_LIBSSH_VFS_SIZE_MASK "I64u"
+        #else
+        #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64
+        #endif
+        char *tmp = aprintf("statvfs:\n"
+                            "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                            "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                            "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                            "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                            "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                            "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                            "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                            "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                            "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                            "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                            "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n",
+                            statvfs->f_bsize, statvfs->f_frsize,
+                            statvfs->f_blocks, statvfs->f_bfree,
+                            statvfs->f_bavail, statvfs->f_files,
+                            statvfs->f_ffree, statvfs->f_favail,
+                            statvfs->f_fsid, statvfs->f_flag,
+                            statvfs->f_namemax);
+        sftp_statvfs_free(statvfs);
+
+        if(!tmp) {
+          result = CURLE_OUT_OF_MEMORY;
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          break;
+        }
+
+        result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+        free(tmp);
+        if(result) {
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = result;
+        }
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+    }
+
+    case SSH_SFTP_GETINFO:
+      if(data->set.get_filetime) {
+        state(data, SSH_SFTP_FILETIME);
+      }
+      else {
+        state(data, SSH_SFTP_TRANS_INIT);
+      }
+      break;
+
+    case SSH_SFTP_FILETIME:
+    {
+      sftp_attributes attrs;
+
+      attrs = sftp_stat(sshc->sftp_session, protop->path);
+      if(attrs) {
+        data->info.filetime = attrs->mtime;
+        sftp_attributes_free(attrs);
+      }
+
+      state(data, SSH_SFTP_TRANS_INIT);
+      break;
+    }
+
+    case SSH_SFTP_TRANS_INIT:
+      if(data->state.upload)
+        state(data, SSH_SFTP_UPLOAD_INIT);
+      else {
+        if(protop->path[strlen(protop->path)-1] == '/')
+          state(data, SSH_SFTP_READDIR_INIT);
+        else
+          state(data, SSH_SFTP_DOWNLOAD_INIT);
+      }
+      break;
+
+    case SSH_SFTP_UPLOAD_INIT:
+    {
+      int flags;
+
+      if(data->state.resume_from) {
+        sftp_attributes attrs;
+
+        if(data->state.resume_from < 0) {
+          attrs = sftp_stat(sshc->sftp_session, protop->path);
+          if(attrs) {
+            curl_off_t size = attrs->size;
+            if(size < 0) {
+              failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
+              MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
+              break;
+            }
+            data->state.resume_from = attrs->size;
+
+            sftp_attributes_free(attrs);
+          }
+          else {
+            data->state.resume_from = 0;
+          }
+        }
+      }
+
+      if(data->set.remote_append)
+        /* Try to open for append, but create if nonexisting */
+        flags = O_WRONLY|O_CREAT|O_APPEND;
+      else if(data->state.resume_from > 0)
+        /* If we have restart position then open for append */
+        flags = O_WRONLY|O_APPEND;
+      else
+        /* Clear file before writing (normal behavior) */
+        flags = O_WRONLY|O_CREAT|O_TRUNC;
+
+      if(sshc->sftp_file)
+        sftp_close(sshc->sftp_file);
+      sshc->sftp_file =
+        sftp_open(sshc->sftp_session, protop->path,
+                  flags, (mode_t)data->set.new_file_perms);
+      if(!sshc->sftp_file) {
+        err = sftp_get_error(sshc->sftp_session);
+
+        if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE ||
+             err == SSH_FX_NO_SUCH_PATH)) &&
+             (data->set.ftp_create_missing_dirs &&
+             (strlen(protop->path) > 1))) {
+               /* try to create the path remotely */
+               rc = 0;
+               sshc->secondCreateDirs = 1;
+               state(data, SSH_SFTP_CREATE_DIRS_INIT);
+               break;
+        }
+        else {
+          MOVE_TO_SFTP_CLOSE_STATE();
+          break;
+        }
+      }
+
+      /* If we have a restart point then we need to seek to the correct
+         position. */
+      if(data->state.resume_from > 0) {
+        /* Let's read off the proper amount of bytes from the input. */
+        if(data->set.seek_func) {
+          Curl_set_in_callback(data, true);
+          seekerr = data->set.seek_func(data->set.seek_client,
+                                        data->state.resume_from, SEEK_SET);
+          Curl_set_in_callback(data, false);
+        }
+
+        if(seekerr != CURL_SEEKFUNC_OK) {
+          curl_off_t passed = 0;
+
+          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+            failf(data, "Could not seek stream");
+            return CURLE_FTP_COULDNT_USE_REST;
+          }
+          /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+          do {
+            char scratch[4*1024];
+            size_t readthisamountnow =
+              (data->state.resume_from - passed >
+                (curl_off_t)sizeof(scratch)) ?
+              sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
+
+            size_t actuallyread =
+              data->state.fread_func(scratch, 1,
+                                     readthisamountnow, data->state.in);
+
+            passed += actuallyread;
+            if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+              /* this checks for greater-than only to make sure that the
+                 CURL_READFUNC_ABORT return code still aborts */
+              failf(data, "Failed to read data");
+              MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
+              break;
+            }
+          } while(passed < data->state.resume_from);
+          if(rc)
+            break;
+        }
+
+        /* now, decrease the size of the read */
+        if(data->state.infilesize > 0) {
+          data->state.infilesize -= data->state.resume_from;
+          data->req.size = data->state.infilesize;
+          Curl_pgrsSetUploadSize(data, data->state.infilesize);
+        }
+
+        rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
+        if(rc) {
+          MOVE_TO_SFTP_CLOSE_STATE();
+          break;
+        }
+      }
+      if(data->state.infilesize > 0) {
+        data->req.size = data->state.infilesize;
+        Curl_pgrsSetUploadSize(data, data->state.infilesize);
+      }
+      /* upload data */
+      Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
+
+      /* not set by Curl_xfer_setup to preserve keepon bits */
+      conn->sockfd = conn->writesockfd;
+
+      /* store this original bitmask setup to use later on if we can't
+         figure out a "real" bitmask */
+      sshc->orig_waitfor = data->req.keepon;
+
+      /* we want to use the _sending_ function even when the socket turns
+         out readable as the underlying libssh sftp send function will deal
+         with both accordingly */
+      data->state.select_bits = CURL_CSELECT_OUT;
+
+      /* since we don't really wait for anything at this point, we want the
+         state machine to move on as soon as possible so we set a very short
+         timeout here */
+      Curl_expire(data, 0, EXPIRE_RUN_NOW);
+
+      state(data, SSH_STOP);
+      break;
+    }
+
+    case SSH_SFTP_CREATE_DIRS_INIT:
+      if(strlen(protop->path) > 1) {
+        sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
+        state(data, SSH_SFTP_CREATE_DIRS);
+      }
+      else {
+        state(data, SSH_SFTP_UPLOAD_INIT);
+      }
+      break;
+
+    case SSH_SFTP_CREATE_DIRS:
+      sshc->slash_pos = strchr(sshc->slash_pos, '/');
+      if(sshc->slash_pos) {
+        *sshc->slash_pos = 0;
+
+        infof(data, "Creating directory '%s'", protop->path);
+        state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
+        break;
+      }
+      state(data, SSH_SFTP_UPLOAD_INIT);
+      break;
+
+    case SSH_SFTP_CREATE_DIRS_MKDIR:
+      /* 'mode' - parameter is preliminary - default to 0644 */
+      rc = sftp_mkdir(sshc->sftp_session, protop->path,
+                      (mode_t)data->set.new_directory_perms);
+      *sshc->slash_pos = '/';
+      ++sshc->slash_pos;
+      if(rc < 0) {
+        /*
+         * Abort if failure wasn't that the dir already exists or the
+         * permission was denied (creation might succeed further down the
+         * path) - retry on unspecific FAILURE also
+         */
+        err = sftp_get_error(sshc->sftp_session);
+        if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
+           (err != SSH_FX_FAILURE) &&
+           (err != SSH_FX_PERMISSION_DENIED)) {
+          MOVE_TO_SFTP_CLOSE_STATE();
+          break;
+        }
+        rc = 0; /* clear rc and continue */
+      }
+      state(data, SSH_SFTP_CREATE_DIRS);
+      break;
+
+    case SSH_SFTP_READDIR_INIT:
+      Curl_pgrsSetDownloadSize(data, -1);
+      if(data->req.no_body) {
+        state(data, SSH_STOP);
+        break;
+      }
+
+      /*
+       * This is a directory that we are trying to get, so produce a directory
+       * listing
+       */
+      sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
+                                    protop->path);
+      if(!sshc->sftp_dir) {
+        failf(data, "Could not open directory for reading: %s",
+              ssh_get_error(sshc->ssh_session));
+        MOVE_TO_SFTP_CLOSE_STATE();
+        break;
+      }
+      state(data, SSH_SFTP_READDIR);
+      break;
+
+    case SSH_SFTP_READDIR:
+      Curl_dyn_reset(&sshc->readdir_buf);
+      if(sshc->readdir_attrs)
+        sftp_attributes_free(sshc->readdir_attrs);
+
+      sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
+      if(sshc->readdir_attrs) {
+        sshc->readdir_filename = sshc->readdir_attrs->name;
+        sshc->readdir_longentry = sshc->readdir_attrs->longname;
+        sshc->readdir_len = strlen(sshc->readdir_filename);
+
+        if(data->set.list_only) {
+          char *tmpLine;
+
+          tmpLine = aprintf("%s\n", sshc->readdir_filename);
+          if(!tmpLine) {
+            state(data, SSH_SFTP_CLOSE);
+            sshc->actualcode = CURLE_OUT_OF_MEMORY;
+            break;
+          }
+          result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                     tmpLine, sshc->readdir_len + 1);
+          free(tmpLine);
+
+          if(result) {
+            state(data, SSH_STOP);
+            break;
+          }
+
+        }
+        else {
+          if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
+            sshc->actualcode = CURLE_OUT_OF_MEMORY;
+            state(data, SSH_STOP);
+            break;
+          }
+
+          if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
+             ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
+              SSH_S_IFLNK)) {
+            sshc->readdir_linkPath = aprintf("%s%s", protop->path,
+                                             sshc->readdir_filename);
+
+            if(!sshc->readdir_linkPath) {
+              state(data, SSH_SFTP_CLOSE);
+              sshc->actualcode = CURLE_OUT_OF_MEMORY;
+              break;
+            }
+
+            state(data, SSH_SFTP_READDIR_LINK);
+            break;
+          }
+          state(data, SSH_SFTP_READDIR_BOTTOM);
+          break;
+        }
+      }
+      else if(sftp_dir_eof(sshc->sftp_dir)) {
+        state(data, SSH_SFTP_READDIR_DONE);
+        break;
+      }
+      else {
+        failf(data, "Could not open remote file for reading: %s",
+              ssh_get_error(sshc->ssh_session));
+        MOVE_TO_SFTP_CLOSE_STATE();
+        break;
+      }
+      break;
+
+    case SSH_SFTP_READDIR_LINK:
+      if(sshc->readdir_link_attrs)
+        sftp_attributes_free(sshc->readdir_link_attrs);
+
+      sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
+                                            sshc->readdir_linkPath);
+      if(sshc->readdir_link_attrs == 0) {
+        failf(data, "Could not read symlink for reading: %s",
+              ssh_get_error(sshc->ssh_session));
+        MOVE_TO_SFTP_CLOSE_STATE();
+        break;
+      }
+
+      if(!sshc->readdir_link_attrs->name) {
+        sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
+                                          sshc->readdir_linkPath);
+        if(!sshc->readdir_filename)
+          sshc->readdir_len = 0;
+        else
+          sshc->readdir_len = strlen(sshc->readdir_tmp);
+        sshc->readdir_longentry = NULL;
+        sshc->readdir_filename = sshc->readdir_tmp;
+      }
+      else {
+        sshc->readdir_len = strlen(sshc->readdir_link_attrs->name);
+        sshc->readdir_filename = sshc->readdir_link_attrs->name;
+        sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
+      }
+
+      Curl_safefree(sshc->readdir_linkPath);
+
+      if(Curl_dyn_addf(&sshc->readdir_buf, " -> %s",
+                       sshc->readdir_filename)) {
+        sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        break;
+      }
+
+      sftp_attributes_free(sshc->readdir_link_attrs);
+      sshc->readdir_link_attrs = NULL;
+      sshc->readdir_filename = NULL;
+      sshc->readdir_longentry = NULL;
+
+      state(data, SSH_SFTP_READDIR_BOTTOM);
+      FALLTHROUGH();
+    case SSH_SFTP_READDIR_BOTTOM:
+      if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1))
+        result = CURLE_OUT_OF_MEMORY;
+      else
+        result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                   Curl_dyn_ptr(&sshc->readdir_buf),
+                                   Curl_dyn_len(&sshc->readdir_buf));
+
+      ssh_string_free_char(sshc->readdir_tmp);
+      sshc->readdir_tmp = NULL;
+
+      if(result) {
+        state(data, SSH_STOP);
+      }
+      else
+        state(data, SSH_SFTP_READDIR);
+      break;
+
+    case SSH_SFTP_READDIR_DONE:
+      sftp_closedir(sshc->sftp_dir);
+      sshc->sftp_dir = NULL;
+
+      /* no data to transfer */
+      Curl_xfer_setup(data, -1, -1, FALSE, -1);
+      state(data, SSH_STOP);
+      break;
+
+    case SSH_SFTP_DOWNLOAD_INIT:
+      /*
+       * Work on getting the specified file
+       */
+      if(sshc->sftp_file)
+        sftp_close(sshc->sftp_file);
+
+      sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path,
+                                  O_RDONLY, (mode_t)data->set.new_file_perms);
+      if(!sshc->sftp_file) {
+        failf(data, "Could not open remote file for reading: %s",
+              ssh_get_error(sshc->ssh_session));
+
+        MOVE_TO_SFTP_CLOSE_STATE();
+        break;
+      }
+      sftp_file_set_nonblocking(sshc->sftp_file);
+      state(data, SSH_SFTP_DOWNLOAD_STAT);
+      break;
+
+    case SSH_SFTP_DOWNLOAD_STAT:
+    {
+      sftp_attributes attrs;
+      curl_off_t size;
+
+      attrs = sftp_fstat(sshc->sftp_file);
+      if(!attrs ||
+              !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
+              (attrs->size == 0)) {
+        /*
+         * sftp_fstat didn't return an error, so maybe the server
+         * just doesn't support stat()
+         * OR the server doesn't return a file size with a stat()
+         * OR file size is 0
+         */
+        data->req.size = -1;
+        data->req.maxdownload = -1;
+        Curl_pgrsSetDownloadSize(data, -1);
+        size = 0;
+      }
+      else {
+        size = attrs->size;
+
+        sftp_attributes_free(attrs);
+
+        if(size < 0) {
+          failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
+          return CURLE_BAD_DOWNLOAD_RESUME;
+        }
+        if(data->state.use_range) {
+          curl_off_t from, to;
+          char *ptr;
+          char *ptr2;
+          CURLofft to_t;
+          CURLofft from_t;
+
+          from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
+          if(from_t == CURL_OFFT_FLOW) {
+            return CURLE_RANGE_ERROR;
+          }
+          while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
+            ptr++;
+          to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
+          if(to_t == CURL_OFFT_FLOW) {
+            return CURLE_RANGE_ERROR;
+          }
+          if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
+             || (to >= size)) {
+            to = size - 1;
+          }
+          if(from_t) {
+            /* from is relative to end of file */
+            from = size - to;
+            to = size - 1;
+          }
+          if(from > size) {
+            failf(data, "Offset (%"
+                  CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
+                  CURL_FORMAT_CURL_OFF_T ")", from, size);
+            return CURLE_BAD_DOWNLOAD_RESUME;
+          }
+          if(from > to) {
+            from = to;
+            size = 0;
+          }
+          else {
+            if((to - from) == CURL_OFF_T_MAX)
+              return CURLE_RANGE_ERROR;
+            size = to - from + 1;
+          }
+
+          rc = sftp_seek64(sshc->sftp_file, from);
+          if(rc) {
+            MOVE_TO_SFTP_CLOSE_STATE();
+            break;
+          }
+        }
+        data->req.size = size;
+        data->req.maxdownload = size;
+        Curl_pgrsSetDownloadSize(data, size);
+      }
+
+      /* We can resume if we can seek to the resume position */
+      if(data->state.resume_from) {
+        if(data->state.resume_from < 0) {
+          /* We're supposed to download the last abs(from) bytes */
+          if((curl_off_t)size < -data->state.resume_from) {
+            failf(data, "Offset (%"
+                  CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
+                  CURL_FORMAT_CURL_OFF_T ")",
+                  data->state.resume_from, size);
+            return CURLE_BAD_DOWNLOAD_RESUME;
+          }
+          /* download from where? */
+          data->state.resume_from += size;
+        }
+        else {
+          if((curl_off_t)size < data->state.resume_from) {
+            failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
+                  ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
+                  data->state.resume_from, size);
+            return CURLE_BAD_DOWNLOAD_RESUME;
+          }
+        }
+        /* Now store the number of bytes we are expected to download */
+        data->req.size = size - data->state.resume_from;
+        data->req.maxdownload = size - data->state.resume_from;
+        Curl_pgrsSetDownloadSize(data,
+                                 size - data->state.resume_from);
+
+        rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
+        if(rc) {
+          MOVE_TO_SFTP_CLOSE_STATE();
+          break;
+        }
+      }
+    }
+
+    /* Setup the actual download */
+    if(data->req.size == 0) {
+      /* no data to transfer */
+      Curl_xfer_setup(data, -1, -1, FALSE, -1);
+      infof(data, "File already completely downloaded");
+      state(data, SSH_STOP);
+      break;
+    }
+    Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);
+
+    /* not set by Curl_xfer_setup to preserve keepon bits */
+    conn->writesockfd = conn->sockfd;
+
+    /* we want to use the _receiving_ function even when the socket turns
+       out writableable as the underlying libssh recv function will deal
+       with both accordingly */
+    data->state.select_bits = CURL_CSELECT_IN;
+
+    if(result) {
+      /* this should never occur; the close state should be entered
+         at the time the error occurs */
+      state(data, SSH_SFTP_CLOSE);
+      sshc->actualcode = result;
+    }
+    else {
+      sshc->sftp_recv_state = 0;
+      state(data, SSH_STOP);
+    }
+    break;
+
+    case SSH_SFTP_CLOSE:
+      if(sshc->sftp_file) {
+        sftp_close(sshc->sftp_file);
+        sshc->sftp_file = NULL;
+      }
+      Curl_safefree(protop->path);
+
+      DEBUGF(infof(data, "SFTP DONE done"));
+
+      /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
+         After nextstate is executed, the control should come back to
+         SSH_SFTP_CLOSE to pass the correct result back  */
+      if(sshc->nextstate != SSH_NO_STATE &&
+         sshc->nextstate != SSH_SFTP_CLOSE) {
+        state(data, sshc->nextstate);
+        sshc->nextstate = SSH_SFTP_CLOSE;
+      }
+      else {
+        state(data, SSH_STOP);
+        result = sshc->actualcode;
+      }
+      break;
+
+    case SSH_SFTP_SHUTDOWN:
+      /* during times we get here due to a broken transfer and then the
+         sftp_handle might not have been taken down so make sure that is done
+         before we proceed */
+
+      if(sshc->sftp_file) {
+        sftp_close(sshc->sftp_file);
+        sshc->sftp_file = NULL;
+      }
+
+      if(sshc->sftp_session) {
+        sftp_free(sshc->sftp_session);
+        sshc->sftp_session = NULL;
+      }
+
+      SSH_STRING_FREE_CHAR(sshc->homedir);
+      data->state.most_recent_ftp_entrypath = NULL;
+
+      state(data, SSH_SESSION_DISCONNECT);
+      break;
+
+    case SSH_SCP_TRANS_INIT:
+      result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
+      if(result) {
+        sshc->actualcode = result;
+        state(data, SSH_STOP);
+        break;
+      }
+
+      /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */
+      ssh_set_blocking(sshc->ssh_session, 1);
+
+      if(data->state.upload) {
+        if(data->state.infilesize < 0) {
+          failf(data, "SCP requires a known file size for upload");
+          sshc->actualcode = CURLE_UPLOAD_FAILED;
+          MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
+          break;
+        }
+
+        sshc->scp_session =
+          ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path);
+        state(data, SSH_SCP_UPLOAD_INIT);
+      }
+      else {
+        sshc->scp_session =
+          ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path);
+        state(data, SSH_SCP_DOWNLOAD_INIT);
+      }
+
+      if(!sshc->scp_session) {
+        err_msg = ssh_get_error(sshc->ssh_session);
+        failf(data, "%s", err_msg);
+        MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
+      }
+
+      break;
+
+    case SSH_SCP_UPLOAD_INIT:
+
+      rc = ssh_scp_init(sshc->scp_session);
+      if(rc != SSH_OK) {
+        err_msg = ssh_get_error(sshc->ssh_session);
+        failf(data, "%s", err_msg);
+        MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
+        break;
+      }
+
+      rc = ssh_scp_push_file(sshc->scp_session, protop->path,
+                             data->state.infilesize,
+                             (int)data->set.new_file_perms);
+      if(rc != SSH_OK) {
+        err_msg = ssh_get_error(sshc->ssh_session);
+        failf(data, "%s", err_msg);
+        MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
+        break;
+      }
+
+      /* upload data */
+      Curl_xfer_setup(data, -1, data->req.size, FALSE, FIRSTSOCKET);
+
+      /* not set by Curl_xfer_setup to preserve keepon bits */
+      conn->sockfd = conn->writesockfd;
+
+      /* store this original bitmask setup to use later on if we can't
+         figure out a "real" bitmask */
+      sshc->orig_waitfor = data->req.keepon;
+
+      /* we want to use the _sending_ function even when the socket turns
+         out readable as the underlying libssh scp send function will deal
+         with both accordingly */
+      data->state.select_bits = CURL_CSELECT_OUT;
+
+      state(data, SSH_STOP);
+
+      break;
+
+    case SSH_SCP_DOWNLOAD_INIT:
+
+      rc = ssh_scp_init(sshc->scp_session);
+      if(rc != SSH_OK) {
+        err_msg = ssh_get_error(sshc->ssh_session);
+        failf(data, "%s", err_msg);
+        MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
+        break;
+      }
+      state(data, SSH_SCP_DOWNLOAD);
+      FALLTHROUGH();
+
+    case SSH_SCP_DOWNLOAD:{
+        curl_off_t bytecount;
+
+        rc = ssh_scp_pull_request(sshc->scp_session);
+        if(rc != SSH_SCP_REQUEST_NEWFILE) {
+          err_msg = ssh_get_error(sshc->ssh_session);
+          failf(data, "%s", err_msg);
+          MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
+          break;
+        }
+
+        /* download data */
+        bytecount = ssh_scp_request_get_size(sshc->scp_session);
+        data->req.maxdownload = (curl_off_t) bytecount;
+        Curl_xfer_setup(data, FIRSTSOCKET, bytecount, FALSE, -1);
+
+        /* not set by Curl_xfer_setup to preserve keepon bits */
+        conn->writesockfd = conn->sockfd;
+
+        /* we want to use the _receiving_ function even when the socket turns
+           out writableable as the underlying libssh recv function will deal
+           with both accordingly */
+        data->state.select_bits = CURL_CSELECT_IN;
+
+        state(data, SSH_STOP);
+        break;
+      }
+    case SSH_SCP_DONE:
+      if(data->state.upload)
+        state(data, SSH_SCP_SEND_EOF);
+      else
+        state(data, SSH_SCP_CHANNEL_FREE);
+      break;
+
+    case SSH_SCP_SEND_EOF:
+      if(sshc->scp_session) {
+        rc = ssh_scp_close(sshc->scp_session);
+        if(rc == SSH_AGAIN) {
+          /* Currently the ssh_scp_close handles waiting for EOF in
+           * blocking way.
+           */
+          break;
+        }
+        if(rc != SSH_OK) {
+          infof(data, "Failed to close libssh scp channel: %s",
+                ssh_get_error(sshc->ssh_session));
+        }
+      }
+
+      state(data, SSH_SCP_CHANNEL_FREE);
+      break;
+
+    case SSH_SCP_CHANNEL_FREE:
+      if(sshc->scp_session) {
+        ssh_scp_free(sshc->scp_session);
+        sshc->scp_session = NULL;
+      }
+      DEBUGF(infof(data, "SCP DONE phase complete"));
+
+      ssh_set_blocking(sshc->ssh_session, 0);
+
+      state(data, SSH_SESSION_DISCONNECT);
+      FALLTHROUGH();
+
+    case SSH_SESSION_DISCONNECT:
+      /* during weird times when we've been prematurely aborted, the channel
+         is still alive when we reach this state and we MUST kill the channel
+         properly first */
+      if(sshc->scp_session) {
+        ssh_scp_free(sshc->scp_session);
+        sshc->scp_session = NULL;
+      }
+
+      ssh_disconnect(sshc->ssh_session);
+      if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) {
+        /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back,
+           tell the connection to forget about it. This libssh
+           bug is fixed in 0.10.0. */
+        Curl_conn_forget_socket(data, FIRSTSOCKET);
+      }
+
+      SSH_STRING_FREE_CHAR(sshc->homedir);
+      data->state.most_recent_ftp_entrypath = NULL;
+
+      state(data, SSH_SESSION_FREE);
+      FALLTHROUGH();
+    case SSH_SESSION_FREE:
+      if(sshc->ssh_session) {
+        ssh_free(sshc->ssh_session);
+        sshc->ssh_session = NULL;
+      }
+
+      /* worst-case scenario cleanup */
+
+      DEBUGASSERT(sshc->ssh_session == NULL);
+      DEBUGASSERT(sshc->scp_session == NULL);
+
+      if(sshc->readdir_tmp) {
+        ssh_string_free_char(sshc->readdir_tmp);
+        sshc->readdir_tmp = NULL;
+      }
+
+      if(sshc->quote_attrs)
+        sftp_attributes_free(sshc->quote_attrs);
+
+      if(sshc->readdir_attrs)
+        sftp_attributes_free(sshc->readdir_attrs);
+
+      if(sshc->readdir_link_attrs)
+        sftp_attributes_free(sshc->readdir_link_attrs);
+
+      if(sshc->privkey)
+        ssh_key_free(sshc->privkey);
+      if(sshc->pubkey)
+        ssh_key_free(sshc->pubkey);
+
+      Curl_safefree(sshc->rsa_pub);
+      Curl_safefree(sshc->rsa);
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      Curl_dyn_free(&sshc->readdir_buf);
+      Curl_safefree(sshc->readdir_linkPath);
+      SSH_STRING_FREE_CHAR(sshc->homedir);
+
+      /* the code we are about to return */
+      result = sshc->actualcode;
+
+      memset(sshc, 0, sizeof(struct ssh_conn));
+
+      connclose(conn, "SSH session free");
+      sshc->state = SSH_SESSION_FREE;   /* current */
+      sshc->nextstate = SSH_NO_STATE;
+      state(data, SSH_STOP);
+      break;
+
+    case SSH_QUIT:
+    default:
+      /* internal error */
+      sshc->nextstate = SSH_NO_STATE;
+      state(data, SSH_STOP);
+      break;
+
+    }
+  } while(!rc && (sshc->state != SSH_STOP));
+
+
+  if(rc == SSH_AGAIN) {
+    /* we would block, we need to wait for the socket to be ready (in the
+       right direction too)! */
+    *block = TRUE;
+  }
+
+  return result;
+}
+
+
+/* called by the multi interface to figure out what socket(s) to wait for and
+   for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
+static int myssh_getsock(struct Curl_easy *data,
+                         struct connectdata *conn,
+                         curl_socket_t *sock)
+{
+  int bitmap = GETSOCK_BLANK;
+  (void)data;
+  sock[0] = conn->sock[FIRSTSOCKET];
+
+  if(conn->waitfor & KEEP_RECV)
+    bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
+
+  if(conn->waitfor & KEEP_SEND)
+    bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
+
+  if(!conn->waitfor)
+    bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
+
+  return bitmap;
+}
+
+static void myssh_block2waitfor(struct connectdata *conn, bool block)
+{
+  struct ssh_conn *sshc = &conn->proto.sshc;
+
+  /* If it didn't block, or nothing was returned by ssh_get_poll_flags
+   * have the original set */
+  conn->waitfor = sshc->orig_waitfor;
+
+  if(block) {
+    int dir = ssh_get_poll_flags(sshc->ssh_session);
+    if(dir & SSH_READ_PENDING) {
+      /* translate the libssh define bits into our own bit defines */
+      conn->waitfor = KEEP_RECV;
+    }
+    else if(dir & SSH_WRITE_PENDING) {
+      conn->waitfor = KEEP_SEND;
+    }
+  }
+}
+
+/* called repeatedly until done from multi.c */
+static CURLcode myssh_multi_statemach(struct Curl_easy *data,
+                                      bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  bool block;    /* we store the status and use that to provide a ssh_getsock()
+                    implementation */
+  CURLcode result = myssh_statemach_act(data, &block);
+
+  *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
+  myssh_block2waitfor(conn, block);
+
+  return result;
+}
+
+static CURLcode myssh_block_statemach(struct Curl_easy *data,
+                                      bool disconnect)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  CURLcode result = CURLE_OK;
+
+  while((sshc->state != SSH_STOP) && !result) {
+    bool block;
+    timediff_t left = 1000;
+    struct curltime now = Curl_now();
+
+    result = myssh_statemach_act(data, &block);
+    if(result)
+      break;
+
+    if(!disconnect) {
+      if(Curl_pgrsUpdate(data))
+        return CURLE_ABORTED_BY_CALLBACK;
+
+      result = Curl_speedcheck(data, now);
+      if(result)
+        break;
+
+      left = Curl_timeleft(data, NULL, FALSE);
+      if(left < 0) {
+        failf(data, "Operation timed out");
+        return CURLE_OPERATION_TIMEDOUT;
+      }
+    }
+
+    if(block) {
+      curl_socket_t fd_read = conn->sock[FIRSTSOCKET];
+      /* wait for the socket to become ready */
+      (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD,
+                               CURL_SOCKET_BAD, left > 1000 ? 1000 : left);
+    }
+
+  }
+
+  return result;
+}
+
+/*
+ * SSH setup connection
+ */
+static CURLcode myssh_setup_connection(struct Curl_easy *data,
+                                       struct connectdata *conn)
+{
+  struct SSHPROTO *ssh;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+
+  data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
+  if(!ssh)
+    return CURLE_OUT_OF_MEMORY;
+  Curl_dyn_init(&sshc->readdir_buf, PATH_MAX * 2);
+
+  return CURLE_OK;
+}
+
+static Curl_recv scp_recv, sftp_recv;
+static Curl_send scp_send, sftp_send;
+
+/*
+ * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
+ * do protocol-specific actions at connect-time.
+ */
+static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
+{
+  struct ssh_conn *ssh;
+  CURLcode result;
+  struct connectdata *conn = data->conn;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  int rc;
+
+  /* initialize per-handle data if not already */
+  if(!data->req.p.ssh)
+    myssh_setup_connection(data, conn);
+
+  /* We default to persistent connections. We set this already in this connect
+     function to make the reuse checks properly be able to check this bit. */
+  connkeep(conn, "SSH default");
+
+  if(conn->handler->protocol & CURLPROTO_SCP) {
+    conn->recv[FIRSTSOCKET] = scp_recv;
+    conn->send[FIRSTSOCKET] = scp_send;
+  }
+  else {
+    conn->recv[FIRSTSOCKET] = sftp_recv;
+    conn->send[FIRSTSOCKET] = sftp_send;
+  }
+
+  ssh = &conn->proto.sshc;
+
+  ssh->ssh_session = ssh_new();
+  if(!ssh->ssh_session) {
+    failf(data, "Failure initialising ssh session");
+    return CURLE_FAILED_INIT;
+  }
+
+  rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
+  if(rc != SSH_OK) {
+    failf(data, "Could not set remote host");
+    return CURLE_FAILED_INIT;
+  }
+
+  rc = ssh_options_parse_config(ssh->ssh_session, NULL);
+  if(rc != SSH_OK) {
+    infof(data, "Could not parse SSH configuration files");
+    /* ignore */
+  }
+
+  rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
+  if(rc != SSH_OK) {
+    failf(data, "Could not set socket");
+    return CURLE_FAILED_INIT;
+  }
+
+  if(conn->user && conn->user[0] != '\0') {
+    infof(data, "User: %s", conn->user);
+    rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
+    if(rc != SSH_OK) {
+      failf(data, "Could not set user");
+      return CURLE_FAILED_INIT;
+    }
+  }
+
+  if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
+    infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
+    rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
+                         data->set.str[STRING_SSH_KNOWNHOSTS]);
+    if(rc != SSH_OK) {
+      failf(data, "Could not set known hosts file path");
+      return CURLE_FAILED_INIT;
+    }
+  }
+
+  if(conn->remote_port) {
+    rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
+                         &conn->remote_port);
+    if(rc != SSH_OK) {
+      failf(data, "Could not set remote port");
+      return CURLE_FAILED_INIT;
+    }
+  }
+
+  if(data->set.ssh_compression) {
+    rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
+                         "zlib,zlib@openssh.com,none");
+    if(rc != SSH_OK) {
+      failf(data, "Could not set compression");
+      return CURLE_FAILED_INIT;
+    }
+  }
+
+  ssh->privkey = NULL;
+  ssh->pubkey = NULL;
+
+  if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
+    rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
+                                    &ssh->pubkey);
+    if(rc != SSH_OK) {
+      failf(data, "Could not load public key file");
+      return CURLE_FAILED_INIT;
+    }
+  }
+
+  /* we do not verify here, we do it at the state machine,
+   * after connection */
+
+  state(data, SSH_INIT);
+
+  result = myssh_multi_statemach(data, done);
+
+  return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
+{
+  CURLcode result;
+
+  result = myssh_multi_statemach(data, dophase_done);
+
+  if(*dophase_done) {
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+  return result;
+}
+
+/*
+ ***********************************************************************
+ *
+ * scp_perform()
+ *
+ * This is the actual DO function for SCP. Get a file according to
+ * the options previously setup.
+ */
+
+static
+CURLcode scp_perform(struct Curl_easy *data,
+                     bool *connected, bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGF(infof(data, "DO phase starts"));
+
+  *dophase_done = FALSE;        /* not done yet */
+
+  /* start the first command in the DO phase */
+  state(data, SSH_SCP_TRANS_INIT);
+
+  result = myssh_multi_statemach(data, dophase_done);
+
+  *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
+
+  if(*dophase_done) {
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+
+  return result;
+}
+
+static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
+{
+  CURLcode result;
+  bool connected = 0;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+
+  *done = FALSE;                /* default to false */
+
+  data->req.size = -1;          /* make sure this is unknown at this point */
+
+  sshc->actualcode = CURLE_OK;  /* reset error code */
+  sshc->secondCreateDirs = 0;   /* reset the create dir attempt state
+                                   variable */
+
+  Curl_pgrsSetUploadCounter(data, 0);
+  Curl_pgrsSetDownloadCounter(data, 0);
+  Curl_pgrsSetUploadSize(data, -1);
+  Curl_pgrsSetDownloadSize(data, -1);
+
+  if(conn->handler->protocol & CURLPROTO_SCP)
+    result = scp_perform(data, &connected, done);
+  else
+    result = sftp_perform(data, &connected, done);
+
+  return result;
+}
+
+/* BLOCKING, but the function is using the state machine so the only reason
+   this is still blocking is that the multi interface code has no support for
+   disconnecting operations that takes a while */
+static CURLcode scp_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn,
+                               bool dead_connection)
+{
+  CURLcode result = CURLE_OK;
+  struct ssh_conn *ssh = &conn->proto.sshc;
+  (void) dead_connection;
+
+  if(ssh->ssh_session) {
+    /* only if there's a session still around to use! */
+
+    state(data, SSH_SESSION_DISCONNECT);
+
+    result = myssh_block_statemach(data, TRUE);
+  }
+
+  return result;
+}
+
+/* generic done function for both SCP and SFTP called from their specific
+   done functions */
+static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
+{
+  CURLcode result = CURLE_OK;
+  struct SSHPROTO *protop = data->req.p.ssh;
+
+  if(!status) {
+    /* run the state-machine */
+    result = myssh_block_statemach(data, FALSE);
+  }
+  else
+    result = status;
+
+  if(protop)
+    Curl_safefree(protop->path);
+  if(Curl_pgrsDone(data))
+    return CURLE_ABORTED_BY_CALLBACK;
+
+  data->req.keepon = 0;   /* clear all bits */
+  return result;
+}
+
+
+static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
+                         bool premature)
+{
+  (void) premature;             /* not used */
+
+  if(!status)
+    state(data, SSH_SCP_DONE);
+
+  return myssh_done(data, status);
+
+}
+
+static ssize_t scp_send(struct Curl_easy *data, int sockindex,
+                        const void *mem, size_t len, CURLcode *err)
+{
+  int rc;
+  struct connectdata *conn = data->conn;
+  (void) sockindex; /* we only support SCP on the fixed known primary socket */
+  (void) err;
+
+  rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
+
+#if 0
+  /* The following code is misleading, mostly added as wishful thinking
+   * that libssh at some point will implement non-blocking ssh_scp_write/read.
+   * Currently rc can only be number of bytes read or SSH_ERROR. */
+  myssh_block2waitfor(conn, (rc == SSH_AGAIN) ? TRUE : FALSE);
+
+  if(rc == SSH_AGAIN) {
+    *err = CURLE_AGAIN;
+    return 0;
+  }
+  else
+#endif
+  if(rc != SSH_OK) {
+    *err = CURLE_SSH;
+    return -1;
+  }
+
+  return len;
+}
+
+static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
+                        char *mem, size_t len, CURLcode *err)
+{
+  ssize_t nread;
+  struct connectdata *conn = data->conn;
+  (void) err;
+  (void) sockindex; /* we only support SCP on the fixed known primary socket */
+
+  /* libssh returns int */
+  nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
+
+#if 0
+  /* The following code is misleading, mostly added as wishful thinking
+   * that libssh at some point will implement non-blocking ssh_scp_write/read.
+   * Currently rc can only be SSH_OK or SSH_ERROR. */
+
+  myssh_block2waitfor(conn, (nread == SSH_AGAIN) ? TRUE : FALSE);
+  if(nread == SSH_AGAIN) {
+    *err = CURLE_AGAIN;
+    nread = -1;
+  }
+#endif
+
+  return nread;
+}
+
+/*
+ * =============== SFTP ===============
+ */
+
+/*
+ ***********************************************************************
+ *
+ * sftp_perform()
+ *
+ * This is the actual DO function for SFTP. Get a file/directory according to
+ * the options previously setup.
+ */
+
+static
+CURLcode sftp_perform(struct Curl_easy *data,
+                      bool *connected,
+                      bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGF(infof(data, "DO phase starts"));
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* start the first command in the DO phase */
+  state(data, SSH_SFTP_QUOTE_INIT);
+
+  /* run the state-machine */
+  result = myssh_multi_statemach(data, dophase_done);
+
+  *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
+
+  if(*dophase_done) {
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+
+  return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode sftp_doing(struct Curl_easy *data,
+                           bool *dophase_done)
+{
+  CURLcode result = myssh_multi_statemach(data, dophase_done);
+  if(*dophase_done) {
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+  return result;
+}
+
+/* BLOCKING, but the function is using the state machine so the only reason
+   this is still blocking is that the multi interface code has no support for
+   disconnecting operations that takes a while */
+static CURLcode sftp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                bool dead_connection)
+{
+  CURLcode result = CURLE_OK;
+  (void) dead_connection;
+
+  DEBUGF(infof(data, "SSH DISCONNECT starts now"));
+
+  if(conn->proto.sshc.ssh_session) {
+    /* only if there's a session still around to use! */
+    state(data, SSH_SFTP_SHUTDOWN);
+    result = myssh_block_statemach(data, TRUE);
+  }
+
+  DEBUGF(infof(data, "SSH DISCONNECT is done"));
+
+  return result;
+
+}
+
+static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
+                          bool premature)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+
+  if(!status) {
+    /* Post quote commands are executed after the SFTP_CLOSE state to avoid
+       errors that could happen due to open file handles during POSTQUOTE
+       operation */
+    if(!premature && data->set.postquote && !conn->bits.retry)
+      sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
+    state(data, SSH_SFTP_CLOSE);
+  }
+  return myssh_done(data, status);
+}
+
+/* return number of sent bytes */
+static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
+                         const void *mem, size_t len, CURLcode *err)
+{
+  ssize_t nwrite;
+  struct connectdata *conn = data->conn;
+  (void)sockindex;
+
+  /* limit the writes to the maximum specified in Section 3 of
+   * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
+   */
+  if(len > 32768)
+    len = 32768;
+
+  nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
+
+  myssh_block2waitfor(conn, FALSE);
+
+#if 0 /* not returned by libssh on write */
+  if(nwrite == SSH_AGAIN) {
+    *err = CURLE_AGAIN;
+    nwrite = 0;
+  }
+  else
+#endif
+  if(nwrite < 0) {
+    *err = CURLE_SSH;
+    nwrite = -1;
+  }
+
+  return nwrite;
+}
+
+/*
+ * Return number of received (decrypted) bytes
+ * or <0 on error
+ */
+static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
+                         char *mem, size_t len, CURLcode *err)
+{
+  ssize_t nread;
+  struct connectdata *conn = data->conn;
+  (void)sockindex;
+
+  DEBUGASSERT(len < CURL_MAX_READ_SIZE);
+
+  switch(conn->proto.sshc.sftp_recv_state) {
+    case 0:
+      conn->proto.sshc.sftp_file_index =
+        sftp_async_read_begin(conn->proto.sshc.sftp_file,
+                              (uint32_t)len);
+      if(conn->proto.sshc.sftp_file_index < 0) {
+        *err = CURLE_RECV_ERROR;
+        return -1;
+      }
+
+      FALLTHROUGH();
+    case 1:
+      conn->proto.sshc.sftp_recv_state = 1;
+
+      nread = sftp_async_read(conn->proto.sshc.sftp_file,
+                              mem, (uint32_t)len,
+                              conn->proto.sshc.sftp_file_index);
+
+      myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);
+
+      if(nread == SSH_AGAIN) {
+        *err = CURLE_AGAIN;
+        return -1;
+      }
+      else if(nread < 0) {
+        *err = CURLE_RECV_ERROR;
+        return -1;
+      }
+
+      conn->proto.sshc.sftp_recv_state = 0;
+      return nread;
+
+    default:
+      /* we never reach here */
+      return -1;
+  }
+}
+
+static void sftp_quote(struct Curl_easy *data)
+{
+  const char *cp;
+  struct connectdata *conn = data->conn;
+  struct SSHPROTO *protop = data->req.p.ssh;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  CURLcode result;
+
+  /*
+   * Support some of the "FTP" commands
+   */
+  char *cmd = sshc->quote_item->data;
+  sshc->acceptfail = FALSE;
+
+  /* if a command starts with an asterisk, which a legal SFTP command never
+     can, the command will be allowed to fail without it causing any
+     aborts or cancels etc. It will cause libcurl to act as if the command
+     is successful, whatever the server responds. */
+
+  if(cmd[0] == '*') {
+    cmd++;
+    sshc->acceptfail = TRUE;
+  }
+
+  if(strcasecompare("pwd", cmd)) {
+    /* output debug output if that is requested */
+    char *tmp = aprintf("257 \"%s\" is current directory.\n",
+                        protop->path);
+    if(!tmp) {
+      sshc->actualcode = CURLE_OUT_OF_MEMORY;
+      state(data, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      return;
+    }
+    Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
+    Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
+
+    /* this sends an FTP-like "header" to the header callback so that the
+       current directory can be read very similar to how it is read when
+       using ordinary FTP. */
+    result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+    free(tmp);
+    if(result) {
+      state(data, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = result;
+    }
+    else
+      state(data, SSH_SFTP_NEXT_QUOTE);
+    return;
+  }
+
+  /*
+   * the arguments following the command must be separated from the
+   * command with a space so we can check for it unconditionally
+   */
+  cp = strchr(cmd, ' ');
+  if(!cp) {
+    failf(data, "Syntax error in SFTP command. Supply parameter(s)");
+    state(data, SSH_SFTP_CLOSE);
+    sshc->nextstate = SSH_NO_STATE;
+    sshc->actualcode = CURLE_QUOTE_ERROR;
+    return;
+  }
+
+  /*
+   * also, every command takes at least one argument so we get that
+   * first argument right now
+   */
+  result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
+  if(result) {
+    if(result == CURLE_OUT_OF_MEMORY)
+      failf(data, "Out of memory");
+    else
+      failf(data, "Syntax error: Bad first parameter");
+    state(data, SSH_SFTP_CLOSE);
+    sshc->nextstate = SSH_NO_STATE;
+    sshc->actualcode = result;
+    return;
+  }
+
+  /*
+   * SFTP is a binary protocol, so we don't send text commands
+   * to the server. Instead, we scan for commands used by
+   * OpenSSH's sftp program and call the appropriate libssh
+   * functions.
+   */
+  if(strncasecompare(cmd, "chgrp ", 6) ||
+     strncasecompare(cmd, "chmod ", 6) ||
+     strncasecompare(cmd, "chown ", 6) ||
+     strncasecompare(cmd, "atime ", 6) ||
+     strncasecompare(cmd, "mtime ", 6)) {
+    /* attribute change */
+
+    /* sshc->quote_path1 contains the mode to set */
+    /* get the destination */
+    result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+    if(result) {
+      if(result == CURLE_OUT_OF_MEMORY)
+        failf(data, "Out of memory");
+      else
+        failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
+              "Bad second parameter");
+      Curl_safefree(sshc->quote_path1);
+      state(data, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = result;
+      return;
+    }
+    sshc->quote_attrs = NULL;
+    state(data, SSH_SFTP_QUOTE_STAT);
+    return;
+  }
+  if(strncasecompare(cmd, "ln ", 3) ||
+     strncasecompare(cmd, "symlink ", 8)) {
+    /* symbolic linking */
+    /* sshc->quote_path1 is the source */
+    /* get the destination */
+    result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+    if(result) {
+      if(result == CURLE_OUT_OF_MEMORY)
+        failf(data, "Out of memory");
+      else
+        failf(data, "Syntax error in ln/symlink: Bad second parameter");
+      Curl_safefree(sshc->quote_path1);
+      state(data, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = result;
+      return;
+    }
+    state(data, SSH_SFTP_QUOTE_SYMLINK);
+    return;
+  }
+  else if(strncasecompare(cmd, "mkdir ", 6)) {
+    /* create dir */
+    state(data, SSH_SFTP_QUOTE_MKDIR);
+    return;
+  }
+  else if(strncasecompare(cmd, "rename ", 7)) {
+    /* rename file */
+    /* first param is the source path */
+    /* second param is the dest. path */
+    result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+    if(result) {
+      if(result == CURLE_OUT_OF_MEMORY)
+        failf(data, "Out of memory");
+      else
+        failf(data, "Syntax error in rename: Bad second parameter");
+      Curl_safefree(sshc->quote_path1);
+      state(data, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = result;
+      return;
+    }
+    state(data, SSH_SFTP_QUOTE_RENAME);
+    return;
+  }
+  else if(strncasecompare(cmd, "rmdir ", 6)) {
+    /* delete dir */
+    state(data, SSH_SFTP_QUOTE_RMDIR);
+    return;
+  }
+  else if(strncasecompare(cmd, "rm ", 3)) {
+    state(data, SSH_SFTP_QUOTE_UNLINK);
+    return;
+  }
+#ifdef HAS_STATVFS_SUPPORT
+  else if(strncasecompare(cmd, "statvfs ", 8)) {
+    state(data, SSH_SFTP_QUOTE_STATVFS);
+    return;
+  }
+#endif
+
+  failf(data, "Unknown SFTP command");
+  Curl_safefree(sshc->quote_path1);
+  Curl_safefree(sshc->quote_path2);
+  state(data, SSH_SFTP_CLOSE);
+  sshc->nextstate = SSH_NO_STATE;
+  sshc->actualcode = CURLE_QUOTE_ERROR;
+}
+
+static void sftp_quote_stat(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  char *cmd = sshc->quote_item->data;
+  sshc->acceptfail = FALSE;
+
+  /* if a command starts with an asterisk, which a legal SFTP command never
+     can, the command will be allowed to fail without it causing any
+     aborts or cancels etc. It will cause libcurl to act as if the command
+     is successful, whatever the server responds. */
+
+  if(cmd[0] == '*') {
+    cmd++;
+    sshc->acceptfail = TRUE;
+  }
+
+  /* We read the file attributes, store them in sshc->quote_attrs
+   * and modify them accordingly to command. Then we switch to
+   * QUOTE_SETSTAT state to write new ones.
+   */
+
+  if(sshc->quote_attrs)
+    sftp_attributes_free(sshc->quote_attrs);
+  sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
+  if(!sshc->quote_attrs) {
+    Curl_safefree(sshc->quote_path1);
+    Curl_safefree(sshc->quote_path2);
+    failf(data, "Attempt to get SFTP stats failed: %d",
+          sftp_get_error(sshc->sftp_session));
+    state(data, SSH_SFTP_CLOSE);
+    sshc->nextstate = SSH_NO_STATE;
+    sshc->actualcode = CURLE_QUOTE_ERROR;
+    return;
+  }
+
+  /* Now set the new attributes... */
+  if(strncasecompare(cmd, "chgrp", 5)) {
+    sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
+    if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+        !sshc->acceptfail) {
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      failf(data, "Syntax error: chgrp gid not a number");
+      state(data, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_QUOTE_ERROR;
+      return;
+    }
+    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
+  }
+  else if(strncasecompare(cmd, "chmod", 5)) {
+    mode_t perms;
+    perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
+    /* permissions are octal */
+    if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      failf(data, "Syntax error: chmod permissions not a number");
+      state(data, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_QUOTE_ERROR;
+      return;
+    }
+    sshc->quote_attrs->permissions = perms;
+    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
+  }
+  else if(strncasecompare(cmd, "chown", 5)) {
+    sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
+    if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+        !sshc->acceptfail) {
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      failf(data, "Syntax error: chown uid not a number");
+      state(data, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_QUOTE_ERROR;
+      return;
+    }
+    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
+  }
+  else if(strncasecompare(cmd, "atime", 5) ||
+          strncasecompare(cmd, "mtime", 5)) {
+    time_t date = Curl_getdate_capped(sshc->quote_path1);
+    bool fail = FALSE;
+    if(date == -1) {
+      failf(data, "incorrect date format for %.*s", 5, cmd);
+      fail = TRUE;
+    }
+#if SIZEOF_TIME_T > 4
+    else if(date > 0xffffffff) {
+      failf(data, "date overflow");
+      fail = TRUE; /* avoid setting a capped time */
+    }
+#endif
+    if(fail) {
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      state(data, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_QUOTE_ERROR;
+      return;
+    }
+    if(strncasecompare(cmd, "atime", 5))
+      sshc->quote_attrs->atime = (uint32_t)date;
+    else /* mtime */
+      sshc->quote_attrs->mtime = (uint32_t)date;
+
+    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
+  }
+
+  /* Now send the completed structure... */
+  state(data, SSH_SFTP_QUOTE_SETSTAT);
+  return;
+}
+
+CURLcode Curl_ssh_init(void)
+{
+  if(ssh_init()) {
+    DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
+    return CURLE_FAILED_INIT;
+  }
+  return CURLE_OK;
+}
+
+void Curl_ssh_cleanup(void)
+{
+  (void)ssh_finalize();
+}
+
+void Curl_ssh_version(char *buffer, size_t buflen)
+{
+  (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
+}
+
+#endif                          /* USE_LIBSSH */
Index: trunk/src/libs/curl-8.7.1/lib/vssh/libssh2.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vssh/libssh2.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vssh/libssh2.c	(revision 104083)
@@ -0,0 +1,3834 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* #define CURL_LIBSSH2_DEBUG */
+
+#include "curl_setup.h"
+
+#ifdef USE_LIBSSH2
+
+#include <limits.h>
+
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "ssh.h"
+#include "url.h"
+#include "speedcheck.h"
+#include "getinfo.h"
+#include "strdup.h"
+#include "strcase.h"
+#include "vtls/vtls.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "inet_ntop.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "strtoofft.h"
+#include "multiif.h"
+#include "select.h"
+#include "warnless.h"
+#include "curl_path.h"
+
+#include <curl_base64.h> /* for base64 encoding/decoding */
+#include <curl_sha256.h>
+
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if LIBSSH2_VERSION_NUM >= 0x010206
+/* libssh2_sftp_statvfs and friends were added in 1.2.6 */
+#define HAS_STATVFS_SUPPORT 1
+#endif
+
+#define sftp_libssh2_realpath(s,p,t,m)                          \
+  libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)),    \
+                          (t), (m), LIBSSH2_SFTP_REALPATH)
+
+/* Local functions: */
+static const char *sftp_libssh2_strerror(unsigned long err);
+static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
+static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
+static LIBSSH2_FREE_FUNC(my_libssh2_free);
+static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data);
+static CURLcode ssh_connect(struct Curl_easy *data, bool *done);
+static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done);
+static CURLcode ssh_do(struct Curl_easy *data, bool *done);
+static CURLcode scp_done(struct Curl_easy *data, CURLcode c, bool premature);
+static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
+static CURLcode scp_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn, bool dead_connection);
+static CURLcode sftp_done(struct Curl_easy *data, CURLcode, bool premature);
+static CURLcode sftp_doing(struct Curl_easy *data, bool *dophase_done);
+static CURLcode sftp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
+static CURLcode sftp_perform(struct Curl_easy *data, bool *connected,
+                             bool *dophase_done);
+static int ssh_getsock(struct Curl_easy *data, struct connectdata *conn,
+                       curl_socket_t *sock);
+static CURLcode ssh_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn);
+static void ssh_attach(struct Curl_easy *data, struct connectdata *conn);
+
+/*
+ * SCP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_scp = {
+  "SCP",                                /* scheme */
+  ssh_setup_connection,                 /* setup_connection */
+  ssh_do,                               /* do_it */
+  scp_done,                             /* done */
+  ZERO_NULL,                            /* do_more */
+  ssh_connect,                          /* connect_it */
+  ssh_multi_statemach,                  /* connecting */
+  scp_doing,                            /* doing */
+  ssh_getsock,                          /* proto_getsock */
+  ssh_getsock,                          /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ssh_getsock,                          /* perform_getsock */
+  scp_disconnect,                       /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ssh_attach,                           /* attach */
+  PORT_SSH,                             /* defport */
+  CURLPROTO_SCP,                        /* protocol */
+  CURLPROTO_SCP,                        /* family */
+  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+  | PROTOPT_NOURLQUERY                  /* flags */
+};
+
+
+/*
+ * SFTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_sftp = {
+  "SFTP",                               /* scheme */
+  ssh_setup_connection,                 /* setup_connection */
+  ssh_do,                               /* do_it */
+  sftp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  ssh_connect,                          /* connect_it */
+  ssh_multi_statemach,                  /* connecting */
+  sftp_doing,                           /* doing */
+  ssh_getsock,                          /* proto_getsock */
+  ssh_getsock,                          /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ssh_getsock,                          /* perform_getsock */
+  sftp_disconnect,                      /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ssh_attach,                           /* attach */
+  PORT_SSH,                             /* defport */
+  CURLPROTO_SFTP,                       /* protocol */
+  CURLPROTO_SFTP,                       /* family */
+  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+  | PROTOPT_NOURLQUERY                  /* flags */
+};
+
+static void
+kbd_callback(const char *name, int name_len, const char *instruction,
+             int instruction_len, int num_prompts,
+             const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
+             LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
+             void **abstract)
+{
+  struct Curl_easy *data = (struct Curl_easy *)*abstract;
+
+#ifdef CURL_LIBSSH2_DEBUG
+  fprintf(stderr, "name=%s\n", name);
+  fprintf(stderr, "name_len=%d\n", name_len);
+  fprintf(stderr, "instruction=%s\n", instruction);
+  fprintf(stderr, "instruction_len=%d\n", instruction_len);
+  fprintf(stderr, "num_prompts=%d\n", num_prompts);
+#else
+  (void)name;
+  (void)name_len;
+  (void)instruction;
+  (void)instruction_len;
+#endif  /* CURL_LIBSSH2_DEBUG */
+  if(num_prompts == 1) {
+    struct connectdata *conn = data->conn;
+    responses[0].text = strdup(conn->passwd);
+    responses[0].length = curlx_uztoui(strlen(conn->passwd));
+  }
+  (void)prompts;
+} /* kbd_callback */
+
+static CURLcode sftp_libssh2_error_to_CURLE(unsigned long err)
+{
+  switch(err) {
+    case LIBSSH2_FX_OK:
+      return CURLE_OK;
+
+    case LIBSSH2_FX_NO_SUCH_FILE:
+    case LIBSSH2_FX_NO_SUCH_PATH:
+      return CURLE_REMOTE_FILE_NOT_FOUND;
+
+    case LIBSSH2_FX_PERMISSION_DENIED:
+    case LIBSSH2_FX_WRITE_PROTECT:
+    case LIBSSH2_FX_LOCK_CONFlICT:
+      return CURLE_REMOTE_ACCESS_DENIED;
+
+    case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
+    case LIBSSH2_FX_QUOTA_EXCEEDED:
+      return CURLE_REMOTE_DISK_FULL;
+
+    case LIBSSH2_FX_FILE_ALREADY_EXISTS:
+      return CURLE_REMOTE_FILE_EXISTS;
+
+    case LIBSSH2_FX_DIR_NOT_EMPTY:
+      return CURLE_QUOTE_ERROR;
+
+    default:
+      break;
+  }
+
+  return CURLE_SSH;
+}
+
+static CURLcode libssh2_session_error_to_CURLE(int err)
+{
+  switch(err) {
+    /* Ordered by order of appearance in libssh2.h */
+    case LIBSSH2_ERROR_NONE:
+      return CURLE_OK;
+
+    /* This is the error returned by libssh2_scp_recv2
+     * on unknown file */
+    case LIBSSH2_ERROR_SCP_PROTOCOL:
+      return CURLE_REMOTE_FILE_NOT_FOUND;
+
+    case LIBSSH2_ERROR_SOCKET_NONE:
+      return CURLE_COULDNT_CONNECT;
+
+    case LIBSSH2_ERROR_ALLOC:
+      return CURLE_OUT_OF_MEMORY;
+
+    case LIBSSH2_ERROR_SOCKET_SEND:
+      return CURLE_SEND_ERROR;
+
+    case LIBSSH2_ERROR_HOSTKEY_INIT:
+    case LIBSSH2_ERROR_HOSTKEY_SIGN:
+    case LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED:
+    case LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED:
+      return CURLE_PEER_FAILED_VERIFICATION;
+
+    case LIBSSH2_ERROR_PASSWORD_EXPIRED:
+      return CURLE_LOGIN_DENIED;
+
+    case LIBSSH2_ERROR_SOCKET_TIMEOUT:
+    case LIBSSH2_ERROR_TIMEOUT:
+      return CURLE_OPERATION_TIMEDOUT;
+
+    case LIBSSH2_ERROR_EAGAIN:
+      return CURLE_AGAIN;
+  }
+
+  return CURLE_SSH;
+}
+
+static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc)
+{
+  (void)abstract; /* arg not used */
+  return malloc(count);
+}
+
+static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc)
+{
+  (void)abstract; /* arg not used */
+  return realloc(ptr, count);
+}
+
+static LIBSSH2_FREE_FUNC(my_libssh2_free)
+{
+  (void)abstract; /* arg not used */
+  if(ptr) /* ssh2 agent sometimes call free with null ptr */
+    free(ptr);
+}
+
+/*
+ * SSH State machine related code
+ */
+/* This is the ONLY way to change SSH state! */
+static void state(struct Curl_easy *data, sshstate nowstate)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[] = {
+    "SSH_STOP",
+    "SSH_INIT",
+    "SSH_S_STARTUP",
+    "SSH_HOSTKEY",
+    "SSH_AUTHLIST",
+    "SSH_AUTH_PKEY_INIT",
+    "SSH_AUTH_PKEY",
+    "SSH_AUTH_PASS_INIT",
+    "SSH_AUTH_PASS",
+    "SSH_AUTH_AGENT_INIT",
+    "SSH_AUTH_AGENT_LIST",
+    "SSH_AUTH_AGENT",
+    "SSH_AUTH_HOST_INIT",
+    "SSH_AUTH_HOST",
+    "SSH_AUTH_KEY_INIT",
+    "SSH_AUTH_KEY",
+    "SSH_AUTH_GSSAPI",
+    "SSH_AUTH_DONE",
+    "SSH_SFTP_INIT",
+    "SSH_SFTP_REALPATH",
+    "SSH_SFTP_QUOTE_INIT",
+    "SSH_SFTP_POSTQUOTE_INIT",
+    "SSH_SFTP_QUOTE",
+    "SSH_SFTP_NEXT_QUOTE",
+    "SSH_SFTP_QUOTE_STAT",
+    "SSH_SFTP_QUOTE_SETSTAT",
+    "SSH_SFTP_QUOTE_SYMLINK",
+    "SSH_SFTP_QUOTE_MKDIR",
+    "SSH_SFTP_QUOTE_RENAME",
+    "SSH_SFTP_QUOTE_RMDIR",
+    "SSH_SFTP_QUOTE_UNLINK",
+    "SSH_SFTP_QUOTE_STATVFS",
+    "SSH_SFTP_GETINFO",
+    "SSH_SFTP_FILETIME",
+    "SSH_SFTP_TRANS_INIT",
+    "SSH_SFTP_UPLOAD_INIT",
+    "SSH_SFTP_CREATE_DIRS_INIT",
+    "SSH_SFTP_CREATE_DIRS",
+    "SSH_SFTP_CREATE_DIRS_MKDIR",
+    "SSH_SFTP_READDIR_INIT",
+    "SSH_SFTP_READDIR",
+    "SSH_SFTP_READDIR_LINK",
+    "SSH_SFTP_READDIR_BOTTOM",
+    "SSH_SFTP_READDIR_DONE",
+    "SSH_SFTP_DOWNLOAD_INIT",
+    "SSH_SFTP_DOWNLOAD_STAT",
+    "SSH_SFTP_CLOSE",
+    "SSH_SFTP_SHUTDOWN",
+    "SSH_SCP_TRANS_INIT",
+    "SSH_SCP_UPLOAD_INIT",
+    "SSH_SCP_DOWNLOAD_INIT",
+    "SSH_SCP_DOWNLOAD",
+    "SSH_SCP_DONE",
+    "SSH_SCP_SEND_EOF",
+    "SSH_SCP_WAIT_EOF",
+    "SSH_SCP_WAIT_CLOSE",
+    "SSH_SCP_CHANNEL_FREE",
+    "SSH_SESSION_DISCONNECT",
+    "SSH_SESSION_FREE",
+    "QUIT"
+  };
+
+  /* a precaution to make sure the lists are in sync */
+  DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
+
+  if(sshc->state != nowstate) {
+    infof(data, "SFTP %p state change from %s to %s",
+          (void *)sshc, names[sshc->state], names[nowstate]);
+  }
+#endif
+
+  sshc->state = nowstate;
+}
+
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+static int sshkeycallback(struct Curl_easy *easy,
+                          const struct curl_khkey *knownkey, /* known */
+                          const struct curl_khkey *foundkey, /* found */
+                          enum curl_khmatch match,
+                          void *clientp)
+{
+  (void)easy;
+  (void)knownkey;
+  (void)foundkey;
+  (void)clientp;
+
+  /* we only allow perfect matches, and we reject everything else */
+  return (match != CURLKHMATCH_OK)?CURLKHSTAT_REJECT:CURLKHSTAT_FINE;
+}
+#endif
+
+/*
+ * Earlier libssh2 versions didn't have the ability to seek to 64bit positions
+ * with 32bit size_t.
+ */
+#ifdef HAVE_LIBSSH2_SFTP_SEEK64
+#define SFTP_SEEK(x,y) libssh2_sftp_seek64(x, (libssh2_uint64_t)y)
+#else
+#define SFTP_SEEK(x,y) libssh2_sftp_seek(x, (size_t)y)
+#endif
+
+/*
+ * Earlier libssh2 versions didn't do SCP properly beyond 32bit sizes on 32bit
+ * architectures so we check of the necessary function is present.
+ */
+#ifndef HAVE_LIBSSH2_SCP_SEND64
+#define SCP_SEND(a,b,c,d) libssh2_scp_send_ex(a, b, (int)(c), (size_t)d, 0, 0)
+#else
+#define SCP_SEND(a,b,c,d) libssh2_scp_send64(a, b, (int)(c),            \
+                                             (libssh2_uint64_t)d, 0, 0)
+#endif
+
+/*
+ * libssh2 1.2.8 fixed the problem with 32bit ints used for sockets on win64.
+ */
+#ifdef HAVE_LIBSSH2_SESSION_HANDSHAKE
+#define session_startup(x,y) libssh2_session_handshake(x, y)
+#else
+#define session_startup(x,y) libssh2_session_startup(x, (int)y)
+#endif
+static int convert_ssh2_keytype(int sshkeytype)
+{
+  int keytype = CURLKHTYPE_UNKNOWN;
+  switch(sshkeytype) {
+  case LIBSSH2_HOSTKEY_TYPE_RSA:
+    keytype = CURLKHTYPE_RSA;
+    break;
+  case LIBSSH2_HOSTKEY_TYPE_DSS:
+    keytype = CURLKHTYPE_DSS;
+    break;
+#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256
+  case LIBSSH2_HOSTKEY_TYPE_ECDSA_256:
+    keytype = CURLKHTYPE_ECDSA;
+    break;
+#endif
+#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384
+  case LIBSSH2_HOSTKEY_TYPE_ECDSA_384:
+    keytype = CURLKHTYPE_ECDSA;
+    break;
+#endif
+#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521
+  case LIBSSH2_HOSTKEY_TYPE_ECDSA_521:
+    keytype = CURLKHTYPE_ECDSA;
+    break;
+#endif
+#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519
+  case LIBSSH2_HOSTKEY_TYPE_ED25519:
+    keytype = CURLKHTYPE_ED25519;
+    break;
+#endif
+  }
+  return keytype;
+}
+
+static CURLcode ssh_knownhost(struct Curl_easy *data)
+{
+  int sshkeytype = 0;
+  size_t keylen = 0;
+  int rc = 0;
+  CURLcode result = CURLE_OK;
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+  if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
+    /* we're asked to verify the host against a file */
+    struct connectdata *conn = data->conn;
+    struct ssh_conn *sshc = &conn->proto.sshc;
+    struct libssh2_knownhost *host = NULL;
+    const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
+                                                    &keylen, &sshkeytype);
+    int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE;
+    int keybit = 0;
+
+    if(remotekey) {
+      /*
+       * A subject to figure out is what host name we need to pass in here.
+       * What host name does OpenSSH store in its file if an IDN name is
+       * used?
+       */
+      enum curl_khmatch keymatch;
+      curl_sshkeycallback func =
+        data->set.ssh_keyfunc ? data->set.ssh_keyfunc : sshkeycallback;
+      struct curl_khkey knownkey;
+      struct curl_khkey *knownkeyp = NULL;
+      struct curl_khkey foundkey;
+
+      switch(sshkeytype) {
+      case LIBSSH2_HOSTKEY_TYPE_RSA:
+        keybit = LIBSSH2_KNOWNHOST_KEY_SSHRSA;
+        break;
+      case LIBSSH2_HOSTKEY_TYPE_DSS:
+        keybit = LIBSSH2_KNOWNHOST_KEY_SSHDSS;
+        break;
+#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256
+      case LIBSSH2_HOSTKEY_TYPE_ECDSA_256:
+        keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_256;
+        break;
+#endif
+#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384
+      case LIBSSH2_HOSTKEY_TYPE_ECDSA_384:
+        keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_384;
+        break;
+#endif
+#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521
+      case LIBSSH2_HOSTKEY_TYPE_ECDSA_521:
+        keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_521;
+        break;
+#endif
+#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519
+      case LIBSSH2_HOSTKEY_TYPE_ED25519:
+        keybit = LIBSSH2_KNOWNHOST_KEY_ED25519;
+        break;
+#endif
+      default:
+        infof(data, "unsupported key type, can't check knownhosts");
+        keybit = 0;
+        break;
+      }
+      if(!keybit)
+        /* no check means failure! */
+        rc = CURLKHSTAT_REJECT;
+      else {
+#ifdef HAVE_LIBSSH2_KNOWNHOST_CHECKP
+        keycheck = libssh2_knownhost_checkp(sshc->kh,
+                                            conn->host.name,
+                                            (conn->remote_port != PORT_SSH)?
+                                            conn->remote_port:-1,
+                                            remotekey, keylen,
+                                            LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+                                            LIBSSH2_KNOWNHOST_KEYENC_RAW|
+                                            keybit,
+                                            &host);
+#else
+        keycheck = libssh2_knownhost_check(sshc->kh,
+                                           conn->host.name,
+                                           remotekey, keylen,
+                                           LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+                                           LIBSSH2_KNOWNHOST_KEYENC_RAW|
+                                           keybit,
+                                           &host);
+#endif
+
+        infof(data, "SSH host check: %d, key: %s", keycheck,
+              (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
+              host->key:"<none>");
+
+        /* setup 'knownkey' */
+        if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
+          knownkey.key = host->key;
+          knownkey.len = 0;
+          knownkey.keytype = convert_ssh2_keytype(sshkeytype);
+          knownkeyp = &knownkey;
+        }
+
+        /* setup 'foundkey' */
+        foundkey.key = remotekey;
+        foundkey.len = keylen;
+        foundkey.keytype = convert_ssh2_keytype(sshkeytype);
+
+        /*
+         * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the
+         * curl_khmatch enum are ever modified, we need to introduce a
+         * translation table here!
+         */
+        keymatch = (enum curl_khmatch)keycheck;
+
+        /* Ask the callback how to behave */
+        Curl_set_in_callback(data, true);
+        rc = func(data, knownkeyp, /* from the knownhosts file */
+                  &foundkey, /* from the remote host */
+                  keymatch, data->set.ssh_keyfunc_userp);
+        Curl_set_in_callback(data, false);
+      }
+    }
+    else
+      /* no remotekey means failure! */
+      rc = CURLKHSTAT_REJECT;
+
+    switch(rc) {
+    default: /* unknown return codes will equal reject */
+    case CURLKHSTAT_REJECT:
+      state(data, SSH_SESSION_FREE);
+      FALLTHROUGH();
+    case CURLKHSTAT_DEFER:
+      /* DEFER means bail out but keep the SSH_HOSTKEY state */
+      result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+      break;
+    case CURLKHSTAT_FINE_REPLACE:
+      /* remove old host+key that doesn't match */
+      if(host)
+        libssh2_knownhost_del(sshc->kh, host);
+      FALLTHROUGH();
+    case CURLKHSTAT_FINE:
+    case CURLKHSTAT_FINE_ADD_TO_FILE:
+      /* proceed */
+      if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
+        /* the found host+key didn't match but has been told to be fine
+           anyway so we add it in memory */
+        int addrc = libssh2_knownhost_add(sshc->kh,
+                                          conn->host.name, NULL,
+                                          remotekey, keylen,
+                                          LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+                                          LIBSSH2_KNOWNHOST_KEYENC_RAW|
+                                          keybit, NULL);
+        if(addrc)
+          infof(data, "WARNING: adding the known host %s failed",
+                conn->host.name);
+        else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE ||
+                rc == CURLKHSTAT_FINE_REPLACE) {
+          /* now we write the entire in-memory list of known hosts to the
+             known_hosts file */
+          int wrc =
+            libssh2_knownhost_writefile(sshc->kh,
+                                        data->set.str[STRING_SSH_KNOWNHOSTS],
+                                        LIBSSH2_KNOWNHOST_FILE_OPENSSH);
+          if(wrc) {
+            infof(data, "WARNING: writing %s failed",
+                  data->set.str[STRING_SSH_KNOWNHOSTS]);
+          }
+        }
+      }
+      break;
+    }
+  }
+#else /* HAVE_LIBSSH2_KNOWNHOST_API */
+  (void)data;
+#endif
+  return result;
+}
+
+static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
+  const char *pubkey_sha256 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256];
+
+  infof(data, "SSH MD5 public key: %s",
+    pubkey_md5 != NULL ? pubkey_md5 : "NULL");
+  infof(data, "SSH SHA256 public key: %s",
+      pubkey_sha256 != NULL ? pubkey_sha256 : "NULL");
+
+  if(pubkey_sha256) {
+    const char *fingerprint = NULL;
+    char *fingerprint_b64 = NULL;
+    size_t fingerprint_b64_len;
+    size_t pub_pos = 0;
+    size_t b64_pos = 0;
+
+#ifdef LIBSSH2_HOSTKEY_HASH_SHA256
+    /* The fingerprint points to static storage (!), don't free() it. */
+    fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
+                                       LIBSSH2_HOSTKEY_HASH_SHA256);
+#else
+    const char *hostkey;
+    size_t len = 0;
+    unsigned char hash[32];
+
+    hostkey = libssh2_session_hostkey(sshc->ssh_session, &len, NULL);
+    if(hostkey) {
+      if(!Curl_sha256it(hash, (const unsigned char *) hostkey, len))
+        fingerprint = (char *) hash;
+    }
+#endif
+
+    if(!fingerprint) {
+      failf(data,
+            "Denied establishing ssh session: sha256 fingerprint "
+            "not available");
+      state(data, SSH_SESSION_FREE);
+      sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+      return sshc->actualcode;
+    }
+
+    /* The length of fingerprint is 32 bytes for SHA256.
+     * See libssh2_hostkey_hash documentation. */
+    if(Curl_base64_encode(fingerprint, 32, &fingerprint_b64,
+                          &fingerprint_b64_len) != CURLE_OK) {
+      state(data, SSH_SESSION_FREE);
+      sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+      return sshc->actualcode;
+    }
+
+    if(!fingerprint_b64) {
+      failf(data, "sha256 fingerprint could not be encoded");
+      state(data, SSH_SESSION_FREE);
+      sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+      return sshc->actualcode;
+    }
+
+    infof(data, "SSH SHA256 fingerprint: %s", fingerprint_b64);
+
+    /* Find the position of any = padding characters in the public key */
+    while((pubkey_sha256[pub_pos] != '=') && pubkey_sha256[pub_pos]) {
+      pub_pos++;
+    }
+
+    /* Find the position of any = padding characters in the base64 coded
+     * hostkey fingerprint */
+    while((fingerprint_b64[b64_pos] != '=') && fingerprint_b64[b64_pos]) {
+      b64_pos++;
+    }
+
+    /* Before we authenticate we check the hostkey's sha256 fingerprint
+     * against a known fingerprint, if available.
+     */
+    if((pub_pos != b64_pos) ||
+       strncmp(fingerprint_b64, pubkey_sha256, pub_pos)) {
+      failf(data,
+            "Denied establishing ssh session: mismatch sha256 fingerprint. "
+            "Remote %s is not equal to %s", fingerprint_b64, pubkey_sha256);
+      free(fingerprint_b64);
+      state(data, SSH_SESSION_FREE);
+      sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+      return sshc->actualcode;
+    }
+
+    free(fingerprint_b64);
+
+    infof(data, "SHA256 checksum match");
+  }
+
+  if(pubkey_md5) {
+    char md5buffer[33];
+    const char *fingerprint = NULL;
+
+    fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
+                                       LIBSSH2_HOSTKEY_HASH_MD5);
+
+    if(fingerprint) {
+      /* The fingerprint points to static storage (!), don't free() it. */
+      int i;
+      for(i = 0; i < 16; i++) {
+        msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
+      }
+
+      infof(data, "SSH MD5 fingerprint: %s", md5buffer);
+    }
+
+    /* This does NOT verify the length of 'pubkey_md5' separately, which will
+       make the comparison below fail unless it is exactly 32 characters */
+    if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
+      if(fingerprint) {
+        failf(data,
+              "Denied establishing ssh session: mismatch md5 fingerprint. "
+              "Remote %s is not equal to %s", md5buffer, pubkey_md5);
+      }
+      else {
+        failf(data,
+              "Denied establishing ssh session: md5 fingerprint "
+              "not available");
+      }
+      state(data, SSH_SESSION_FREE);
+      sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+      return sshc->actualcode;
+    }
+    infof(data, "MD5 checksum match");
+  }
+
+  if(!pubkey_md5 && !pubkey_sha256) {
+    if(data->set.ssh_hostkeyfunc) {
+      size_t keylen = 0;
+      int sshkeytype = 0;
+      int rc = 0;
+      /* we handle the process to the callback */
+      const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
+                                                      &keylen, &sshkeytype);
+      if(remotekey) {
+        int keytype = convert_ssh2_keytype(sshkeytype);
+        Curl_set_in_callback(data, true);
+        rc = data->set.ssh_hostkeyfunc(data->set.ssh_hostkeyfunc_userp,
+                                       keytype, remotekey, keylen);
+        Curl_set_in_callback(data, false);
+        if(rc!= CURLKHMATCH_OK) {
+          state(data, SSH_SESSION_FREE);
+          sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+          return sshc->actualcode;
+        }
+      }
+      else {
+        state(data, SSH_SESSION_FREE);
+        sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+        return sshc->actualcode;
+      }
+      return CURLE_OK;
+    }
+    else {
+      return ssh_knownhost(data);
+    }
+  }
+  else {
+    /* as we already matched, we skip the check for known hosts */
+    return CURLE_OK;
+  }
+}
+
+/*
+ * ssh_force_knownhost_key_type() will check the known hosts file and try to
+ * force a specific public key type from the server if an entry is found.
+ */
+static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+
+#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519
+  static const char * const hostkey_method_ssh_ed25519
+    = "ssh-ed25519";
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521
+  static const char * const hostkey_method_ssh_ecdsa_521
+    = "ecdsa-sha2-nistp521";
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384
+  static const char * const hostkey_method_ssh_ecdsa_384
+    = "ecdsa-sha2-nistp384";
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256
+  static const char * const hostkey_method_ssh_ecdsa_256
+    = "ecdsa-sha2-nistp256";
+#endif
+  static const char * const hostkey_method_ssh_rsa
+    = "ssh-rsa";
+  static const char * const hostkey_method_ssh_rsa_all
+    = "rsa-sha2-256,rsa-sha2-512,ssh-rsa";
+  static const char * const hostkey_method_ssh_dss
+    = "ssh-dss";
+
+  const char *hostkey_method = NULL;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  struct libssh2_knownhost* store = NULL;
+  const char *kh_name_end = NULL;
+  size_t kh_name_size = 0;
+  int port = 0;
+  bool found = false;
+
+  if(sshc->kh && !data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
+    /* lets try to find our host in the known hosts file */
+    while(!libssh2_knownhost_get(sshc->kh, &store, store)) {
+      /* For non-standard ports, the name will be enclosed in */
+      /* square brackets, followed by a colon and the port */
+      if(store) {
+        if(store->name) {
+          if(store->name[0] == '[') {
+            kh_name_end = strstr(store->name, "]:");
+            if(!kh_name_end) {
+              infof(data, "Invalid host pattern %s in %s",
+                    store->name, data->set.str[STRING_SSH_KNOWNHOSTS]);
+              continue;
+            }
+            port = atoi(kh_name_end + 2);
+            if(kh_name_end && (port == conn->remote_port)) {
+              kh_name_size = strlen(store->name) - 1 - strlen(kh_name_end);
+              if(strncmp(store->name + 1,
+                 conn->host.name, kh_name_size) == 0) {
+                found = true;
+                break;
+              }
+            }
+          }
+          else if(strcmp(store->name, conn->host.name) == 0) {
+            found = true;
+            break;
+          }
+        }
+        else {
+          found = true;
+          break;
+        }
+      }
+    }
+
+    if(found) {
+      int rc;
+      infof(data, "Found host %s in %s",
+            conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
+
+      switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) {
+#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519
+      case LIBSSH2_KNOWNHOST_KEY_ED25519:
+        hostkey_method = hostkey_method_ssh_ed25519;
+        break;
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521
+      case LIBSSH2_KNOWNHOST_KEY_ECDSA_521:
+        hostkey_method = hostkey_method_ssh_ecdsa_521;
+        break;
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384
+      case LIBSSH2_KNOWNHOST_KEY_ECDSA_384:
+        hostkey_method = hostkey_method_ssh_ecdsa_384;
+        break;
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256
+      case LIBSSH2_KNOWNHOST_KEY_ECDSA_256:
+        hostkey_method = hostkey_method_ssh_ecdsa_256;
+        break;
+#endif
+      case LIBSSH2_KNOWNHOST_KEY_SSHRSA:
+#ifdef HAVE_LIBSSH2_VERSION
+        if(libssh2_version(0x010900))
+          /* since 1.9.0 libssh2_session_method_pref() works as expected */
+          hostkey_method = hostkey_method_ssh_rsa_all;
+        else
+#endif
+          /* old libssh2 which cannot correctly remove unsupported methods due
+           * to bug in src/kex.c or does not support the new methods anyways.
+           */
+          hostkey_method = hostkey_method_ssh_rsa;
+        break;
+      case LIBSSH2_KNOWNHOST_KEY_SSHDSS:
+        hostkey_method = hostkey_method_ssh_dss;
+        break;
+      case LIBSSH2_KNOWNHOST_KEY_RSA1:
+        failf(data, "Found host key type RSA1 which is not supported");
+        return CURLE_SSH;
+      default:
+        failf(data, "Unknown host key type: %i",
+              (store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK));
+        return CURLE_SSH;
+      }
+
+      infof(data, "Set \"%s\" as SSH hostkey type", hostkey_method);
+      rc = libssh2_session_method_pref(sshc->ssh_session,
+                                       LIBSSH2_METHOD_HOSTKEY, hostkey_method);
+      if(rc) {
+        char *errmsg = NULL;
+        int errlen;
+        libssh2_session_last_error(sshc->ssh_session, &errmsg, &errlen, 0);
+        failf(data, "libssh2: %s", errmsg);
+        result = libssh2_session_error_to_CURLE(rc);
+      }
+    }
+    else {
+      infof(data, "Did not find host %s in %s",
+            conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
+    }
+  }
+
+#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
+
+  return result;
+}
+
+/*
+ * ssh_statemach_act() runs the SSH state machine as far as it can without
+ * blocking and without reaching the end.  The data the pointer 'block' points
+ * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
+ * meaning it wants to be called again when the socket is ready
+ */
+
+static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct SSHPROTO *sshp = data->req.p.ssh;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  int rc = LIBSSH2_ERROR_NONE;
+  int ssherr;
+  unsigned long sftperr;
+  int seekerr = CURL_SEEKFUNC_OK;
+  size_t readdir_len;
+  *block = 0; /* we're not blocking by default */
+
+  do {
+    switch(sshc->state) {
+    case SSH_INIT:
+      sshc->secondCreateDirs = 0;
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_OK;
+
+      /* Set libssh2 to non-blocking, since everything internally is
+         non-blocking */
+      libssh2_session_set_blocking(sshc->ssh_session, 0);
+
+      result = ssh_force_knownhost_key_type(data);
+      if(result) {
+        state(data, SSH_SESSION_FREE);
+        sshc->actualcode = result;
+        break;
+      }
+
+      state(data, SSH_S_STARTUP);
+      FALLTHROUGH();
+
+    case SSH_S_STARTUP:
+      rc = session_startup(sshc->ssh_session, sock);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc) {
+        char *err_msg = NULL;
+        (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
+        failf(data, "Failure establishing ssh session: %d, %s", rc, err_msg);
+
+        state(data, SSH_SESSION_FREE);
+        sshc->actualcode = CURLE_FAILED_INIT;
+        break;
+      }
+
+      state(data, SSH_HOSTKEY);
+
+      FALLTHROUGH();
+    case SSH_HOSTKEY:
+      /*
+       * Before we authenticate we should check the hostkey's fingerprint
+       * against our known hosts. How that is handled (reading from file,
+       * whatever) is up to us.
+       */
+      result = ssh_check_fingerprint(data);
+      if(!result)
+        state(data, SSH_AUTHLIST);
+      /* ssh_check_fingerprint sets state appropriately on error */
+      break;
+
+    case SSH_AUTHLIST:
+      /*
+       * Figure out authentication methods
+       * NB: As soon as we have provided a username to an openssh server we
+       * must never change it later. Thus, always specify the correct username
+       * here, even though the libssh2 docs kind of indicate that it should be
+       * possible to get a 'generic' list (not user-specific) of authentication
+       * methods, presumably with a blank username. That won't work in my
+       * experience.
+       * So always specify it here.
+       */
+      sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
+                                             conn->user,
+                                             curlx_uztoui(strlen(conn->user)));
+
+      if(!sshc->authlist) {
+        if(libssh2_userauth_authenticated(sshc->ssh_session)) {
+          sshc->authed = TRUE;
+          infof(data, "SSH user accepted with no authentication");
+          state(data, SSH_AUTH_DONE);
+          break;
+        }
+        ssherr = libssh2_session_last_errno(sshc->ssh_session);
+        if(ssherr == LIBSSH2_ERROR_EAGAIN)
+          rc = LIBSSH2_ERROR_EAGAIN;
+        else {
+          state(data, SSH_SESSION_FREE);
+          sshc->actualcode = libssh2_session_error_to_CURLE(ssherr);
+        }
+        break;
+      }
+      infof(data, "SSH authentication methods available: %s",
+            sshc->authlist);
+
+      state(data, SSH_AUTH_PKEY_INIT);
+      break;
+
+    case SSH_AUTH_PKEY_INIT:
+      /*
+       * Check the supported auth types in the order I feel is most secure
+       * with the requested type of authentication
+       */
+      sshc->authed = FALSE;
+
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
+         (strstr(sshc->authlist, "publickey") != NULL)) {
+        bool out_of_memory = FALSE;
+
+        sshc->rsa_pub = sshc->rsa = NULL;
+
+        if(data->set.str[STRING_SSH_PRIVATE_KEY])
+          sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]);
+        else {
+          /* To ponder about: should really the lib be messing about with the
+             HOME environment variable etc? */
+          char *home = curl_getenv("HOME");
+
+          /* If no private key file is specified, try some common paths. */
+          if(home) {
+            /* Try ~/.ssh first. */
+            sshc->rsa = aprintf("%s/.ssh/id_rsa", home);
+            if(!sshc->rsa)
+              out_of_memory = TRUE;
+            else if(access(sshc->rsa, R_OK) != 0) {
+              Curl_safefree(sshc->rsa);
+              sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
+              if(!sshc->rsa)
+                out_of_memory = TRUE;
+              else if(access(sshc->rsa, R_OK) != 0) {
+                Curl_safefree(sshc->rsa);
+              }
+            }
+            free(home);
+          }
+          if(!out_of_memory && !sshc->rsa) {
+            /* Nothing found; try the current dir. */
+            sshc->rsa = strdup("id_rsa");
+            if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
+              Curl_safefree(sshc->rsa);
+              sshc->rsa = strdup("id_dsa");
+              if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
+                Curl_safefree(sshc->rsa);
+                /* Out of guesses. Set to the empty string to avoid
+                 * surprising info messages. */
+                sshc->rsa = strdup("");
+              }
+            }
+          }
+        }
+
+        /*
+         * Unless the user explicitly specifies a public key file, let
+         * libssh2 extract the public key from the private key file.
+         * This is done by simply passing sshc->rsa_pub = NULL.
+         */
+        if(data->set.str[STRING_SSH_PUBLIC_KEY]
+           /* treat empty string the same way as NULL */
+           && data->set.str[STRING_SSH_PUBLIC_KEY][0]) {
+          sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]);
+          if(!sshc->rsa_pub)
+            out_of_memory = TRUE;
+        }
+
+        if(out_of_memory || !sshc->rsa) {
+          Curl_safefree(sshc->rsa);
+          Curl_safefree(sshc->rsa_pub);
+          state(data, SSH_SESSION_FREE);
+          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+          break;
+        }
+
+        sshc->passphrase = data->set.ssl.key_passwd;
+        if(!sshc->passphrase)
+          sshc->passphrase = "";
+
+        if(sshc->rsa_pub)
+          infof(data, "Using SSH public key file '%s'", sshc->rsa_pub);
+        infof(data, "Using SSH private key file '%s'", sshc->rsa);
+
+        state(data, SSH_AUTH_PKEY);
+      }
+      else {
+        state(data, SSH_AUTH_PASS_INIT);
+      }
+      break;
+
+    case SSH_AUTH_PKEY:
+      /* The function below checks if the files exists, no need to stat() here.
+       */
+      rc = libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session,
+                                                  conn->user,
+                                                  curlx_uztoui(
+                                                    strlen(conn->user)),
+                                                  sshc->rsa_pub,
+                                                  sshc->rsa, sshc->passphrase);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+
+      Curl_safefree(sshc->rsa_pub);
+      Curl_safefree(sshc->rsa);
+
+      if(rc == 0) {
+        sshc->authed = TRUE;
+        infof(data, "Initialized SSH public key authentication");
+        state(data, SSH_AUTH_DONE);
+      }
+      else {
+        char *err_msg = NULL;
+        char unknown[] = "Reason unknown (-1)";
+        if(rc == -1) {
+          /* No error message has been set and the last set error message, if
+             any, is from a previous error so ignore it. #11837 */
+          err_msg = unknown;
+        }
+        else {
+          (void)libssh2_session_last_error(sshc->ssh_session,
+                                           &err_msg, NULL, 0);
+        }
+        infof(data, "SSH public key authentication failed: %s", err_msg);
+        state(data, SSH_AUTH_PASS_INIT);
+        rc = 0; /* clear rc and continue */
+      }
+      break;
+
+    case SSH_AUTH_PASS_INIT:
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
+         (strstr(sshc->authlist, "password") != NULL)) {
+        state(data, SSH_AUTH_PASS);
+      }
+      else {
+        state(data, SSH_AUTH_HOST_INIT);
+        rc = 0; /* clear rc and continue */
+      }
+      break;
+
+    case SSH_AUTH_PASS:
+      rc = libssh2_userauth_password_ex(sshc->ssh_session, conn->user,
+                                        curlx_uztoui(strlen(conn->user)),
+                                        conn->passwd,
+                                        curlx_uztoui(strlen(conn->passwd)),
+                                        NULL);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc == 0) {
+        sshc->authed = TRUE;
+        infof(data, "Initialized password authentication");
+        state(data, SSH_AUTH_DONE);
+      }
+      else {
+        state(data, SSH_AUTH_HOST_INIT);
+        rc = 0; /* clear rc and continue */
+      }
+      break;
+
+    case SSH_AUTH_HOST_INIT:
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
+         (strstr(sshc->authlist, "hostbased") != NULL)) {
+        state(data, SSH_AUTH_HOST);
+      }
+      else {
+        state(data, SSH_AUTH_AGENT_INIT);
+      }
+      break;
+
+    case SSH_AUTH_HOST:
+      state(data, SSH_AUTH_AGENT_INIT);
+      break;
+
+    case SSH_AUTH_AGENT_INIT:
+#ifdef HAVE_LIBSSH2_AGENT_API
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_AGENT)
+         && (strstr(sshc->authlist, "publickey") != NULL)) {
+
+        /* Connect to the ssh-agent */
+        /* The agent could be shared by a curl thread i believe
+           but nothing obvious as keys can be added/removed at any time */
+        if(!sshc->ssh_agent) {
+          sshc->ssh_agent = libssh2_agent_init(sshc->ssh_session);
+          if(!sshc->ssh_agent) {
+            infof(data, "Could not create agent object");
+
+            state(data, SSH_AUTH_KEY_INIT);
+            break;
+          }
+        }
+
+        rc = libssh2_agent_connect(sshc->ssh_agent);
+        if(rc == LIBSSH2_ERROR_EAGAIN)
+          break;
+        if(rc < 0) {
+          infof(data, "Failure connecting to agent");
+          state(data, SSH_AUTH_KEY_INIT);
+          rc = 0; /* clear rc and continue */
+        }
+        else {
+          state(data, SSH_AUTH_AGENT_LIST);
+        }
+      }
+      else
+#endif /* HAVE_LIBSSH2_AGENT_API */
+        state(data, SSH_AUTH_KEY_INIT);
+      break;
+
+    case SSH_AUTH_AGENT_LIST:
+#ifdef HAVE_LIBSSH2_AGENT_API
+      rc = libssh2_agent_list_identities(sshc->ssh_agent);
+
+      if(rc == LIBSSH2_ERROR_EAGAIN)
+        break;
+      if(rc < 0) {
+        infof(data, "Failure requesting identities to agent");
+        state(data, SSH_AUTH_KEY_INIT);
+        rc = 0; /* clear rc and continue */
+      }
+      else {
+        state(data, SSH_AUTH_AGENT);
+        sshc->sshagent_prev_identity = NULL;
+      }
+#endif
+      break;
+
+    case SSH_AUTH_AGENT:
+#ifdef HAVE_LIBSSH2_AGENT_API
+      /* as prev_identity evolves only after an identity user auth finished we
+         can safely request it again as long as EAGAIN is returned here or by
+         libssh2_agent_userauth */
+      rc = libssh2_agent_get_identity(sshc->ssh_agent,
+                                      &sshc->sshagent_identity,
+                                      sshc->sshagent_prev_identity);
+      if(rc == LIBSSH2_ERROR_EAGAIN)
+        break;
+
+      if(rc == 0) {
+        rc = libssh2_agent_userauth(sshc->ssh_agent, conn->user,
+                                    sshc->sshagent_identity);
+
+        if(rc < 0) {
+          if(rc != LIBSSH2_ERROR_EAGAIN) {
+            /* tried and failed? go to next identity */
+            sshc->sshagent_prev_identity = sshc->sshagent_identity;
+          }
+          break;
+        }
+      }
+
+      if(rc < 0)
+        infof(data, "Failure requesting identities to agent");
+      else if(rc == 1)
+        infof(data, "No identity would match");
+
+      if(rc == LIBSSH2_ERROR_NONE) {
+        sshc->authed = TRUE;
+        infof(data, "Agent based authentication successful");
+        state(data, SSH_AUTH_DONE);
+      }
+      else {
+        state(data, SSH_AUTH_KEY_INIT);
+        rc = 0; /* clear rc and continue */
+      }
+#endif
+      break;
+
+    case SSH_AUTH_KEY_INIT:
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
+         && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
+        state(data, SSH_AUTH_KEY);
+      }
+      else {
+        state(data, SSH_AUTH_DONE);
+      }
+      break;
+
+    case SSH_AUTH_KEY:
+      /* Authentication failed. Continue with keyboard-interactive now. */
+      rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
+                                                    conn->user,
+                                                    curlx_uztoui(
+                                                      strlen(conn->user)),
+                                                    &kbd_callback);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc == 0) {
+        sshc->authed = TRUE;
+        infof(data, "Initialized keyboard interactive authentication");
+      }
+      state(data, SSH_AUTH_DONE);
+      break;
+
+    case SSH_AUTH_DONE:
+      if(!sshc->authed) {
+        failf(data, "Authentication failure");
+        state(data, SSH_SESSION_FREE);
+        sshc->actualcode = CURLE_LOGIN_DENIED;
+        break;
+      }
+
+      /*
+       * At this point we have an authenticated ssh session.
+       */
+      infof(data, "Authentication complete");
+
+      Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */
+
+      conn->sockfd = sock;
+      conn->writesockfd = CURL_SOCKET_BAD;
+
+      if(conn->handler->protocol == CURLPROTO_SFTP) {
+        state(data, SSH_SFTP_INIT);
+        break;
+      }
+      infof(data, "SSH CONNECT phase done");
+      state(data, SSH_STOP);
+      break;
+
+    case SSH_SFTP_INIT:
+      /*
+       * Start the libssh2 sftp session
+       */
+      sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session);
+      if(!sshc->sftp_session) {
+        char *err_msg = NULL;
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+
+        (void)libssh2_session_last_error(sshc->ssh_session,
+                                         &err_msg, NULL, 0);
+        failf(data, "Failure initializing sftp session: %s", err_msg);
+        state(data, SSH_SESSION_FREE);
+        sshc->actualcode = CURLE_FAILED_INIT;
+        break;
+      }
+      state(data, SSH_SFTP_REALPATH);
+      break;
+
+    case SSH_SFTP_REALPATH:
+    {
+      char tempHome[PATH_MAX];
+
+      /*
+       * Get the "home" directory
+       */
+      rc = sftp_libssh2_realpath(sshc->sftp_session, ".",
+                                 tempHome, PATH_MAX-1);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc > 0) {
+        /* It seems that this string is not always NULL terminated */
+        tempHome[rc] = '\0';
+        sshc->homedir = strdup(tempHome);
+        if(!sshc->homedir) {
+          state(data, SSH_SFTP_CLOSE);
+          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+          break;
+        }
+        data->state.most_recent_ftp_entrypath = sshc->homedir;
+      }
+      else {
+        /* Return the error type */
+        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        if(sftperr)
+          result = sftp_libssh2_error_to_CURLE(sftperr);
+        else
+          /* in this case, the error wasn't in the SFTP level but for example
+             a time-out or similar */
+          result = CURLE_SSH;
+        sshc->actualcode = result;
+        DEBUGF(infof(data, "error = %lu makes libcurl = %d",
+                     sftperr, (int)result));
+        state(data, SSH_STOP);
+        break;
+      }
+    }
+    /* This is the last step in the SFTP connect phase. Do note that while
+       we get the homedir here, we get the "workingpath" in the DO action
+       since the homedir will remain the same between request but the
+       working path will not. */
+    DEBUGF(infof(data, "SSH CONNECT phase done"));
+    state(data, SSH_STOP);
+    break;
+
+    case SSH_SFTP_QUOTE_INIT:
+
+      result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
+      if(result) {
+        sshc->actualcode = result;
+        state(data, SSH_STOP);
+        break;
+      }
+
+      if(data->set.quote) {
+        infof(data, "Sending quote commands");
+        sshc->quote_item = data->set.quote;
+        state(data, SSH_SFTP_QUOTE);
+      }
+      else {
+        state(data, SSH_SFTP_GETINFO);
+      }
+      break;
+
+    case SSH_SFTP_POSTQUOTE_INIT:
+      if(data->set.postquote) {
+        infof(data, "Sending quote commands");
+        sshc->quote_item = data->set.postquote;
+        state(data, SSH_SFTP_QUOTE);
+      }
+      else {
+        state(data, SSH_STOP);
+      }
+      break;
+
+    case SSH_SFTP_QUOTE:
+      /* Send any quote commands */
+    {
+      const char *cp;
+
+      /*
+       * Support some of the "FTP" commands
+       *
+       * 'sshc->quote_item' is already verified to be non-NULL before it
+       * switched to this state.
+       */
+      char *cmd = sshc->quote_item->data;
+      sshc->acceptfail = FALSE;
+
+      /* if a command starts with an asterisk, which a legal SFTP command never
+         can, the command will be allowed to fail without it causing any
+         aborts or cancels etc. It will cause libcurl to act as if the command
+         is successful, whatever the server responds. */
+
+      if(cmd[0] == '*') {
+        cmd++;
+        sshc->acceptfail = TRUE;
+      }
+
+      if(strcasecompare("pwd", cmd)) {
+        /* output debug output if that is requested */
+        char *tmp = aprintf("257 \"%s\" is current directory.\n",
+                            sshp->path);
+        if(!tmp) {
+          result = CURLE_OUT_OF_MEMORY;
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          break;
+        }
+        Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4);
+        Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
+
+        /* this sends an FTP-like "header" to the header callback so that the
+           current directory can be read very similar to how it is read when
+           using ordinary FTP. */
+        result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+        free(tmp);
+        if(result) {
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = result;
+        }
+        else
+          state(data, SSH_SFTP_NEXT_QUOTE);
+        break;
+      }
+
+      /*
+       * the arguments following the command must be separated from the
+       * command with a space so we can check for it unconditionally
+       */
+      cp = strchr(cmd, ' ');
+      if(!cp) {
+        failf(data, "Syntax error command '%s', missing parameter",
+              cmd);
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+
+      /*
+       * also, every command takes at least one argument so we get that
+       * first argument right now
+       */
+      result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
+      if(result) {
+        if(result == CURLE_OUT_OF_MEMORY)
+          failf(data, "Out of memory");
+        else
+          failf(data, "Syntax error: Bad first parameter to '%s'", cmd);
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = result;
+        break;
+      }
+
+      /*
+       * SFTP is a binary protocol, so we don't send text commands
+       * to the server. Instead, we scan for commands used by
+       * OpenSSH's sftp program and call the appropriate libssh2
+       * functions.
+       */
+      if(strncasecompare(cmd, "chgrp ", 6) ||
+         strncasecompare(cmd, "chmod ", 6) ||
+         strncasecompare(cmd, "chown ", 6) ||
+         strncasecompare(cmd, "atime ", 6) ||
+         strncasecompare(cmd, "mtime ", 6)) {
+        /* attribute change */
+
+        /* sshc->quote_path1 contains the mode to set */
+        /* get the destination */
+        result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+        if(result) {
+          if(result == CURLE_OUT_OF_MEMORY)
+            failf(data, "Out of memory");
+          else
+            failf(data, "Syntax error in %s: Bad second parameter", cmd);
+          Curl_safefree(sshc->quote_path1);
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = result;
+          break;
+        }
+        memset(&sshp->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+        state(data, SSH_SFTP_QUOTE_STAT);
+        break;
+      }
+      if(strncasecompare(cmd, "ln ", 3) ||
+         strncasecompare(cmd, "symlink ", 8)) {
+        /* symbolic linking */
+        /* sshc->quote_path1 is the source */
+        /* get the destination */
+        result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+        if(result) {
+          if(result == CURLE_OUT_OF_MEMORY)
+            failf(data, "Out of memory");
+          else
+            failf(data,
+                  "Syntax error in ln/symlink: Bad second parameter");
+          Curl_safefree(sshc->quote_path1);
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = result;
+          break;
+        }
+        state(data, SSH_SFTP_QUOTE_SYMLINK);
+        break;
+      }
+      else if(strncasecompare(cmd, "mkdir ", 6)) {
+        /* create dir */
+        state(data, SSH_SFTP_QUOTE_MKDIR);
+        break;
+      }
+      else if(strncasecompare(cmd, "rename ", 7)) {
+        /* rename file */
+        /* first param is the source path */
+        /* second param is the dest. path */
+        result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+        if(result) {
+          if(result == CURLE_OUT_OF_MEMORY)
+            failf(data, "Out of memory");
+          else
+            failf(data, "Syntax error in rename: Bad second parameter");
+          Curl_safefree(sshc->quote_path1);
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = result;
+          break;
+        }
+        state(data, SSH_SFTP_QUOTE_RENAME);
+        break;
+      }
+      else if(strncasecompare(cmd, "rmdir ", 6)) {
+        /* delete dir */
+        state(data, SSH_SFTP_QUOTE_RMDIR);
+        break;
+      }
+      else if(strncasecompare(cmd, "rm ", 3)) {
+        state(data, SSH_SFTP_QUOTE_UNLINK);
+        break;
+      }
+#ifdef HAS_STATVFS_SUPPORT
+      else if(strncasecompare(cmd, "statvfs ", 8)) {
+        state(data, SSH_SFTP_QUOTE_STATVFS);
+        break;
+      }
+#endif
+
+      failf(data, "Unknown SFTP command");
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      state(data, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_QUOTE_ERROR;
+      break;
+    }
+
+    case SSH_SFTP_NEXT_QUOTE:
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+
+      sshc->quote_item = sshc->quote_item->next;
+
+      if(sshc->quote_item) {
+        state(data, SSH_SFTP_QUOTE);
+      }
+      else {
+        if(sshc->nextstate != SSH_NO_STATE) {
+          state(data, sshc->nextstate);
+          sshc->nextstate = SSH_NO_STATE;
+        }
+        else {
+          state(data, SSH_SFTP_GETINFO);
+        }
+      }
+      break;
+
+    case SSH_SFTP_QUOTE_STAT:
+    {
+      char *cmd = sshc->quote_item->data;
+      sshc->acceptfail = FALSE;
+
+      /* if a command starts with an asterisk, which a legal SFTP command never
+         can, the command will be allowed to fail without it causing any
+         aborts or cancels etc. It will cause libcurl to act as if the command
+         is successful, whatever the server responds. */
+
+      if(cmd[0] == '*') {
+        cmd++;
+        sshc->acceptfail = TRUE;
+      }
+
+      if(!strncasecompare(cmd, "chmod", 5)) {
+        /* Since chown and chgrp only set owner OR group but libssh2 wants to
+         * set them both at once, we need to obtain the current ownership
+         * first.  This takes an extra protocol round trip.
+         */
+        rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
+                                  curlx_uztoui(strlen(sshc->quote_path2)),
+                                  LIBSSH2_SFTP_STAT,
+                                  &sshp->quote_attrs);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        if(rc && !sshc->acceptfail) { /* get those attributes */
+          sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+          Curl_safefree(sshc->quote_path1);
+          Curl_safefree(sshc->quote_path2);
+          failf(data, "Attempt to get SFTP stats failed: %s",
+                sftp_libssh2_strerror(sftperr));
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+      }
+
+      /* Now set the new attributes... */
+      if(strncasecompare(cmd, "chgrp", 5)) {
+        sshp->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
+        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+        if(sshp->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+           !sshc->acceptfail) {
+          Curl_safefree(sshc->quote_path1);
+          Curl_safefree(sshc->quote_path2);
+          failf(data, "Syntax error: chgrp gid not a number");
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+      }
+      else if(strncasecompare(cmd, "chmod", 5)) {
+        sshp->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
+        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
+        /* permissions are octal */
+        if(sshp->quote_attrs.permissions == 0 &&
+           !ISDIGIT(sshc->quote_path1[0])) {
+          Curl_safefree(sshc->quote_path1);
+          Curl_safefree(sshc->quote_path2);
+          failf(data, "Syntax error: chmod permissions not a number");
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+      }
+      else if(strncasecompare(cmd, "chown", 5)) {
+        sshp->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
+        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+        if(sshp->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+           !sshc->acceptfail) {
+          Curl_safefree(sshc->quote_path1);
+          Curl_safefree(sshc->quote_path2);
+          failf(data, "Syntax error: chown uid not a number");
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+      }
+      else if(strncasecompare(cmd, "atime", 5) ||
+              strncasecompare(cmd, "mtime", 5)) {
+        time_t date = Curl_getdate_capped(sshc->quote_path1);
+        bool fail = FALSE;
+
+        if(date == -1) {
+          failf(data, "incorrect date format for %.*s", 5, cmd);
+          fail = TRUE;
+        }
+#if SIZEOF_TIME_T > SIZEOF_LONG
+        if(date > 0xffffffff) {
+          /* if 'long' can't old >32bit, this date cannot be sent */
+          failf(data, "date overflow");
+          fail = TRUE;
+        }
+#endif
+        if(fail) {
+          Curl_safefree(sshc->quote_path1);
+          Curl_safefree(sshc->quote_path2);
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+        if(strncasecompare(cmd, "atime", 5))
+          sshp->quote_attrs.atime = (unsigned long)date;
+        else /* mtime */
+          sshp->quote_attrs.mtime = (unsigned long)date;
+
+        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME;
+      }
+
+      /* Now send the completed structure... */
+      state(data, SSH_SFTP_QUOTE_SETSTAT);
+      break;
+    }
+
+    case SSH_SFTP_QUOTE_SETSTAT:
+      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
+                                curlx_uztoui(strlen(sshc->quote_path2)),
+                                LIBSSH2_SFTP_SETSTAT,
+                                &sshp->quote_attrs);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc && !sshc->acceptfail) {
+        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        Curl_safefree(sshc->quote_path1);
+        Curl_safefree(sshc->quote_path2);
+        failf(data, "Attempt to set SFTP stats failed: %s",
+              sftp_libssh2_strerror(sftperr));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_SYMLINK:
+      rc = libssh2_sftp_symlink_ex(sshc->sftp_session, sshc->quote_path1,
+                                   curlx_uztoui(strlen(sshc->quote_path1)),
+                                   sshc->quote_path2,
+                                   curlx_uztoui(strlen(sshc->quote_path2)),
+                                   LIBSSH2_SFTP_SYMLINK);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc && !sshc->acceptfail) {
+        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        Curl_safefree(sshc->quote_path1);
+        Curl_safefree(sshc->quote_path2);
+        failf(data, "symlink command failed: %s",
+              sftp_libssh2_strerror(sftperr));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_MKDIR:
+      rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1,
+                                 curlx_uztoui(strlen(sshc->quote_path1)),
+                                 data->set.new_directory_perms);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc && !sshc->acceptfail) {
+        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        Curl_safefree(sshc->quote_path1);
+        failf(data, "mkdir command failed: %s",
+              sftp_libssh2_strerror(sftperr));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_RENAME:
+      rc = libssh2_sftp_rename_ex(sshc->sftp_session, sshc->quote_path1,
+                                  curlx_uztoui(strlen(sshc->quote_path1)),
+                                  sshc->quote_path2,
+                                  curlx_uztoui(strlen(sshc->quote_path2)),
+                                  LIBSSH2_SFTP_RENAME_OVERWRITE |
+                                  LIBSSH2_SFTP_RENAME_ATOMIC |
+                                  LIBSSH2_SFTP_RENAME_NATIVE);
+
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc && !sshc->acceptfail) {
+        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        Curl_safefree(sshc->quote_path1);
+        Curl_safefree(sshc->quote_path2);
+        failf(data, "rename command failed: %s",
+              sftp_libssh2_strerror(sftperr));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_RMDIR:
+      rc = libssh2_sftp_rmdir_ex(sshc->sftp_session, sshc->quote_path1,
+                                 curlx_uztoui(strlen(sshc->quote_path1)));
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc && !sshc->acceptfail) {
+        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        Curl_safefree(sshc->quote_path1);
+        failf(data, "rmdir command failed: %s",
+              sftp_libssh2_strerror(sftperr));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_UNLINK:
+      rc = libssh2_sftp_unlink_ex(sshc->sftp_session, sshc->quote_path1,
+                                  curlx_uztoui(strlen(sshc->quote_path1)));
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc && !sshc->acceptfail) {
+        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        Curl_safefree(sshc->quote_path1);
+        failf(data, "rm command failed: %s", sftp_libssh2_strerror(sftperr));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+#ifdef HAS_STATVFS_SUPPORT
+    case SSH_SFTP_QUOTE_STATVFS:
+    {
+      LIBSSH2_SFTP_STATVFS statvfs;
+      rc = libssh2_sftp_statvfs(sshc->sftp_session, sshc->quote_path1,
+                                curlx_uztoui(strlen(sshc->quote_path1)),
+                                &statvfs);
+
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc && !sshc->acceptfail) {
+        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        Curl_safefree(sshc->quote_path1);
+        failf(data, "statvfs command failed: %s",
+              sftp_libssh2_strerror(sftperr));
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      else if(rc == 0) {
+        #ifdef _MSC_VER
+        #define CURL_LIBSSH2_VFS_SIZE_MASK "I64u"
+        #else
+        #define CURL_LIBSSH2_VFS_SIZE_MASK "llu"
+        #endif
+        char *tmp = aprintf("statvfs:\n"
+                            "f_bsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
+                            "f_frsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
+                            "f_blocks: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
+                            "f_bfree: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
+                            "f_bavail: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
+                            "f_files: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
+                            "f_ffree: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
+                            "f_favail: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
+                            "f_fsid: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
+                            "f_flag: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
+                            "f_namemax: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n",
+                            statvfs.f_bsize, statvfs.f_frsize,
+                            statvfs.f_blocks, statvfs.f_bfree,
+                            statvfs.f_bavail, statvfs.f_files,
+                            statvfs.f_ffree, statvfs.f_favail,
+                            statvfs.f_fsid, statvfs.f_flag,
+                            statvfs.f_namemax);
+        if(!tmp) {
+          result = CURLE_OUT_OF_MEMORY;
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          break;
+        }
+
+        result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+        free(tmp);
+        if(result) {
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = result;
+        }
+      }
+      state(data, SSH_SFTP_NEXT_QUOTE);
+      break;
+    }
+#endif
+    case SSH_SFTP_GETINFO:
+    {
+      if(data->set.get_filetime) {
+        state(data, SSH_SFTP_FILETIME);
+      }
+      else {
+        state(data, SSH_SFTP_TRANS_INIT);
+      }
+      break;
+    }
+
+    case SSH_SFTP_FILETIME:
+    {
+      LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
+                                curlx_uztoui(strlen(sshp->path)),
+                                LIBSSH2_SFTP_STAT, &attrs);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc == 0) {
+        data->info.filetime = attrs.mtime;
+      }
+
+      state(data, SSH_SFTP_TRANS_INIT);
+      break;
+    }
+
+    case SSH_SFTP_TRANS_INIT:
+      if(data->state.upload)
+        state(data, SSH_SFTP_UPLOAD_INIT);
+      else {
+        if(sshp->path[strlen(sshp->path)-1] == '/')
+          state(data, SSH_SFTP_READDIR_INIT);
+        else
+          state(data, SSH_SFTP_DOWNLOAD_INIT);
+      }
+      break;
+
+    case SSH_SFTP_UPLOAD_INIT:
+    {
+      unsigned long flags;
+      /*
+       * NOTE!!!  libssh2 requires that the destination path is a full path
+       *          that includes the destination file and name OR ends in a "/"
+       *          If this is not done the destination file will be named the
+       *          same name as the last directory in the path.
+       */
+
+      if(data->state.resume_from) {
+        LIBSSH2_SFTP_ATTRIBUTES attrs;
+        if(data->state.resume_from < 0) {
+          rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
+                                    curlx_uztoui(strlen(sshp->path)),
+                                    LIBSSH2_SFTP_STAT, &attrs);
+          if(rc == LIBSSH2_ERROR_EAGAIN) {
+            break;
+          }
+          if(rc) {
+            data->state.resume_from = 0;
+          }
+          else {
+            curl_off_t size = attrs.filesize;
+            if(size < 0) {
+              failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
+              return CURLE_BAD_DOWNLOAD_RESUME;
+            }
+            data->state.resume_from = attrs.filesize;
+          }
+        }
+      }
+
+      if(data->set.remote_append)
+        /* Try to open for append, but create if nonexisting */
+        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
+      else if(data->state.resume_from > 0)
+        /* If we have restart position then open for append */
+        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
+      else
+        /* Clear file before writing (normal behavior) */
+        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
+
+      sshc->sftp_handle =
+        libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
+                             curlx_uztoui(strlen(sshp->path)),
+                             flags, data->set.new_file_perms,
+                             LIBSSH2_SFTP_OPENFILE);
+
+      if(!sshc->sftp_handle) {
+        rc = libssh2_session_last_errno(sshc->ssh_session);
+
+        if(LIBSSH2_ERROR_EAGAIN == rc)
+          break;
+
+        if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
+          /* only when there was an SFTP protocol error can we extract
+             the sftp error! */
+          sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        else
+          sftperr = LIBSSH2_FX_OK; /* not an sftp error at all */
+
+        if(sshc->secondCreateDirs) {
+          state(data, SSH_SFTP_CLOSE);
+          sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
+            sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH;
+          failf(data, "Creating the dir/file failed: %s",
+                sftp_libssh2_strerror(sftperr));
+          break;
+        }
+        if(((sftperr == LIBSSH2_FX_NO_SUCH_FILE) ||
+            (sftperr == LIBSSH2_FX_FAILURE) ||
+            (sftperr == LIBSSH2_FX_NO_SUCH_PATH)) &&
+           (data->set.ftp_create_missing_dirs &&
+            (strlen(sshp->path) > 1))) {
+          /* try to create the path remotely */
+          rc = 0; /* clear rc and continue */
+          sshc->secondCreateDirs = 1;
+          state(data, SSH_SFTP_CREATE_DIRS_INIT);
+          break;
+        }
+        state(data, SSH_SFTP_CLOSE);
+        sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
+          sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH;
+        if(!sshc->actualcode) {
+          /* Sometimes, for some reason libssh2_sftp_last_error() returns zero
+             even though libssh2_sftp_open() failed previously! We need to
+             work around that! */
+          sshc->actualcode = CURLE_SSH;
+          sftperr = LIBSSH2_FX_OK;
+        }
+        failf(data, "Upload failed: %s (%lu/%d)",
+              sftperr != LIBSSH2_FX_OK ?
+              sftp_libssh2_strerror(sftperr):"ssh error",
+              sftperr, rc);
+        break;
+      }
+
+      /* If we have a restart point then we need to seek to the correct
+         position. */
+      if(data->state.resume_from > 0) {
+        /* Let's read off the proper amount of bytes from the input. */
+        if(data->set.seek_func) {
+          Curl_set_in_callback(data, true);
+          seekerr = data->set.seek_func(data->set.seek_client,
+                                        data->state.resume_from, SEEK_SET);
+          Curl_set_in_callback(data, false);
+        }
+
+        if(seekerr != CURL_SEEKFUNC_OK) {
+          curl_off_t passed = 0;
+
+          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+            failf(data, "Could not seek stream");
+            return CURLE_FTP_COULDNT_USE_REST;
+          }
+          /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+          do {
+            char scratch[4*1024];
+            size_t readthisamountnow =
+              (data->state.resume_from - passed >
+                (curl_off_t)sizeof(scratch)) ?
+              sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
+
+            size_t actuallyread;
+            Curl_set_in_callback(data, true);
+            actuallyread = data->state.fread_func(scratch, 1,
+                                                  readthisamountnow,
+                                                  data->state.in);
+            Curl_set_in_callback(data, false);
+
+            passed += actuallyread;
+            if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+              /* this checks for greater-than only to make sure that the
+                 CURL_READFUNC_ABORT return code still aborts */
+              failf(data, "Failed to read data");
+              return CURLE_FTP_COULDNT_USE_REST;
+            }
+          } while(passed < data->state.resume_from);
+        }
+
+        /* now, decrease the size of the read */
+        if(data->state.infilesize > 0) {
+          data->state.infilesize -= data->state.resume_from;
+          data->req.size = data->state.infilesize;
+          Curl_pgrsSetUploadSize(data, data->state.infilesize);
+        }
+
+        SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+      }
+      if(data->state.infilesize > 0) {
+        data->req.size = data->state.infilesize;
+        Curl_pgrsSetUploadSize(data, data->state.infilesize);
+      }
+      /* upload data */
+      Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
+
+      /* not set by Curl_xfer_setup to preserve keepon bits */
+      conn->sockfd = conn->writesockfd;
+
+      if(result) {
+        state(data, SSH_SFTP_CLOSE);
+        sshc->actualcode = result;
+      }
+      else {
+        /* store this original bitmask setup to use later on if we can't
+           figure out a "real" bitmask */
+        sshc->orig_waitfor = data->req.keepon;
+
+        /* we want to use the _sending_ function even when the socket turns
+           out readable as the underlying libssh2 sftp send function will deal
+           with both accordingly */
+        data->state.select_bits = CURL_CSELECT_OUT;
+
+        /* since we don't really wait for anything at this point, we want the
+           state machine to move on as soon as possible so we set a very short
+           timeout here */
+        Curl_expire(data, 0, EXPIRE_RUN_NOW);
+
+        state(data, SSH_STOP);
+      }
+      break;
+    }
+
+    case SSH_SFTP_CREATE_DIRS_INIT:
+      if(strlen(sshp->path) > 1) {
+        sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */
+        state(data, SSH_SFTP_CREATE_DIRS);
+      }
+      else {
+        state(data, SSH_SFTP_UPLOAD_INIT);
+      }
+      break;
+
+    case SSH_SFTP_CREATE_DIRS:
+      sshc->slash_pos = strchr(sshc->slash_pos, '/');
+      if(sshc->slash_pos) {
+        *sshc->slash_pos = 0;
+
+        infof(data, "Creating directory '%s'", sshp->path);
+        state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
+        break;
+      }
+      state(data, SSH_SFTP_UPLOAD_INIT);
+      break;
+
+    case SSH_SFTP_CREATE_DIRS_MKDIR:
+      /* 'mode' - parameter is preliminary - default to 0644 */
+      rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshp->path,
+                                 curlx_uztoui(strlen(sshp->path)),
+                                 data->set.new_directory_perms);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      *sshc->slash_pos = '/';
+      ++sshc->slash_pos;
+      if(rc < 0) {
+        /*
+         * Abort if failure wasn't that the dir already exists or the
+         * permission was denied (creation might succeed further down the
+         * path) - retry on unspecific FAILURE also
+         */
+        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        if((sftperr != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
+           (sftperr != LIBSSH2_FX_FAILURE) &&
+           (sftperr != LIBSSH2_FX_PERMISSION_DENIED)) {
+          result = sftp_libssh2_error_to_CURLE(sftperr);
+          state(data, SSH_SFTP_CLOSE);
+          sshc->actualcode = result?result:CURLE_SSH;
+          break;
+        }
+        rc = 0; /* clear rc and continue */
+      }
+      state(data, SSH_SFTP_CREATE_DIRS);
+      break;
+
+    case SSH_SFTP_READDIR_INIT:
+      Curl_pgrsSetDownloadSize(data, -1);
+      if(data->req.no_body) {
+        state(data, SSH_STOP);
+        break;
+      }
+
+      /*
+       * This is a directory that we are trying to get, so produce a directory
+       * listing
+       */
+      sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session,
+                                               sshp->path,
+                                               curlx_uztoui(
+                                                 strlen(sshp->path)),
+                                               0, 0, LIBSSH2_SFTP_OPENDIR);
+      if(!sshc->sftp_handle) {
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        failf(data, "Could not open directory for reading: %s",
+              sftp_libssh2_strerror(sftperr));
+        state(data, SSH_SFTP_CLOSE);
+        result = sftp_libssh2_error_to_CURLE(sftperr);
+        sshc->actualcode = result?result:CURLE_SSH;
+        break;
+      }
+      sshp->readdir_filename = malloc(PATH_MAX + 1);
+      if(!sshp->readdir_filename) {
+        state(data, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        break;
+      }
+      sshp->readdir_longentry = malloc(PATH_MAX + 1);
+      if(!sshp->readdir_longentry) {
+        Curl_safefree(sshp->readdir_filename);
+        state(data, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        break;
+      }
+      Curl_dyn_init(&sshp->readdir, PATH_MAX * 2);
+      state(data, SSH_SFTP_READDIR);
+      break;
+
+    case SSH_SFTP_READDIR:
+      rc = libssh2_sftp_readdir_ex(sshc->sftp_handle,
+                                   sshp->readdir_filename,
+                                   PATH_MAX,
+                                   sshp->readdir_longentry,
+                                   PATH_MAX,
+                                   &sshp->readdir_attrs);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc > 0) {
+        readdir_len = (size_t) rc;
+        sshp->readdir_filename[readdir_len] = '\0';
+
+        if(data->set.list_only) {
+          result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                     sshp->readdir_filename,
+                                     readdir_len);
+          if(!result)
+            result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                       (char *)"\n", 1);
+          if(result) {
+            state(data, SSH_STOP);
+            break;
+          }
+
+        }
+        else {
+          result = Curl_dyn_add(&sshp->readdir, sshp->readdir_longentry);
+
+          if(!result) {
+            if((sshp->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
+               ((sshp->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+                LIBSSH2_SFTP_S_IFLNK)) {
+              Curl_dyn_init(&sshp->readdir_link, PATH_MAX);
+              result = Curl_dyn_addf(&sshp->readdir_link, "%s%s", sshp->path,
+                                     sshp->readdir_filename);
+              state(data, SSH_SFTP_READDIR_LINK);
+              if(!result)
+                break;
+            }
+            else {
+              state(data, SSH_SFTP_READDIR_BOTTOM);
+              break;
+            }
+          }
+          sshc->actualcode = result;
+          state(data, SSH_SFTP_CLOSE);
+          break;
+        }
+      }
+      else if(rc == 0) {
+        Curl_safefree(sshp->readdir_filename);
+        Curl_safefree(sshp->readdir_longentry);
+        state(data, SSH_SFTP_READDIR_DONE);
+        break;
+      }
+      else if(rc < 0) {
+        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        result = sftp_libssh2_error_to_CURLE(sftperr);
+        sshc->actualcode = result?result:CURLE_SSH;
+        failf(data, "Could not open remote file for reading: %s :: %d",
+              sftp_libssh2_strerror(sftperr),
+              libssh2_session_last_errno(sshc->ssh_session));
+        Curl_safefree(sshp->readdir_filename);
+        Curl_safefree(sshp->readdir_longentry);
+        state(data, SSH_SFTP_CLOSE);
+        break;
+      }
+      break;
+
+    case SSH_SFTP_READDIR_LINK:
+      rc =
+        libssh2_sftp_symlink_ex(sshc->sftp_session,
+                                Curl_dyn_ptr(&sshp->readdir_link),
+                                (int)Curl_dyn_len(&sshp->readdir_link),
+                                sshp->readdir_filename,
+                                PATH_MAX, LIBSSH2_SFTP_READLINK);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      Curl_dyn_free(&sshp->readdir_link);
+
+      /* append filename and extra output */
+      result = Curl_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename);
+
+      if(result) {
+        Curl_safefree(sshp->readdir_filename);
+        Curl_safefree(sshp->readdir_longentry);
+        state(data, SSH_SFTP_CLOSE);
+        sshc->actualcode = result;
+        break;
+      }
+
+      state(data, SSH_SFTP_READDIR_BOTTOM);
+      break;
+
+    case SSH_SFTP_READDIR_BOTTOM:
+      result = Curl_dyn_addn(&sshp->readdir, "\n", 1);
+      if(!result)
+        result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                   Curl_dyn_ptr(&sshp->readdir),
+                                   Curl_dyn_len(&sshp->readdir));
+
+      if(result) {
+        Curl_dyn_free(&sshp->readdir);
+        state(data, SSH_STOP);
+      }
+      else {
+        Curl_dyn_reset(&sshp->readdir);
+        state(data, SSH_SFTP_READDIR);
+      }
+      break;
+
+    case SSH_SFTP_READDIR_DONE:
+      if(libssh2_sftp_closedir(sshc->sftp_handle) ==
+         LIBSSH2_ERROR_EAGAIN) {
+        rc = LIBSSH2_ERROR_EAGAIN;
+        break;
+      }
+      sshc->sftp_handle = NULL;
+      Curl_safefree(sshp->readdir_filename);
+      Curl_safefree(sshp->readdir_longentry);
+
+      /* no data to transfer */
+      Curl_xfer_setup(data, -1, -1, FALSE, -1);
+      state(data, SSH_STOP);
+      break;
+
+    case SSH_SFTP_DOWNLOAD_INIT:
+      /*
+       * Work on getting the specified file
+       */
+      sshc->sftp_handle =
+        libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
+                             curlx_uztoui(strlen(sshp->path)),
+                             LIBSSH2_FXF_READ, data->set.new_file_perms,
+                             LIBSSH2_SFTP_OPENFILE);
+      if(!sshc->sftp_handle) {
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        failf(data, "Could not open remote file for reading: %s",
+              sftp_libssh2_strerror(sftperr));
+        state(data, SSH_SFTP_CLOSE);
+        result = sftp_libssh2_error_to_CURLE(sftperr);
+        sshc->actualcode = result?result:CURLE_SSH;
+        break;
+      }
+      state(data, SSH_SFTP_DOWNLOAD_STAT);
+      break;
+
+    case SSH_SFTP_DOWNLOAD_STAT:
+    {
+      LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
+                                curlx_uztoui(strlen(sshp->path)),
+                                LIBSSH2_SFTP_STAT, &attrs);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      if(rc ||
+         !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) ||
+         (attrs.filesize == 0)) {
+        /*
+         * libssh2_sftp_open() didn't return an error, so maybe the server
+         * just doesn't support stat()
+         * OR the server doesn't return a file size with a stat()
+         * OR file size is 0
+         */
+        data->req.size = -1;
+        data->req.maxdownload = -1;
+        Curl_pgrsSetDownloadSize(data, -1);
+      }
+      else {
+        curl_off_t size = attrs.filesize;
+
+        if(size < 0) {
+          failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
+          return CURLE_BAD_DOWNLOAD_RESUME;
+        }
+        if(data->state.use_range) {
+          curl_off_t from, to;
+          char *ptr;
+          char *ptr2;
+          CURLofft to_t;
+          CURLofft from_t;
+
+          from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
+          if(from_t == CURL_OFFT_FLOW)
+            return CURLE_RANGE_ERROR;
+          while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
+            ptr++;
+          to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
+          if(to_t == CURL_OFFT_FLOW)
+            return CURLE_RANGE_ERROR;
+          if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
+             || (to >= size)) {
+            to = size - 1;
+          }
+          if(from_t) {
+            /* from is relative to end of file */
+            from = size - to;
+            to = size - 1;
+          }
+          if(from > size) {
+            failf(data, "Offset (%"
+                  CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
+                  CURL_FORMAT_CURL_OFF_T ")", from,
+                  (curl_off_t)attrs.filesize);
+            return CURLE_BAD_DOWNLOAD_RESUME;
+          }
+          if(from > to) {
+            from = to;
+            size = 0;
+          }
+          else {
+            if((to - from) == CURL_OFF_T_MAX)
+              return CURLE_RANGE_ERROR;
+            size = to - from + 1;
+          }
+
+          SFTP_SEEK(sshc->sftp_handle, from);
+        }
+        data->req.size = size;
+        data->req.maxdownload = size;
+        Curl_pgrsSetDownloadSize(data, size);
+      }
+
+      /* We can resume if we can seek to the resume position */
+      if(data->state.resume_from) {
+        if(data->state.resume_from < 0) {
+          /* We're supposed to download the last abs(from) bytes */
+          if((curl_off_t)attrs.filesize < -data->state.resume_from) {
+            failf(data, "Offset (%"
+                  CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
+                  CURL_FORMAT_CURL_OFF_T ")",
+                  data->state.resume_from, (curl_off_t)attrs.filesize);
+            return CURLE_BAD_DOWNLOAD_RESUME;
+          }
+          /* download from where? */
+          data->state.resume_from += attrs.filesize;
+        }
+        else {
+          if((curl_off_t)attrs.filesize < data->state.resume_from) {
+            failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
+                  ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
+                  data->state.resume_from, (curl_off_t)attrs.filesize);
+            return CURLE_BAD_DOWNLOAD_RESUME;
+          }
+        }
+        /* Now store the number of bytes we are expected to download */
+        data->req.size = attrs.filesize - data->state.resume_from;
+        data->req.maxdownload = attrs.filesize - data->state.resume_from;
+        Curl_pgrsSetDownloadSize(data,
+                                 attrs.filesize - data->state.resume_from);
+        SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+      }
+    }
+
+    /* Setup the actual download */
+    if(data->req.size == 0) {
+      /* no data to transfer */
+      Curl_xfer_setup(data, -1, -1, FALSE, -1);
+      infof(data, "File already completely downloaded");
+      state(data, SSH_STOP);
+      break;
+    }
+    Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);
+
+    /* not set by Curl_xfer_setup to preserve keepon bits */
+    conn->writesockfd = conn->sockfd;
+
+    /* we want to use the _receiving_ function even when the socket turns
+       out writableable as the underlying libssh2 recv function will deal
+       with both accordingly */
+    data->state.select_bits = CURL_CSELECT_IN;
+
+    if(result) {
+      /* this should never occur; the close state should be entered
+         at the time the error occurs */
+      state(data, SSH_SFTP_CLOSE);
+      sshc->actualcode = result;
+    }
+    else {
+      state(data, SSH_STOP);
+    }
+    break;
+
+    case SSH_SFTP_CLOSE:
+      if(sshc->sftp_handle) {
+        rc = libssh2_sftp_close(sshc->sftp_handle);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        if(rc < 0) {
+          char *err_msg = NULL;
+          (void)libssh2_session_last_error(sshc->ssh_session,
+                                           &err_msg, NULL, 0);
+          infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
+        }
+        sshc->sftp_handle = NULL;
+      }
+
+      Curl_safefree(sshp->path);
+
+      DEBUGF(infof(data, "SFTP DONE done"));
+
+      /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
+         After nextstate is executed, the control should come back to
+         SSH_SFTP_CLOSE to pass the correct result back  */
+      if(sshc->nextstate != SSH_NO_STATE &&
+         sshc->nextstate != SSH_SFTP_CLOSE) {
+        state(data, sshc->nextstate);
+        sshc->nextstate = SSH_SFTP_CLOSE;
+      }
+      else {
+        state(data, SSH_STOP);
+        result = sshc->actualcode;
+      }
+      break;
+
+    case SSH_SFTP_SHUTDOWN:
+      /* during times we get here due to a broken transfer and then the
+         sftp_handle might not have been taken down so make sure that is done
+         before we proceed */
+
+      if(sshc->sftp_handle) {
+        rc = libssh2_sftp_close(sshc->sftp_handle);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        if(rc < 0) {
+          char *err_msg = NULL;
+          (void)libssh2_session_last_error(sshc->ssh_session, &err_msg,
+                                           NULL, 0);
+          infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
+        }
+        sshc->sftp_handle = NULL;
+      }
+      if(sshc->sftp_session) {
+        rc = libssh2_sftp_shutdown(sshc->sftp_session);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        if(rc < 0) {
+          infof(data, "Failed to stop libssh2 sftp subsystem");
+        }
+        sshc->sftp_session = NULL;
+      }
+
+      Curl_safefree(sshc->homedir);
+      data->state.most_recent_ftp_entrypath = NULL;
+
+      state(data, SSH_SESSION_DISCONNECT);
+      break;
+
+    case SSH_SCP_TRANS_INIT:
+      result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
+      if(result) {
+        sshc->actualcode = result;
+        state(data, SSH_STOP);
+        break;
+      }
+
+      if(data->state.upload) {
+        if(data->state.infilesize < 0) {
+          failf(data, "SCP requires a known file size for upload");
+          sshc->actualcode = CURLE_UPLOAD_FAILED;
+          state(data, SSH_SCP_CHANNEL_FREE);
+          break;
+        }
+        state(data, SSH_SCP_UPLOAD_INIT);
+      }
+      else {
+        state(data, SSH_SCP_DOWNLOAD_INIT);
+      }
+      break;
+
+    case SSH_SCP_UPLOAD_INIT:
+      /*
+       * libssh2 requires that the destination path is a full path that
+       * includes the destination file and name OR ends in a "/" .  If this is
+       * not done the destination file will be named the same name as the last
+       * directory in the path.
+       */
+      sshc->ssh_channel =
+        SCP_SEND(sshc->ssh_session, sshp->path, data->set.new_file_perms,
+                 data->state.infilesize);
+      if(!sshc->ssh_channel) {
+        int ssh_err;
+        char *err_msg = NULL;
+
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+
+        ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
+                                                   &err_msg, NULL, 0));
+        failf(data, "%s", err_msg);
+        state(data, SSH_SCP_CHANNEL_FREE);
+        sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
+        /* Map generic errors to upload failed */
+        if(sshc->actualcode == CURLE_SSH ||
+           sshc->actualcode == CURLE_REMOTE_FILE_NOT_FOUND)
+          sshc->actualcode = CURLE_UPLOAD_FAILED;
+        break;
+      }
+
+      /* upload data */
+      data->req.size = data->state.infilesize;
+      Curl_pgrsSetUploadSize(data, data->state.infilesize);
+      Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
+
+      /* not set by Curl_xfer_setup to preserve keepon bits */
+      conn->sockfd = conn->writesockfd;
+
+      if(result) {
+        state(data, SSH_SCP_CHANNEL_FREE);
+        sshc->actualcode = result;
+      }
+      else {
+        /* store this original bitmask setup to use later on if we can't
+           figure out a "real" bitmask */
+        sshc->orig_waitfor = data->req.keepon;
+
+        /* we want to use the _sending_ function even when the socket turns
+           out readable as the underlying libssh2 scp send function will deal
+           with both accordingly */
+        data->state.select_bits = CURL_CSELECT_OUT;
+
+        state(data, SSH_STOP);
+      }
+      break;
+
+    case SSH_SCP_DOWNLOAD_INIT:
+    {
+      curl_off_t bytecount;
+
+      /*
+       * We must check the remote file; if it is a directory no values will
+       * be set in sb
+       */
+
+      /*
+       * If support for >2GB files exists, use it.
+       */
+
+      /* get a fresh new channel from the ssh layer */
+#if LIBSSH2_VERSION_NUM < 0x010700
+      struct stat sb;
+      memset(&sb, 0, sizeof(struct stat));
+      sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
+                                           sshp->path, &sb);
+#else
+      libssh2_struct_stat sb;
+      memset(&sb, 0, sizeof(libssh2_struct_stat));
+      sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session,
+                                            sshp->path, &sb);
+#endif
+
+      if(!sshc->ssh_channel) {
+        int ssh_err;
+        char *err_msg = NULL;
+
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+
+
+        ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
+                                                   &err_msg, NULL, 0));
+        failf(data, "%s", err_msg);
+        state(data, SSH_SCP_CHANNEL_FREE);
+        sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
+        break;
+      }
+
+      /* download data */
+      bytecount = (curl_off_t)sb.st_size;
+      data->req.maxdownload = (curl_off_t)sb.st_size;
+      Curl_xfer_setup(data, FIRSTSOCKET, bytecount, FALSE, -1);
+
+      /* not set by Curl_xfer_setup to preserve keepon bits */
+      conn->writesockfd = conn->sockfd;
+
+      /* we want to use the _receiving_ function even when the socket turns
+         out writableable as the underlying libssh2 recv function will deal
+         with both accordingly */
+      data->state.select_bits = CURL_CSELECT_IN;
+
+      if(result) {
+        state(data, SSH_SCP_CHANNEL_FREE);
+        sshc->actualcode = result;
+      }
+      else
+        state(data, SSH_STOP);
+    }
+    break;
+
+    case SSH_SCP_DONE:
+      if(data->state.upload)
+        state(data, SSH_SCP_SEND_EOF);
+      else
+        state(data, SSH_SCP_CHANNEL_FREE);
+      break;
+
+    case SSH_SCP_SEND_EOF:
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_send_eof(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        if(rc) {
+          char *err_msg = NULL;
+          (void)libssh2_session_last_error(sshc->ssh_session,
+                                           &err_msg, NULL, 0);
+          infof(data, "Failed to send libssh2 channel EOF: %d %s",
+                rc, err_msg);
+        }
+      }
+      state(data, SSH_SCP_WAIT_EOF);
+      break;
+
+    case SSH_SCP_WAIT_EOF:
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_wait_eof(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        if(rc) {
+          char *err_msg = NULL;
+          (void)libssh2_session_last_error(sshc->ssh_session,
+                                           &err_msg, NULL, 0);
+          infof(data, "Failed to get channel EOF: %d %s", rc, err_msg);
+        }
+      }
+      state(data, SSH_SCP_WAIT_CLOSE);
+      break;
+
+    case SSH_SCP_WAIT_CLOSE:
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_wait_closed(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        if(rc) {
+          char *err_msg = NULL;
+          (void)libssh2_session_last_error(sshc->ssh_session,
+                                           &err_msg, NULL, 0);
+          infof(data, "Channel failed to close: %d %s", rc, err_msg);
+        }
+      }
+      state(data, SSH_SCP_CHANNEL_FREE);
+      break;
+
+    case SSH_SCP_CHANNEL_FREE:
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_free(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        if(rc < 0) {
+          char *err_msg = NULL;
+          (void)libssh2_session_last_error(sshc->ssh_session,
+                                           &err_msg, NULL, 0);
+          infof(data, "Failed to free libssh2 scp subsystem: %d %s",
+                rc, err_msg);
+        }
+        sshc->ssh_channel = NULL;
+      }
+      DEBUGF(infof(data, "SCP DONE phase complete"));
+#if 0 /* PREV */
+      state(data, SSH_SESSION_DISCONNECT);
+#endif
+      state(data, SSH_STOP);
+      result = sshc->actualcode;
+      break;
+
+    case SSH_SESSION_DISCONNECT:
+      /* during weird times when we've been prematurely aborted, the channel
+         is still alive when we reach this state and we MUST kill the channel
+         properly first */
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_free(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        if(rc < 0) {
+          char *err_msg = NULL;
+          (void)libssh2_session_last_error(sshc->ssh_session,
+                                           &err_msg, NULL, 0);
+          infof(data, "Failed to free libssh2 scp subsystem: %d %s",
+                rc, err_msg);
+        }
+        sshc->ssh_channel = NULL;
+      }
+
+      if(sshc->ssh_session) {
+        rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        if(rc < 0) {
+          char *err_msg = NULL;
+          (void)libssh2_session_last_error(sshc->ssh_session,
+                                           &err_msg, NULL, 0);
+          infof(data, "Failed to disconnect libssh2 session: %d %s",
+                rc, err_msg);
+        }
+      }
+
+      Curl_safefree(sshc->homedir);
+      data->state.most_recent_ftp_entrypath = NULL;
+
+      state(data, SSH_SESSION_FREE);
+      break;
+
+    case SSH_SESSION_FREE:
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+      if(sshc->kh) {
+        libssh2_knownhost_free(sshc->kh);
+        sshc->kh = NULL;
+      }
+#endif
+
+#ifdef HAVE_LIBSSH2_AGENT_API
+      if(sshc->ssh_agent) {
+        rc = libssh2_agent_disconnect(sshc->ssh_agent);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        if(rc < 0) {
+          char *err_msg = NULL;
+          (void)libssh2_session_last_error(sshc->ssh_session,
+                                           &err_msg, NULL, 0);
+          infof(data, "Failed to disconnect from libssh2 agent: %d %s",
+                rc, err_msg);
+        }
+        libssh2_agent_free(sshc->ssh_agent);
+        sshc->ssh_agent = NULL;
+
+        /* NB: there is no need to free identities, they are part of internal
+           agent stuff */
+        sshc->sshagent_identity = NULL;
+        sshc->sshagent_prev_identity = NULL;
+      }
+#endif
+
+      if(sshc->ssh_session) {
+        rc = libssh2_session_free(sshc->ssh_session);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        if(rc < 0) {
+          char *err_msg = NULL;
+          (void)libssh2_session_last_error(sshc->ssh_session,
+                                           &err_msg, NULL, 0);
+          infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg);
+        }
+        sshc->ssh_session = NULL;
+      }
+
+      /* worst-case scenario cleanup */
+
+      DEBUGASSERT(sshc->ssh_session == NULL);
+      DEBUGASSERT(sshc->ssh_channel == NULL);
+      DEBUGASSERT(sshc->sftp_session == NULL);
+      DEBUGASSERT(sshc->sftp_handle == NULL);
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+      DEBUGASSERT(sshc->kh == NULL);
+#endif
+#ifdef HAVE_LIBSSH2_AGENT_API
+      DEBUGASSERT(sshc->ssh_agent == NULL);
+#endif
+
+      Curl_safefree(sshc->rsa_pub);
+      Curl_safefree(sshc->rsa);
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      Curl_safefree(sshc->homedir);
+
+      /* the code we are about to return */
+      result = sshc->actualcode;
+
+      memset(sshc, 0, sizeof(struct ssh_conn));
+
+      connclose(conn, "SSH session free");
+      sshc->state = SSH_SESSION_FREE; /* current */
+      sshc->nextstate = SSH_NO_STATE;
+      state(data, SSH_STOP);
+      break;
+
+    case SSH_QUIT:
+    default:
+      /* internal error */
+      sshc->nextstate = SSH_NO_STATE;
+      state(data, SSH_STOP);
+      break;
+    }
+
+  } while(!rc && (sshc->state != SSH_STOP));
+
+  if(rc == LIBSSH2_ERROR_EAGAIN) {
+    /* we would block, we need to wait for the socket to be ready (in the
+       right direction too)! */
+    *block = TRUE;
+  }
+
+  return result;
+}
+
+/* called by the multi interface to figure out what socket(s) to wait for and
+   for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
+static int ssh_getsock(struct Curl_easy *data,
+                       struct connectdata *conn,
+                       curl_socket_t *sock)
+{
+  int bitmap = GETSOCK_BLANK;
+  (void)data;
+
+  sock[0] = conn->sock[FIRSTSOCKET];
+
+  if(conn->waitfor & KEEP_RECV)
+    bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
+
+  if(conn->waitfor & KEEP_SEND)
+    bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
+
+  return bitmap;
+}
+
+/*
+ * When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this
+ * function is used to figure out in what direction and stores this info so
+ * that the multi interface can take advantage of it. Make sure to call this
+ * function in all cases so that when it _doesn't_ return EAGAIN we can
+ * restore the default wait bits.
+ */
+static void ssh_block2waitfor(struct Curl_easy *data, bool block)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  int dir = 0;
+  if(block) {
+    dir = libssh2_session_block_directions(sshc->ssh_session);
+    if(dir) {
+      /* translate the libssh2 define bits into our own bit defines */
+      conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) |
+        ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0);
+    }
+  }
+  if(!dir)
+    /* It didn't block or libssh2 didn't reveal in which direction, put back
+       the original set */
+    conn->waitfor = sshc->orig_waitfor;
+}
+
+/* called repeatedly until done from multi.c */
+static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  CURLcode result = CURLE_OK;
+  bool block; /* we store the status and use that to provide a ssh_getsock()
+                 implementation */
+  do {
+    result = ssh_statemach_act(data, &block);
+    *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
+    /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
+       try again */
+  } while(!result && !*done && !block);
+  ssh_block2waitfor(data, block);
+
+  return result;
+}
+
+static CURLcode ssh_block_statemach(struct Curl_easy *data,
+                                    struct connectdata *conn,
+                                    bool disconnect)
+{
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  CURLcode result = CURLE_OK;
+  struct curltime dis = Curl_now();
+
+  while((sshc->state != SSH_STOP) && !result) {
+    bool block;
+    timediff_t left = 1000;
+    struct curltime now = Curl_now();
+
+    result = ssh_statemach_act(data, &block);
+    if(result)
+      break;
+
+    if(!disconnect) {
+      if(Curl_pgrsUpdate(data))
+        return CURLE_ABORTED_BY_CALLBACK;
+
+      result = Curl_speedcheck(data, now);
+      if(result)
+        break;
+
+      left = Curl_timeleft(data, NULL, FALSE);
+      if(left < 0) {
+        failf(data, "Operation timed out");
+        return CURLE_OPERATION_TIMEDOUT;
+      }
+    }
+    else if(Curl_timediff(now, dis) > 1000) {
+      /* disconnect timeout */
+      failf(data, "Disconnect timed out");
+      result = CURLE_OK;
+      break;
+    }
+
+    if(block) {
+      int dir = libssh2_session_block_directions(sshc->ssh_session);
+      curl_socket_t sock = conn->sock[FIRSTSOCKET];
+      curl_socket_t fd_read = CURL_SOCKET_BAD;
+      curl_socket_t fd_write = CURL_SOCKET_BAD;
+      if(LIBSSH2_SESSION_BLOCK_INBOUND & dir)
+        fd_read = sock;
+      if(LIBSSH2_SESSION_BLOCK_OUTBOUND & dir)
+        fd_write = sock;
+      /* wait for the socket to become ready */
+      (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write,
+                              left>1000?1000:left);
+    }
+  }
+
+  return result;
+}
+
+/*
+ * SSH setup and connection
+ */
+static CURLcode ssh_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn)
+{
+  struct SSHPROTO *ssh;
+  (void)conn;
+
+  data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
+  if(!ssh)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+static Curl_recv scp_recv, sftp_recv;
+static Curl_send scp_send, sftp_send;
+
+#ifndef CURL_DISABLE_PROXY
+static ssize_t ssh_tls_recv(libssh2_socket_t sock, void *buffer,
+                            size_t length, int flags, void **abstract)
+{
+  struct Curl_easy *data = (struct Curl_easy *)*abstract;
+  ssize_t nread;
+  CURLcode result;
+  struct connectdata *conn = data->conn;
+  Curl_recv *backup = conn->recv[0];
+  struct ssh_conn *ssh = &conn->proto.sshc;
+  int socknum = Curl_conn_sockindex(data, sock);
+  (void)flags;
+
+  /* swap in the TLS reader function for this call only, and then swap back
+     the SSH one again */
+  conn->recv[0] = ssh->tls_recv;
+  result = Curl_conn_recv(data, socknum, buffer, length, &nread);
+  conn->recv[0] = backup;
+  if(result == CURLE_AGAIN)
+    return -EAGAIN; /* magic return code for libssh2 */
+  else if(result)
+    return -1; /* generic error */
+  Curl_debug(data, CURLINFO_DATA_IN, (char *)buffer, (size_t)nread);
+  return nread;
+}
+
+static ssize_t ssh_tls_send(libssh2_socket_t sock, const void *buffer,
+                            size_t length, int flags, void **abstract)
+{
+  struct Curl_easy *data = (struct Curl_easy *)*abstract;
+  size_t nwrite;
+  CURLcode result;
+  struct connectdata *conn = data->conn;
+  Curl_send *backup = conn->send[0];
+  struct ssh_conn *ssh = &conn->proto.sshc;
+  int socknum = Curl_conn_sockindex(data, sock);
+  (void)flags;
+
+  /* swap in the TLS writer function for this call only, and then swap back
+     the SSH one again */
+  conn->send[0] = ssh->tls_send;
+  result = Curl_conn_send(data, socknum, buffer, length, &nwrite);
+  conn->send[0] = backup;
+  if(result == CURLE_AGAIN)
+    return -EAGAIN; /* magic return code for libssh2 */
+  else if(result)
+    return -1; /* error */
+  Curl_debug(data, CURLINFO_DATA_OUT, (char *)buffer, nwrite);
+  return (ssize_t)nwrite;
+}
+#endif
+
+/*
+ * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
+ * do protocol-specific actions at connect-time.
+ */
+static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
+{
+#ifdef CURL_LIBSSH2_DEBUG
+  curl_socket_t sock;
+#endif
+  struct ssh_conn *sshc;
+  CURLcode result;
+  struct connectdata *conn = data->conn;
+
+  /* initialize per-handle data if not already */
+  if(!data->req.p.ssh) {
+    result = ssh_setup_connection(data, conn);
+    if(result)
+      return result;
+  }
+
+  /* We default to persistent connections. We set this already in this connect
+     function to make the reuse checks properly be able to check this bit. */
+  connkeep(conn, "SSH default");
+
+  sshc = &conn->proto.sshc;
+
+#ifdef CURL_LIBSSH2_DEBUG
+  if(conn->user) {
+    infof(data, "User: %s", conn->user);
+  }
+  if(conn->passwd) {
+    infof(data, "Password: %s", conn->passwd);
+  }
+  sock = conn->sock[FIRSTSOCKET];
+#endif /* CURL_LIBSSH2_DEBUG */
+
+  /* libcurl MUST to set custom memory functions so that the kbd_callback
+     function's memory allocations can be properly freed */
+  sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
+                                              my_libssh2_free,
+                                              my_libssh2_realloc, data);
+
+  if(!sshc->ssh_session) {
+    failf(data, "Failure initialising ssh session");
+    return CURLE_FAILED_INIT;
+  }
+
+#ifdef HAVE_LIBSSH2_VERSION
+  /* Set the packet read timeout if the libssh2 version supports it */
+#if LIBSSH2_VERSION_NUM >= 0x010B00
+  if(data->set.server_response_timeout > 0) {
+    libssh2_session_set_read_timeout(sshc->ssh_session,
+                                     data->set.server_response_timeout / 1000);
+  }
+#endif
+#endif
+
+#ifndef CURL_DISABLE_PROXY
+  if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
+    /*
+      Setup libssh2 callbacks to make it read/write TLS from the socket.
+
+      ssize_t
+      recvcb(libssh2_socket_t sock, void *buffer, size_t length,
+      int flags, void **abstract);
+
+      ssize_t
+      sendcb(libssh2_socket_t sock, const void *buffer, size_t length,
+      int flags, void **abstract);
+
+    */
+#if LIBSSH2_VERSION_NUM >= 0x010b01
+    infof(data, "Uses HTTPS proxy");
+    libssh2_session_callback_set2(sshc->ssh_session,
+                                  LIBSSH2_CALLBACK_RECV,
+                                  (libssh2_cb_generic *)ssh_tls_recv);
+    libssh2_session_callback_set2(sshc->ssh_session,
+                                  LIBSSH2_CALLBACK_SEND,
+                                  (libssh2_cb_generic *)ssh_tls_send);
+#else
+    /*
+     * This crazy union dance is here to avoid assigning a void pointer a
+     * function pointer as it is invalid C. The problem is of course that
+     * libssh2 has such an API...
+     */
+    union receive {
+      void *recvp;
+      ssize_t (*recvptr)(libssh2_socket_t, void *, size_t, int, void **);
+    };
+    union transfer {
+      void *sendp;
+      ssize_t (*sendptr)(libssh2_socket_t, const void *, size_t, int, void **);
+    };
+    union receive sshrecv;
+    union transfer sshsend;
+
+    sshrecv.recvptr = ssh_tls_recv;
+    sshsend.sendptr = ssh_tls_send;
+
+    infof(data, "Uses HTTPS proxy");
+    libssh2_session_callback_set(sshc->ssh_session,
+                                 LIBSSH2_CALLBACK_RECV, sshrecv.recvp);
+    libssh2_session_callback_set(sshc->ssh_session,
+                                 LIBSSH2_CALLBACK_SEND, sshsend.sendp);
+#endif
+
+    /* Store the underlying TLS recv/send function pointers to be used when
+       reading from the proxy */
+    sshc->tls_recv = conn->recv[FIRSTSOCKET];
+    sshc->tls_send = conn->send[FIRSTSOCKET];
+  }
+
+#endif /* CURL_DISABLE_PROXY */
+  if(conn->handler->protocol & CURLPROTO_SCP) {
+    conn->recv[FIRSTSOCKET] = scp_recv;
+    conn->send[FIRSTSOCKET] = scp_send;
+  }
+  else {
+    conn->recv[FIRSTSOCKET] = sftp_recv;
+    conn->send[FIRSTSOCKET] = sftp_send;
+  }
+
+  if(data->set.ssh_compression) {
+#if LIBSSH2_VERSION_NUM >= 0x010208
+    if(libssh2_session_flag(sshc->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0)
+#endif
+      infof(data, "Failed to enable compression for ssh session");
+  }
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+  if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
+    int rc;
+    sshc->kh = libssh2_knownhost_init(sshc->ssh_session);
+    if(!sshc->kh) {
+      libssh2_session_free(sshc->ssh_session);
+      sshc->ssh_session = NULL;
+      return CURLE_FAILED_INIT;
+    }
+
+    /* read all known hosts from there */
+    rc = libssh2_knownhost_readfile(sshc->kh,
+                                    data->set.str[STRING_SSH_KNOWNHOSTS],
+                                    LIBSSH2_KNOWNHOST_FILE_OPENSSH);
+    if(rc < 0)
+      infof(data, "Failed to read known hosts from %s",
+            data->set.str[STRING_SSH_KNOWNHOSTS]);
+  }
+#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
+
+#ifdef CURL_LIBSSH2_DEBUG
+  libssh2_trace(sshc->ssh_session, ~0);
+  infof(data, "SSH socket: %d", (int)sock);
+#endif /* CURL_LIBSSH2_DEBUG */
+
+  state(data, SSH_INIT);
+
+  result = ssh_multi_statemach(data, done);
+
+  return result;
+}
+
+/*
+ ***********************************************************************
+ *
+ * scp_perform()
+ *
+ * This is the actual DO function for SCP. Get a file according to
+ * the options previously setup.
+ */
+
+static
+CURLcode scp_perform(struct Curl_easy *data,
+                     bool *connected,
+                     bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGF(infof(data, "DO phase starts"));
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* start the first command in the DO phase */
+  state(data, SSH_SCP_TRANS_INIT);
+
+  /* run the state-machine */
+  result = ssh_multi_statemach(data, dophase_done);
+
+  *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
+
+  if(*dophase_done) {
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+
+  return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode scp_doing(struct Curl_easy *data,
+                          bool *dophase_done)
+{
+  CURLcode result;
+  result = ssh_multi_statemach(data, dophase_done);
+
+  if(*dophase_done) {
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+  return result;
+}
+
+/*
+ * The DO function is generic for both protocols. There was previously two
+ * separate ones but this way means less duplicated code.
+ */
+
+static CURLcode ssh_do(struct Curl_easy *data, bool *done)
+{
+  CURLcode result;
+  bool connected = 0;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+
+  *done = FALSE; /* default to false */
+
+  data->req.size = -1; /* make sure this is unknown at this point */
+
+  sshc->actualcode = CURLE_OK; /* reset error code */
+  sshc->secondCreateDirs = 0;   /* reset the create dir attempt state
+                                   variable */
+
+  Curl_pgrsSetUploadCounter(data, 0);
+  Curl_pgrsSetDownloadCounter(data, 0);
+  Curl_pgrsSetUploadSize(data, -1);
+  Curl_pgrsSetDownloadSize(data, -1);
+
+  if(conn->handler->protocol & CURLPROTO_SCP)
+    result = scp_perform(data, &connected,  done);
+  else
+    result = sftp_perform(data, &connected,  done);
+
+  return result;
+}
+
+/* BLOCKING, but the function is using the state machine so the only reason
+   this is still blocking is that the multi interface code has no support for
+   disconnecting operations that takes a while */
+static CURLcode scp_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn,
+                               bool dead_connection)
+{
+  CURLcode result = CURLE_OK;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  (void) dead_connection;
+
+  if(sshc->ssh_session) {
+    /* only if there's a session still around to use! */
+    state(data, SSH_SESSION_DISCONNECT);
+    result = ssh_block_statemach(data, conn, TRUE);
+  }
+
+  return result;
+}
+
+/* generic done function for both SCP and SFTP called from their specific
+   done functions */
+static CURLcode ssh_done(struct Curl_easy *data, CURLcode status)
+{
+  CURLcode result = CURLE_OK;
+  struct SSHPROTO *sshp = data->req.p.ssh;
+  struct connectdata *conn = data->conn;
+
+  if(!status)
+    /* run the state-machine */
+    result = ssh_block_statemach(data, conn, FALSE);
+  else
+    result = status;
+
+  Curl_safefree(sshp->path);
+  Curl_safefree(sshp->readdir_filename);
+  Curl_safefree(sshp->readdir_longentry);
+  Curl_dyn_free(&sshp->readdir);
+
+  if(Curl_pgrsDone(data))
+    return CURLE_ABORTED_BY_CALLBACK;
+
+  data->req.keepon = 0; /* clear all bits */
+  return result;
+}
+
+
+static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
+                         bool premature)
+{
+  (void)premature; /* not used */
+
+  if(!status)
+    state(data, SSH_SCP_DONE);
+
+  return ssh_done(data, status);
+
+}
+
+static ssize_t scp_send(struct Curl_easy *data, int sockindex,
+                        const void *mem, size_t len, CURLcode *err)
+{
+  ssize_t nwrite;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  (void)sockindex; /* we only support SCP on the fixed known primary socket */
+
+  /* libssh2_channel_write() returns int! */
+  nwrite = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len);
+
+  ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+  if(nwrite == LIBSSH2_ERROR_EAGAIN) {
+    *err = CURLE_AGAIN;
+    nwrite = 0;
+  }
+  else if(nwrite < LIBSSH2_ERROR_NONE) {
+    *err = libssh2_session_error_to_CURLE((int)nwrite);
+    nwrite = -1;
+  }
+
+  return nwrite;
+}
+
+static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
+                        char *mem, size_t len, CURLcode *err)
+{
+  ssize_t nread;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  (void)sockindex; /* we only support SCP on the fixed known primary socket */
+
+  /* libssh2_channel_read() returns int */
+  nread = (ssize_t) libssh2_channel_read(sshc->ssh_channel, mem, len);
+
+  ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+  if(nread == LIBSSH2_ERROR_EAGAIN) {
+    *err = CURLE_AGAIN;
+    nread = -1;
+  }
+
+  return nread;
+}
+
+/*
+ * =============== SFTP ===============
+ */
+
+/*
+ ***********************************************************************
+ *
+ * sftp_perform()
+ *
+ * This is the actual DO function for SFTP. Get a file/directory according to
+ * the options previously setup.
+ */
+
+static
+CURLcode sftp_perform(struct Curl_easy *data,
+                      bool *connected,
+                      bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGF(infof(data, "DO phase starts"));
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* start the first command in the DO phase */
+  state(data, SSH_SFTP_QUOTE_INIT);
+
+  /* run the state-machine */
+  result = ssh_multi_statemach(data, dophase_done);
+
+  *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
+
+  if(*dophase_done) {
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+
+  return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode sftp_doing(struct Curl_easy *data,
+                           bool *dophase_done)
+{
+  CURLcode result = ssh_multi_statemach(data, dophase_done);
+
+  if(*dophase_done) {
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+  return result;
+}
+
+/* BLOCKING, but the function is using the state machine so the only reason
+   this is still blocking is that the multi interface code has no support for
+   disconnecting operations that takes a while */
+static CURLcode sftp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead_connection)
+{
+  CURLcode result = CURLE_OK;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  (void) dead_connection;
+
+  DEBUGF(infof(data, "SSH DISCONNECT starts now"));
+
+  if(sshc->ssh_session) {
+    /* only if there's a session still around to use! */
+    state(data, SSH_SFTP_SHUTDOWN);
+    result = ssh_block_statemach(data, conn, TRUE);
+  }
+
+  DEBUGF(infof(data, "SSH DISCONNECT is done"));
+
+  return result;
+
+}
+
+static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
+                               bool premature)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+
+  if(!status) {
+    /* Post quote commands are executed after the SFTP_CLOSE state to avoid
+       errors that could happen due to open file handles during POSTQUOTE
+       operation */
+    if(!premature && data->set.postquote && !conn->bits.retry)
+      sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
+    state(data, SSH_SFTP_CLOSE);
+  }
+  return ssh_done(data, status);
+}
+
+/* return number of sent bytes */
+static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
+                         const void *mem, size_t len, CURLcode *err)
+{
+  ssize_t nwrite;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  (void)sockindex;
+
+  nwrite = libssh2_sftp_write(sshc->sftp_handle, mem, len);
+
+  ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+  if(nwrite == LIBSSH2_ERROR_EAGAIN) {
+    *err = CURLE_AGAIN;
+    nwrite = 0;
+  }
+  else if(nwrite < LIBSSH2_ERROR_NONE) {
+    *err = libssh2_session_error_to_CURLE((int)nwrite);
+    nwrite = -1;
+  }
+
+  return nwrite;
+}
+
+/*
+ * Return number of received (decrypted) bytes
+ * or <0 on error
+ */
+static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
+                         char *mem, size_t len, CURLcode *err)
+{
+  ssize_t nread;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  (void)sockindex;
+
+  nread = libssh2_sftp_read(sshc->sftp_handle, mem, len);
+
+  ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+  if(nread == LIBSSH2_ERROR_EAGAIN) {
+    *err = CURLE_AGAIN;
+    nread = -1;
+
+  }
+  else if(nread < 0) {
+    *err = libssh2_session_error_to_CURLE((int)nread);
+  }
+  return nread;
+}
+
+static const char *sftp_libssh2_strerror(unsigned long err)
+{
+  switch(err) {
+    case LIBSSH2_FX_NO_SUCH_FILE:
+      return "No such file or directory";
+
+    case LIBSSH2_FX_PERMISSION_DENIED:
+      return "Permission denied";
+
+    case LIBSSH2_FX_FAILURE:
+      return "Operation failed";
+
+    case LIBSSH2_FX_BAD_MESSAGE:
+      return "Bad message from SFTP server";
+
+    case LIBSSH2_FX_NO_CONNECTION:
+      return "Not connected to SFTP server";
+
+    case LIBSSH2_FX_CONNECTION_LOST:
+      return "Connection to SFTP server lost";
+
+    case LIBSSH2_FX_OP_UNSUPPORTED:
+      return "Operation not supported by SFTP server";
+
+    case LIBSSH2_FX_INVALID_HANDLE:
+      return "Invalid handle";
+
+    case LIBSSH2_FX_NO_SUCH_PATH:
+      return "No such file or directory";
+
+    case LIBSSH2_FX_FILE_ALREADY_EXISTS:
+      return "File already exists";
+
+    case LIBSSH2_FX_WRITE_PROTECT:
+      return "File is write protected";
+
+    case LIBSSH2_FX_NO_MEDIA:
+      return "No media";
+
+    case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
+      return "Disk full";
+
+    case LIBSSH2_FX_QUOTA_EXCEEDED:
+      return "User quota exceeded";
+
+    case LIBSSH2_FX_UNKNOWN_PRINCIPLE:
+      return "Unknown principle";
+
+    case LIBSSH2_FX_LOCK_CONFlICT:
+      return "File lock conflict";
+
+    case LIBSSH2_FX_DIR_NOT_EMPTY:
+      return "Directory not empty";
+
+    case LIBSSH2_FX_NOT_A_DIRECTORY:
+      return "Not a directory";
+
+    case LIBSSH2_FX_INVALID_FILENAME:
+      return "Invalid filename";
+
+    case LIBSSH2_FX_LINK_LOOP:
+      return "Link points to itself";
+  }
+  return "Unknown error in libssh2";
+}
+
+CURLcode Curl_ssh_init(void)
+{
+#ifdef HAVE_LIBSSH2_INIT
+  if(libssh2_init(0)) {
+    DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n"));
+    return CURLE_FAILED_INIT;
+  }
+#endif
+  return CURLE_OK;
+}
+
+void Curl_ssh_cleanup(void)
+{
+#ifdef HAVE_LIBSSH2_EXIT
+  (void)libssh2_exit();
+#endif
+}
+
+void Curl_ssh_version(char *buffer, size_t buflen)
+{
+  (void)msnprintf(buffer, buflen, "libssh2/%s", CURL_LIBSSH2_VERSION);
+}
+
+/* The SSH session is associated with the *CONNECTION* but the callback user
+ * pointer is an easy handle pointer. This function allows us to reassign the
+ * user pointer to the *CURRENT* (new) easy handle.
+ */
+static void ssh_attach(struct Curl_easy *data, struct connectdata *conn)
+{
+  DEBUGASSERT(data);
+  DEBUGASSERT(conn);
+  if(conn->handler->protocol & PROTO_FAMILY_SSH) {
+    struct ssh_conn *sshc = &conn->proto.sshc;
+    if(sshc->ssh_session) {
+      /* only re-attach if the session already exists */
+      void **abstract = libssh2_session_abstract(sshc->ssh_session);
+      *abstract = data;
+    }
+  }
+}
+#endif /* USE_LIBSSH2 */
Index: trunk/src/libs/curl-8.7.1/lib/vssh/ssh.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vssh/ssh.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vssh/ssh.h	(revision 104083)
@@ -0,0 +1,273 @@
+#ifndef HEADER_CURL_SSH_H
+#define HEADER_CURL_SSH_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_LIBSSH2)
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+#elif defined(USE_LIBSSH)
+#include <libssh/libssh.h>
+#include <libssh/sftp.h>
+#elif defined(USE_WOLFSSH)
+#include <wolfssh/ssh.h>
+#include <wolfssh/wolfsftp.h>
+#endif
+
+/****************************************************************************
+ * SSH unique setup
+ ***************************************************************************/
+typedef enum {
+  SSH_NO_STATE = -1,  /* Used for "nextState" so say there is none */
+  SSH_STOP = 0,       /* do nothing state, stops the state machine */
+
+  SSH_INIT,           /* First state in SSH-CONNECT */
+  SSH_S_STARTUP,      /* Session startup */
+  SSH_HOSTKEY,        /* verify hostkey */
+  SSH_AUTHLIST,
+  SSH_AUTH_PKEY_INIT,
+  SSH_AUTH_PKEY,
+  SSH_AUTH_PASS_INIT,
+  SSH_AUTH_PASS,
+  SSH_AUTH_AGENT_INIT, /* initialize then wait for connection to agent */
+  SSH_AUTH_AGENT_LIST, /* ask for list then wait for entire list to come */
+  SSH_AUTH_AGENT,      /* attempt one key at a time */
+  SSH_AUTH_HOST_INIT,
+  SSH_AUTH_HOST,
+  SSH_AUTH_KEY_INIT,
+  SSH_AUTH_KEY,
+  SSH_AUTH_GSSAPI,
+  SSH_AUTH_DONE,
+  SSH_SFTP_INIT,
+  SSH_SFTP_REALPATH,   /* Last state in SSH-CONNECT */
+
+  SSH_SFTP_QUOTE_INIT, /* First state in SFTP-DO */
+  SSH_SFTP_POSTQUOTE_INIT, /* (Possibly) First state in SFTP-DONE */
+  SSH_SFTP_QUOTE,
+  SSH_SFTP_NEXT_QUOTE,
+  SSH_SFTP_QUOTE_STAT,
+  SSH_SFTP_QUOTE_SETSTAT,
+  SSH_SFTP_QUOTE_SYMLINK,
+  SSH_SFTP_QUOTE_MKDIR,
+  SSH_SFTP_QUOTE_RENAME,
+  SSH_SFTP_QUOTE_RMDIR,
+  SSH_SFTP_QUOTE_UNLINK,
+  SSH_SFTP_QUOTE_STATVFS,
+  SSH_SFTP_GETINFO,
+  SSH_SFTP_FILETIME,
+  SSH_SFTP_TRANS_INIT,
+  SSH_SFTP_UPLOAD_INIT,
+  SSH_SFTP_CREATE_DIRS_INIT,
+  SSH_SFTP_CREATE_DIRS,
+  SSH_SFTP_CREATE_DIRS_MKDIR,
+  SSH_SFTP_READDIR_INIT,
+  SSH_SFTP_READDIR,
+  SSH_SFTP_READDIR_LINK,
+  SSH_SFTP_READDIR_BOTTOM,
+  SSH_SFTP_READDIR_DONE,
+  SSH_SFTP_DOWNLOAD_INIT,
+  SSH_SFTP_DOWNLOAD_STAT, /* Last state in SFTP-DO */
+  SSH_SFTP_CLOSE,    /* Last state in SFTP-DONE */
+  SSH_SFTP_SHUTDOWN, /* First state in SFTP-DISCONNECT */
+  SSH_SCP_TRANS_INIT, /* First state in SCP-DO */
+  SSH_SCP_UPLOAD_INIT,
+  SSH_SCP_DOWNLOAD_INIT,
+  SSH_SCP_DOWNLOAD,
+  SSH_SCP_DONE,
+  SSH_SCP_SEND_EOF,
+  SSH_SCP_WAIT_EOF,
+  SSH_SCP_WAIT_CLOSE,
+  SSH_SCP_CHANNEL_FREE,   /* Last state in SCP-DONE */
+  SSH_SESSION_DISCONNECT, /* First state in SCP-DISCONNECT */
+  SSH_SESSION_FREE,       /* Last state in SCP/SFTP-DISCONNECT */
+  SSH_QUIT,
+  SSH_LAST  /* never used */
+} sshstate;
+
+/* this struct is used in the HandleData struct which is part of the
+   Curl_easy, which means this is used on a per-easy handle basis.
+   Everything that is strictly related to a connection is banned from this
+   struct. */
+struct SSHPROTO {
+  char *path;                  /* the path we operate on */
+#ifdef USE_LIBSSH2
+  struct dynbuf readdir_link;
+  struct dynbuf readdir;
+  char *readdir_filename;
+  char *readdir_longentry;
+
+  LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */
+
+  /* Here's a set of struct members used by the SFTP_READDIR state */
+  LIBSSH2_SFTP_ATTRIBUTES readdir_attrs;
+#endif
+};
+
+/* ssh_conn is used for struct connection-oriented data in the connectdata
+   struct */
+struct ssh_conn {
+  const char *authlist;       /* List of auth. methods, managed by libssh2 */
+
+  /* common */
+  const char *passphrase;     /* pass-phrase to use */
+  char *rsa_pub;              /* strdup'ed public key file */
+  char *rsa;                  /* strdup'ed private key file */
+  bool authed;                /* the connection has been authenticated fine */
+  bool acceptfail;            /* used by the SFTP_QUOTE (continue if
+                                 quote command fails) */
+  sshstate state;             /* always use ssh.c:state() to change state! */
+  sshstate nextstate;         /* the state to goto after stopping */
+  CURLcode actualcode;        /* the actual error code */
+  struct curl_slist *quote_item; /* for the quote option */
+  char *quote_path1;          /* two generic pointers for the QUOTE stuff */
+  char *quote_path2;
+
+  char *homedir;              /* when doing SFTP we figure out home dir in the
+                                 connect phase */
+  /* end of READDIR stuff */
+
+  int secondCreateDirs;         /* counter use by the code to see if the
+                                   second attempt has been made to change
+                                   to/create a directory */
+  int orig_waitfor;             /* default READ/WRITE bits wait for */
+  char *slash_pos;              /* used by the SFTP_CREATE_DIRS state */
+
+#if defined(USE_LIBSSH)
+  char *readdir_linkPath;
+  size_t readdir_len;
+  struct dynbuf readdir_buf;
+/* our variables */
+  unsigned kbd_state; /* 0 or 1 */
+  ssh_key privkey;
+  ssh_key pubkey;
+  int auth_methods;
+  ssh_session ssh_session;
+  ssh_scp scp_session;
+  sftp_session sftp_session;
+  sftp_file sftp_file;
+  sftp_dir sftp_dir;
+
+  unsigned sftp_recv_state; /* 0 or 1 */
+  int sftp_file_index; /* for async read */
+  sftp_attributes readdir_attrs; /* used by the SFTP readdir actions */
+  sftp_attributes readdir_link_attrs; /* used by the SFTP readdir actions */
+  sftp_attributes quote_attrs; /* used by the SFTP_QUOTE state */
+
+  const char *readdir_filename; /* points within readdir_attrs */
+  const char *readdir_longentry;
+  char *readdir_tmp;
+#elif defined(USE_LIBSSH2)
+  LIBSSH2_SESSION *ssh_session; /* Secure Shell session */
+  LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */
+  LIBSSH2_SFTP *sftp_session;   /* SFTP handle */
+  LIBSSH2_SFTP_HANDLE *sftp_handle;
+
+#ifndef CURL_DISABLE_PROXY
+  /* for HTTPS proxy storage */
+  Curl_recv *tls_recv;
+  Curl_send *tls_send;
+#endif
+
+#ifdef HAVE_LIBSSH2_AGENT_API
+  LIBSSH2_AGENT *ssh_agent;     /* proxy to ssh-agent/pageant */
+  struct libssh2_agent_publickey *sshagent_identity,
+                                 *sshagent_prev_identity;
+#endif
+
+  /* note that HAVE_LIBSSH2_KNOWNHOST_API is a define set in the libssh2.h
+     header */
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+  LIBSSH2_KNOWNHOSTS *kh;
+#endif
+#elif defined(USE_WOLFSSH)
+  WOLFSSH *ssh_session;
+  WOLFSSH_CTX *ctx;
+  word32 handleSz;
+  byte handle[WOLFSSH_MAX_HANDLE];
+  curl_off_t offset;
+#endif /* USE_LIBSSH */
+};
+
+#if defined(USE_LIBSSH2)
+
+/* Feature detection based on version numbers to better work with
+   non-configure platforms */
+
+#if !defined(LIBSSH2_VERSION_NUM) || (LIBSSH2_VERSION_NUM < 0x001000)
+#  error "SCP/SFTP protocols require libssh2 0.16 or later"
+#endif
+
+#if LIBSSH2_VERSION_NUM >= 0x010000
+#define HAVE_LIBSSH2_SFTP_SEEK64 1
+#endif
+
+#if LIBSSH2_VERSION_NUM >= 0x010100
+#define HAVE_LIBSSH2_VERSION 1
+#endif
+
+#if LIBSSH2_VERSION_NUM >= 0x010205
+#define HAVE_LIBSSH2_INIT 1
+#define HAVE_LIBSSH2_EXIT 1
+#endif
+
+#if LIBSSH2_VERSION_NUM >= 0x010206
+#define HAVE_LIBSSH2_KNOWNHOST_CHECKP 1
+#define HAVE_LIBSSH2_SCP_SEND64 1
+#endif
+
+#if LIBSSH2_VERSION_NUM >= 0x010208
+#define HAVE_LIBSSH2_SESSION_HANDSHAKE 1
+#endif
+
+#ifdef HAVE_LIBSSH2_VERSION
+/* get it run-time if possible */
+#define CURL_LIBSSH2_VERSION libssh2_version(0)
+#else
+/* use build-time if run-time not possible */
+#define CURL_LIBSSH2_VERSION LIBSSH2_VERSION
+#endif
+
+#endif /* USE_LIBSSH2 */
+
+#ifdef USE_SSH
+
+extern const struct Curl_handler Curl_handler_scp;
+extern const struct Curl_handler Curl_handler_sftp;
+
+/* generic SSH backend functions */
+CURLcode Curl_ssh_init(void);
+void Curl_ssh_cleanup(void);
+void Curl_ssh_version(char *buffer, size_t buflen);
+void Curl_ssh_attach(struct Curl_easy *data,
+                     struct connectdata *conn);
+#else
+/* for non-SSH builds */
+#define Curl_ssh_cleanup()
+#define Curl_ssh_attach(x,y)
+#define Curl_ssh_init() 0
+#endif
+
+#endif /* HEADER_CURL_SSH_H */
Index: trunk/src/libs/curl-8.7.1/lib/vssh/wolfssh.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vssh/wolfssh.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vssh/wolfssh.c	(revision 104083)
@@ -0,0 +1,1167 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_WOLFSSH
+
+#include <limits.h>
+
+#include <wolfssh/ssh.h>
+#include <wolfssh/wolfsftp.h>
+#include "urldata.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "sendf.h"
+#include "progress.h"
+#include "curl_path.h"
+#include "strtoofft.h"
+#include "transfer.h"
+#include "speedcheck.h"
+#include "select.h"
+#include "multiif.h"
+#include "warnless.h"
+#include "strdup.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+static CURLcode wssh_connect(struct Curl_easy *data, bool *done);
+static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done);
+static CURLcode wssh_do(struct Curl_easy *data, bool *done);
+#if 0
+static CURLcode wscp_done(struct Curl_easy *data,
+                          CURLcode, bool premature);
+static CURLcode wscp_doing(struct Curl_easy *data,
+                           bool *dophase_done);
+static CURLcode wscp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                bool dead_connection);
+#endif
+static CURLcode wsftp_done(struct Curl_easy *data,
+                           CURLcode, bool premature);
+static CURLcode wsftp_doing(struct Curl_easy *data,
+                            bool *dophase_done);
+static CURLcode wsftp_disconnect(struct Curl_easy *data,
+                                 struct connectdata *conn,
+                                 bool dead);
+static int wssh_getsock(struct Curl_easy *data,
+                        struct connectdata *conn,
+                        curl_socket_t *sock);
+static CURLcode wssh_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+
+#if 0
+/*
+ * SCP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_scp = {
+  "SCP",                                /* scheme */
+  wssh_setup_connection,                /* setup_connection */
+  wssh_do,                              /* do_it */
+  wscp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  wssh_connect,                         /* connect_it */
+  wssh_multi_statemach,                 /* connecting */
+  wscp_doing,                           /* doing */
+  wssh_getsock,                         /* proto_getsock */
+  wssh_getsock,                         /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  wssh_getsock,                         /* perform_getsock */
+  wscp_disconnect,                      /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_SSH,                             /* defport */
+  CURLPROTO_SCP,                        /* protocol */
+  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+  | PROTOPT_NOURLQUERY                  /* flags */
+};
+
+#endif
+
+/*
+ * SFTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_sftp = {
+  "SFTP",                               /* scheme */
+  wssh_setup_connection,                /* setup_connection */
+  wssh_do,                              /* do_it */
+  wsftp_done,                           /* done */
+  ZERO_NULL,                            /* do_more */
+  wssh_connect,                         /* connect_it */
+  wssh_multi_statemach,                 /* connecting */
+  wsftp_doing,                          /* doing */
+  wssh_getsock,                         /* proto_getsock */
+  wssh_getsock,                         /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  wssh_getsock,                         /* perform_getsock */
+  wsftp_disconnect,                     /* disconnect */
+  ZERO_NULL,                            /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_SSH,                             /* defport */
+  CURLPROTO_SFTP,                       /* protocol */
+  CURLPROTO_SFTP,                       /* family */
+  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+  | PROTOPT_NOURLQUERY                  /* flags */
+};
+
+/*
+ * SSH State machine related code
+ */
+/* This is the ONLY way to change SSH state! */
+static void state(struct Curl_easy *data, sshstate nowstate)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[] = {
+    "SSH_STOP",
+    "SSH_INIT",
+    "SSH_S_STARTUP",
+    "SSH_HOSTKEY",
+    "SSH_AUTHLIST",
+    "SSH_AUTH_PKEY_INIT",
+    "SSH_AUTH_PKEY",
+    "SSH_AUTH_PASS_INIT",
+    "SSH_AUTH_PASS",
+    "SSH_AUTH_AGENT_INIT",
+    "SSH_AUTH_AGENT_LIST",
+    "SSH_AUTH_AGENT",
+    "SSH_AUTH_HOST_INIT",
+    "SSH_AUTH_HOST",
+    "SSH_AUTH_KEY_INIT",
+    "SSH_AUTH_KEY",
+    "SSH_AUTH_GSSAPI",
+    "SSH_AUTH_DONE",
+    "SSH_SFTP_INIT",
+    "SSH_SFTP_REALPATH",
+    "SSH_SFTP_QUOTE_INIT",
+    "SSH_SFTP_POSTQUOTE_INIT",
+    "SSH_SFTP_QUOTE",
+    "SSH_SFTP_NEXT_QUOTE",
+    "SSH_SFTP_QUOTE_STAT",
+    "SSH_SFTP_QUOTE_SETSTAT",
+    "SSH_SFTP_QUOTE_SYMLINK",
+    "SSH_SFTP_QUOTE_MKDIR",
+    "SSH_SFTP_QUOTE_RENAME",
+    "SSH_SFTP_QUOTE_RMDIR",
+    "SSH_SFTP_QUOTE_UNLINK",
+    "SSH_SFTP_QUOTE_STATVFS",
+    "SSH_SFTP_GETINFO",
+    "SSH_SFTP_FILETIME",
+    "SSH_SFTP_TRANS_INIT",
+    "SSH_SFTP_UPLOAD_INIT",
+    "SSH_SFTP_CREATE_DIRS_INIT",
+    "SSH_SFTP_CREATE_DIRS",
+    "SSH_SFTP_CREATE_DIRS_MKDIR",
+    "SSH_SFTP_READDIR_INIT",
+    "SSH_SFTP_READDIR",
+    "SSH_SFTP_READDIR_LINK",
+    "SSH_SFTP_READDIR_BOTTOM",
+    "SSH_SFTP_READDIR_DONE",
+    "SSH_SFTP_DOWNLOAD_INIT",
+    "SSH_SFTP_DOWNLOAD_STAT",
+    "SSH_SFTP_CLOSE",
+    "SSH_SFTP_SHUTDOWN",
+    "SSH_SCP_TRANS_INIT",
+    "SSH_SCP_UPLOAD_INIT",
+    "SSH_SCP_DOWNLOAD_INIT",
+    "SSH_SCP_DOWNLOAD",
+    "SSH_SCP_DONE",
+    "SSH_SCP_SEND_EOF",
+    "SSH_SCP_WAIT_EOF",
+    "SSH_SCP_WAIT_CLOSE",
+    "SSH_SCP_CHANNEL_FREE",
+    "SSH_SESSION_DISCONNECT",
+    "SSH_SESSION_FREE",
+    "QUIT"
+  };
+
+  /* a precaution to make sure the lists are in sync */
+  DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
+
+  if(sshc->state != nowstate) {
+    infof(data, "wolfssh %p state change from %s to %s",
+          (void *)sshc, names[sshc->state], names[nowstate]);
+  }
+#endif
+
+  sshc->state = nowstate;
+}
+
+static ssize_t wscp_send(struct Curl_easy *data, int sockindex,
+                         const void *mem, size_t len, CURLcode *err)
+{
+  ssize_t nwrite = 0;
+  (void)data;
+  (void)sockindex; /* we only support SCP on the fixed known primary socket */
+  (void)mem;
+  (void)len;
+  (void)err;
+
+  return nwrite;
+}
+
+static ssize_t wscp_recv(struct Curl_easy *data, int sockindex,
+                         char *mem, size_t len, CURLcode *err)
+{
+  ssize_t nread = 0;
+  (void)data;
+  (void)sockindex; /* we only support SCP on the fixed known primary socket */
+  (void)mem;
+  (void)len;
+  (void)err;
+
+  return nread;
+}
+
+/* return number of sent bytes */
+static ssize_t wsftp_send(struct Curl_easy *data, int sockindex,
+                          const void *mem, size_t len, CURLcode *err)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  word32 offset[2];
+  int rc;
+  (void)sockindex;
+
+  offset[0] = (word32)sshc->offset&0xFFFFFFFF;
+  offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF;
+
+  rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle,
+                                    sshc->handleSz,
+                                    &offset[0],
+                                    (byte *)mem, (word32)len);
+
+  if(rc == WS_FATAL_ERROR)
+    rc = wolfSSH_get_error(sshc->ssh_session);
+  if(rc == WS_WANT_READ) {
+    conn->waitfor = KEEP_RECV;
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+  else if(rc == WS_WANT_WRITE) {
+    conn->waitfor = KEEP_SEND;
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+  if(rc < 0) {
+    failf(data, "wolfSSH_SFTP_SendWritePacket returned %d", rc);
+    return -1;
+  }
+  DEBUGASSERT(rc == (int)len);
+  infof(data, "sent %zu bytes SFTP from offset %" CURL_FORMAT_CURL_OFF_T,
+        len, sshc->offset);
+  sshc->offset += len;
+  return (ssize_t)rc;
+}
+
+/*
+ * Return number of received (decrypted) bytes
+ * or <0 on error
+ */
+static ssize_t wsftp_recv(struct Curl_easy *data, int sockindex,
+                          char *mem, size_t len, CURLcode *err)
+{
+  int rc;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  word32 offset[2];
+  (void)sockindex;
+
+  offset[0] = (word32)sshc->offset&0xFFFFFFFF;
+  offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF;
+
+  rc = wolfSSH_SFTP_SendReadPacket(sshc->ssh_session, sshc->handle,
+                                   sshc->handleSz,
+                                   &offset[0],
+                                   (byte *)mem, (word32)len);
+  if(rc == WS_FATAL_ERROR)
+    rc = wolfSSH_get_error(sshc->ssh_session);
+  if(rc == WS_WANT_READ) {
+    conn->waitfor = KEEP_RECV;
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+  else if(rc == WS_WANT_WRITE) {
+    conn->waitfor = KEEP_SEND;
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+
+  DEBUGASSERT(rc <= (int)len);
+
+  if(rc < 0) {
+    failf(data, "wolfSSH_SFTP_SendReadPacket returned %d", rc);
+    return -1;
+  }
+  sshc->offset += len;
+
+  return (ssize_t)rc;
+}
+
+/*
+ * SSH setup and connection
+ */
+static CURLcode wssh_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  struct SSHPROTO *ssh;
+  (void)conn;
+
+  data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
+  if(!ssh)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+static int userauth(byte authtype,
+                    WS_UserAuthData* authdata,
+                    void *ctx)
+{
+  struct Curl_easy *data = ctx;
+  DEBUGF(infof(data, "wolfssh callback: type %s",
+               authtype == WOLFSSH_USERAUTH_PASSWORD ? "PASSWORD" :
+               "PUBLICCKEY"));
+  if(authtype == WOLFSSH_USERAUTH_PASSWORD) {
+    authdata->sf.password.password = (byte *)data->conn->passwd;
+    authdata->sf.password.passwordSz = (word32) strlen(data->conn->passwd);
+  }
+
+  return 0;
+}
+
+static CURLcode wssh_connect(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  int rc;
+
+  /* initialize per-handle data if not already */
+  if(!data->req.p.ssh)
+    wssh_setup_connection(data, conn);
+
+  /* We default to persistent connections. We set this already in this connect
+     function to make the reuse checks properly be able to check this bit. */
+  connkeep(conn, "SSH default");
+
+  if(conn->handler->protocol & CURLPROTO_SCP) {
+    conn->recv[FIRSTSOCKET] = wscp_recv;
+    conn->send[FIRSTSOCKET] = wscp_send;
+  }
+  else {
+    conn->recv[FIRSTSOCKET] = wsftp_recv;
+    conn->send[FIRSTSOCKET] = wsftp_send;
+  }
+  sshc = &conn->proto.sshc;
+  sshc->ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL);
+  if(!sshc->ctx) {
+    failf(data, "No wolfSSH context");
+    goto error;
+  }
+
+  sshc->ssh_session = wolfSSH_new(sshc->ctx);
+  if(!sshc->ssh_session) {
+    failf(data, "No wolfSSH session");
+    goto error;
+  }
+
+  rc = wolfSSH_SetUsername(sshc->ssh_session, conn->user);
+  if(rc != WS_SUCCESS) {
+    failf(data, "wolfSSH failed to set user name");
+    goto error;
+  }
+
+  /* set callback for authentication */
+  wolfSSH_SetUserAuth(sshc->ctx, userauth);
+  wolfSSH_SetUserAuthCtx(sshc->ssh_session, data);
+
+  rc = wolfSSH_set_fd(sshc->ssh_session, (int)sock);
+  if(rc) {
+    failf(data, "wolfSSH failed to set socket");
+    goto error;
+  }
+
+#if 0
+  wolfSSH_Debugging_ON();
+#endif
+
+  *done = TRUE;
+  if(conn->handler->protocol & CURLPROTO_SCP)
+    state(data, SSH_INIT);
+  else
+    state(data, SSH_SFTP_INIT);
+
+  return wssh_multi_statemach(data, done);
+error:
+  wolfSSH_free(sshc->ssh_session);
+  wolfSSH_CTX_free(sshc->ctx);
+  return CURLE_FAILED_INIT;
+}
+
+/*
+ * wssh_statemach_act() runs the SSH state machine as far as it can without
+ * blocking and without reaching the end.  The data the pointer 'block' points
+ * to will be set to TRUE if the wolfssh function returns EAGAIN meaning it
+ * wants to be called again when the socket is ready
+ */
+
+static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  struct SSHPROTO *sftp_scp = data->req.p.ssh;
+  WS_SFTPNAME *name;
+  int rc = 0;
+  *block = FALSE; /* we're not blocking by default */
+
+  do {
+    switch(sshc->state) {
+    case SSH_INIT:
+      state(data, SSH_S_STARTUP);
+      break;
+
+    case SSH_S_STARTUP:
+      rc = wolfSSH_connect(sshc->ssh_session);
+      if(rc != WS_SUCCESS)
+        rc = wolfSSH_get_error(sshc->ssh_session);
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(rc != WS_SUCCESS) {
+        state(data, SSH_STOP);
+        return CURLE_SSH;
+      }
+      infof(data, "wolfssh connected");
+      state(data, SSH_STOP);
+      break;
+    case SSH_STOP:
+      break;
+
+    case SSH_SFTP_INIT:
+      rc = wolfSSH_SFTP_connect(sshc->ssh_session);
+      if(rc != WS_SUCCESS)
+        rc = wolfSSH_get_error(sshc->ssh_session);
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(rc == WS_SUCCESS) {
+        infof(data, "wolfssh SFTP connected");
+        state(data, SSH_SFTP_REALPATH);
+      }
+      else {
+        failf(data, "wolfssh SFTP connect error %d", rc);
+        return CURLE_SSH;
+      }
+      break;
+    case SSH_SFTP_REALPATH:
+      name = wolfSSH_SFTP_RealPath(sshc->ssh_session, (char *)".");
+      rc = wolfSSH_get_error(sshc->ssh_session);
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(name && (rc == WS_SUCCESS)) {
+        sshc->homedir = Curl_memdup0(name->fName, name->fSz);
+        if(!sshc->homedir)
+          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        wolfSSH_SFTPNAME_list_free(name);
+        state(data, SSH_STOP);
+        return CURLE_OK;
+      }
+      failf(data, "wolfssh SFTP realpath %d", rc);
+      return CURLE_SSH;
+
+    case SSH_SFTP_QUOTE_INIT:
+      result = Curl_getworkingpath(data, sshc->homedir, &sftp_scp->path);
+      if(result) {
+        sshc->actualcode = result;
+        state(data, SSH_STOP);
+        break;
+      }
+
+      if(data->set.quote) {
+        infof(data, "Sending quote commands");
+        sshc->quote_item = data->set.quote;
+        state(data, SSH_SFTP_QUOTE);
+      }
+      else {
+        state(data, SSH_SFTP_GETINFO);
+      }
+      break;
+    case SSH_SFTP_GETINFO:
+      if(data->set.get_filetime) {
+        state(data, SSH_SFTP_FILETIME);
+      }
+      else {
+        state(data, SSH_SFTP_TRANS_INIT);
+      }
+      break;
+    case SSH_SFTP_TRANS_INIT:
+      if(data->state.upload)
+        state(data, SSH_SFTP_UPLOAD_INIT);
+      else {
+        if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
+          state(data, SSH_SFTP_READDIR_INIT);
+        else
+          state(data, SSH_SFTP_DOWNLOAD_INIT);
+      }
+      break;
+    case SSH_SFTP_UPLOAD_INIT: {
+      word32 flags;
+      WS_SFTP_FILEATRB createattrs;
+      if(data->state.resume_from) {
+        WS_SFTP_FILEATRB attrs;
+        if(data->state.resume_from < 0) {
+          rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path,
+                                 &attrs);
+          if(rc != WS_SUCCESS)
+            break;
+
+          if(rc) {
+            data->state.resume_from = 0;
+          }
+          else {
+            curl_off_t size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0];
+            if(size < 0) {
+              failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
+              return CURLE_BAD_DOWNLOAD_RESUME;
+            }
+            data->state.resume_from = size;
+          }
+        }
+      }
+
+      if(data->set.remote_append)
+        /* Try to open for append, but create if nonexisting */
+        flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_APPEND;
+      else if(data->state.resume_from > 0)
+        /* If we have restart position then open for append */
+        flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_APPEND;
+      else
+        /* Clear file before writing (normal behavior) */
+        flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_TRUNC;
+
+      memset(&createattrs, 0, sizeof(createattrs));
+      createattrs.per = (word32)data->set.new_file_perms;
+      sshc->handleSz = sizeof(sshc->handle);
+      rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path,
+                             flags, &createattrs,
+                             sshc->handle, &sshc->handleSz);
+      if(rc == WS_FATAL_ERROR)
+        rc = wolfSSH_get_error(sshc->ssh_session);
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(rc == WS_SUCCESS) {
+        infof(data, "wolfssh SFTP open succeeded");
+      }
+      else {
+        failf(data, "wolfssh SFTP upload open failed: %d", rc);
+        return CURLE_SSH;
+      }
+      state(data, SSH_SFTP_DOWNLOAD_STAT);
+
+      /* If we have a restart point then we need to seek to the correct
+         position. */
+      if(data->state.resume_from > 0) {
+        /* Let's read off the proper amount of bytes from the input. */
+        int seekerr = CURL_SEEKFUNC_OK;
+        if(data->set.seek_func) {
+          Curl_set_in_callback(data, true);
+          seekerr = data->set.seek_func(data->set.seek_client,
+                                        data->state.resume_from, SEEK_SET);
+          Curl_set_in_callback(data, false);
+        }
+
+        if(seekerr != CURL_SEEKFUNC_OK) {
+          curl_off_t passed = 0;
+
+          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+            failf(data, "Could not seek stream");
+            return CURLE_FTP_COULDNT_USE_REST;
+          }
+          /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+          do {
+            char scratch[4*1024];
+            size_t readthisamountnow =
+              (data->state.resume_from - passed >
+                (curl_off_t)sizeof(scratch)) ?
+              sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
+
+            size_t actuallyread;
+            Curl_set_in_callback(data, true);
+            actuallyread = data->state.fread_func(scratch, 1,
+                                                  readthisamountnow,
+                                                  data->state.in);
+            Curl_set_in_callback(data, false);
+
+            passed += actuallyread;
+            if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+              /* this checks for greater-than only to make sure that the
+                 CURL_READFUNC_ABORT return code still aborts */
+              failf(data, "Failed to read data");
+              return CURLE_FTP_COULDNT_USE_REST;
+            }
+          } while(passed < data->state.resume_from);
+        }
+
+        /* now, decrease the size of the read */
+        if(data->state.infilesize > 0) {
+          data->state.infilesize -= data->state.resume_from;
+          data->req.size = data->state.infilesize;
+          Curl_pgrsSetUploadSize(data, data->state.infilesize);
+        }
+
+        sshc->offset += data->state.resume_from;
+      }
+      if(data->state.infilesize > 0) {
+        data->req.size = data->state.infilesize;
+        Curl_pgrsSetUploadSize(data, data->state.infilesize);
+      }
+      /* upload data */
+      Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
+
+      /* not set by Curl_xfer_setup to preserve keepon bits */
+      conn->sockfd = conn->writesockfd;
+
+      if(result) {
+        state(data, SSH_SFTP_CLOSE);
+        sshc->actualcode = result;
+      }
+      else {
+        /* store this original bitmask setup to use later on if we can't
+           figure out a "real" bitmask */
+        sshc->orig_waitfor = data->req.keepon;
+
+        /* we want to use the _sending_ function even when the socket turns
+           out readable as the underlying libssh2 sftp send function will deal
+           with both accordingly */
+        data->state.select_bits = CURL_CSELECT_OUT;
+
+        /* since we don't really wait for anything at this point, we want the
+           state machine to move on as soon as possible so we set a very short
+           timeout here */
+        Curl_expire(data, 0, EXPIRE_RUN_NOW);
+
+        state(data, SSH_STOP);
+      }
+      break;
+    }
+    case SSH_SFTP_DOWNLOAD_INIT:
+      sshc->handleSz = sizeof(sshc->handle);
+      rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path,
+                             WOLFSSH_FXF_READ, NULL,
+                             sshc->handle, &sshc->handleSz);
+      if(rc == WS_FATAL_ERROR)
+        rc = wolfSSH_get_error(sshc->ssh_session);
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(rc == WS_SUCCESS) {
+        infof(data, "wolfssh SFTP open succeeded");
+        state(data, SSH_SFTP_DOWNLOAD_STAT);
+        return CURLE_OK;
+      }
+
+      failf(data, "wolfssh SFTP open failed: %d", rc);
+      return CURLE_SSH;
+
+    case SSH_SFTP_DOWNLOAD_STAT: {
+      WS_SFTP_FILEATRB attrs;
+      curl_off_t size;
+
+      rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, &attrs);
+      if(rc == WS_FATAL_ERROR)
+        rc = wolfSSH_get_error(sshc->ssh_session);
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(rc == WS_SUCCESS) {
+        infof(data, "wolfssh STAT succeeded");
+      }
+      else {
+        failf(data, "wolfssh SFTP open failed: %d", rc);
+        data->req.size = -1;
+        data->req.maxdownload = -1;
+        Curl_pgrsSetDownloadSize(data, -1);
+        return CURLE_SSH;
+      }
+
+      size = ((curl_off_t)attrs.sz[1] <<32) | attrs.sz[0];
+
+      data->req.size = size;
+      data->req.maxdownload = size;
+      Curl_pgrsSetDownloadSize(data, size);
+
+      infof(data, "SFTP download %" CURL_FORMAT_CURL_OFF_T " bytes", size);
+
+      /* We cannot seek with wolfSSH so resuming and range requests are not
+         possible */
+      if(data->state.use_range || data->state.resume_from) {
+        infof(data, "wolfSSH cannot do range/seek on SFTP");
+        return CURLE_BAD_DOWNLOAD_RESUME;
+      }
+
+      /* Setup the actual download */
+      if(data->req.size == 0) {
+        /* no data to transfer */
+        Curl_xfer_setup(data, -1, -1, FALSE, -1);
+        infof(data, "File already completely downloaded");
+        state(data, SSH_STOP);
+        break;
+      }
+      Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);
+
+      /* not set by Curl_xfer_setup to preserve keepon bits */
+      conn->writesockfd = conn->sockfd;
+
+      /* we want to use the _receiving_ function even when the socket turns
+         out writableable as the underlying libssh2 recv function will deal
+         with both accordingly */
+      data->state.select_bits = CURL_CSELECT_IN;
+
+      if(result) {
+        /* this should never occur; the close state should be entered
+           at the time the error occurs */
+        state(data, SSH_SFTP_CLOSE);
+        sshc->actualcode = result;
+      }
+      else {
+        state(data, SSH_STOP);
+      }
+      break;
+    }
+    case SSH_SFTP_CLOSE:
+      if(sshc->handleSz)
+        rc = wolfSSH_SFTP_Close(sshc->ssh_session, sshc->handle,
+                                sshc->handleSz);
+      else
+        rc = WS_SUCCESS; /* directory listing */
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(rc == WS_SUCCESS) {
+        state(data, SSH_STOP);
+        return CURLE_OK;
+      }
+
+      failf(data, "wolfssh SFTP CLOSE failed: %d", rc);
+      return CURLE_SSH;
+
+    case SSH_SFTP_READDIR_INIT:
+      Curl_pgrsSetDownloadSize(data, -1);
+      if(data->req.no_body) {
+        state(data, SSH_STOP);
+        break;
+      }
+      state(data, SSH_SFTP_READDIR);
+      break;
+
+    case SSH_SFTP_READDIR:
+      name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path);
+      if(!name)
+        rc = wolfSSH_get_error(sshc->ssh_session);
+      else
+        rc = WS_SUCCESS;
+
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(name && (rc == WS_SUCCESS)) {
+        WS_SFTPNAME *origname = name;
+        result = CURLE_OK;
+        while(name) {
+          char *line = aprintf("%s\n",
+                               data->set.list_only ?
+                               name->fName : name->lName);
+          if(!line) {
+            state(data, SSH_SFTP_CLOSE);
+            sshc->actualcode = CURLE_OUT_OF_MEMORY;
+            break;
+          }
+          result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                     line, strlen(line));
+          free(line);
+          if(result) {
+            sshc->actualcode = result;
+            break;
+          }
+          name = name->next;
+        }
+        wolfSSH_SFTPNAME_list_free(origname);
+        state(data, SSH_STOP);
+        return result;
+      }
+      failf(data, "wolfssh SFTP ls failed: %d", rc);
+      return CURLE_SSH;
+
+    case SSH_SFTP_SHUTDOWN:
+      Curl_safefree(sshc->homedir);
+      wolfSSH_free(sshc->ssh_session);
+      wolfSSH_CTX_free(sshc->ctx);
+      state(data, SSH_STOP);
+      return CURLE_OK;
+    default:
+      break;
+    }
+  } while(!rc && (sshc->state != SSH_STOP));
+  return result;
+}
+
+/* called repeatedly until done from multi.c */
+static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  CURLcode result = CURLE_OK;
+  bool block; /* we store the status and use that to provide a ssh_getsock()
+                 implementation */
+  do {
+    result = wssh_statemach_act(data, &block);
+    *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
+    /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
+       try again */
+    if(*done) {
+      DEBUGF(infof(data, "wssh_statemach_act says DONE"));
+    }
+  } while(!result && !*done && !block);
+
+  return result;
+}
+
+static
+CURLcode wscp_perform(struct Curl_easy *data,
+                      bool *connected,
+                      bool *dophase_done)
+{
+  (void)data;
+  (void)connected;
+  (void)dophase_done;
+  return CURLE_OK;
+}
+
+static
+CURLcode wsftp_perform(struct Curl_easy *data,
+                       bool *connected,
+                       bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGF(infof(data, "DO phase starts"));
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* start the first command in the DO phase */
+  state(data, SSH_SFTP_QUOTE_INIT);
+
+  /* run the state-machine */
+  result = wssh_multi_statemach(data, dophase_done);
+
+  *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
+
+  if(*dophase_done) {
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+
+  return result;
+}
+
+/*
+ * The DO function is generic for both protocols.
+ */
+static CURLcode wssh_do(struct Curl_easy *data, bool *done)
+{
+  CURLcode result;
+  bool connected = 0;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+
+  *done = FALSE; /* default to false */
+  data->req.size = -1; /* make sure this is unknown at this point */
+  sshc->actualcode = CURLE_OK; /* reset error code */
+  sshc->secondCreateDirs = 0;   /* reset the create dir attempt state
+                                   variable */
+
+  Curl_pgrsSetUploadCounter(data, 0);
+  Curl_pgrsSetDownloadCounter(data, 0);
+  Curl_pgrsSetUploadSize(data, -1);
+  Curl_pgrsSetDownloadSize(data, -1);
+
+  if(conn->handler->protocol & CURLPROTO_SCP)
+    result = wscp_perform(data, &connected,  done);
+  else
+    result = wsftp_perform(data, &connected,  done);
+
+  return result;
+}
+
+static CURLcode wssh_block_statemach(struct Curl_easy *data,
+                                    bool disconnect)
+{
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  CURLcode result = CURLE_OK;
+
+  while((sshc->state != SSH_STOP) && !result) {
+    bool block;
+    timediff_t left = 1000;
+    struct curltime now = Curl_now();
+
+    result = wssh_statemach_act(data, &block);
+    if(result)
+      break;
+
+    if(!disconnect) {
+      if(Curl_pgrsUpdate(data))
+        return CURLE_ABORTED_BY_CALLBACK;
+
+      result = Curl_speedcheck(data, now);
+      if(result)
+        break;
+
+      left = Curl_timeleft(data, NULL, FALSE);
+      if(left < 0) {
+        failf(data, "Operation timed out");
+        return CURLE_OPERATION_TIMEDOUT;
+      }
+    }
+
+    if(!result) {
+      int dir = conn->waitfor;
+      curl_socket_t sock = conn->sock[FIRSTSOCKET];
+      curl_socket_t fd_read = CURL_SOCKET_BAD;
+      curl_socket_t fd_write = CURL_SOCKET_BAD;
+      if(dir == KEEP_RECV)
+        fd_read = sock;
+      else if(dir == KEEP_SEND)
+        fd_write = sock;
+
+      /* wait for the socket to become ready */
+      (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write,
+                              left>1000?1000:left); /* ignore result */
+    }
+  }
+
+  return result;
+}
+
+/* generic done function for both SCP and SFTP called from their specific
+   done functions */
+static CURLcode wssh_done(struct Curl_easy *data, CURLcode status)
+{
+  CURLcode result = CURLE_OK;
+  struct SSHPROTO *sftp_scp = data->req.p.ssh;
+
+  if(!status) {
+    /* run the state-machine */
+    result = wssh_block_statemach(data, FALSE);
+  }
+  else
+    result = status;
+
+  if(sftp_scp)
+    Curl_safefree(sftp_scp->path);
+  if(Curl_pgrsDone(data))
+    return CURLE_ABORTED_BY_CALLBACK;
+
+  data->req.keepon = 0; /* clear all bits */
+  return result;
+}
+
+#if 0
+static CURLcode wscp_done(struct Curl_easy *data,
+                         CURLcode code, bool premature)
+{
+  CURLcode result = CURLE_OK;
+  (void)conn;
+  (void)code;
+  (void)premature;
+
+  return result;
+}
+
+static CURLcode wscp_doing(struct Curl_easy *data,
+                          bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+  (void)conn;
+  (void)dophase_done;
+
+  return result;
+}
+
+static CURLcode wscp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead_connection)
+{
+  CURLcode result = CURLE_OK;
+  (void)data;
+  (void)conn;
+  (void)dead_connection;
+
+  return result;
+}
+#endif
+
+static CURLcode wsftp_done(struct Curl_easy *data,
+                          CURLcode code, bool premature)
+{
+  (void)premature;
+  state(data, SSH_SFTP_CLOSE);
+
+  return wssh_done(data, code);
+}
+
+static CURLcode wsftp_doing(struct Curl_easy *data,
+                           bool *dophase_done)
+{
+  CURLcode result = wssh_multi_statemach(data, dophase_done);
+
+  if(*dophase_done) {
+    DEBUGF(infof(data, "DO phase is complete"));
+  }
+  return result;
+}
+
+static CURLcode wsftp_disconnect(struct Curl_easy *data,
+                                 struct connectdata *conn,
+                                 bool dead)
+{
+  CURLcode result = CURLE_OK;
+  (void)dead;
+
+  DEBUGF(infof(data, "SSH DISCONNECT starts now"));
+
+  if(conn->proto.sshc.ssh_session) {
+    /* only if there's a session still around to use! */
+    state(data, SSH_SFTP_SHUTDOWN);
+    result = wssh_block_statemach(data, TRUE);
+  }
+
+  DEBUGF(infof(data, "SSH DISCONNECT is done"));
+  return result;
+}
+
+static int wssh_getsock(struct Curl_easy *data,
+                        struct connectdata *conn,
+                        curl_socket_t *sock)
+{
+  int bitmap = GETSOCK_BLANK;
+  int dir = conn->waitfor;
+  (void)data;
+  sock[0] = conn->sock[FIRSTSOCKET];
+
+  if(dir == KEEP_RECV)
+    bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
+  else if(dir == KEEP_SEND)
+    bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
+
+  return bitmap;
+}
+
+void Curl_ssh_version(char *buffer, size_t buflen)
+{
+  (void)msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING);
+}
+
+CURLcode Curl_ssh_init(void)
+{
+  if(WS_SUCCESS != wolfSSH_Init()) {
+    DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n"));
+    return CURLE_FAILED_INIT;
+  }
+
+  return CURLE_OK;
+}
+void Curl_ssh_cleanup(void)
+{
+  (void)wolfSSH_Cleanup();
+}
+
+#endif /* USE_WOLFSSH */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/bearssl.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/bearssl.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/bearssl.c	(revision 104083)
@@ -0,0 +1,1226 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Michael Forney, <mforney@mforney.org>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_BEARSSL
+
+#include <bearssl.h>
+
+#include "bearssl.h"
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "vtls.h"
+#include "vtls_int.h"
+#include "connect.h"
+#include "select.h"
+#include "multiif.h"
+#include "curl_printf.h"
+#include "strcase.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+struct x509_context {
+  const br_x509_class *vtable;
+  br_x509_minimal_context minimal;
+  br_x509_decoder_context decoder;
+  bool verifyhost;
+  bool verifypeer;
+  int cert_num;
+};
+
+struct bearssl_ssl_backend_data {
+  br_ssl_client_context ctx;
+  struct x509_context x509;
+  unsigned char buf[BR_SSL_BUFSIZE_BIDI];
+  br_x509_trust_anchor *anchors;
+  size_t anchors_len;
+  const char *protocols[ALPN_ENTRIES_MAX];
+  /* SSL client context is active */
+  bool active;
+  /* size of pending write, yet to be flushed */
+  size_t pending_write;
+};
+
+struct cafile_parser {
+  CURLcode err;
+  bool in_cert;
+  br_x509_decoder_context xc;
+  /* array of trust anchors loaded from CAfile */
+  br_x509_trust_anchor *anchors;
+  size_t anchors_len;
+  /* buffer for DN data */
+  unsigned char dn[1024];
+  size_t dn_len;
+};
+
+#define CAFILE_SOURCE_PATH 1
+#define CAFILE_SOURCE_BLOB 2
+struct cafile_source {
+  int type;
+  const char *data;
+  size_t len;
+};
+
+static void append_dn(void *ctx, const void *buf, size_t len)
+{
+  struct cafile_parser *ca = ctx;
+
+  if(ca->err != CURLE_OK || !ca->in_cert)
+    return;
+  if(sizeof(ca->dn) - ca->dn_len < len) {
+    ca->err = CURLE_FAILED_INIT;
+    return;
+  }
+  memcpy(ca->dn + ca->dn_len, buf, len);
+  ca->dn_len += len;
+}
+
+static void x509_push(void *ctx, const void *buf, size_t len)
+{
+  struct cafile_parser *ca = ctx;
+
+  if(ca->in_cert)
+    br_x509_decoder_push(&ca->xc, buf, len);
+}
+
+static CURLcode load_cafile(struct cafile_source *source,
+                            br_x509_trust_anchor **anchors,
+                            size_t *anchors_len)
+{
+  struct cafile_parser ca;
+  br_pem_decoder_context pc;
+  br_x509_trust_anchor *ta;
+  size_t ta_size;
+  br_x509_trust_anchor *new_anchors;
+  size_t new_anchors_len;
+  br_x509_pkey *pkey;
+  FILE *fp = 0;
+  unsigned char buf[BUFSIZ];
+  const unsigned char *p;
+  const char *name;
+  size_t n, i, pushed;
+
+  DEBUGASSERT(source->type == CAFILE_SOURCE_PATH
+              || source->type == CAFILE_SOURCE_BLOB);
+
+  if(source->type == CAFILE_SOURCE_PATH) {
+    fp = fopen(source->data, "rb");
+    if(!fp)
+      return CURLE_SSL_CACERT_BADFILE;
+  }
+
+  if(source->type == CAFILE_SOURCE_BLOB && source->len > (size_t)INT_MAX)
+    return CURLE_SSL_CACERT_BADFILE;
+
+  ca.err = CURLE_OK;
+  ca.in_cert = FALSE;
+  ca.anchors = NULL;
+  ca.anchors_len = 0;
+  br_pem_decoder_init(&pc);
+  br_pem_decoder_setdest(&pc, x509_push, &ca);
+  do {
+    if(source->type == CAFILE_SOURCE_PATH) {
+      n = fread(buf, 1, sizeof(buf), fp);
+      if(n == 0)
+        break;
+      p = buf;
+    }
+    else if(source->type == CAFILE_SOURCE_BLOB) {
+      n = source->len;
+      p = (unsigned char *) source->data;
+    }
+    while(n) {
+      pushed = br_pem_decoder_push(&pc, p, n);
+      if(ca.err)
+        goto fail;
+      p += pushed;
+      n -= pushed;
+
+      switch(br_pem_decoder_event(&pc)) {
+      case 0:
+        break;
+      case BR_PEM_BEGIN_OBJ:
+        name = br_pem_decoder_name(&pc);
+        if(strcmp(name, "CERTIFICATE") && strcmp(name, "X509 CERTIFICATE"))
+          break;
+        br_x509_decoder_init(&ca.xc, append_dn, &ca);
+        ca.in_cert = TRUE;
+        ca.dn_len = 0;
+        break;
+      case BR_PEM_END_OBJ:
+        if(!ca.in_cert)
+          break;
+        ca.in_cert = FALSE;
+        if(br_x509_decoder_last_error(&ca.xc)) {
+          ca.err = CURLE_SSL_CACERT_BADFILE;
+          goto fail;
+        }
+        /* add trust anchor */
+        if(ca.anchors_len == SIZE_MAX / sizeof(ca.anchors[0])) {
+          ca.err = CURLE_OUT_OF_MEMORY;
+          goto fail;
+        }
+        new_anchors_len = ca.anchors_len + 1;
+        new_anchors = realloc(ca.anchors,
+                              new_anchors_len * sizeof(ca.anchors[0]));
+        if(!new_anchors) {
+          ca.err = CURLE_OUT_OF_MEMORY;
+          goto fail;
+        }
+        ca.anchors = new_anchors;
+        ca.anchors_len = new_anchors_len;
+        ta = &ca.anchors[ca.anchors_len - 1];
+        ta->dn.data = NULL;
+        ta->flags = 0;
+        if(br_x509_decoder_isCA(&ca.xc))
+          ta->flags |= BR_X509_TA_CA;
+        pkey = br_x509_decoder_get_pkey(&ca.xc);
+        if(!pkey) {
+          ca.err = CURLE_SSL_CACERT_BADFILE;
+          goto fail;
+        }
+        ta->pkey = *pkey;
+
+        /* calculate space needed for trust anchor data */
+        ta_size = ca.dn_len;
+        switch(pkey->key_type) {
+        case BR_KEYTYPE_RSA:
+          ta_size += pkey->key.rsa.nlen + pkey->key.rsa.elen;
+          break;
+        case BR_KEYTYPE_EC:
+          ta_size += pkey->key.ec.qlen;
+          break;
+        default:
+          ca.err = CURLE_FAILED_INIT;
+          goto fail;
+        }
+
+        /* fill in trust anchor DN and public key data */
+        ta->dn.data = malloc(ta_size);
+        if(!ta->dn.data) {
+          ca.err = CURLE_OUT_OF_MEMORY;
+          goto fail;
+        }
+        memcpy(ta->dn.data, ca.dn, ca.dn_len);
+        ta->dn.len = ca.dn_len;
+        switch(pkey->key_type) {
+        case BR_KEYTYPE_RSA:
+          ta->pkey.key.rsa.n = ta->dn.data + ta->dn.len;
+          memcpy(ta->pkey.key.rsa.n, pkey->key.rsa.n, pkey->key.rsa.nlen);
+          ta->pkey.key.rsa.e = ta->pkey.key.rsa.n + ta->pkey.key.rsa.nlen;
+          memcpy(ta->pkey.key.rsa.e, pkey->key.rsa.e, pkey->key.rsa.elen);
+          break;
+        case BR_KEYTYPE_EC:
+          ta->pkey.key.ec.q = ta->dn.data + ta->dn.len;
+          memcpy(ta->pkey.key.ec.q, pkey->key.ec.q, pkey->key.ec.qlen);
+          break;
+        }
+        break;
+      default:
+        ca.err = CURLE_SSL_CACERT_BADFILE;
+        goto fail;
+      }
+    }
+  } while(source->type != CAFILE_SOURCE_BLOB);
+  if(fp && ferror(fp))
+    ca.err = CURLE_READ_ERROR;
+  else if(ca.in_cert)
+    ca.err = CURLE_SSL_CACERT_BADFILE;
+
+fail:
+  if(fp)
+    fclose(fp);
+  if(ca.err == CURLE_OK) {
+    *anchors = ca.anchors;
+    *anchors_len = ca.anchors_len;
+  }
+  else {
+    for(i = 0; i < ca.anchors_len; ++i)
+      free(ca.anchors[i].dn.data);
+    free(ca.anchors);
+  }
+
+  return ca.err;
+}
+
+static void x509_start_chain(const br_x509_class **ctx,
+                             const char *server_name)
+{
+  struct x509_context *x509 = (struct x509_context *)ctx;
+
+  if(!x509->verifypeer) {
+    x509->cert_num = 0;
+    return;
+  }
+
+  if(!x509->verifyhost)
+    server_name = NULL;
+  x509->minimal.vtable->start_chain(&x509->minimal.vtable, server_name);
+}
+
+static void x509_start_cert(const br_x509_class **ctx, uint32_t length)
+{
+  struct x509_context *x509 = (struct x509_context *)ctx;
+
+  if(!x509->verifypeer) {
+    /* Only decode the first cert in the chain to obtain the public key */
+    if(x509->cert_num == 0)
+      br_x509_decoder_init(&x509->decoder, NULL, NULL);
+    return;
+  }
+
+  x509->minimal.vtable->start_cert(&x509->minimal.vtable, length);
+}
+
+static void x509_append(const br_x509_class **ctx, const unsigned char *buf,
+                        size_t len)
+{
+  struct x509_context *x509 = (struct x509_context *)ctx;
+
+  if(!x509->verifypeer) {
+    if(x509->cert_num == 0)
+      br_x509_decoder_push(&x509->decoder, buf, len);
+    return;
+  }
+
+  x509->minimal.vtable->append(&x509->minimal.vtable, buf, len);
+}
+
+static void x509_end_cert(const br_x509_class **ctx)
+{
+  struct x509_context *x509 = (struct x509_context *)ctx;
+
+  if(!x509->verifypeer) {
+    x509->cert_num++;
+    return;
+  }
+
+  x509->minimal.vtable->end_cert(&x509->minimal.vtable);
+}
+
+static unsigned x509_end_chain(const br_x509_class **ctx)
+{
+  struct x509_context *x509 = (struct x509_context *)ctx;
+
+  if(!x509->verifypeer) {
+    return br_x509_decoder_last_error(&x509->decoder);
+  }
+
+  return x509->minimal.vtable->end_chain(&x509->minimal.vtable);
+}
+
+static const br_x509_pkey *x509_get_pkey(const br_x509_class *const *ctx,
+                                         unsigned *usages)
+{
+  struct x509_context *x509 = (struct x509_context *)ctx;
+
+  if(!x509->verifypeer) {
+    /* Nothing in the chain is verified, just return the public key of the
+       first certificate and allow its usage for both TLS_RSA_* and
+       TLS_ECDHE_* */
+    if(usages)
+      *usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN;
+    return br_x509_decoder_get_pkey(&x509->decoder);
+  }
+
+  return x509->minimal.vtable->get_pkey(&x509->minimal.vtable, usages);
+}
+
+static const br_x509_class x509_vtable = {
+  sizeof(struct x509_context),
+  x509_start_chain,
+  x509_start_cert,
+  x509_append,
+  x509_end_cert,
+  x509_end_chain,
+  x509_get_pkey
+};
+
+struct st_cipher {
+  const char *name; /* Cipher suite IANA name. It starts with "TLS_" prefix */
+  const char *alias_name; /* Alias name is the same as OpenSSL cipher name */
+  uint16_t num; /* BearSSL cipher suite */
+};
+
+/* Macro to initialize st_cipher data structure */
+#define CIPHER_DEF(num, alias) { #num, alias, BR_##num }
+
+static const struct st_cipher ciphertable[] = {
+  /* RFC 2246 TLS 1.0 */
+  CIPHER_DEF(TLS_RSA_WITH_3DES_EDE_CBC_SHA,                        /* 0x000A */
+             "DES-CBC3-SHA"),
+
+  /* RFC 3268 TLS 1.0 AES */
+  CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA,                         /* 0x002F */
+             "AES128-SHA"),
+  CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA,                         /* 0x0035 */
+             "AES256-SHA"),
+
+  /* RFC 5246 TLS 1.2 */
+  CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA256,                      /* 0x003C */
+             "AES128-SHA256"),
+  CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA256,                      /* 0x003D */
+             "AES256-SHA256"),
+
+  /* RFC 5288 TLS 1.2 AES GCM */
+  CIPHER_DEF(TLS_RSA_WITH_AES_128_GCM_SHA256,                      /* 0x009C */
+             "AES128-GCM-SHA256"),
+  CIPHER_DEF(TLS_RSA_WITH_AES_256_GCM_SHA384,                      /* 0x009D */
+             "AES256-GCM-SHA384"),
+
+  /* RFC 4492 TLS 1.0 ECC */
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,                 /* 0xC003 */
+             "ECDH-ECDSA-DES-CBC3-SHA"),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,                  /* 0xC004 */
+             "ECDH-ECDSA-AES128-SHA"),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,                  /* 0xC005 */
+             "ECDH-ECDSA-AES256-SHA"),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,                /* 0xC008 */
+             "ECDHE-ECDSA-DES-CBC3-SHA"),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,                 /* 0xC009 */
+             "ECDHE-ECDSA-AES128-SHA"),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,                 /* 0xC00A */
+             "ECDHE-ECDSA-AES256-SHA"),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,                   /* 0xC00D */
+             "ECDH-RSA-DES-CBC3-SHA"),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,                    /* 0xC00E */
+             "ECDH-RSA-AES128-SHA"),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,                    /* 0xC00F */
+             "ECDH-RSA-AES256-SHA"),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,                  /* 0xC012 */
+             "ECDHE-RSA-DES-CBC3-SHA"),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,                   /* 0xC013 */
+             "ECDHE-RSA-AES128-SHA"),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,                   /* 0xC014 */
+             "ECDHE-RSA-AES256-SHA"),
+
+  /* RFC 5289 TLS 1.2 ECC HMAC SHA256/384 */
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,              /* 0xC023 */
+             "ECDHE-ECDSA-AES128-SHA256"),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,              /* 0xC024 */
+             "ECDHE-ECDSA-AES256-SHA384"),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,               /* 0xC025 */
+             "ECDH-ECDSA-AES128-SHA256"),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,               /* 0xC026 */
+             "ECDH-ECDSA-AES256-SHA384"),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,                /* 0xC027 */
+             "ECDHE-RSA-AES128-SHA256"),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,                /* 0xC028 */
+             "ECDHE-RSA-AES256-SHA384"),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,                 /* 0xC029 */
+             "ECDH-RSA-AES128-SHA256"),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,                 /* 0xC02A */
+             "ECDH-RSA-AES256-SHA384"),
+
+  /* RFC 5289 TLS 1.2 GCM */
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,              /* 0xC02B */
+             "ECDHE-ECDSA-AES128-GCM-SHA256"),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,              /* 0xC02C */
+             "ECDHE-ECDSA-AES256-GCM-SHA384"),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,               /* 0xC02D */
+             "ECDH-ECDSA-AES128-GCM-SHA256"),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,               /* 0xC02E */
+             "ECDH-ECDSA-AES256-GCM-SHA384"),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,                /* 0xC02F */
+             "ECDHE-RSA-AES128-GCM-SHA256"),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,                /* 0xC030 */
+             "ECDHE-RSA-AES256-GCM-SHA384"),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,                 /* 0xC031 */
+             "ECDH-RSA-AES128-GCM-SHA256"),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,                 /* 0xC032 */
+             "ECDH-RSA-AES256-GCM-SHA384"),
+#ifdef BR_TLS_RSA_WITH_AES_128_CCM
+
+  /* RFC 6655 TLS 1.2 CCM
+     Supported since BearSSL 0.6 */
+  CIPHER_DEF(TLS_RSA_WITH_AES_128_CCM,                             /* 0xC09C */
+             "AES128-CCM"),
+  CIPHER_DEF(TLS_RSA_WITH_AES_256_CCM,                             /* 0xC09D */
+             "AES256-CCM"),
+  CIPHER_DEF(TLS_RSA_WITH_AES_128_CCM_8,                           /* 0xC0A0 */
+             "AES128-CCM8"),
+  CIPHER_DEF(TLS_RSA_WITH_AES_256_CCM_8,                           /* 0xC0A1 */
+             "AES256-CCM8"),
+
+  /* RFC 7251 TLS 1.2 ECC CCM
+     Supported since BearSSL 0.6 */
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CCM,                     /* 0xC0AC */
+             "ECDHE-ECDSA-AES128-CCM"),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CCM,                     /* 0xC0AD */
+             "ECDHE-ECDSA-AES256-CCM"),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,                   /* 0xC0AE */
+             "ECDHE-ECDSA-AES128-CCM8"),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,                   /* 0xC0AF */
+             "ECDHE-ECDSA-AES256-CCM8"),
+#endif
+
+  /* RFC 7905 TLS 1.2 ChaCha20-Poly1305
+     Supported since BearSSL 0.2 */
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,          /* 0xCCA8 */
+             "ECDHE-RSA-CHACHA20-POLY1305"),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,        /* 0xCCA9 */
+             "ECDHE-ECDSA-CHACHA20-POLY1305"),
+};
+
+#define NUM_OF_CIPHERS (sizeof(ciphertable) / sizeof(ciphertable[0]))
+#define CIPHER_NAME_BUF_LEN 64
+
+static bool is_separator(char c)
+{
+  /* Return whether character is a cipher list separator. */
+  switch(c) {
+    case ' ':
+    case '\t':
+    case ':':
+    case ',':
+    case ';':
+      return true;
+  }
+  return false;
+}
+
+static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data,
+                                             br_ssl_engine_context *ssl_eng,
+                                             const char *ciphers)
+{
+  uint16_t selected_ciphers[NUM_OF_CIPHERS];
+  size_t selected_count = 0;
+  const char *cipher_start = ciphers;
+  const char *cipher_end;
+  size_t i, j;
+
+  if(!cipher_start)
+    return CURLE_SSL_CIPHER;
+
+  while(true) {
+    const char *cipher;
+    size_t clen;
+
+    /* Extract the next cipher name from the ciphers string */
+    while(is_separator(*cipher_start))
+      ++cipher_start;
+    if(!*cipher_start)
+      break;
+    cipher_end = cipher_start;
+    while(*cipher_end && !is_separator(*cipher_end))
+      ++cipher_end;
+
+    clen = cipher_end - cipher_start;
+    cipher = cipher_start;
+
+    cipher_start = cipher_end;
+
+    /* Lookup the cipher name in the table of available ciphers. If the cipher
+       name starts with "TLS_" we do the lookup by IANA name. Otherwise, we try
+       to match cipher name by an (OpenSSL) alias. */
+    if(strncasecompare(cipher, "TLS_", 4)) {
+      for(i = 0; i < NUM_OF_CIPHERS &&
+            (strlen(ciphertable[i].name) == clen) &&
+            !strncasecompare(cipher, ciphertable[i].name, clen); ++i);
+    }
+    else {
+      for(i = 0; i < NUM_OF_CIPHERS &&
+            (strlen(ciphertable[i].alias_name) == clen) &&
+            !strncasecompare(cipher, ciphertable[i].alias_name, clen); ++i);
+    }
+    if(i == NUM_OF_CIPHERS) {
+      infof(data, "BearSSL: unknown cipher in list: %.*s",
+            (int)clen, cipher);
+      continue;
+    }
+
+    /* No duplicates allowed */
+    for(j = 0; j < selected_count &&
+          selected_ciphers[j] != ciphertable[i].num; j++);
+    if(j < selected_count) {
+      infof(data, "BearSSL: duplicate cipher in list: %.*s",
+            (int)clen, cipher);
+      continue;
+    }
+
+    DEBUGASSERT(selected_count < NUM_OF_CIPHERS);
+    selected_ciphers[selected_count] = ciphertable[i].num;
+    ++selected_count;
+  }
+
+  if(selected_count == 0) {
+    failf(data, "BearSSL: no supported cipher in list");
+    return CURLE_SSL_CIPHER;
+  }
+
+  br_ssl_engine_set_suites(ssl_eng, selected_ciphers, selected_count);
+  return CURLE_OK;
+}
+
+static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct bearssl_ssl_backend_data *backend =
+    (struct bearssl_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+  const char * const ssl_cafile =
+    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+    (ca_info_blob ? NULL : conn_config->CAfile);
+  const char *hostname = connssl->peer.hostname;
+  const bool verifypeer = conn_config->verifypeer;
+  const bool verifyhost = conn_config->verifyhost;
+  CURLcode ret;
+  unsigned version_min, version_max;
+  int session_set = 0;
+
+  DEBUGASSERT(backend);
+  CURL_TRC_CF(data, cf, "connect_step1");
+
+  switch(conn_config->version) {
+  case CURL_SSLVERSION_SSLv2:
+    failf(data, "BearSSL does not support SSLv2");
+    return CURLE_SSL_CONNECT_ERROR;
+  case CURL_SSLVERSION_SSLv3:
+    failf(data, "BearSSL does not support SSLv3");
+    return CURLE_SSL_CONNECT_ERROR;
+  case CURL_SSLVERSION_TLSv1_0:
+    version_min = BR_TLS10;
+    version_max = BR_TLS10;
+    break;
+  case CURL_SSLVERSION_TLSv1_1:
+    version_min = BR_TLS11;
+    version_max = BR_TLS11;
+    break;
+  case CURL_SSLVERSION_TLSv1_2:
+    version_min = BR_TLS12;
+    version_max = BR_TLS12;
+    break;
+  case CURL_SSLVERSION_DEFAULT:
+  case CURL_SSLVERSION_TLSv1:
+    version_min = BR_TLS10;
+    version_max = BR_TLS12;
+    break;
+  default:
+    failf(data, "BearSSL: unknown CURLOPT_SSLVERSION");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  if(verifypeer) {
+    if(ca_info_blob) {
+      struct cafile_source source;
+      source.type = CAFILE_SOURCE_BLOB;
+      source.data = ca_info_blob->data;
+      source.len = ca_info_blob->len;
+
+      CURL_TRC_CF(data, cf, "connect_step1, load ca_info_blob");
+      ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
+      if(ret != CURLE_OK) {
+        failf(data, "error importing CA certificate blob");
+        return ret;
+      }
+    }
+
+    if(ssl_cafile) {
+      struct cafile_source source;
+      source.type = CAFILE_SOURCE_PATH;
+      source.data = ssl_cafile;
+      source.len = 0;
+
+      CURL_TRC_CF(data, cf, "connect_step1, load cafile");
+      ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
+      if(ret != CURLE_OK) {
+        failf(data, "error setting certificate verify locations."
+              " CAfile: %s", ssl_cafile);
+        return ret;
+      }
+    }
+  }
+
+  /* initialize SSL context */
+  br_ssl_client_init_full(&backend->ctx, &backend->x509.minimal,
+                          backend->anchors, backend->anchors_len);
+  br_ssl_engine_set_versions(&backend->ctx.eng, version_min, version_max);
+  br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf,
+                           sizeof(backend->buf), 1);
+
+  if(conn_config->cipher_list) {
+    /* Override the ciphers as specified. For the default cipher list see the
+       BearSSL source code of br_ssl_client_init_full() */
+    CURL_TRC_CF(data, cf, "connect_step1, set ciphers");
+    ret = bearssl_set_selected_ciphers(data, &backend->ctx.eng,
+                                       conn_config->cipher_list);
+    if(ret)
+      return ret;
+  }
+
+  /* initialize X.509 context */
+  backend->x509.vtable = &x509_vtable;
+  backend->x509.verifypeer = verifypeer;
+  backend->x509.verifyhost = verifyhost;
+  br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable);
+
+  if(ssl_config->primary.sessionid) {
+    void *session;
+
+    CURL_TRC_CF(data, cf, "connect_step1, check session cache");
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(cf, data, &session, NULL)) {
+      br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
+      session_set = 1;
+      infof(data, "BearSSL: reusing session ID");
+    }
+    Curl_ssl_sessionid_unlock(data);
+  }
+
+  if(connssl->alpn) {
+    struct alpn_proto_buf proto;
+    size_t i;
+
+    for(i = 0; i < connssl->alpn->count; ++i) {
+      backend->protocols[i] = connssl->alpn->entries[i];
+    }
+    br_ssl_engine_set_protocol_names(&backend->ctx.eng, backend->protocols,
+                                     connssl->alpn->count);
+    Curl_alpn_to_proto_str(&proto, connssl->alpn);
+    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+  }
+
+  if(connssl->peer.type != CURL_SSL_PEER_DNS) {
+    if(verifyhost) {
+      failf(data, "BearSSL: "
+            "host verification of IP address is not supported");
+      return CURLE_PEER_FAILED_VERIFICATION;
+    }
+    hostname = NULL;
+  }
+  else {
+    if(!connssl->peer.sni) {
+      failf(data, "Failed to set SNI");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    hostname = connssl->peer.sni;
+    CURL_TRC_CF(data, cf, "connect_step1, SNI set");
+  }
+
+  /* give application a chance to interfere with SSL set up. */
+  if(data->set.ssl.fsslctx) {
+    Curl_set_in_callback(data, true);
+    ret = (*data->set.ssl.fsslctx)(data, &backend->ctx,
+                                   data->set.ssl.fsslctxp);
+    Curl_set_in_callback(data, false);
+    if(ret) {
+      failf(data, "BearSSL: error signaled by ssl ctx callback");
+      return ret;
+    }
+  }
+
+  if(!br_ssl_client_reset(&backend->ctx, hostname, session_set))
+    return CURLE_FAILED_INIT;
+  backend->active = TRUE;
+
+  connssl->connecting_state = ssl_connect_2;
+
+  return CURLE_OK;
+}
+
+static void bearssl_adjust_pollset(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   struct easy_pollset *ps)
+{
+  if(!cf->connected) {
+    curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
+    if(sock != CURL_SOCKET_BAD) {
+      struct ssl_connect_data *connssl = cf->ctx;
+      struct bearssl_ssl_backend_data *backend =
+        (struct bearssl_ssl_backend_data *)connssl->backend;
+      unsigned state = br_ssl_engine_current_state(&backend->ctx.eng);
+
+      if(state & BR_SSL_SENDREC) {
+        Curl_pollset_set_out_only(data, ps, sock);
+      }
+      else {
+        Curl_pollset_set_in_only(data, ps, sock);
+      }
+    }
+  }
+}
+
+static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  unsigned target)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct bearssl_ssl_backend_data *backend =
+    (struct bearssl_ssl_backend_data *)connssl->backend;
+  unsigned state;
+  unsigned char *buf;
+  size_t len;
+  ssize_t ret;
+  CURLcode result;
+  int err;
+
+  DEBUGASSERT(backend);
+
+  for(;;) {
+    state = br_ssl_engine_current_state(&backend->ctx.eng);
+    if(state & BR_SSL_CLOSED) {
+      err = br_ssl_engine_last_error(&backend->ctx.eng);
+      switch(err) {
+      case BR_ERR_OK:
+        /* TLS close notify */
+        if(connssl->state != ssl_connection_complete) {
+          failf(data, "SSL: connection closed during handshake");
+          return CURLE_SSL_CONNECT_ERROR;
+        }
+        return CURLE_OK;
+      case BR_ERR_X509_EXPIRED:
+        failf(data, "SSL: X.509 verification: "
+              "certificate is expired or not yet valid");
+        return CURLE_PEER_FAILED_VERIFICATION;
+      case BR_ERR_X509_BAD_SERVER_NAME:
+        failf(data, "SSL: X.509 verification: "
+              "expected server name was not found in the chain");
+        return CURLE_PEER_FAILED_VERIFICATION;
+      case BR_ERR_X509_NOT_TRUSTED:
+        failf(data, "SSL: X.509 verification: "
+              "chain could not be linked to a trust anchor");
+        return CURLE_PEER_FAILED_VERIFICATION;
+      }
+      /* X.509 errors are documented to have the range 32..63 */
+      if(err >= 32 && err < 64)
+        return CURLE_PEER_FAILED_VERIFICATION;
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    if(state & target)
+      return CURLE_OK;
+    if(state & BR_SSL_SENDREC) {
+      buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
+      ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result);
+      CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result);
+      if(ret <= 0) {
+        return result;
+      }
+      br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret);
+    }
+    else if(state & BR_SSL_RECVREC) {
+      buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len);
+      ret = Curl_conn_cf_recv(cf->next, data, (char *)buf, len, &result);
+      CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result);
+      if(ret == 0) {
+        failf(data, "SSL: EOF without close notify");
+        return CURLE_READ_ERROR;
+      }
+      if(ret <= 0) {
+        return result;
+      }
+      br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret);
+    }
+  }
+}
+
+static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct bearssl_ssl_backend_data *backend =
+    (struct bearssl_ssl_backend_data *)connssl->backend;
+  CURLcode ret;
+
+  DEBUGASSERT(backend);
+  CURL_TRC_CF(data, cf, "connect_step2");
+
+  ret = bearssl_run_until(cf, data, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
+  if(ret == CURLE_AGAIN)
+    return CURLE_OK;
+  if(ret == CURLE_OK) {
+    unsigned int tver;
+    if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) {
+      failf(data, "SSL: connection closed during handshake");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    connssl->connecting_state = ssl_connect_3;
+    /* Informational message */
+    tver = br_ssl_engine_get_version(&backend->ctx.eng);
+    if(tver == 0x0303)
+      infof(data, "SSL connection using TLSv1.2");
+    else if(tver == 0x0304)
+      infof(data, "SSL connection using TLSv1.3");
+    else
+      infof(data, "SSL connection using TLS 0x%x", tver);
+  }
+  return ret;
+}
+
+static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct bearssl_ssl_backend_data *backend =
+    (struct bearssl_ssl_backend_data *)connssl->backend;
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  CURLcode ret;
+
+  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+  DEBUGASSERT(backend);
+  CURL_TRC_CF(data, cf, "connect_step3");
+
+  if(connssl->alpn) {
+    const char *proto;
+
+    proto = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
+    Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto,
+                             proto? strlen(proto) : 0);
+  }
+
+  if(ssl_config->primary.sessionid) {
+    bool incache;
+    bool added = FALSE;
+    void *oldsession;
+    br_ssl_session_parameters *session;
+
+    session = malloc(sizeof(*session));
+    if(!session)
+      return CURLE_OUT_OF_MEMORY;
+    br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
+    Curl_ssl_sessionid_lock(data);
+    incache = !(Curl_ssl_getsessionid(cf, data, &oldsession, NULL));
+    if(incache)
+      Curl_ssl_delsessionid(data, oldsession);
+    ret = Curl_ssl_addsessionid(cf, data, session, 0, &added);
+    Curl_ssl_sessionid_unlock(data);
+    if(!added)
+      free(session);
+    if(ret) {
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  connssl->connecting_state = ssl_connect_done;
+
+  return CURLE_OK;
+}
+
+static ssize_t bearssl_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                            const void *buf, size_t len, CURLcode *err)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct bearssl_ssl_backend_data *backend =
+    (struct bearssl_ssl_backend_data *)connssl->backend;
+  unsigned char *app;
+  size_t applen;
+
+  DEBUGASSERT(backend);
+
+  for(;;) {
+    *err = bearssl_run_until(cf, data, BR_SSL_SENDAPP);
+    if(*err)
+      return -1;
+    app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen);
+    if(!app) {
+      failf(data, "SSL: connection closed during write");
+      *err = CURLE_SEND_ERROR;
+      return -1;
+    }
+    if(backend->pending_write) {
+      applen = backend->pending_write;
+      backend->pending_write = 0;
+      return applen;
+    }
+    if(applen > len)
+      applen = len;
+    memcpy(app, buf, applen);
+    br_ssl_engine_sendapp_ack(&backend->ctx.eng, applen);
+    br_ssl_engine_flush(&backend->ctx.eng, 0);
+    backend->pending_write = applen;
+  }
+}
+
+static ssize_t bearssl_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                            char *buf, size_t len, CURLcode *err)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct bearssl_ssl_backend_data *backend =
+    (struct bearssl_ssl_backend_data *)connssl->backend;
+  unsigned char *app;
+  size_t applen;
+
+  DEBUGASSERT(backend);
+
+  *err = bearssl_run_until(cf, data, BR_SSL_RECVAPP);
+  if(*err != CURLE_OK)
+    return -1;
+  app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen);
+  if(!app)
+    return 0;
+  if(applen > len)
+    applen = len;
+  memcpy(buf, app, applen);
+  br_ssl_engine_recvapp_ack(&backend->ctx.eng, applen);
+
+  return applen;
+}
+
+static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
+                                       struct Curl_easy *data,
+                                       bool nonblocking,
+                                       bool *done)
+{
+  CURLcode ret;
+  struct ssl_connect_data *connssl = cf->ctx;
+  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+  timediff_t timeout_ms;
+  int what;
+
+  CURL_TRC_CF(data, cf, "connect_common(blocking=%d)", !nonblocking);
+  /* check if the connection has already been established */
+  if(ssl_connection_complete == connssl->state) {
+    CURL_TRC_CF(data, cf, "connect_common, connected");
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  if(ssl_connect_1 == connssl->connecting_state) {
+    ret = bearssl_connect_step1(cf, data);
+    if(ret)
+      return ret;
+  }
+
+  while(ssl_connect_2 == connssl->connecting_state ||
+        ssl_connect_2_reading == connssl->connecting_state ||
+        ssl_connect_2_writing == connssl->connecting_state) {
+    /* check allowed time left */
+    timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    /* if ssl is expecting something, check if it's available. */
+    if(ssl_connect_2_reading == connssl->connecting_state ||
+       ssl_connect_2_writing == connssl->connecting_state) {
+
+      curl_socket_t writefd = ssl_connect_2_writing ==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+      curl_socket_t readfd = ssl_connect_2_reading ==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+      CURL_TRC_CF(data, cf, "connect_common, check socket");
+      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+                               nonblocking?0:timeout_ms);
+      CURL_TRC_CF(data, cf, "connect_common, check socket -> %d", what);
+      if(what < 0) {
+        /* fatal error */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      else if(0 == what) {
+        if(nonblocking) {
+          *done = FALSE;
+          return CURLE_OK;
+        }
+        else {
+          /* timeout */
+          failf(data, "SSL connection timeout");
+          return CURLE_OPERATION_TIMEDOUT;
+        }
+      }
+      /* socket is readable or writable */
+    }
+
+    /* Run transaction, and return to the caller if it failed or if this
+     * connection is done nonblocking and this loop would execute again. This
+     * permits the owner of a multi handle to abort a connection attempt
+     * before step2 has completed while ensuring that a client using select()
+     * or epoll() will always have a valid fdset to wait on.
+     */
+    ret = bearssl_connect_step2(cf, data);
+    if(ret || (nonblocking &&
+               (ssl_connect_2 == connssl->connecting_state ||
+                ssl_connect_2_reading == connssl->connecting_state ||
+                ssl_connect_2_writing == connssl->connecting_state)))
+      return ret;
+  }
+
+  if(ssl_connect_3 == connssl->connecting_state) {
+    ret = bearssl_connect_step3(cf, data);
+    if(ret)
+      return ret;
+  }
+
+  if(ssl_connect_done == connssl->connecting_state) {
+    connssl->state = ssl_connection_complete;
+    *done = TRUE;
+  }
+  else
+    *done = FALSE;
+
+  /* Reset our connect state machine */
+  connssl->connecting_state = ssl_connect_1;
+
+  return CURLE_OK;
+}
+
+static size_t bearssl_version(char *buffer, size_t size)
+{
+  return msnprintf(buffer, size, "BearSSL");
+}
+
+static bool bearssl_data_pending(struct Curl_cfilter *cf,
+                                 const struct Curl_easy *data)
+{
+  struct ssl_connect_data *ctx = cf->ctx;
+  struct bearssl_ssl_backend_data *backend;
+
+  (void)data;
+  DEBUGASSERT(ctx && ctx->backend);
+  backend = (struct bearssl_ssl_backend_data *)ctx->backend;
+  return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP;
+}
+
+static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM,
+                               unsigned char *entropy, size_t length)
+{
+  static br_hmac_drbg_context ctx;
+  static bool seeded = FALSE;
+
+  if(!seeded) {
+    br_prng_seeder seeder;
+
+    br_hmac_drbg_init(&ctx, &br_sha256_vtable, NULL, 0);
+    seeder = br_prng_seeder_system(NULL);
+    if(!seeder || !seeder(&ctx.vtable))
+      return CURLE_FAILED_INIT;
+    seeded = TRUE;
+  }
+  br_hmac_drbg_generate(&ctx, entropy, length);
+
+  return CURLE_OK;
+}
+
+static CURLcode bearssl_connect(struct Curl_cfilter *cf,
+                                struct Curl_easy *data)
+{
+  CURLcode ret;
+  bool done = FALSE;
+
+  ret = bearssl_connect_common(cf, data, FALSE, &done);
+  if(ret)
+    return ret;
+
+  DEBUGASSERT(done);
+
+  return CURLE_OK;
+}
+
+static CURLcode bearssl_connect_nonblocking(struct Curl_cfilter *cf,
+                                            struct Curl_easy *data,
+                                            bool *done)
+{
+  return bearssl_connect_common(cf, data, TRUE, done);
+}
+
+static void *bearssl_get_internals(struct ssl_connect_data *connssl,
+                                   CURLINFO info UNUSED_PARAM)
+{
+  struct bearssl_ssl_backend_data *backend =
+    (struct bearssl_ssl_backend_data *)connssl->backend;
+  DEBUGASSERT(backend);
+  return &backend->ctx;
+}
+
+static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct bearssl_ssl_backend_data *backend =
+    (struct bearssl_ssl_backend_data *)connssl->backend;
+  size_t i;
+
+  DEBUGASSERT(backend);
+
+  if(backend->active) {
+    backend->active = FALSE;
+    br_ssl_engine_close(&backend->ctx.eng);
+    (void)bearssl_run_until(cf, data, BR_SSL_CLOSED);
+  }
+  if(backend->anchors) {
+    for(i = 0; i < backend->anchors_len; ++i)
+      free(backend->anchors[i].dn.data);
+    Curl_safefree(backend->anchors);
+  }
+}
+
+static void bearssl_session_free(void *ptr)
+{
+  free(ptr);
+}
+
+static CURLcode bearssl_sha256sum(const unsigned char *input,
+                                  size_t inputlen,
+                                  unsigned char *sha256sum,
+                                  size_t sha256len UNUSED_PARAM)
+{
+  br_sha256_context ctx;
+
+  br_sha256_init(&ctx);
+  br_sha256_update(&ctx, input, inputlen);
+  br_sha256_out(&ctx, sha256sum);
+  return CURLE_OK;
+}
+
+const struct Curl_ssl Curl_ssl_bearssl = {
+  { CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */
+  SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX | SSLSUPP_HTTPS_PROXY,
+  sizeof(struct bearssl_ssl_backend_data),
+
+  Curl_none_init,                  /* init */
+  Curl_none_cleanup,               /* cleanup */
+  bearssl_version,                 /* version */
+  Curl_none_check_cxn,             /* check_cxn */
+  Curl_none_shutdown,              /* shutdown */
+  bearssl_data_pending,            /* data_pending */
+  bearssl_random,                  /* random */
+  Curl_none_cert_status_request,   /* cert_status_request */
+  bearssl_connect,                 /* connect */
+  bearssl_connect_nonblocking,     /* connect_nonblocking */
+  bearssl_adjust_pollset,          /* adjust_pollset */
+  bearssl_get_internals,           /* get_internals */
+  bearssl_close,                   /* close_one */
+  Curl_none_close_all,             /* close_all */
+  bearssl_session_free,            /* session_free */
+  Curl_none_set_engine,            /* set_engine */
+  Curl_none_set_engine_default,    /* set_engine_default */
+  Curl_none_engines_list,          /* engines_list */
+  Curl_none_false_start,           /* false_start */
+  bearssl_sha256sum,               /* sha256sum */
+  NULL,                            /* associate_connection */
+  NULL,                            /* disassociate_connection */
+  NULL,                            /* free_multi_ssl_backend_data */
+  bearssl_recv,                    /* recv decrypted data */
+  bearssl_send,                    /* send data to encrypt */
+};
+
+#endif /* USE_BEARSSL */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/bearssl.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/bearssl.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/bearssl.h	(revision 104083)
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_BEARSSL_H
+#define HEADER_CURL_BEARSSL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Michael Forney, <mforney@mforney.org>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_BEARSSL
+
+extern const struct Curl_ssl Curl_ssl_bearssl;
+
+#endif /* USE_BEARSSL */
+#endif /* HEADER_CURL_BEARSSL_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/gtls.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/gtls.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/gtls.c	(revision 104083)
@@ -0,0 +1,1679 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ *
+ * Note: don't use the GnuTLS' *_t variable type names in this source code,
+ * since they were not present in 1.0.X.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_GNUTLS
+
+#include <gnutls/abstract.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <gnutls/crypto.h>
+#include <nettle/sha2.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "gtls.h"
+#include "vtls.h"
+#include "vtls_int.h"
+#include "vauth/vauth.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "strcase.h"
+#include "warnless.h"
+#include "x509asn1.h"
+#include "multiif.h"
+#include "curl_printf.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Enable GnuTLS debugging by defining GTLSDEBUG */
+/*#define GTLSDEBUG */
+
+#ifdef GTLSDEBUG
+static void tls_log_func(int level, const char *str)
+{
+    fprintf(stderr, "|<%d>| %s", level, str);
+}
+#endif
+static bool gtls_inited = FALSE;
+
+#if !defined(GNUTLS_VERSION_NUMBER) || (GNUTLS_VERSION_NUMBER < 0x03010a)
+#error "too old GnuTLS version"
+#endif
+
+# include <gnutls/ocsp.h>
+
+struct gtls_ssl_backend_data {
+  struct gtls_instance gtls;
+};
+
+static ssize_t gtls_push(void *s, const void *buf, size_t blen)
+{
+  struct Curl_cfilter *cf = s;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  ssize_t nwritten;
+  CURLcode result;
+
+  DEBUGASSERT(data);
+  nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+  if(nwritten < 0) {
+    struct gtls_ssl_backend_data *backend =
+      (struct gtls_ssl_backend_data *)connssl->backend;
+    gnutls_transport_set_errno(backend->gtls.session,
+                               (CURLE_AGAIN == result)? EAGAIN : EINVAL);
+    nwritten = -1;
+  }
+  return nwritten;
+}
+
+static ssize_t gtls_pull(void *s, void *buf, size_t blen)
+{
+  struct Curl_cfilter *cf = s;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  ssize_t nread;
+  CURLcode result;
+
+  DEBUGASSERT(data);
+  nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+  if(nread < 0) {
+    struct gtls_ssl_backend_data *backend =
+      (struct gtls_ssl_backend_data *)connssl->backend;
+    gnutls_transport_set_errno(backend->gtls.session,
+                               (CURLE_AGAIN == result)? EAGAIN : EINVAL);
+    nread = -1;
+  }
+  else if(nread == 0)
+    connssl->peer_closed = TRUE;
+  return nread;
+}
+
+/* gtls_init()
+ *
+ * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
+ * are not thread-safe and thus this function itself is not thread-safe and
+ * must only be called from within curl_global_init() to keep the thread
+ * situation under control!
+ */
+static int gtls_init(void)
+{
+  int ret = 1;
+  if(!gtls_inited) {
+    ret = gnutls_global_init()?0:1;
+#ifdef GTLSDEBUG
+    gnutls_global_set_log_function(tls_log_func);
+    gnutls_global_set_log_level(2);
+#endif
+    gtls_inited = TRUE;
+  }
+  return ret;
+}
+
+static void gtls_cleanup(void)
+{
+  if(gtls_inited) {
+    gnutls_global_deinit();
+    gtls_inited = FALSE;
+  }
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void showtime(struct Curl_easy *data,
+                     const char *text,
+                     time_t stamp)
+{
+  struct tm buffer;
+  const struct tm *tm = &buffer;
+  char str[96];
+  CURLcode result = Curl_gmtime(stamp, &buffer);
+  if(result)
+    return;
+
+  msnprintf(str,
+            sizeof(str),
+            "  %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
+            text,
+            Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+            tm->tm_mday,
+            Curl_month[tm->tm_mon],
+            tm->tm_year + 1900,
+            tm->tm_hour,
+            tm->tm_min,
+            tm->tm_sec);
+  infof(data, "%s", str);
+}
+#endif
+
+static gnutls_datum_t load_file(const char *file)
+{
+  FILE *f;
+  gnutls_datum_t loaded_file = { NULL, 0 };
+  long filelen;
+  void *ptr;
+
+  f = fopen(file, "rb");
+  if(!f)
+    return loaded_file;
+  if(fseek(f, 0, SEEK_END) != 0
+     || (filelen = ftell(f)) < 0
+     || fseek(f, 0, SEEK_SET) != 0
+     || !(ptr = malloc((size_t)filelen)))
+    goto out;
+  if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
+    free(ptr);
+    goto out;
+  }
+
+  loaded_file.data = ptr;
+  loaded_file.size = (unsigned int)filelen;
+out:
+  fclose(f);
+  return loaded_file;
+}
+
+static void unload_file(gnutls_datum_t data)
+{
+  free(data.data);
+}
+
+
+/* this function does a SSL/TLS (re-)handshake */
+static CURLcode handshake(struct Curl_cfilter *cf,
+                          struct Curl_easy *data,
+                          bool duringconnect,
+                          bool nonblocking)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct gtls_ssl_backend_data *backend =
+    (struct gtls_ssl_backend_data *)connssl->backend;
+  gnutls_session_t session;
+  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+
+  DEBUGASSERT(backend);
+  session = backend->gtls.session;
+
+  for(;;) {
+    timediff_t timeout_ms;
+    int rc;
+
+    /* check allowed time left */
+    timeout_ms = Curl_timeleft(data, NULL, duringconnect);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    /* if ssl is expecting something, check if it's available. */
+    if(connssl->connecting_state == ssl_connect_2_reading
+       || connssl->connecting_state == ssl_connect_2_writing) {
+      int what;
+      curl_socket_t writefd = ssl_connect_2_writing ==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+      curl_socket_t readfd = ssl_connect_2_reading ==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+                               nonblocking?0:
+                               timeout_ms?timeout_ms:1000);
+      if(what < 0) {
+        /* fatal error */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      else if(0 == what) {
+        if(nonblocking)
+          return CURLE_OK;
+        else if(timeout_ms) {
+          /* timeout */
+          failf(data, "SSL connection timeout at %ld", (long)timeout_ms);
+          return CURLE_OPERATION_TIMEDOUT;
+        }
+      }
+      /* socket is readable or writable */
+    }
+
+    rc = gnutls_handshake(session);
+
+    if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
+      connssl->connecting_state =
+        gnutls_record_get_direction(session)?
+        ssl_connect_2_writing:ssl_connect_2_reading;
+      continue;
+    }
+    else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
+      const char *strerr = NULL;
+
+      if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
+        int alert = gnutls_alert_get(session);
+        strerr = gnutls_alert_get_name(alert);
+      }
+
+      if(!strerr)
+        strerr = gnutls_strerror(rc);
+
+      infof(data, "gnutls_handshake() warning: %s", strerr);
+      continue;
+    }
+    else if(rc < 0) {
+      const char *strerr = NULL;
+
+      if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
+        int alert = gnutls_alert_get(session);
+        strerr = gnutls_alert_get_name(alert);
+      }
+
+      if(!strerr)
+        strerr = gnutls_strerror(rc);
+
+      failf(data, "gnutls_handshake() failed: %s", strerr);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+
+    /* Reset our connect state machine */
+    connssl->connecting_state = ssl_connect_1;
+    return CURLE_OK;
+  }
+}
+
+static gnutls_x509_crt_fmt_t do_file_type(const char *type)
+{
+  if(!type || !type[0])
+    return GNUTLS_X509_FMT_PEM;
+  if(strcasecompare(type, "PEM"))
+    return GNUTLS_X509_FMT_PEM;
+  if(strcasecompare(type, "DER"))
+    return GNUTLS_X509_FMT_DER;
+  return GNUTLS_X509_FMT_PEM; /* default to PEM */
+}
+
+#define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509"
+/* If GnuTLS was compiled without support for SRP it will error out if SRP is
+   requested in the priority string, so treat it specially
+ */
+#define GNUTLS_SRP "+SRP"
+
+static CURLcode
+set_ssl_version_min_max(struct Curl_easy *data,
+                        struct ssl_primary_config *conn_config,
+                        const char **prioritylist,
+                        const char *tls13support)
+{
+  long ssl_version = conn_config->version;
+  long ssl_version_max = conn_config->version_max;
+
+  if((ssl_version == CURL_SSLVERSION_DEFAULT) ||
+     (ssl_version == CURL_SSLVERSION_TLSv1))
+    ssl_version = CURL_SSLVERSION_TLSv1_0;
+  if(ssl_version_max == CURL_SSLVERSION_MAX_NONE)
+    ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT;
+  if(!tls13support) {
+    /* If the running GnuTLS doesn't support TLS 1.3, we must not specify a
+       prioritylist involving that since it will make GnuTLS return an en
+       error back at us */
+    if((ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) ||
+       (ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT)) {
+      ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+    }
+  }
+  else if(ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT) {
+    ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
+  }
+
+  switch(ssl_version | ssl_version_max) {
+  case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0:
+    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+      "+VERS-TLS1.0";
+    return CURLE_OK;
+  case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1:
+    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+      "+VERS-TLS1.1:+VERS-TLS1.0";
+    return CURLE_OK;
+  case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2:
+    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+      "+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0";
+    return CURLE_OK;
+  case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1:
+    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+      "+VERS-TLS1.1";
+    return CURLE_OK;
+  case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2:
+    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+      "+VERS-TLS1.2:+VERS-TLS1.1";
+    return CURLE_OK;
+  case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2:
+    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+      "+VERS-TLS1.2";
+    return CURLE_OK;
+  case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3:
+    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+      "+VERS-TLS1.3";
+    return CURLE_OK;
+  case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_3:
+    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0";
+    return CURLE_OK;
+  case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_3:
+    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+      "+VERS-TLS1.3:+VERS-TLS1.2:+VERS-TLS1.1";
+    return CURLE_OK;
+  case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_3:
+    *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+      "+VERS-TLS1.3:+VERS-TLS1.2";
+    return CURLE_OK;
+  }
+
+  failf(data, "GnuTLS: cannot set ssl protocol");
+  return CURLE_SSL_CONNECT_ERROR;
+}
+
+CURLcode gtls_client_init(struct Curl_easy *data,
+                          struct ssl_primary_config *config,
+                          struct ssl_config_data *ssl_config,
+                          struct ssl_peer *peer,
+                          struct gtls_instance *gtls,
+                          long *pverifyresult)
+{
+  unsigned int init_flags;
+  int rc;
+  bool sni = TRUE; /* default is SNI enabled */
+  const char *prioritylist;
+  const char *err = NULL;
+  const char *tls13support;
+  CURLcode result;
+
+  if(!gtls_inited)
+    gtls_init();
+
+  *pverifyresult = 0;
+
+  if(config->version == CURL_SSLVERSION_SSLv2) {
+    failf(data, "GnuTLS does not support SSLv2");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+  else if(config->version == CURL_SSLVERSION_SSLv3)
+    sni = FALSE; /* SSLv3 has no SNI */
+
+  /* allocate a cred struct */
+  rc = gnutls_certificate_allocate_credentials(&gtls->cred);
+  if(rc != GNUTLS_E_SUCCESS) {
+    failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+#ifdef USE_GNUTLS_SRP
+  if(config->username && Curl_auth_allowed_to_host(data)) {
+    infof(data, "Using TLS-SRP username: %s", config->username);
+
+    rc = gnutls_srp_allocate_client_credentials(&gtls->srp_client_cred);
+    if(rc != GNUTLS_E_SUCCESS) {
+      failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
+            gnutls_strerror(rc));
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred,
+                                           config->username,
+                                           config->password);
+    if(rc != GNUTLS_E_SUCCESS) {
+      failf(data, "gnutls_srp_set_client_cred() failed: %s",
+            gnutls_strerror(rc));
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+  }
+#endif
+
+  if(config->verifypeer) {
+    bool imported_native_ca = false;
+
+    if(ssl_config->native_ca_store) {
+      rc = gnutls_certificate_set_x509_system_trust(gtls->cred);
+      if(rc < 0)
+        infof(data, "error reading native ca store (%s), continuing anyway",
+              gnutls_strerror(rc));
+      else {
+        infof(data, "found %d certificates in native ca store", rc);
+        if(rc > 0)
+          imported_native_ca = true;
+      }
+    }
+
+    if(config->CAfile) {
+      /* set the trusted CA cert bundle file */
+      gnutls_certificate_set_verify_flags(gtls->cred,
+                                          GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
+
+      rc = gnutls_certificate_set_x509_trust_file(gtls->cred,
+                                                  config->CAfile,
+                                                  GNUTLS_X509_FMT_PEM);
+      if(rc < 0) {
+        infof(data, "error reading ca cert file %s (%s)%s",
+              config->CAfile, gnutls_strerror(rc),
+              (imported_native_ca ? ", continuing anyway" : ""));
+        if(!imported_native_ca) {
+          *pverifyresult = rc;
+          return CURLE_SSL_CACERT_BADFILE;
+        }
+      }
+      else
+        infof(data, "found %d certificates in %s", rc, config->CAfile);
+    }
+
+    if(config->CApath) {
+      /* set the trusted CA cert directory */
+      rc = gnutls_certificate_set_x509_trust_dir(gtls->cred,
+                                                 config->CApath,
+                                                 GNUTLS_X509_FMT_PEM);
+      if(rc < 0) {
+        infof(data, "error reading ca cert file %s (%s)%s",
+              config->CApath, gnutls_strerror(rc),
+              (imported_native_ca ? ", continuing anyway" : ""));
+        if(!imported_native_ca) {
+          *pverifyresult = rc;
+          return CURLE_SSL_CACERT_BADFILE;
+        }
+      }
+      else
+        infof(data, "found %d certificates in %s", rc, config->CApath);
+    }
+  }
+
+  if(config->CRLfile) {
+    /* set the CRL list file */
+    rc = gnutls_certificate_set_x509_crl_file(gtls->cred,
+                                              config->CRLfile,
+                                              GNUTLS_X509_FMT_PEM);
+    if(rc < 0) {
+      failf(data, "error reading crl file %s (%s)",
+            config->CRLfile, gnutls_strerror(rc));
+      return CURLE_SSL_CRL_BADFILE;
+    }
+    else
+      infof(data, "found %d CRL in %s", rc, config->CRLfile);
+  }
+
+  /* Initialize TLS session as a client */
+  init_flags = GNUTLS_CLIENT;
+
+#if defined(GNUTLS_FORCE_CLIENT_CERT)
+  init_flags |= GNUTLS_FORCE_CLIENT_CERT;
+#endif
+
+#if defined(GNUTLS_NO_TICKETS)
+  /* Disable TLS session tickets */
+  init_flags |= GNUTLS_NO_TICKETS;
+#endif
+
+  rc = gnutls_init(&gtls->session, init_flags);
+  if(rc != GNUTLS_E_SUCCESS) {
+    failf(data, "gnutls_init() failed: %d", rc);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  if(sni && peer->sni) {
+    if(gnutls_server_name_set(gtls->session, GNUTLS_NAME_DNS,
+                              peer->sni, strlen(peer->sni)) < 0) {
+      failf(data, "Failed to set SNI");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+
+  /* Use default priorities */
+  rc = gnutls_set_default_priority(gtls->session);
+  if(rc != GNUTLS_E_SUCCESS)
+    return CURLE_SSL_CONNECT_ERROR;
+
+  /* "In GnuTLS 3.6.5, TLS 1.3 is enabled by default" */
+  tls13support = gnutls_check_version("3.6.5");
+
+  /* Ensure +SRP comes at the *end* of all relevant strings so that it can be
+   * removed if a run-time error indicates that SRP is not supported by this
+   * GnuTLS version */
+
+  if(config->version == CURL_SSLVERSION_SSLv2 ||
+     config->version == CURL_SSLVERSION_SSLv3) {
+    failf(data, "GnuTLS does not support SSLv2 or SSLv3");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  if(config->version == CURL_SSLVERSION_TLSv1_3) {
+    if(!tls13support) {
+      failf(data, "This GnuTLS installation does not support TLS 1.3");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+
+  /* At this point we know we have a supported TLS version, so set it */
+  result = set_ssl_version_min_max(data, config, &prioritylist, tls13support);
+  if(result)
+    return result;
+
+#ifdef USE_GNUTLS_SRP
+  /* Only add SRP to the cipher list if SRP is requested. Otherwise
+   * GnuTLS will disable TLS 1.3 support. */
+  if(config->username) {
+    char *prioritysrp = aprintf("%s:" GNUTLS_SRP, prioritylist);
+    if(!prioritysrp)
+      return CURLE_OUT_OF_MEMORY;
+    rc = gnutls_priority_set_direct(gtls->session, prioritysrp, &err);
+    free(prioritysrp);
+
+    if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
+      infof(data, "This GnuTLS does not support SRP");
+    }
+  }
+  else {
+#endif
+    infof(data, "GnuTLS ciphers: %s", prioritylist);
+    rc = gnutls_priority_set_direct(gtls->session, prioritylist, &err);
+#ifdef USE_GNUTLS_SRP
+  }
+#endif
+
+  if(rc != GNUTLS_E_SUCCESS) {
+    failf(data, "Error %d setting GnuTLS cipher list starting with %s",
+          rc, err);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  if(config->clientcert) {
+    if(ssl_config->key_passwd) {
+      const unsigned int supported_key_encryption_algorithms =
+        GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
+        GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
+        GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
+        GNUTLS_PKCS_USE_PBES2_AES_256;
+      rc = gnutls_certificate_set_x509_key_file2(
+           gtls->cred,
+           config->clientcert,
+           ssl_config->key ? ssl_config->key : config->clientcert,
+           do_file_type(ssl_config->cert_type),
+           ssl_config->key_passwd,
+           supported_key_encryption_algorithms);
+      if(rc != GNUTLS_E_SUCCESS) {
+        failf(data,
+              "error reading X.509 potentially-encrypted key file: %s",
+              gnutls_strerror(rc));
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+    }
+    else {
+      if(gnutls_certificate_set_x509_key_file(
+           gtls->cred,
+           config->clientcert,
+           ssl_config->key ? ssl_config->key : config->clientcert,
+           do_file_type(ssl_config->cert_type) ) !=
+         GNUTLS_E_SUCCESS) {
+        failf(data, "error reading X.509 key or certificate file");
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+    }
+  }
+
+#ifdef USE_GNUTLS_SRP
+  /* put the credentials to the current session */
+  if(config->username) {
+    rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_SRP,
+                                gtls->srp_client_cred);
+    if(rc != GNUTLS_E_SUCCESS) {
+      failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+  else
+#endif
+  {
+    rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_CERTIFICATE,
+                                gtls->cred);
+    if(rc != GNUTLS_E_SUCCESS) {
+      failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+
+  if(config->verifystatus) {
+    rc = gnutls_ocsp_status_request_enable_client(gtls->session,
+                                                  NULL, 0, NULL);
+    if(rc != GNUTLS_E_SUCCESS) {
+      failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode
+gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct gtls_ssl_backend_data *backend =
+    (struct gtls_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  long * const pverifyresult = &ssl_config->certverifyresult;
+  CURLcode result;
+
+  DEBUGASSERT(backend);
+
+  if(connssl->state == ssl_connection_complete)
+    /* to make us tolerant against being called more than once for the
+       same connection */
+    return CURLE_OK;
+
+  result = gtls_client_init(data, conn_config, ssl_config,
+                            &connssl->peer,
+                            &backend->gtls, pverifyresult);
+  if(result)
+    return result;
+
+  if(connssl->alpn) {
+    struct alpn_proto_buf proto;
+    gnutls_datum_t alpn[ALPN_ENTRIES_MAX];
+    size_t i;
+
+    for(i = 0; i < connssl->alpn->count; ++i) {
+      alpn[i].data = (unsigned char *)connssl->alpn->entries[i];
+      alpn[i].size = (unsigned)strlen(connssl->alpn->entries[i]);
+    }
+    if(gnutls_alpn_set_protocols(backend->gtls.session, alpn,
+                                 (unsigned)connssl->alpn->count, 0)) {
+      failf(data, "failed setting ALPN");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    Curl_alpn_to_proto_str(&proto, connssl->alpn);
+    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+  }
+
+  /* This might be a reconnect, so we check for a session ID in the cache
+     to speed up things */
+  if(conn_config->sessionid) {
+    void *ssl_sessionid;
+    size_t ssl_idsize;
+
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, &ssl_idsize)) {
+      /* we got a session id, use it! */
+      gnutls_session_set_data(backend->gtls.session,
+                              ssl_sessionid, ssl_idsize);
+
+      /* Informational message */
+      infof(data, "SSL reusing session ID");
+    }
+    Curl_ssl_sessionid_unlock(data);
+  }
+
+  /* register callback functions and handle to send and receive data. */
+  gnutls_transport_set_ptr(backend->gtls.session, cf);
+  gnutls_transport_set_push_function(backend->gtls.session, gtls_push);
+  gnutls_transport_set_pull_function(backend->gtls.session, gtls_pull);
+
+  return CURLE_OK;
+}
+
+static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
+                                    gnutls_x509_crt_t cert,
+                                    const char *pinnedpubkey)
+{
+  /* Scratch */
+  size_t len1 = 0, len2 = 0;
+  unsigned char *buff1 = NULL;
+
+  gnutls_pubkey_t key = NULL;
+
+  /* Result is returned to caller */
+  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+  /* if a path wasn't specified, don't pin */
+  if(!pinnedpubkey)
+    return CURLE_OK;
+
+  if(!cert)
+    return result;
+
+  do {
+    int ret;
+
+    /* Begin Gyrations to get the public key     */
+    gnutls_pubkey_init(&key);
+
+    ret = gnutls_pubkey_import_x509(key, cert, 0);
+    if(ret < 0)
+      break; /* failed */
+
+    ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1);
+    if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0)
+      break; /* failed */
+
+    buff1 = malloc(len1);
+    if(!buff1)
+      break; /* failed */
+
+    len2 = len1;
+
+    ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2);
+    if(ret < 0 || len1 != len2)
+      break; /* failed */
+
+    /* End Gyrations */
+
+    /* The one good exit point */
+    result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
+  } while(0);
+
+  if(key)
+    gnutls_pubkey_deinit(key);
+
+  Curl_safefree(buff1);
+
+  return result;
+}
+
+CURLcode
+Curl_gtls_verifyserver(struct Curl_easy *data,
+                       gnutls_session_t session,
+                       struct ssl_primary_config *config,
+                       struct ssl_config_data *ssl_config,
+                       struct ssl_peer *peer,
+                       const char *pinned_key)
+{
+  unsigned int cert_list_size;
+  const gnutls_datum_t *chainp;
+  unsigned int verify_status = 0;
+  gnutls_x509_crt_t x509_cert, x509_issuer;
+  gnutls_datum_t issuerp;
+  gnutls_datum_t certfields;
+  char certname[65] = ""; /* limited to 64 chars by ASN.1 */
+  size_t size;
+  time_t certclock;
+  int rc;
+  CURLcode result = CURLE_OK;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  const char *ptr;
+  unsigned int algo;
+  unsigned int bits;
+  gnutls_protocol_t version = gnutls_protocol_get_version(session);
+#endif
+  long * const certverifyresult = &ssl_config->certverifyresult;
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
+  ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
+                                     gnutls_cipher_get(session),
+                                     gnutls_mac_get(session));
+
+  infof(data, "SSL connection using %s / %s",
+        gnutls_protocol_get_name(version), ptr);
+#endif
+
+  /* This function will return the peer's raw certificate (chain) as sent by
+     the peer. These certificates are in raw format (DER encoded for
+     X.509). In case of a X.509 then a certificate list may be present. The
+     first certificate in the list is the peer's certificate, following the
+     issuer's certificate, then the issuer's issuer etc. */
+
+  chainp = gnutls_certificate_get_peers(session, &cert_list_size);
+  if(!chainp) {
+    if(config->verifypeer ||
+       config->verifyhost ||
+       config->issuercert) {
+#ifdef USE_GNUTLS_SRP
+      if(ssl_config->primary.username && !config->verifypeer &&
+         gnutls_cipher_get(session)) {
+        /* no peer cert, but auth is ok if we have SRP user and cipher and no
+           peer verify */
+      }
+      else {
+#endif
+        failf(data, "failed to get server cert");
+        *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND;
+        return CURLE_PEER_FAILED_VERIFICATION;
+#ifdef USE_GNUTLS_SRP
+      }
+#endif
+    }
+    infof(data, " common name: WARNING couldn't obtain");
+  }
+
+  if(data->set.ssl.certinfo && chainp) {
+    unsigned int i;
+
+    result = Curl_ssl_init_certinfo(data, cert_list_size);
+    if(result)
+      return result;
+
+    for(i = 0; i < cert_list_size; i++) {
+      const char *beg = (const char *) chainp[i].data;
+      const char *end = beg + chainp[i].size;
+
+      result = Curl_extract_certinfo(data, i, beg, end);
+      if(result)
+        return result;
+    }
+  }
+
+  if(config->verifypeer) {
+    /* This function will try to verify the peer's certificate and return its
+       status (trusted, invalid etc.). The value of status should be one or
+       more of the gnutls_certificate_status_t enumerated elements bitwise
+       or'd. To avoid denial of service attacks some default upper limits
+       regarding the certificate key size and chain size are set. To override
+       them use gnutls_certificate_set_verify_limits(). */
+
+    rc = gnutls_certificate_verify_peers2(session, &verify_status);
+    if(rc < 0) {
+      failf(data, "server cert verify failed: %d", rc);
+      *certverifyresult = rc;
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+
+    *certverifyresult = verify_status;
+
+    /* verify_status is a bitmask of gnutls_certificate_status bits */
+    if(verify_status & GNUTLS_CERT_INVALID) {
+      if(config->verifypeer) {
+        failf(data, "server certificate verification failed. CAfile: %s "
+              "CRLfile: %s", config->CAfile ? config->CAfile:
+              "none",
+              ssl_config->primary.CRLfile ?
+              ssl_config->primary.CRLfile : "none");
+        return CURLE_PEER_FAILED_VERIFICATION;
+      }
+      else
+        infof(data, "  server certificate verification FAILED");
+    }
+    else
+      infof(data, "  server certificate verification OK");
+  }
+  else
+    infof(data, "  server certificate verification SKIPPED");
+
+  if(config->verifystatus) {
+    if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
+      gnutls_datum_t status_request;
+      gnutls_ocsp_resp_t ocsp_resp;
+
+      gnutls_ocsp_cert_status_t status;
+      gnutls_x509_crl_reason_t reason;
+
+      rc = gnutls_ocsp_status_request_get(session, &status_request);
+
+      infof(data, " server certificate status verification FAILED");
+
+      if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+        failf(data, "No OCSP response received");
+        return CURLE_SSL_INVALIDCERTSTATUS;
+      }
+
+      if(rc < 0) {
+        failf(data, "Invalid OCSP response received");
+        return CURLE_SSL_INVALIDCERTSTATUS;
+      }
+
+      gnutls_ocsp_resp_init(&ocsp_resp);
+
+      rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
+      if(rc < 0) {
+        failf(data, "Invalid OCSP response received");
+        return CURLE_SSL_INVALIDCERTSTATUS;
+      }
+
+      (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
+                                        &status, NULL, NULL, NULL, &reason);
+
+      switch(status) {
+      case GNUTLS_OCSP_CERT_GOOD:
+        break;
+
+      case GNUTLS_OCSP_CERT_REVOKED: {
+        const char *crl_reason;
+
+        switch(reason) {
+          default:
+          case GNUTLS_X509_CRLREASON_UNSPECIFIED:
+            crl_reason = "unspecified reason";
+            break;
+
+          case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
+            crl_reason = "private key compromised";
+            break;
+
+          case GNUTLS_X509_CRLREASON_CACOMPROMISE:
+            crl_reason = "CA compromised";
+            break;
+
+          case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
+            crl_reason = "affiliation has changed";
+            break;
+
+          case GNUTLS_X509_CRLREASON_SUPERSEDED:
+            crl_reason = "certificate superseded";
+            break;
+
+          case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
+            crl_reason = "operation has ceased";
+            break;
+
+          case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
+            crl_reason = "certificate is on hold";
+            break;
+
+          case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
+            crl_reason = "will be removed from delta CRL";
+            break;
+
+          case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
+            crl_reason = "privilege withdrawn";
+            break;
+
+          case GNUTLS_X509_CRLREASON_AACOMPROMISE:
+            crl_reason = "AA compromised";
+            break;
+        }
+
+        failf(data, "Server certificate was revoked: %s", crl_reason);
+        break;
+      }
+
+      default:
+      case GNUTLS_OCSP_CERT_UNKNOWN:
+        failf(data, "Server certificate status is unknown");
+        break;
+      }
+
+      gnutls_ocsp_resp_deinit(ocsp_resp);
+
+      return CURLE_SSL_INVALIDCERTSTATUS;
+    }
+    else
+      infof(data, "  server certificate status verification OK");
+  }
+  else
+    infof(data, "  server certificate status verification SKIPPED");
+
+  /* initialize an X.509 certificate structure. */
+  gnutls_x509_crt_init(&x509_cert);
+
+  if(chainp)
+    /* convert the given DER or PEM encoded Certificate to the native
+       gnutls_x509_crt_t format */
+    gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
+
+  if(config->issuercert) {
+    gnutls_x509_crt_init(&x509_issuer);
+    issuerp = load_file(config->issuercert);
+    gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
+    rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
+    gnutls_x509_crt_deinit(x509_issuer);
+    unload_file(issuerp);
+    if(rc <= 0) {
+      failf(data, "server certificate issuer check failed (IssuerCert: %s)",
+            config->issuercert?config->issuercert:"none");
+      gnutls_x509_crt_deinit(x509_cert);
+      return CURLE_SSL_ISSUER_ERROR;
+    }
+    infof(data, "  server certificate issuer check OK (Issuer Cert: %s)",
+          config->issuercert?config->issuercert:"none");
+  }
+
+  size = sizeof(certname);
+  rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
+                                     0, /* the first and only one */
+                                     FALSE,
+                                     certname,
+                                     &size);
+  if(rc) {
+    infof(data, "error fetching CN from cert:%s",
+          gnutls_strerror(rc));
+  }
+
+  /* This function will check if the given certificate's subject matches the
+     given hostname. This is a basic implementation of the matching described
+     in RFC2818 (HTTPS), which takes into account wildcards, and the subject
+     alternative name PKIX extension. Returns non zero on success, and zero on
+     failure. */
+  rc = gnutls_x509_crt_check_hostname(x509_cert, peer->hostname);
+#if GNUTLS_VERSION_NUMBER < 0x030306
+  /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
+     addresses. */
+  if(!rc) {
+#ifdef ENABLE_IPV6
+    #define use_addr in6_addr
+#else
+    #define use_addr in_addr
+#endif
+    unsigned char addrbuf[sizeof(struct use_addr)];
+    size_t addrlen = 0;
+
+    if(Curl_inet_pton(AF_INET, peer->hostname, addrbuf) > 0)
+      addrlen = 4;
+#ifdef ENABLE_IPV6
+    else if(Curl_inet_pton(AF_INET6, peer->hostname, addrbuf) > 0)
+      addrlen = 16;
+#endif
+
+    if(addrlen) {
+      unsigned char certaddr[sizeof(struct use_addr)];
+      int i;
+
+      for(i = 0; ; i++) {
+        size_t certaddrlen = sizeof(certaddr);
+        int ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
+                                                       &certaddrlen, NULL);
+        /* If this happens, it wasn't an IP address. */
+        if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+          continue;
+        if(ret < 0)
+          break;
+        if(ret != GNUTLS_SAN_IPADDRESS)
+          continue;
+        if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) {
+          rc = 1;
+          break;
+        }
+      }
+    }
+  }
+#endif
+  if(!rc) {
+    if(config->verifyhost) {
+      failf(data, "SSL: certificate subject name (%s) does not match "
+            "target host name '%s'", certname, peer->dispname);
+      gnutls_x509_crt_deinit(x509_cert);
+      return CURLE_PEER_FAILED_VERIFICATION;
+    }
+    else
+      infof(data, "  common name: %s (does not match '%s')",
+            certname, peer->dispname);
+  }
+  else
+    infof(data, "  common name: %s (matched)", certname);
+
+  /* Check for time-based validity */
+  certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
+
+  if(certclock == (time_t)-1) {
+    if(config->verifypeer) {
+      failf(data, "server cert expiration date verify failed");
+      *certverifyresult = GNUTLS_CERT_EXPIRED;
+      gnutls_x509_crt_deinit(x509_cert);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    else
+      infof(data, "  server certificate expiration date verify FAILED");
+  }
+  else {
+    if(certclock < time(NULL)) {
+      if(config->verifypeer) {
+        failf(data, "server certificate expiration date has passed.");
+        *certverifyresult = GNUTLS_CERT_EXPIRED;
+        gnutls_x509_crt_deinit(x509_cert);
+        return CURLE_PEER_FAILED_VERIFICATION;
+      }
+      else
+        infof(data, "  server certificate expiration date FAILED");
+    }
+    else
+      infof(data, "  server certificate expiration date OK");
+  }
+
+  certclock = gnutls_x509_crt_get_activation_time(x509_cert);
+
+  if(certclock == (time_t)-1) {
+    if(config->verifypeer) {
+      failf(data, "server cert activation date verify failed");
+      *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED;
+      gnutls_x509_crt_deinit(x509_cert);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    else
+      infof(data, "  server certificate activation date verify FAILED");
+  }
+  else {
+    if(certclock > time(NULL)) {
+      if(config->verifypeer) {
+        failf(data, "server certificate not activated yet.");
+        *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED;
+        gnutls_x509_crt_deinit(x509_cert);
+        return CURLE_PEER_FAILED_VERIFICATION;
+      }
+      else
+        infof(data, "  server certificate activation date FAILED");
+    }
+    else
+      infof(data, "  server certificate activation date OK");
+  }
+
+  if(pinned_key) {
+    result = pkp_pin_peer_pubkey(data, x509_cert, pinned_key);
+    if(result != CURLE_OK) {
+      failf(data, "SSL: public key does not match pinned public key");
+      gnutls_x509_crt_deinit(x509_cert);
+      return result;
+    }
+  }
+
+  /* Show:
+
+  - subject
+  - start date
+  - expire date
+  - common name
+  - issuer
+
+  */
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  /* public key algorithm's parameters */
+  algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
+  infof(data, "  certificate public key: %s",
+        gnutls_pk_algorithm_get_name(algo));
+
+  /* version of the X.509 certificate. */
+  infof(data, "  certificate version: #%d",
+        gnutls_x509_crt_get_version(x509_cert));
+
+
+  rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields);
+  if(rc)
+    infof(data, "Failed to get certificate name");
+  else {
+    infof(data, "  subject: %s", certfields.data);
+
+    certclock = gnutls_x509_crt_get_activation_time(x509_cert);
+    showtime(data, "start date", certclock);
+
+    certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
+    showtime(data, "expire date", certclock);
+
+    gnutls_free(certfields.data);
+  }
+
+  rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields);
+  if(rc)
+    infof(data, "Failed to get certificate issuer");
+  else {
+    infof(data, "  issuer: %s", certfields.data);
+
+    gnutls_free(certfields.data);
+  }
+#endif
+
+  gnutls_x509_crt_deinit(x509_cert);
+
+  return result;
+}
+
+static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  gnutls_session_t session)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  const char *pinned_key = Curl_ssl_cf_is_proxy(cf)?
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+  CURLcode result;
+
+  result = Curl_gtls_verifyserver(data, session, conn_config, ssl_config,
+                                  &connssl->peer, pinned_key);
+  if(result)
+    goto out;
+
+  if(connssl->alpn) {
+    gnutls_datum_t proto;
+    int rc;
+
+    rc = gnutls_alpn_get_selected_protocol(session, &proto);
+    if(rc == 0)
+      Curl_alpn_set_negotiated(cf, data, proto.data, proto.size);
+    else
+      Curl_alpn_set_negotiated(cf, data, NULL, 0);
+  }
+
+  if(ssl_config->primary.sessionid) {
+    /* we always unconditionally get the session id here, as even if we
+       already got it from the cache and asked to use it in the connection, it
+       might've been rejected and then a new one is in use now and we need to
+       detect that. */
+    void *connect_sessionid;
+    size_t connect_idsize = 0;
+
+    /* get the session ID data size */
+    gnutls_session_get_data(session, NULL, &connect_idsize);
+    connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
+
+    if(connect_sessionid) {
+      bool incache;
+      bool added = FALSE;
+      void *ssl_sessionid;
+
+      /* extract session ID to the allocated buffer */
+      gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+
+      Curl_ssl_sessionid_lock(data);
+      incache = !(Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL));
+      if(incache) {
+        /* there was one before in the cache, so instead of risking that the
+           previous one was rejected, we just kill that and store the new */
+        Curl_ssl_delsessionid(data, ssl_sessionid);
+      }
+
+      /* store this session id */
+      result = Curl_ssl_addsessionid(cf, data, connect_sessionid,
+                                     connect_idsize, &added);
+      Curl_ssl_sessionid_unlock(data);
+      if(!added)
+        free(connect_sessionid);
+      if(result) {
+        result = CURLE_OUT_OF_MEMORY;
+      }
+    }
+    else
+      result = CURLE_OUT_OF_MEMORY;
+  }
+
+out:
+  return result;
+}
+
+/*
+ * This function is called after the TCP connect has completed. Setup the TLS
+ * layer and do all necessary magic.
+ */
+/* We use connssl->connecting_state to keep track of the connection status;
+   there are three states: 'ssl_connect_1' (not started yet or complete),
+   'ssl_connect_2_reading' (waiting for data from server), and
+   'ssl_connect_2_writing' (waiting to be able to write).
+ */
+static CURLcode
+gtls_connect_common(struct Curl_cfilter *cf,
+                    struct Curl_easy *data,
+                    bool nonblocking,
+                    bool *done)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  int rc;
+  CURLcode result = CURLE_OK;
+
+  /* Initiate the connection, if not already done */
+  if(ssl_connect_1 == connssl->connecting_state) {
+    rc = gtls_connect_step1(cf, data);
+    if(rc) {
+      result = rc;
+      goto out;
+    }
+  }
+
+  rc = handshake(cf, data, TRUE, nonblocking);
+  if(rc) {
+    /* handshake() sets its own error message with failf() */
+    result = rc;
+    goto out;
+  }
+
+  /* Finish connecting once the handshake is done */
+  if(ssl_connect_1 == connssl->connecting_state) {
+    struct gtls_ssl_backend_data *backend =
+      (struct gtls_ssl_backend_data *)connssl->backend;
+    gnutls_session_t session;
+    DEBUGASSERT(backend);
+    session = backend->gtls.session;
+    rc = gtls_verifyserver(cf, data, session);
+    if(rc) {
+      result = rc;
+      goto out;
+    }
+    connssl->state = ssl_connection_complete;
+  }
+
+out:
+  *done = ssl_connect_1 == connssl->connecting_state;
+
+  return result;
+}
+
+static CURLcode gtls_connect_nonblocking(struct Curl_cfilter *cf,
+                                         struct Curl_easy *data,
+                                         bool *done)
+{
+  return gtls_connect_common(cf, data, TRUE, done);
+}
+
+static CURLcode gtls_connect(struct Curl_cfilter *cf,
+                             struct Curl_easy *data)
+{
+  CURLcode result;
+  bool done = FALSE;
+
+  result = gtls_connect_common(cf, data, FALSE, &done);
+  if(result)
+    return result;
+
+  DEBUGASSERT(done);
+
+  return CURLE_OK;
+}
+
+static bool gtls_data_pending(struct Curl_cfilter *cf,
+                              const struct Curl_easy *data)
+{
+  struct ssl_connect_data *ctx = cf->ctx;
+  struct gtls_ssl_backend_data *backend;
+
+  (void)data;
+  DEBUGASSERT(ctx && ctx->backend);
+  backend = (struct gtls_ssl_backend_data *)ctx->backend;
+  if(backend->gtls.session &&
+     0 != gnutls_record_check_pending(backend->gtls.session))
+    return TRUE;
+  return FALSE;
+}
+
+static ssize_t gtls_send(struct Curl_cfilter *cf,
+                         struct Curl_easy *data,
+                         const void *mem,
+                         size_t len,
+                         CURLcode *curlcode)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct gtls_ssl_backend_data *backend =
+    (struct gtls_ssl_backend_data *)connssl->backend;
+  ssize_t rc;
+
+  (void)data;
+  DEBUGASSERT(backend);
+  rc = gnutls_record_send(backend->gtls.session, mem, len);
+
+  if(rc < 0) {
+    *curlcode = (rc == GNUTLS_E_AGAIN)
+      ? CURLE_AGAIN
+      : CURLE_SEND_ERROR;
+
+    rc = -1;
+  }
+
+  return rc;
+}
+
+static void gtls_close(struct Curl_cfilter *cf,
+                       struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct gtls_ssl_backend_data *backend =
+    (struct gtls_ssl_backend_data *)connssl->backend;
+
+  (void) data;
+  DEBUGASSERT(backend);
+
+  if(backend->gtls.session) {
+    char buf[32];
+    /* Maybe the server has already sent a close notify alert.
+       Read it to avoid an RST on the TCP connection. */
+    (void)gnutls_record_recv(backend->gtls.session, buf, sizeof(buf));
+    gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
+    gnutls_deinit(backend->gtls.session);
+    backend->gtls.session = NULL;
+  }
+  if(backend->gtls.cred) {
+    gnutls_certificate_free_credentials(backend->gtls.cred);
+    backend->gtls.cred = NULL;
+  }
+#ifdef USE_GNUTLS_SRP
+  if(backend->gtls.srp_client_cred) {
+    gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
+    backend->gtls.srp_client_cred = NULL;
+  }
+#endif
+}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+static int gtls_shutdown(struct Curl_cfilter *cf,
+                         struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct gtls_ssl_backend_data *backend =
+    (struct gtls_ssl_backend_data *)connssl->backend;
+  int retval = 0;
+
+  DEBUGASSERT(backend);
+
+#ifndef CURL_DISABLE_FTP
+  /* This has only been tested on the proftpd server, and the mod_tls code
+     sends a close notify alert without waiting for a close notify alert in
+     response. Thus we wait for a close notify alert from the server, but
+     we do not send one. Let's hope other servers do the same... */
+
+  if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
+    gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
+#endif
+
+  if(backend->gtls.session) {
+    ssize_t result;
+    bool done = FALSE;
+    char buf[120];
+
+    while(!done && !connssl->peer_closed) {
+      int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
+                                 SSL_SHUTDOWN_TIMEOUT);
+      if(what > 0) {
+        /* Something to read, let's do it and hope that it is the close
+           notify alert from the server */
+        result = gnutls_record_recv(backend->gtls.session,
+                                    buf, sizeof(buf));
+        switch(result) {
+        case 0:
+          /* This is the expected response. There was no data but only
+             the close notify alert */
+          done = TRUE;
+          break;
+        case GNUTLS_E_AGAIN:
+        case GNUTLS_E_INTERRUPTED:
+          infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED");
+          break;
+        default:
+          retval = -1;
+          done = TRUE;
+          break;
+        }
+      }
+      else if(0 == what) {
+        /* timeout */
+        failf(data, "SSL shutdown timeout");
+        done = TRUE;
+      }
+      else {
+        /* anything that gets here is fatally bad */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        retval = -1;
+        done = TRUE;
+      }
+    }
+    gnutls_deinit(backend->gtls.session);
+  }
+  gnutls_certificate_free_credentials(backend->gtls.cred);
+
+#ifdef USE_GNUTLS_SRP
+  {
+    struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+    if(ssl_config->primary.username)
+      gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
+  }
+#endif
+
+  backend->gtls.cred = NULL;
+  backend->gtls.session = NULL;
+
+  return retval;
+}
+
+static ssize_t gtls_recv(struct Curl_cfilter *cf,
+                         struct Curl_easy *data,
+                         char *buf,
+                         size_t buffersize,
+                         CURLcode *curlcode)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct gtls_ssl_backend_data *backend =
+    (struct gtls_ssl_backend_data *)connssl->backend;
+  ssize_t ret;
+
+  (void)data;
+  DEBUGASSERT(backend);
+
+  ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
+  if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
+    *curlcode = CURLE_AGAIN;
+    ret = -1;
+    goto out;
+  }
+
+  if(ret == GNUTLS_E_REHANDSHAKE) {
+    /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
+       proper way" takes a whole lot of work. */
+    CURLcode result = handshake(cf, data, FALSE, FALSE);
+    if(result)
+      /* handshake() writes error message on its own */
+      *curlcode = result;
+    else
+      *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
+    ret = -1;
+    goto out;
+  }
+
+  if(ret < 0) {
+    failf(data, "GnuTLS recv error (%d): %s",
+
+          (int)ret, gnutls_strerror((int)ret));
+    *curlcode = CURLE_RECV_ERROR;
+    ret = -1;
+    goto out;
+  }
+
+out:
+  return ret;
+}
+
+static void gtls_session_free(void *ptr)
+{
+  free(ptr);
+}
+
+static size_t gtls_version(char *buffer, size_t size)
+{
+  return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
+}
+
+/* data might be NULL! */
+static CURLcode gtls_random(struct Curl_easy *data,
+                            unsigned char *entropy, size_t length)
+{
+  int rc;
+  (void)data;
+  rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
+  return rc?CURLE_FAILED_INIT:CURLE_OK;
+}
+
+static CURLcode gtls_sha256sum(const unsigned char *tmp, /* input */
+                               size_t tmplen,
+                               unsigned char *sha256sum, /* output */
+                               size_t sha256len)
+{
+  struct sha256_ctx SHA256pw;
+  sha256_init(&SHA256pw);
+  sha256_update(&SHA256pw, (unsigned int)tmplen, tmp);
+  sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum);
+  return CURLE_OK;
+}
+
+static bool gtls_cert_status_request(void)
+{
+  return TRUE;
+}
+
+static void *gtls_get_internals(struct ssl_connect_data *connssl,
+                                CURLINFO info UNUSED_PARAM)
+{
+  struct gtls_ssl_backend_data *backend =
+    (struct gtls_ssl_backend_data *)connssl->backend;
+  (void)info;
+  DEBUGASSERT(backend);
+  return backend->gtls.session;
+}
+
+const struct Curl_ssl Curl_ssl_gnutls = {
+  { CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */
+
+  SSLSUPP_CA_PATH  |
+  SSLSUPP_CERTINFO |
+  SSLSUPP_PINNEDPUBKEY |
+  SSLSUPP_HTTPS_PROXY,
+
+  sizeof(struct gtls_ssl_backend_data),
+
+  gtls_init,                     /* init */
+  gtls_cleanup,                  /* cleanup */
+  gtls_version,                  /* version */
+  Curl_none_check_cxn,           /* check_cxn */
+  gtls_shutdown,                 /* shutdown */
+  gtls_data_pending,             /* data_pending */
+  gtls_random,                   /* random */
+  gtls_cert_status_request,      /* cert_status_request */
+  gtls_connect,                  /* connect */
+  gtls_connect_nonblocking,      /* connect_nonblocking */
+  Curl_ssl_adjust_pollset,       /* adjust_pollset */
+  gtls_get_internals,            /* get_internals */
+  gtls_close,                    /* close_one */
+  Curl_none_close_all,           /* close_all */
+  gtls_session_free,             /* session_free */
+  Curl_none_set_engine,          /* set_engine */
+  Curl_none_set_engine_default,  /* set_engine_default */
+  Curl_none_engines_list,        /* engines_list */
+  Curl_none_false_start,         /* false_start */
+  gtls_sha256sum,                /* sha256sum */
+  NULL,                          /* associate_connection */
+  NULL,                          /* disassociate_connection */
+  NULL,                          /* free_multi_ssl_backend_data */
+  gtls_recv,                     /* recv decrypted data */
+  gtls_send,                     /* send data to encrypt */
+};
+
+#endif /* USE_GNUTLS */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/gtls.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/gtls.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/gtls.h	(revision 104083)
@@ -0,0 +1,75 @@
+#ifndef HEADER_CURL_GTLS_H
+#define HEADER_CURL_GTLS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include <curl/curl.h>
+
+#ifdef USE_GNUTLS
+
+#include <gnutls/gnutls.h>
+
+#ifdef HAVE_GNUTLS_SRP
+/* the function exists */
+#ifdef USE_TLS_SRP
+/* the functionality is not disabled */
+#define USE_GNUTLS_SRP
+#endif
+#endif
+
+struct Curl_easy;
+struct Curl_cfilter;
+struct ssl_primary_config;
+struct ssl_config_data;
+struct ssl_peer;
+
+struct gtls_instance {
+  gnutls_session_t session;
+  gnutls_certificate_credentials_t cred;
+#ifdef USE_GNUTLS_SRP
+  gnutls_srp_client_credentials_t srp_client_cred;
+#endif
+};
+
+CURLcode
+gtls_client_init(struct Curl_easy *data,
+                 struct ssl_primary_config *config,
+                 struct ssl_config_data *ssl_config,
+                 struct ssl_peer *peer,
+                 struct gtls_instance *gtls,
+                 long *pverifyresult);
+
+CURLcode
+Curl_gtls_verifyserver(struct Curl_easy *data,
+                       gnutls_session_t session,
+                       struct ssl_primary_config *config,
+                       struct ssl_config_data *ssl_config,
+                       struct ssl_peer *peer,
+                       const char *pinned_key);
+
+extern const struct Curl_ssl Curl_ssl_gnutls;
+
+#endif /* USE_GNUTLS */
+#endif /* HEADER_CURL_GTLS_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/hostcheck.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/hostcheck.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/hostcheck.c	(revision 104083)
@@ -0,0 +1,135 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_OPENSSL)                        \
+  || defined(USE_SCHANNEL)
+/* these backends use functions from this file */
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#include "curl_memrchr.h"
+
+#include "hostcheck.h"
+#include "strcase.h"
+#include "hostip.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* check the two input strings with given length, but do not
+   assume they end in nul-bytes */
+static bool pmatch(const char *hostname, size_t hostlen,
+                   const char *pattern, size_t patternlen)
+{
+  if(hostlen != patternlen)
+    return FALSE;
+  return strncasecompare(hostname, pattern, hostlen);
+}
+
+/*
+ * Match a hostname against a wildcard pattern.
+ * E.g.
+ *  "foo.host.com" matches "*.host.com".
+ *
+ * We use the matching rule described in RFC6125, section 6.4.3.
+ * https://datatracker.ietf.org/doc/html/rfc6125#section-6.4.3
+ *
+ * In addition: ignore trailing dots in the host names and wildcards, so that
+ * the names are used normalized. This is what the browsers do.
+ *
+ * Do not allow wildcard matching on IP numbers. There are apparently
+ * certificates being used with an IP address in the CN field, thus making no
+ * apparent distinction between a name and an IP. We need to detect the use of
+ * an IP address and not wildcard match on such names.
+ *
+ * Only match on "*" being used for the leftmost label, not "a*", "a*b" nor
+ * "*b".
+ *
+ * Return TRUE on a match. FALSE if not.
+ *
+ * @unittest: 1397
+ */
+
+static bool hostmatch(const char *hostname,
+                      size_t hostlen,
+                      const char *pattern,
+                      size_t patternlen)
+{
+  const char *pattern_label_end;
+
+  DEBUGASSERT(pattern);
+  DEBUGASSERT(patternlen);
+  DEBUGASSERT(hostname);
+  DEBUGASSERT(hostlen);
+
+  /* normalize pattern and hostname by stripping off trailing dots */
+  if(hostname[hostlen-1]=='.')
+    hostlen--;
+  if(pattern[patternlen-1]=='.')
+    patternlen--;
+
+  if(strncmp(pattern, "*.", 2))
+    return pmatch(hostname, hostlen, pattern, patternlen);
+
+  /* detect IP address as hostname and fail the match if so */
+  else if(Curl_host_is_ipnum(hostname))
+    return FALSE;
+
+  /* We require at least 2 dots in the pattern to avoid too wide wildcard
+     match. */
+  pattern_label_end = memchr(pattern, '.', patternlen);
+  if(!pattern_label_end ||
+     (memrchr(pattern, '.', patternlen) == pattern_label_end))
+    return pmatch(hostname, hostlen, pattern, patternlen);
+  else {
+    const char *hostname_label_end = memchr(hostname, '.', hostlen);
+    if(hostname_label_end) {
+      size_t skiphost = hostname_label_end - hostname;
+      size_t skiplen = pattern_label_end - pattern;
+      return pmatch(hostname_label_end, hostlen - skiphost,
+                    pattern_label_end, patternlen - skiplen);
+    }
+  }
+  return FALSE;
+}
+
+/*
+ * Curl_cert_hostcheck() returns TRUE if a match and FALSE if not.
+ */
+bool Curl_cert_hostcheck(const char *match, size_t matchlen,
+                         const char *hostname, size_t hostlen)
+{
+  if(match && *match && hostname && *hostname)
+    return hostmatch(hostname, hostlen, match, matchlen);
+  return FALSE;
+}
+
+#endif /* OPENSSL or SCHANNEL */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/hostcheck.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/hostcheck.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/hostcheck.h	(revision 104083)
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_HOSTCHECK_H
+#define HEADER_CURL_HOSTCHECK_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+/* returns TRUE if there's a match */
+bool Curl_cert_hostcheck(const char *match_pattern, size_t matchlen,
+                         const char *hostname, size_t hostlen);
+
+#endif /* HEADER_CURL_HOSTCHECK_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/keylog.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/keylog.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/keylog.c	(revision 104083)
@@ -0,0 +1,166 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(USE_OPENSSL) || \
+  defined(USE_WOLFSSL) || \
+  (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \
+  defined(USE_QUICHE)
+
+#include "keylog.h"
+#include <curl/curl.h>
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define KEYLOG_LABEL_MAXLEN (sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET") - 1)
+
+#define CLIENT_RANDOM_SIZE  32
+
+/*
+ * The master secret in TLS 1.2 and before is always 48 bytes. In TLS 1.3, the
+ * secret size depends on the cipher suite's hash function which is 32 bytes
+ * for SHA-256 and 48 bytes for SHA-384.
+ */
+#define SECRET_MAXLEN       48
+
+
+/* The fp for the open SSLKEYLOGFILE, or NULL if not open */
+static FILE *keylog_file_fp;
+
+void
+Curl_tls_keylog_open(void)
+{
+  char *keylog_file_name;
+
+  if(!keylog_file_fp) {
+    keylog_file_name = curl_getenv("SSLKEYLOGFILE");
+    if(keylog_file_name) {
+      keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT);
+      if(keylog_file_fp) {
+#ifdef _WIN32
+        if(setvbuf(keylog_file_fp, NULL, _IONBF, 0))
+#else
+        if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096))
+#endif
+        {
+          fclose(keylog_file_fp);
+          keylog_file_fp = NULL;
+        }
+      }
+      Curl_safefree(keylog_file_name);
+    }
+  }
+}
+
+void
+Curl_tls_keylog_close(void)
+{
+  if(keylog_file_fp) {
+    fclose(keylog_file_fp);
+    keylog_file_fp = NULL;
+  }
+}
+
+bool
+Curl_tls_keylog_enabled(void)
+{
+  return keylog_file_fp != NULL;
+}
+
+bool
+Curl_tls_keylog_write_line(const char *line)
+{
+  /* The current maximum valid keylog line length LF and NUL is 195. */
+  size_t linelen;
+  char buf[256];
+
+  if(!keylog_file_fp || !line) {
+    return false;
+  }
+
+  linelen = strlen(line);
+  if(linelen == 0 || linelen > sizeof(buf) - 2) {
+    /* Empty line or too big to fit in a LF and NUL. */
+    return false;
+  }
+
+  memcpy(buf, line, linelen);
+  if(line[linelen - 1] != '\n') {
+    buf[linelen++] = '\n';
+  }
+  buf[linelen] = '\0';
+
+  /* Using fputs here instead of fprintf since libcurl's fprintf replacement
+     may not be thread-safe. */
+  fputs(buf, keylog_file_fp);
+  return true;
+}
+
+bool
+Curl_tls_keylog_write(const char *label,
+                      const unsigned char client_random[CLIENT_RANDOM_SIZE],
+                      const unsigned char *secret, size_t secretlen)
+{
+  const char *hex = "0123456789ABCDEF";
+  size_t pos, i;
+  char line[KEYLOG_LABEL_MAXLEN + 1 + 2 * CLIENT_RANDOM_SIZE + 1 +
+            2 * SECRET_MAXLEN + 1 + 1];
+
+  if(!keylog_file_fp) {
+    return false;
+  }
+
+  pos = strlen(label);
+  if(pos > KEYLOG_LABEL_MAXLEN || !secretlen || secretlen > SECRET_MAXLEN) {
+    /* Should never happen - sanity check anyway. */
+    return false;
+  }
+
+  memcpy(line, label, pos);
+  line[pos++] = ' ';
+
+  /* Client Random */
+  for(i = 0; i < CLIENT_RANDOM_SIZE; i++) {
+    line[pos++] = hex[client_random[i] >> 4];
+    line[pos++] = hex[client_random[i] & 0xF];
+  }
+  line[pos++] = ' ';
+
+  /* Secret */
+  for(i = 0; i < secretlen; i++) {
+    line[pos++] = hex[secret[i] >> 4];
+    line[pos++] = hex[secret[i] & 0xF];
+  }
+  line[pos++] = '\n';
+  line[pos] = '\0';
+
+  /* Using fputs here instead of fprintf since libcurl's fprintf replacement
+     may not be thread-safe. */
+  fputs(line, keylog_file_fp);
+  return true;
+}
+
+#endif  /* TLS or QUIC backend */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/keylog.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/keylog.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/keylog.h	(revision 104083)
@@ -0,0 +1,58 @@
+#ifndef HEADER_CURL_KEYLOG_H
+#define HEADER_CURL_KEYLOG_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+/*
+ * Opens the TLS key log file if requested by the user. The SSLKEYLOGFILE
+ * environment variable specifies the output file.
+ */
+void Curl_tls_keylog_open(void);
+
+/*
+ * Closes the TLS key log file if not already.
+ */
+void Curl_tls_keylog_close(void);
+
+/*
+ * Returns true if the user successfully enabled the TLS key log file.
+ */
+bool Curl_tls_keylog_enabled(void);
+
+/*
+ * Appends a key log file entry.
+ * Returns true iff the key log file is open and a valid entry was provided.
+ */
+bool Curl_tls_keylog_write(const char *label,
+                           const unsigned char client_random[32],
+                           const unsigned char *secret, size_t secretlen);
+
+/*
+ * Appends a line to the key log file, ensure it is terminated by a LF.
+ * Returns true iff the key log file is open and a valid line was provided.
+ */
+bool Curl_tls_keylog_write_line(const char *line);
+
+#endif /* HEADER_CURL_KEYLOG_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/mbedtls.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/mbedtls.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/mbedtls.c	(revision 104083)
@@ -0,0 +1,1352 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all mbedTLS-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ *
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_MBEDTLS
+
+/* Define this to enable lots of debugging for mbedTLS */
+/* #define MBEDTLS_DEBUG */
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+/* mbedTLS (as of v3.5.1) has a duplicate function declaration
+   in its public headers. Disable the warning that detects it. */
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+#include <mbedtls/version.h>
+#if MBEDTLS_VERSION_NUMBER >= 0x02040000
+#include <mbedtls/net_sockets.h>
+#else
+#include <mbedtls/net.h>
+#endif
+#include <mbedtls/ssl.h>
+#include <mbedtls/x509.h>
+
+#include <mbedtls/error.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/sha256.h>
+
+#if MBEDTLS_VERSION_MAJOR >= 2
+#  ifdef MBEDTLS_DEBUG
+#    include <mbedtls/debug.h>
+#  endif
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "mbedtls.h"
+#include "vtls.h"
+#include "vtls_int.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "multiif.h"
+#include "mbedtls_threadlock.h"
+#include "strdup.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* ALPN for http2 */
+#ifdef USE_HTTP2
+#  undef HAS_ALPN
+#  ifdef MBEDTLS_SSL_ALPN
+#    define HAS_ALPN
+#  endif
+#endif
+
+struct mbed_ssl_backend_data {
+  mbedtls_ctr_drbg_context ctr_drbg;
+  mbedtls_entropy_context entropy;
+  mbedtls_ssl_context ssl;
+  mbedtls_x509_crt cacert;
+  mbedtls_x509_crt clicert;
+#ifdef MBEDTLS_X509_CRL_PARSE_C
+  mbedtls_x509_crl crl;
+#endif
+  mbedtls_pk_context pk;
+  mbedtls_ssl_config config;
+#ifdef HAS_ALPN
+  const char *protocols[3];
+#endif
+};
+
+/* apply threading? */
+#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
+    defined(_WIN32)
+#define THREADING_SUPPORT
+#endif
+
+#ifndef MBEDTLS_ERROR_C
+#define mbedtls_strerror(a,b,c) b[0] = 0
+#endif
+
+#if defined(THREADING_SUPPORT)
+static mbedtls_entropy_context ts_entropy;
+
+static int entropy_init_initialized = 0;
+
+static void entropy_init_mutex(mbedtls_entropy_context *ctx)
+{
+  /* lock 0 = entropy_init_mutex() */
+  Curl_mbedtlsthreadlock_lock_function(0);
+  if(entropy_init_initialized == 0) {
+    mbedtls_entropy_init(ctx);
+    entropy_init_initialized = 1;
+  }
+  Curl_mbedtlsthreadlock_unlock_function(0);
+}
+
+static void entropy_cleanup_mutex(mbedtls_entropy_context *ctx)
+{
+  /* lock 0 = use same lock as init */
+  Curl_mbedtlsthreadlock_lock_function(0);
+  if(entropy_init_initialized == 1) {
+    mbedtls_entropy_free(ctx);
+    entropy_init_initialized = 0;
+  }
+  Curl_mbedtlsthreadlock_unlock_function(0);
+}
+
+static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
+{
+  int ret;
+  /* lock 1 = entropy_func_mutex() */
+  Curl_mbedtlsthreadlock_lock_function(1);
+  ret = mbedtls_entropy_func(data, output, len);
+  Curl_mbedtlsthreadlock_unlock_function(1);
+
+  return ret;
+}
+
+#endif /* THREADING_SUPPORT */
+
+#ifdef MBEDTLS_DEBUG
+static void mbed_debug(void *context, int level, const char *f_name,
+                       int line_nb, const char *line)
+{
+  struct Curl_easy *data = NULL;
+
+  if(!context)
+    return;
+
+  data = (struct Curl_easy *)context;
+
+  infof(data, "%s", line);
+  (void) level;
+}
+#endif
+
+static int mbedtls_bio_cf_write(void *bio,
+                                const unsigned char *buf, size_t blen)
+{
+  struct Curl_cfilter *cf = bio;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  ssize_t nwritten;
+  CURLcode result;
+
+  DEBUGASSERT(data);
+  if(!data)
+    return 0;
+
+  nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result);
+  CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %zd, err=%d",
+              blen, nwritten, result);
+  if(nwritten < 0 && CURLE_AGAIN == result) {
+    nwritten = MBEDTLS_ERR_SSL_WANT_WRITE;
+  }
+  return (int)nwritten;
+}
+
+static int mbedtls_bio_cf_read(void *bio, unsigned char *buf, size_t blen)
+{
+  struct Curl_cfilter *cf = bio;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  ssize_t nread;
+  CURLcode result;
+
+  DEBUGASSERT(data);
+  if(!data)
+    return 0;
+  /* OpenSSL catches this case, so should we. */
+  if(!buf)
+    return 0;
+
+  nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &result);
+  CURL_TRC_CF(data, cf, "mbedtls_bio_cf_in_read(len=%zu) -> %zd, err=%d",
+              blen, nread, result);
+  if(nread < 0 && CURLE_AGAIN == result) {
+    nread = MBEDTLS_ERR_SSL_WANT_READ;
+  }
+  return (int)nread;
+}
+
+/*
+ *  profile
+ */
+static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
+{
+  /* Hashes from SHA-1 and above */
+  MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) |
+  MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) |
+  MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) |
+  MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
+  MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
+  MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
+  0xFFFFFFF, /* Any PK alg    */
+  0xFFFFFFF, /* Any curve     */
+  1024,      /* RSA min key len */
+};
+
+/* See https://tls.mbed.org/discussions/generic/
+   howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
+*/
+#define RSA_PUB_DER_MAX_BYTES   (38 + 2 * MBEDTLS_MPI_MAX_SIZE)
+#define ECP_PUB_DER_MAX_BYTES   (30 + 2 * MBEDTLS_ECP_MAX_BYTES)
+
+#define PUB_DER_MAX_BYTES   (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
+                             RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
+
+#if MBEDTLS_VERSION_NUMBER >= 0x03020000
+static CURLcode mbedtls_version_from_curl(
+  mbedtls_ssl_protocol_version* mbedver, long version)
+{
+  switch(version) {
+  case CURL_SSLVERSION_TLSv1_0:
+  case CURL_SSLVERSION_TLSv1_1:
+  case CURL_SSLVERSION_TLSv1_2:
+    *mbedver = MBEDTLS_SSL_VERSION_TLS1_2;
+    return CURLE_OK;
+  case CURL_SSLVERSION_TLSv1_3:
+    break;
+  }
+
+  return CURLE_SSL_CONNECT_ERROR;
+}
+#else
+static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
+{
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+  switch(version) {
+    case CURL_SSLVERSION_TLSv1_0:
+    case CURL_SSLVERSION_TLSv1_1:
+    case CURL_SSLVERSION_TLSv1_2:
+      *mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
+      return CURLE_OK;
+    case CURL_SSLVERSION_TLSv1_3:
+      break;
+  }
+#else
+  switch(version) {
+    case CURL_SSLVERSION_TLSv1_0:
+      *mbedver = MBEDTLS_SSL_MINOR_VERSION_1;
+      return CURLE_OK;
+    case CURL_SSLVERSION_TLSv1_1:
+      *mbedver = MBEDTLS_SSL_MINOR_VERSION_2;
+      return CURLE_OK;
+    case CURL_SSLVERSION_TLSv1_2:
+      *mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
+      return CURLE_OK;
+    case CURL_SSLVERSION_TLSv1_3:
+      break;
+  }
+#endif
+
+  return CURLE_SSL_CONNECT_ERROR;
+}
+#endif
+
+static CURLcode
+set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct mbed_ssl_backend_data *backend =
+    (struct mbed_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+#if MBEDTLS_VERSION_NUMBER >= 0x03020000
+  mbedtls_ssl_protocol_version mbedtls_ver_min = MBEDTLS_SSL_VERSION_TLS1_2;
+  mbedtls_ssl_protocol_version mbedtls_ver_max = MBEDTLS_SSL_VERSION_TLS1_2;
+#elif MBEDTLS_VERSION_NUMBER >= 0x03000000
+  int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3;
+  int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3;
+#else
+  int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
+  int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1;
+#endif
+  long ssl_version = conn_config->version;
+  long ssl_version_max = conn_config->version_max;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(backend);
+
+  switch(ssl_version) {
+    case CURL_SSLVERSION_DEFAULT:
+    case CURL_SSLVERSION_TLSv1:
+      ssl_version = CURL_SSLVERSION_TLSv1_0;
+      break;
+  }
+
+  switch(ssl_version_max) {
+    case CURL_SSLVERSION_MAX_NONE:
+    case CURL_SSLVERSION_MAX_DEFAULT:
+      ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+      break;
+  }
+
+  result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version);
+  if(result) {
+    failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
+    return result;
+  }
+  result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16);
+  if(result) {
+    failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
+    return result;
+  }
+
+#if MBEDTLS_VERSION_NUMBER >= 0x03020000
+  mbedtls_ssl_conf_min_tls_version(&backend->config, mbedtls_ver_min);
+  mbedtls_ssl_conf_max_tls_version(&backend->config, mbedtls_ver_max);
+#else
+  mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                               mbedtls_ver_min);
+  mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                               mbedtls_ver_max);
+#endif
+
+  return result;
+}
+
+static CURLcode
+mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct mbed_ssl_backend_data *backend =
+    (struct mbed_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  const char * const ssl_cafile =
+    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+    (ca_info_blob ? NULL : conn_config->CAfile);
+  const bool verifypeer = conn_config->verifypeer;
+  const char * const ssl_capath = conn_config->CApath;
+  char * const ssl_cert = ssl_config->primary.clientcert;
+  const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
+  const char * const ssl_crlfile = ssl_config->primary.CRLfile;
+  const char *hostname = connssl->peer.hostname;
+  int ret = -1;
+  char errorbuf[128];
+
+  DEBUGASSERT(backend);
+
+  if((conn_config->version == CURL_SSLVERSION_SSLv2) ||
+     (conn_config->version == CURL_SSLVERSION_SSLv3)) {
+    failf(data, "Not supported SSL version");
+    return CURLE_NOT_BUILT_IN;
+  }
+
+#ifdef THREADING_SUPPORT
+  mbedtls_ctr_drbg_init(&backend->ctr_drbg);
+
+  ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex,
+                              &ts_entropy, NULL, 0);
+  if(ret) {
+    mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+    failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s",
+          -ret, errorbuf);
+    return CURLE_FAILED_INIT;
+  }
+#else
+  mbedtls_entropy_init(&backend->entropy);
+  mbedtls_ctr_drbg_init(&backend->ctr_drbg);
+
+  ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, mbedtls_entropy_func,
+                              &backend->entropy, NULL, 0);
+  if(ret) {
+    mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+    failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s",
+          -ret, errorbuf);
+    return CURLE_FAILED_INIT;
+  }
+#endif /* THREADING_SUPPORT */
+
+  /* Load the trusted CA */
+  mbedtls_x509_crt_init(&backend->cacert);
+
+  if(ca_info_blob && verifypeer) {
+    /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null
+       terminated even when provided the exact length, forcing us to waste
+       extra memory here. */
+    unsigned char *newblob = Curl_memdup0(ca_info_blob->data,
+                                          ca_info_blob->len);
+    if(!newblob)
+      return CURLE_OUT_OF_MEMORY;
+    ret = mbedtls_x509_crt_parse(&backend->cacert, newblob,
+                                 ca_info_blob->len + 1);
+    free(newblob);
+    if(ret<0) {
+      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+      failf(data, "Error importing ca cert blob - mbedTLS: (-0x%04X) %s",
+            -ret, errorbuf);
+      return CURLE_SSL_CERTPROBLEM;
+    }
+  }
+
+  if(ssl_cafile && verifypeer) {
+#ifdef MBEDTLS_FS_IO
+    ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile);
+
+    if(ret<0) {
+      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+      failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
+            ssl_cafile, -ret, errorbuf);
+      return CURLE_SSL_CACERT_BADFILE;
+    }
+#else
+    failf(data, "mbedtls: functions that use the filesystem not built in");
+    return CURLE_NOT_BUILT_IN;
+#endif
+  }
+
+  if(ssl_capath) {
+#ifdef MBEDTLS_FS_IO
+    ret = mbedtls_x509_crt_parse_path(&backend->cacert, ssl_capath);
+
+    if(ret<0) {
+      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+      failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s",
+            ssl_capath, -ret, errorbuf);
+
+      if(verifypeer)
+        return CURLE_SSL_CACERT_BADFILE;
+    }
+#else
+    failf(data, "mbedtls: functions that use the filesystem not built in");
+    return CURLE_NOT_BUILT_IN;
+#endif
+  }
+
+  /* Load the client certificate */
+  mbedtls_x509_crt_init(&backend->clicert);
+
+  if(ssl_cert) {
+#ifdef MBEDTLS_FS_IO
+    ret = mbedtls_x509_crt_parse_file(&backend->clicert, ssl_cert);
+
+    if(ret) {
+      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+      failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s",
+            ssl_cert, -ret, errorbuf);
+
+      return CURLE_SSL_CERTPROBLEM;
+    }
+#else
+    failf(data, "mbedtls: functions that use the filesystem not built in");
+    return CURLE_NOT_BUILT_IN;
+#endif
+  }
+
+  if(ssl_cert_blob) {
+    /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null
+       terminated even when provided the exact length, forcing us to waste
+       extra memory here. */
+    unsigned char *newblob = Curl_memdup0(ssl_cert_blob->data,
+                                          ssl_cert_blob->len);
+    if(!newblob)
+      return CURLE_OUT_OF_MEMORY;
+    ret = mbedtls_x509_crt_parse(&backend->clicert, newblob,
+                                 ssl_cert_blob->len + 1);
+    free(newblob);
+
+    if(ret) {
+      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+      failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
+            ssl_config->key, -ret, errorbuf);
+      return CURLE_SSL_CERTPROBLEM;
+    }
+  }
+
+  /* Load the client private key */
+  mbedtls_pk_init(&backend->pk);
+
+  if(ssl_config->key || ssl_config->key_blob) {
+    if(ssl_config->key) {
+#ifdef MBEDTLS_FS_IO
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+      ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key,
+                                     ssl_config->key_passwd,
+                                     mbedtls_ctr_drbg_random,
+                                     &backend->ctr_drbg);
+#else
+      ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key,
+                                     ssl_config->key_passwd);
+#endif
+
+      if(ret) {
+        mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+        failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
+              ssl_config->key, -ret, errorbuf);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+#else
+      failf(data, "mbedtls: functions that use the filesystem not built in");
+      return CURLE_NOT_BUILT_IN;
+#endif
+    }
+    else {
+      const struct curl_blob *ssl_key_blob = ssl_config->key_blob;
+      const unsigned char *key_data =
+        (const unsigned char *)ssl_key_blob->data;
+      const char *passwd = ssl_config->key_passwd;
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+      ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len,
+                                 (const unsigned char *)passwd,
+                                 passwd ? strlen(passwd) : 0,
+                                 mbedtls_ctr_drbg_random,
+                                 &backend->ctr_drbg);
+#else
+      ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len,
+                                 (const unsigned char *)passwd,
+                                 passwd ? strlen(passwd) : 0);
+#endif
+
+      if(ret) {
+        mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+        failf(data, "Error parsing private key - mbedTLS: (-0x%04X) %s",
+              -ret, errorbuf);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+    }
+
+    if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) ||
+                     mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY)))
+      ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
+  }
+
+  /* Load the CRL */
+#ifdef MBEDTLS_X509_CRL_PARSE_C
+  mbedtls_x509_crl_init(&backend->crl);
+
+  if(ssl_crlfile) {
+#ifdef MBEDTLS_FS_IO
+    ret = mbedtls_x509_crl_parse_file(&backend->crl, ssl_crlfile);
+
+    if(ret) {
+      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+      failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s",
+            ssl_crlfile, -ret, errorbuf);
+
+      return CURLE_SSL_CRL_BADFILE;
+    }
+#else
+    failf(data, "mbedtls: functions that use the filesystem not built in");
+    return CURLE_NOT_BUILT_IN;
+#endif
+  }
+#else
+  if(ssl_crlfile) {
+    failf(data, "mbedtls: crl support not built in");
+    return CURLE_NOT_BUILT_IN;
+  }
+#endif
+
+  infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->port);
+
+  mbedtls_ssl_config_init(&backend->config);
+  ret = mbedtls_ssl_config_defaults(&backend->config,
+                                    MBEDTLS_SSL_IS_CLIENT,
+                                    MBEDTLS_SSL_TRANSPORT_STREAM,
+                                    MBEDTLS_SSL_PRESET_DEFAULT);
+  if(ret) {
+    failf(data, "mbedTLS: ssl_config failed");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  mbedtls_ssl_init(&backend->ssl);
+  if(mbedtls_ssl_setup(&backend->ssl, &backend->config)) {
+    failf(data, "mbedTLS: ssl_init failed");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  /* new profile with RSA min key len = 1024 ... */
+  mbedtls_ssl_conf_cert_profile(&backend->config,
+                                &mbedtls_x509_crt_profile_fr);
+
+  switch(conn_config->version) {
+  case CURL_SSLVERSION_DEFAULT:
+  case CURL_SSLVERSION_TLSv1:
+#if MBEDTLS_VERSION_NUMBER < 0x03000000
+    mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                                 MBEDTLS_SSL_MINOR_VERSION_1);
+    infof(data, "mbedTLS: Set min SSL version to TLS 1.0");
+    break;
+#endif
+  case CURL_SSLVERSION_TLSv1_0:
+  case CURL_SSLVERSION_TLSv1_1:
+  case CURL_SSLVERSION_TLSv1_2:
+  case CURL_SSLVERSION_TLSv1_3:
+    {
+      CURLcode result = set_ssl_version_min_max(cf, data);
+      if(result != CURLE_OK)
+        return result;
+      break;
+    }
+  default:
+    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
+
+  mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random,
+                       &backend->ctr_drbg);
+  mbedtls_ssl_set_bio(&backend->ssl, cf,
+                      mbedtls_bio_cf_write,
+                      mbedtls_bio_cf_read,
+                      NULL /*  rev_timeout() */);
+
+  mbedtls_ssl_conf_ciphersuites(&backend->config,
+                                mbedtls_ssl_list_ciphersuites());
+
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+  mbedtls_ssl_conf_renegotiation(&backend->config,
+                                 MBEDTLS_SSL_RENEGOTIATION_ENABLED);
+#endif
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+  mbedtls_ssl_conf_session_tickets(&backend->config,
+                                   MBEDTLS_SSL_SESSION_TICKETS_DISABLED);
+#endif
+
+  /* Check if there's a cached ID we can/should use here! */
+  if(ssl_config->primary.sessionid) {
+    void *old_session = NULL;
+
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(cf, data, &old_session, NULL)) {
+      ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
+      if(ret) {
+        Curl_ssl_sessionid_unlock(data);
+        failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      infof(data, "mbedTLS reusing session");
+    }
+    Curl_ssl_sessionid_unlock(data);
+  }
+
+  mbedtls_ssl_conf_ca_chain(&backend->config,
+                            &backend->cacert,
+#ifdef MBEDTLS_X509_CRL_PARSE_C
+                            &backend->crl);
+#else
+                            NULL);
+#endif
+
+  if(ssl_config->key || ssl_config->key_blob) {
+    mbedtls_ssl_conf_own_cert(&backend->config,
+                              &backend->clicert, &backend->pk);
+  }
+
+  if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni?
+                              connssl->peer.sni : connssl->peer.hostname)) {
+    /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and
+       the name to set in the SNI extension. So even if curl connects to a
+       host specified as an IP address, this function must be used. */
+    failf(data, "Failed to set SNI");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+#ifdef HAS_ALPN
+  if(connssl->alpn) {
+    struct alpn_proto_buf proto;
+    size_t i;
+
+    for(i = 0; i < connssl->alpn->count; ++i) {
+      backend->protocols[i] = connssl->alpn->entries[i];
+    }
+    /* this function doesn't clone the protocols array, which is why we need
+       to keep it around */
+    if(mbedtls_ssl_conf_alpn_protocols(&backend->config,
+                                       &backend->protocols[0])) {
+      failf(data, "Failed setting ALPN protocols");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    Curl_alpn_to_proto_str(&proto, connssl->alpn);
+    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+  }
+#endif
+
+#ifdef MBEDTLS_DEBUG
+  /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */
+  mbedtls_ssl_conf_dbg(&backend->config, mbed_debug, data);
+  /* - 0 No debug
+   * - 1 Error
+   * - 2 State change
+   * - 3 Informational
+   * - 4 Verbose
+   */
+  mbedtls_debug_set_threshold(4);
+#endif
+
+  /* give application a chance to interfere with mbedTLS set up. */
+  if(data->set.ssl.fsslctx) {
+    ret = (*data->set.ssl.fsslctx)(data, &backend->config,
+                                   data->set.ssl.fsslctxp);
+    if(ret) {
+      failf(data, "error signaled by ssl ctx callback");
+      return ret;
+    }
+  }
+
+  connssl->connecting_state = ssl_connect_2;
+
+  return CURLE_OK;
+}
+
+static CURLcode
+mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  int ret;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct mbed_ssl_backend_data *backend =
+    (struct mbed_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  const mbedtls_x509_crt *peercert;
+  const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+
+  DEBUGASSERT(backend);
+
+  ret = mbedtls_ssl_handshake(&backend->ssl);
+
+  if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
+    connssl->connecting_state = ssl_connect_2_reading;
+    return CURLE_OK;
+  }
+  else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+    connssl->connecting_state = ssl_connect_2_writing;
+    return CURLE_OK;
+  }
+  else if(ret) {
+    char errorbuf[128];
+    mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+    failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s",
+          -ret, errorbuf);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  infof(data, "mbedTLS: Handshake complete, cipher is %s",
+        mbedtls_ssl_get_ciphersuite(&backend->ssl));
+
+  ret = mbedtls_ssl_get_verify_result(&backend->ssl);
+
+  if(!conn_config->verifyhost)
+    /* Ignore hostname errors if verifyhost is disabled */
+    ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
+
+  if(ret && conn_config->verifypeer) {
+    if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
+      failf(data, "Cert verify failed: BADCERT_EXPIRED");
+
+    else if(ret & MBEDTLS_X509_BADCERT_REVOKED)
+      failf(data, "Cert verify failed: BADCERT_REVOKED");
+
+    else if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
+      failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
+
+    else if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
+      failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
+
+    else if(ret & MBEDTLS_X509_BADCERT_FUTURE)
+      failf(data, "Cert verify failed: BADCERT_FUTURE");
+
+    return CURLE_PEER_FAILED_VERIFICATION;
+  }
+
+  peercert = mbedtls_ssl_get_peer_cert(&backend->ssl);
+
+  if(peercert && data->set.verbose) {
+#ifndef MBEDTLS_X509_REMOVE_INFO
+    const size_t bufsize = 16384;
+    char *buffer = malloc(bufsize);
+
+    if(!buffer)
+      return CURLE_OUT_OF_MEMORY;
+
+    if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0)
+      infof(data, "Dumping cert info: %s", buffer);
+    else
+      infof(data, "Unable to dump certificate information");
+
+    free(buffer);
+#else
+    infof(data, "Unable to dump certificate information");
+#endif
+  }
+
+  if(pinnedpubkey) {
+    int size;
+    CURLcode result;
+    mbedtls_x509_crt *p = NULL;
+    unsigned char *pubkey = NULL;
+
+#if MBEDTLS_VERSION_NUMBER == 0x03000000
+    if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) ||
+       !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) {
+#else
+    if(!peercert || !peercert->raw.p || !peercert->raw.len) {
+#endif
+      failf(data, "Failed due to missing peer certificate");
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    p = calloc(1, sizeof(*p));
+
+    if(!p)
+      return CURLE_OUT_OF_MEMORY;
+
+    pubkey = malloc(PUB_DER_MAX_BYTES);
+
+    if(!pubkey) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto pinnedpubkey_error;
+    }
+
+    mbedtls_x509_crt_init(p);
+
+    /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
+       needs a non-const key, for now.
+       https://github.com/ARMmbed/mbedtls/issues/396 */
+#if MBEDTLS_VERSION_NUMBER == 0x03000000
+    if(mbedtls_x509_crt_parse_der(p,
+                        peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p),
+                        peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) {
+#else
+    if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
+#endif
+      failf(data, "Failed copying peer certificate");
+      result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+      goto pinnedpubkey_error;
+    }
+
+#if MBEDTLS_VERSION_NUMBER == 0x03000000
+    size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey,
+                                       PUB_DER_MAX_BYTES);
+#else
+    size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
+#endif
+
+    if(size <= 0) {
+      failf(data, "Failed copying public key from peer certificate");
+      result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+      goto pinnedpubkey_error;
+    }
+
+    /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */
+    result = Curl_pin_peer_pubkey(data,
+                                  pinnedpubkey,
+                                  &pubkey[PUB_DER_MAX_BYTES - size], size);
+pinnedpubkey_error:
+    mbedtls_x509_crt_free(p);
+    free(p);
+    free(pubkey);
+    if(result) {
+      return result;
+    }
+  }
+
+#ifdef HAS_ALPN
+  if(connssl->alpn) {
+    const char *proto = mbedtls_ssl_get_alpn_protocol(&backend->ssl);
+
+    Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto,
+                             proto? strlen(proto) : 0);
+  }
+#endif
+
+  connssl->connecting_state = ssl_connect_3;
+  infof(data, "SSL connected");
+
+  return CURLE_OK;
+}
+
+static CURLcode
+mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  CURLcode retcode = CURLE_OK;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct mbed_ssl_backend_data *backend =
+    (struct mbed_ssl_backend_data *)connssl->backend;
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+
+  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+  DEBUGASSERT(backend);
+
+  if(ssl_config->primary.sessionid) {
+    int ret;
+    mbedtls_ssl_session *our_ssl_sessionid;
+    void *old_ssl_sessionid = NULL;
+    bool added = FALSE;
+
+    our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
+    if(!our_ssl_sessionid)
+      return CURLE_OUT_OF_MEMORY;
+
+    mbedtls_ssl_session_init(our_ssl_sessionid);
+
+    ret = mbedtls_ssl_get_session(&backend->ssl, our_ssl_sessionid);
+    if(ret) {
+      if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED)
+        mbedtls_ssl_session_free(our_ssl_sessionid);
+      free(our_ssl_sessionid);
+      failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+
+    /* If there's already a matching session in the cache, delete it */
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL))
+      Curl_ssl_delsessionid(data, old_ssl_sessionid);
+
+    retcode = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid,
+                                    0, &added);
+    Curl_ssl_sessionid_unlock(data);
+    if(!added) {
+      mbedtls_ssl_session_free(our_ssl_sessionid);
+      free(our_ssl_sessionid);
+    }
+    if(retcode) {
+      failf(data, "failed to store ssl session");
+      return retcode;
+    }
+  }
+
+  connssl->connecting_state = ssl_connect_done;
+
+  return CURLE_OK;
+}
+
+static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                         const void *mem, size_t len,
+                         CURLcode *curlcode)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct mbed_ssl_backend_data *backend =
+    (struct mbed_ssl_backend_data *)connssl->backend;
+  int ret = -1;
+
+  (void)data;
+  DEBUGASSERT(backend);
+  ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
+
+  if(ret < 0) {
+    *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ?
+      CURLE_AGAIN : CURLE_SEND_ERROR;
+    ret = -1;
+  }
+
+  return ret;
+}
+
+static void mbedtls_close_all(struct Curl_easy *data)
+{
+  (void)data;
+}
+
+static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct mbed_ssl_backend_data *backend =
+    (struct mbed_ssl_backend_data *)connssl->backend;
+  char buf[32];
+
+  (void)data;
+  DEBUGASSERT(backend);
+
+  /* Maybe the server has already sent a close notify alert.
+     Read it to avoid an RST on the TCP connection. */
+  (void)mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, sizeof(buf));
+
+  mbedtls_pk_free(&backend->pk);
+  mbedtls_x509_crt_free(&backend->clicert);
+  mbedtls_x509_crt_free(&backend->cacert);
+#ifdef MBEDTLS_X509_CRL_PARSE_C
+  mbedtls_x509_crl_free(&backend->crl);
+#endif
+  mbedtls_ssl_config_free(&backend->config);
+  mbedtls_ssl_free(&backend->ssl);
+  mbedtls_ctr_drbg_free(&backend->ctr_drbg);
+#ifndef THREADING_SUPPORT
+  mbedtls_entropy_free(&backend->entropy);
+#endif /* THREADING_SUPPORT */
+}
+
+static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                         char *buf, size_t buffersize,
+                         CURLcode *curlcode)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct mbed_ssl_backend_data *backend =
+    (struct mbed_ssl_backend_data *)connssl->backend;
+  int ret = -1;
+  ssize_t len = -1;
+
+  (void)data;
+  DEBUGASSERT(backend);
+
+  ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf,
+                         buffersize);
+
+  if(ret <= 0) {
+    if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
+      return 0;
+
+    *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ?
+      CURLE_AGAIN : CURLE_RECV_ERROR;
+    return -1;
+  }
+
+  len = ret;
+
+  return len;
+}
+
+static void mbedtls_session_free(void *ptr)
+{
+  mbedtls_ssl_session_free(ptr);
+  free(ptr);
+}
+
+static size_t mbedtls_version(char *buffer, size_t size)
+{
+#ifdef MBEDTLS_VERSION_C
+  /* if mbedtls_version_get_number() is available it is better */
+  unsigned int version = mbedtls_version_get_number();
+  return msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24,
+                   (version>>16)&0xff, (version>>8)&0xff);
+#else
+  return msnprintf(buffer, size, "mbedTLS/%s", MBEDTLS_VERSION_STRING);
+#endif
+}
+
+static CURLcode mbedtls_random(struct Curl_easy *data,
+                               unsigned char *entropy, size_t length)
+{
+#if defined(MBEDTLS_CTR_DRBG_C)
+  int ret = -1;
+  char errorbuf[128];
+  mbedtls_entropy_context ctr_entropy;
+  mbedtls_ctr_drbg_context ctr_drbg;
+  mbedtls_entropy_init(&ctr_entropy);
+  mbedtls_ctr_drbg_init(&ctr_drbg);
+
+  ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
+                              &ctr_entropy, NULL, 0);
+
+  if(ret) {
+    mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+    failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s",
+          -ret, errorbuf);
+  }
+  else {
+    ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length);
+
+    if(ret) {
+      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+      failf(data, "mbedtls_ctr_drbg_random returned (-0x%04X) %s",
+            -ret, errorbuf);
+    }
+  }
+
+  mbedtls_ctr_drbg_free(&ctr_drbg);
+  mbedtls_entropy_free(&ctr_entropy);
+
+  return ret == 0 ? CURLE_OK : CURLE_FAILED_INIT;
+#elif defined(MBEDTLS_HAVEGE_C)
+  mbedtls_havege_state hs;
+  mbedtls_havege_init(&hs);
+  mbedtls_havege_random(&hs, entropy, length);
+  mbedtls_havege_free(&hs);
+  return CURLE_OK;
+#else
+  return CURLE_NOT_BUILT_IN;
+#endif
+}
+
+static CURLcode
+mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
+                    bool nonblocking,
+                    bool *done)
+{
+  CURLcode retcode;
+  struct ssl_connect_data *connssl = cf->ctx;
+  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+  timediff_t timeout_ms;
+  int what;
+
+  /* check if the connection has already been established */
+  if(ssl_connection_complete == connssl->state) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  if(ssl_connect_1 == connssl->connecting_state) {
+    /* Find out how much more time we're allowed */
+    timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+    retcode = mbed_connect_step1(cf, data);
+    if(retcode)
+      return retcode;
+  }
+
+  while(ssl_connect_2 == connssl->connecting_state ||
+        ssl_connect_2_reading == connssl->connecting_state ||
+        ssl_connect_2_writing == connssl->connecting_state) {
+
+    /* check allowed time left */
+    timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    /* if ssl is expecting something, check if it's available. */
+    if(connssl->connecting_state == ssl_connect_2_reading
+       || connssl->connecting_state == ssl_connect_2_writing) {
+
+      curl_socket_t writefd = ssl_connect_2_writing ==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+      curl_socket_t readfd = ssl_connect_2_reading ==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+                               nonblocking ? 0 : timeout_ms);
+      if(what < 0) {
+        /* fatal error */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      else if(0 == what) {
+        if(nonblocking) {
+          *done = FALSE;
+          return CURLE_OK;
+        }
+        else {
+          /* timeout */
+          failf(data, "SSL connection timeout");
+          return CURLE_OPERATION_TIMEDOUT;
+        }
+      }
+      /* socket is readable or writable */
+    }
+
+    /* Run transaction, and return to the caller if it failed or if
+     * this connection is part of a multi handle and this loop would
+     * execute again. This permits the owner of a multi handle to
+     * abort a connection attempt before step2 has completed while
+     * ensuring that a client using select() or epoll() will always
+     * have a valid fdset to wait on.
+     */
+    retcode = mbed_connect_step2(cf, data);
+    if(retcode || (nonblocking &&
+                   (ssl_connect_2 == connssl->connecting_state ||
+                    ssl_connect_2_reading == connssl->connecting_state ||
+                    ssl_connect_2_writing == connssl->connecting_state)))
+      return retcode;
+
+  } /* repeat step2 until all transactions are done. */
+
+  if(ssl_connect_3 == connssl->connecting_state) {
+    retcode = mbed_connect_step3(cf, data);
+    if(retcode)
+      return retcode;
+  }
+
+  if(ssl_connect_done == connssl->connecting_state) {
+    connssl->state = ssl_connection_complete;
+    *done = TRUE;
+  }
+  else
+    *done = FALSE;
+
+  /* Reset our connect state machine */
+  connssl->connecting_state = ssl_connect_1;
+
+  return CURLE_OK;
+}
+
+static CURLcode mbedtls_connect_nonblocking(struct Curl_cfilter *cf,
+                                            struct Curl_easy *data,
+                                            bool *done)
+{
+  return mbed_connect_common(cf, data, TRUE, done);
+}
+
+
+static CURLcode mbedtls_connect(struct Curl_cfilter *cf,
+                                struct Curl_easy *data)
+{
+  CURLcode retcode;
+  bool done = FALSE;
+
+  retcode = mbed_connect_common(cf, data, FALSE, &done);
+  if(retcode)
+    return retcode;
+
+  DEBUGASSERT(done);
+
+  return CURLE_OK;
+}
+
+/*
+ * return 0 error initializing SSL
+ * return 1 SSL initialized successfully
+ */
+static int mbedtls_init(void)
+{
+  if(!Curl_mbedtlsthreadlock_thread_setup())
+    return 0;
+#ifdef THREADING_SUPPORT
+  entropy_init_mutex(&ts_entropy);
+#endif
+  return 1;
+}
+
+static void mbedtls_cleanup(void)
+{
+#ifdef THREADING_SUPPORT
+  entropy_cleanup_mutex(&ts_entropy);
+#endif
+  (void)Curl_mbedtlsthreadlock_thread_cleanup();
+}
+
+static bool mbedtls_data_pending(struct Curl_cfilter *cf,
+                                 const struct Curl_easy *data)
+{
+  struct ssl_connect_data *ctx = cf->ctx;
+  struct mbed_ssl_backend_data *backend;
+
+  (void)data;
+  DEBUGASSERT(ctx && ctx->backend);
+  backend = (struct mbed_ssl_backend_data *)ctx->backend;
+  return mbedtls_ssl_get_bytes_avail(&backend->ssl) != 0;
+}
+
+static CURLcode mbedtls_sha256sum(const unsigned char *input,
+                                  size_t inputlen,
+                                  unsigned char *sha256sum,
+                                  size_t sha256len UNUSED_PARAM)
+{
+  /* TODO: explain this for different mbedtls 2.x vs 3 version */
+  (void)sha256len;
+#if MBEDTLS_VERSION_NUMBER < 0x02070000
+  mbedtls_sha256(input, inputlen, sha256sum, 0);
+#else
+  /* returns 0 on success, otherwise failure */
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+  if(mbedtls_sha256(input, inputlen, sha256sum, 0) != 0)
+#else
+  if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0)
+#endif
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+#endif
+  return CURLE_OK;
+}
+
+static void *mbedtls_get_internals(struct ssl_connect_data *connssl,
+                                   CURLINFO info UNUSED_PARAM)
+{
+  struct mbed_ssl_backend_data *backend =
+    (struct mbed_ssl_backend_data *)connssl->backend;
+  (void)info;
+  DEBUGASSERT(backend);
+  return &backend->ssl;
+}
+
+const struct Curl_ssl Curl_ssl_mbedtls = {
+  { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */
+
+  SSLSUPP_CA_PATH |
+  SSLSUPP_CAINFO_BLOB |
+  SSLSUPP_PINNEDPUBKEY |
+  SSLSUPP_SSL_CTX |
+  SSLSUPP_HTTPS_PROXY,
+
+  sizeof(struct mbed_ssl_backend_data),
+
+  mbedtls_init,                     /* init */
+  mbedtls_cleanup,                  /* cleanup */
+  mbedtls_version,                  /* version */
+  Curl_none_check_cxn,              /* check_cxn */
+  Curl_none_shutdown,               /* shutdown */
+  mbedtls_data_pending,             /* data_pending */
+  mbedtls_random,                   /* random */
+  Curl_none_cert_status_request,    /* cert_status_request */
+  mbedtls_connect,                  /* connect */
+  mbedtls_connect_nonblocking,      /* connect_nonblocking */
+  Curl_ssl_adjust_pollset,          /* adjust_pollset */
+  mbedtls_get_internals,            /* get_internals */
+  mbedtls_close,                    /* close_one */
+  mbedtls_close_all,                /* close_all */
+  mbedtls_session_free,             /* session_free */
+  Curl_none_set_engine,             /* set_engine */
+  Curl_none_set_engine_default,     /* set_engine_default */
+  Curl_none_engines_list,           /* engines_list */
+  Curl_none_false_start,            /* false_start */
+  mbedtls_sha256sum,                /* sha256sum */
+  NULL,                             /* associate_connection */
+  NULL,                             /* disassociate_connection */
+  NULL,                             /* free_multi_ssl_backend_data */
+  mbed_recv,                        /* recv decrypted data */
+  mbed_send,                        /* send data to encrypt */
+};
+
+#endif /* USE_MBEDTLS */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/mbedtls.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/mbedtls.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/mbedtls.h	(revision 104083)
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_MBEDTLS_H
+#define HEADER_CURL_MBEDTLS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_MBEDTLS
+
+extern const struct Curl_ssl Curl_ssl_mbedtls;
+
+#endif /* USE_MBEDTLS */
+#endif /* HEADER_CURL_MBEDTLS_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/mbedtls_threadlock.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/mbedtls_threadlock.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/mbedtls_threadlock.c	(revision 104083)
@@ -0,0 +1,134 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(USE_MBEDTLS) &&                                     \
+  ((defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) ||   \
+    defined(_WIN32))
+
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+#  include <pthread.h>
+#  define MBEDTLS_MUTEX_T pthread_mutex_t
+#elif defined(_WIN32)
+#  define MBEDTLS_MUTEX_T HANDLE
+#endif
+
+#include "mbedtls_threadlock.h"
+#include "curl_printf.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* number of thread locks */
+#define NUMT                    2
+
+/* This array will store all of the mutexes available to Mbedtls. */
+static MBEDTLS_MUTEX_T *mutex_buf = NULL;
+
+int Curl_mbedtlsthreadlock_thread_setup(void)
+{
+  int i;
+
+  mutex_buf = calloc(1, NUMT * sizeof(MBEDTLS_MUTEX_T));
+  if(!mutex_buf)
+    return 0;     /* error, no number of threads defined */
+
+  for(i = 0;  i < NUMT;  i++) {
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+    if(pthread_mutex_init(&mutex_buf[i], NULL))
+      return 0; /* pthread_mutex_init failed */
+#elif defined(_WIN32)
+    mutex_buf[i] = CreateMutex(0, FALSE, 0);
+    if(mutex_buf[i] == 0)
+      return 0;  /* CreateMutex failed */
+#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
+  }
+
+  return 1; /* OK */
+}
+
+int Curl_mbedtlsthreadlock_thread_cleanup(void)
+{
+  int i;
+
+  if(!mutex_buf)
+    return 0; /* error, no threads locks defined */
+
+  for(i = 0; i < NUMT; i++) {
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+    if(pthread_mutex_destroy(&mutex_buf[i]))
+      return 0; /* pthread_mutex_destroy failed */
+#elif defined(_WIN32)
+    if(!CloseHandle(mutex_buf[i]))
+      return 0; /* CloseHandle failed */
+#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
+  }
+  free(mutex_buf);
+  mutex_buf = NULL;
+
+  return 1; /* OK */
+}
+
+int Curl_mbedtlsthreadlock_lock_function(int n)
+{
+  if(n < NUMT) {
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+    if(pthread_mutex_lock(&mutex_buf[n])) {
+      DEBUGF(fprintf(stderr,
+                     "Error: mbedtlsthreadlock_lock_function failed\n"));
+      return 0; /* pthread_mutex_lock failed */
+    }
+#elif defined(_WIN32)
+    if(WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED) {
+      DEBUGF(fprintf(stderr,
+                     "Error: mbedtlsthreadlock_lock_function failed\n"));
+      return 0; /* pthread_mutex_lock failed */
+    }
+#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
+  }
+  return 1; /* OK */
+}
+
+int Curl_mbedtlsthreadlock_unlock_function(int n)
+{
+  if(n < NUMT) {
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+    if(pthread_mutex_unlock(&mutex_buf[n])) {
+      DEBUGF(fprintf(stderr,
+                     "Error: mbedtlsthreadlock_unlock_function failed\n"));
+      return 0; /* pthread_mutex_unlock failed */
+    }
+#elif defined(_WIN32)
+    if(!ReleaseMutex(mutex_buf[n])) {
+      DEBUGF(fprintf(stderr,
+                     "Error: mbedtlsthreadlock_unlock_function failed\n"));
+      return 0; /* pthread_mutex_lock failed */
+    }
+#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
+  }
+  return 1; /* OK */
+}
+
+#endif /* USE_MBEDTLS */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/mbedtls_threadlock.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/mbedtls_threadlock.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/mbedtls_threadlock.h	(revision 104083)
@@ -0,0 +1,50 @@
+#ifndef HEADER_CURL_MBEDTLS_THREADLOCK_H
+#define HEADER_CURL_MBEDTLS_THREADLOCK_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_MBEDTLS
+
+#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
+    defined(_WIN32)
+
+int Curl_mbedtlsthreadlock_thread_setup(void);
+int Curl_mbedtlsthreadlock_thread_cleanup(void);
+int Curl_mbedtlsthreadlock_lock_function(int n);
+int Curl_mbedtlsthreadlock_unlock_function(int n);
+
+#else
+
+#define Curl_mbedtlsthreadlock_thread_setup() 1
+#define Curl_mbedtlsthreadlock_thread_cleanup() 1
+#define Curl_mbedtlsthreadlock_lock_function(x) 1
+#define Curl_mbedtlsthreadlock_unlock_function(x) 1
+
+#endif /* (USE_THREADS_POSIX && HAVE_PTHREAD_H) || _WIN32 */
+
+#endif /* USE_MBEDTLS */
+
+#endif /* HEADER_CURL_MBEDTLS_THREADLOCK_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/openssl.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/openssl.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/openssl.c	(revision 104083)
@@ -0,0 +1,4994 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ */
+
+#include "curl_setup.h"
+
+#if defined(USE_QUICHE) || defined(USE_OPENSSL)
+
+#include <limits.h>
+
+/* Wincrypt must be included before anything that could include OpenSSL. */
+#if defined(USE_WIN32_CRYPTO)
+#include <wincrypt.h>
+/* Undefine wincrypt conflicting symbols for BoringSSL. */
+#undef X509_NAME
+#undef X509_EXTENSIONS
+#undef PKCS7_ISSUER_AND_SERIAL
+#undef PKCS7_SIGNER_INFO
+#undef OCSP_REQUEST
+#undef OCSP_RESPONSE
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "formdata.h" /* for the boundary function */
+#include "url.h" /* for the ssl config check function */
+#include "inet_pton.h"
+#include "openssl.h"
+#include "connect.h"
+#include "slist.h"
+#include "select.h"
+#include "vtls.h"
+#include "vtls_int.h"
+#include "vauth/vauth.h"
+#include "keylog.h"
+#include "strcase.h"
+#include "hostcheck.h"
+#include "multiif.h"
+#include "strerror.h"
+#include "curl_printf.h"
+
+#include <openssl/ssl.h>
+#include <openssl/rand.h>
+#include <openssl/x509v3.h>
+#ifndef OPENSSL_NO_DSA
+#include <openssl/dsa.h>
+#endif
+#include <openssl/dh.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+#include <openssl/conf.h>
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
+#include <openssl/pkcs12.h>
+#include <openssl/tls1.h>
+#include <openssl/evp.h>
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
+#include <openssl/ocsp.h>
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090700fL) && /* 0.9.7 or later */     \
+  !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_UI_CONSOLE)
+#define USE_OPENSSL_ENGINE
+#include <openssl/engine.h>
+#endif
+
+#include "warnless.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+/* Uncomment the ALLOW_RENEG line to a real #define if you want to allow TLS
+   renegotiations when built with BoringSSL. Renegotiating is non-compliant
+   with HTTP/2 and "an extremely dangerous protocol feature". Beware.
+
+#define ALLOW_RENEG 1
+ */
+
+#ifndef OPENSSL_VERSION_NUMBER
+#error "OPENSSL_VERSION_NUMBER not defined"
+#endif
+
+#ifdef USE_OPENSSL_ENGINE
+#include <openssl/ui.h>
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+#define SSL_METHOD_QUAL const
+#else
+#define SSL_METHOD_QUAL
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
+#define HAVE_ERR_REMOVE_THREAD_STATE 1
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \
+    !(defined(LIBRESSL_VERSION_NUMBER) && \
+      LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER
+#define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */
+#define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */
+#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */
+#define CONST_EXTS const
+#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1
+
+/* funny typecast define due to difference in API */
+#ifdef LIBRESSL_VERSION_NUMBER
+#define ARG2_X509_signature_print (X509_ALGOR *)
+#else
+#define ARG2_X509_signature_print
+#endif
+
+#else
+/* For OpenSSL before 1.1.0 */
+#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x)
+#define X509_get0_notBefore(x) X509_get_notBefore(x)
+#define X509_get0_notAfter(x) X509_get_notAfter(x)
+#define CONST_EXTS /* nope */
+#ifndef LIBRESSL_VERSION_NUMBER
+#define OpenSSL_version_num() SSLeay()
+#endif
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \
+    !(defined(LIBRESSL_VERSION_NUMBER) && \
+      LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#define HAVE_X509_GET0_SIGNATURE 1
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) /* 1.0.2 or later */
+#define HAVE_SSL_GET_SHUTDOWN 1
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10002003L && \
+  OPENSSL_VERSION_NUMBER <= 0x10002FFFL && \
+  !defined(OPENSSL_NO_COMP)
+#define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1
+#endif
+
+#if (OPENSSL_VERSION_NUMBER < 0x0090808fL)
+/* not present in older OpenSSL */
+#define OPENSSL_load_builtin_modules(x)
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+#define HAVE_EVP_PKEY_GET_PARAMS 1
+#endif
+
+#ifdef HAVE_EVP_PKEY_GET_PARAMS
+#include <openssl/core_names.h>
+#define DECLARE_PKEY_PARAM_BIGNUM(name) BIGNUM *name = NULL
+#define FREE_PKEY_PARAM_BIGNUM(name) BN_clear_free(name)
+#else
+#define DECLARE_PKEY_PARAM_BIGNUM(name) const BIGNUM *name
+#define FREE_PKEY_PARAM_BIGNUM(name)
+#endif
+
+/*
+ * Whether SSL_CTX_set_keylog_callback is available.
+ * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287
+ * BoringSSL: supported since d28f59c27bac (committed 2015-11-19)
+ * LibreSSL: supported since 3.5.0 (released 2022-02-24)
+ */
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
+     !defined(LIBRESSL_VERSION_NUMBER)) || \
+    (defined(LIBRESSL_VERSION_NUMBER) && \
+     LIBRESSL_VERSION_NUMBER >= 0x3050000fL) || \
+    defined(OPENSSL_IS_BORINGSSL)
+#define HAVE_KEYLOG_CALLBACK
+#endif
+
+/* Whether SSL_CTX_set_ciphersuites is available.
+ * OpenSSL: supported since 1.1.1 (commit a53b5be6a05)
+ * BoringSSL: no
+ * LibreSSL: supported since 3.4.1 (released 2021-10-14)
+ */
+#if ((OPENSSL_VERSION_NUMBER >= 0x10101000L && \
+      !defined(LIBRESSL_VERSION_NUMBER)) || \
+     (defined(LIBRESSL_VERSION_NUMBER) && \
+      LIBRESSL_VERSION_NUMBER >= 0x3040100fL)) && \
+    !defined(OPENSSL_IS_BORINGSSL)
+  #define HAVE_SSL_CTX_SET_CIPHERSUITES
+  #if !defined(OPENSSL_IS_AWSLC)
+    #define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
+  #endif
+#endif
+
+/*
+ * Whether SSL_CTX_set1_curves_list is available.
+ * OpenSSL: supported since 1.0.2, see
+ *   https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html
+ * BoringSSL: supported since 5fd1807d95f7 (committed 2016-09-30)
+ * LibreSSL: since 2.5.3 (April 12, 2017)
+ */
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) ||  \
+  defined(OPENSSL_IS_BORINGSSL)
+#define HAVE_SSL_CTX_SET_EC_CURVES
+#endif
+
+#if defined(LIBRESSL_VERSION_NUMBER)
+#define OSSL_PACKAGE "LibreSSL"
+#elif defined(OPENSSL_IS_BORINGSSL)
+#define OSSL_PACKAGE "BoringSSL"
+#elif defined(OPENSSL_IS_AWSLC)
+#define OSSL_PACKAGE "AWS-LC"
+#else
+# if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
+#   define OSSL_PACKAGE "quictls"
+# else
+#   define OSSL_PACKAGE "OpenSSL"
+#endif
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+/* up2date versions of OpenSSL maintain reasonably secure defaults without
+ * breaking compatibility, so it is better not to override the defaults in curl
+ */
+#define DEFAULT_CIPHER_SELECTION NULL
+#else
+/* ... but it is not the case with old versions of OpenSSL */
+#define DEFAULT_CIPHER_SELECTION \
+  "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH"
+#endif
+
+#ifdef HAVE_OPENSSL_SRP
+/* the function exists */
+#ifdef USE_TLS_SRP
+/* the functionality is not disabled */
+#define USE_OPENSSL_SRP
+#endif
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+#define HAVE_RANDOM_INIT_BY_DEFAULT 1
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
+    !(defined(LIBRESSL_VERSION_NUMBER) && \
+      LIBRESSL_VERSION_NUMBER < 0x2070100fL) && \
+    !defined(OPENSSL_IS_BORINGSSL) && \
+    !defined(OPENSSL_IS_AWSLC)
+#define HAVE_OPENSSL_VERSION
+#endif
+
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+typedef uint32_t sslerr_t;
+#else
+typedef unsigned long sslerr_t;
+#endif
+
+/*
+ * Whether the OpenSSL version has the API needed to support sharing an
+ * X509_STORE between connections. The API is:
+ * * `X509_STORE_up_ref`       -- Introduced: OpenSSL 1.1.0.
+ */
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* OpenSSL >= 1.1.0 */
+#define HAVE_SSL_X509_STORE_SHARE
+#endif
+
+/* What API version do we use? */
+#if defined(LIBRESSL_VERSION_NUMBER)
+#define USE_PRE_1_1_API (LIBRESSL_VERSION_NUMBER < 0x2070000f)
+#else /* !LIBRESSL_VERSION_NUMBER */
+#define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#endif /* !LIBRESSL_VERSION_NUMBER */
+
+struct ossl_ssl_backend_data {
+  /* these ones requires specific SSL-types */
+  SSL_CTX* ctx;
+  SSL*     handle;
+  X509*    server_cert;
+  BIO_METHOD *bio_method;
+  CURLcode io_result;       /* result of last BIO cfilter operation */
+#ifndef HAVE_KEYLOG_CALLBACK
+  /* Set to true once a valid keylog entry has been created to avoid dupes. */
+  bool     keylog_done;
+#endif
+  bool x509_store_setup;            /* x509 store has been set up */
+};
+
+#if defined(HAVE_SSL_X509_STORE_SHARE)
+struct multi_ssl_backend_data {
+  char *CAfile;         /* CAfile path used to generate X509 store */
+  X509_STORE *store;    /* cached X509 store or NULL if none */
+  struct curltime time; /* when the cached store was created */
+};
+#endif /* HAVE_SSL_X509_STORE_SHARE */
+
+#define push_certinfo(_label, _num)             \
+do {                              \
+  long info_len = BIO_get_mem_data(mem, &ptr); \
+  Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \
+  if(1 != BIO_reset(mem))                                        \
+    break;                                                       \
+} while(0)
+
+static void pubkey_show(struct Curl_easy *data,
+                        BIO *mem,
+                        int num,
+                        const char *type,
+                        const char *name,
+                        const BIGNUM *bn)
+{
+  char *ptr;
+  char namebuf[32];
+
+  msnprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
+
+  if(bn)
+    BN_print(mem, bn);
+  push_certinfo(namebuf, num);
+}
+
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+#define print_pubkey_BN(_type, _name, _num)              \
+  pubkey_show(data, mem, _num, #_type, #_name, _name)
+
+#else
+#define print_pubkey_BN(_type, _name, _num)    \
+do {                              \
+  if(_type->_name) { \
+    pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \
+  } \
+} while(0)
+#endif
+
+static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)
+{
+  int i, ilen;
+
+  ilen = (int)len;
+  if(ilen < 0)
+    return 1; /* buffer too big */
+
+  i = i2t_ASN1_OBJECT(buf, ilen, a);
+
+  if(i >= ilen)
+    return 1; /* buffer too small */
+
+  return 0;
+}
+
+static void X509V3_ext(struct Curl_easy *data,
+                       int certnum,
+                       CONST_EXTS STACK_OF(X509_EXTENSION) *exts)
+{
+  int i;
+
+  if((int)sk_X509_EXTENSION_num(exts) <= 0)
+    /* no extensions, bail out */
+    return;
+
+  for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) {
+    ASN1_OBJECT *obj;
+    X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
+    BUF_MEM *biomem;
+    char namebuf[128];
+    BIO *bio_out = BIO_new(BIO_s_mem());
+
+    if(!bio_out)
+      return;
+
+    obj = X509_EXTENSION_get_object(ext);
+
+    asn1_object_dump(obj, namebuf, sizeof(namebuf));
+
+    if(!X509V3_EXT_print(bio_out, ext, 0, 0))
+      ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext));
+
+    BIO_get_mem_ptr(bio_out, &biomem);
+    Curl_ssl_push_certinfo_len(data, certnum, namebuf, biomem->data,
+                               biomem->length);
+    BIO_free(bio_out);
+  }
+}
+
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+typedef size_t numcert_t;
+#else
+typedef int numcert_t;
+#endif
+
+CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl)
+{
+  CURLcode result;
+  STACK_OF(X509) *sk;
+  int i;
+  numcert_t numcerts;
+  BIO *mem;
+
+  DEBUGASSERT(ssl);
+
+  sk = SSL_get_peer_cert_chain(ssl);
+  if(!sk) {
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  numcerts = sk_X509_num(sk);
+
+  result = Curl_ssl_init_certinfo(data, (int)numcerts);
+  if(result) {
+    return result;
+  }
+
+  mem = BIO_new(BIO_s_mem());
+  if(!mem) {
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  for(i = 0; i < (int)numcerts; i++) {
+    ASN1_INTEGER *num;
+    X509 *x = sk_X509_value(sk, i);
+    EVP_PKEY *pubkey = NULL;
+    int j;
+    char *ptr;
+    const ASN1_BIT_STRING *psig = NULL;
+
+    X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
+    push_certinfo("Subject", i);
+
+    X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE);
+    push_certinfo("Issuer", i);
+
+    BIO_printf(mem, "%lx", X509_get_version(x));
+    push_certinfo("Version", i);
+
+    num = X509_get_serialNumber(x);
+    if(num->type == V_ASN1_NEG_INTEGER)
+      BIO_puts(mem, "-");
+    for(j = 0; j < num->length; j++)
+      BIO_printf(mem, "%02x", num->data[j]);
+    push_certinfo("Serial Number", i);
+
+#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS)
+    {
+      const X509_ALGOR *sigalg = NULL;
+      X509_PUBKEY *xpubkey = NULL;
+      ASN1_OBJECT *pubkeyoid = NULL;
+
+      X509_get0_signature(&psig, &sigalg, x);
+      if(sigalg) {
+        const ASN1_OBJECT *sigalgoid = NULL;
+        X509_ALGOR_get0(&sigalgoid, NULL, NULL, sigalg);
+        i2a_ASN1_OBJECT(mem, sigalgoid);
+        push_certinfo("Signature Algorithm", i);
+      }
+
+      xpubkey = X509_get_X509_PUBKEY(x);
+      if(xpubkey) {
+        X509_PUBKEY_get0_param(&pubkeyoid, NULL, NULL, NULL, xpubkey);
+        if(pubkeyoid) {
+          i2a_ASN1_OBJECT(mem, pubkeyoid);
+          push_certinfo("Public Key Algorithm", i);
+        }
+      }
+
+      X509V3_ext(data, i, X509_get0_extensions(x));
+    }
+#else
+    {
+      /* before OpenSSL 1.0.2 */
+      X509_CINF *cinf = x->cert_info;
+
+      i2a_ASN1_OBJECT(mem, cinf->signature->algorithm);
+      push_certinfo("Signature Algorithm", i);
+
+      i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm);
+      push_certinfo("Public Key Algorithm", i);
+
+      X509V3_ext(data, i, cinf->extensions);
+
+      psig = x->signature;
+    }
+#endif
+
+    ASN1_TIME_print(mem, X509_get0_notBefore(x));
+    push_certinfo("Start date", i);
+
+    ASN1_TIME_print(mem, X509_get0_notAfter(x));
+    push_certinfo("Expire date", i);
+
+    pubkey = X509_get_pubkey(x);
+    if(!pubkey)
+      infof(data, "   Unable to load public key");
+    else {
+      int pktype;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+      pktype = EVP_PKEY_id(pubkey);
+#else
+      pktype = pubkey->type;
+#endif
+      switch(pktype) {
+      case EVP_PKEY_RSA:
+      {
+#ifndef HAVE_EVP_PKEY_GET_PARAMS
+        RSA *rsa;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+        rsa = EVP_PKEY_get0_RSA(pubkey);
+#else
+        rsa = pubkey->pkey.rsa;
+#endif /* HAVE_OPAQUE_EVP_PKEY */
+#endif /* !HAVE_EVP_PKEY_GET_PARAMS */
+
+        {
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+          DECLARE_PKEY_PARAM_BIGNUM(n);
+          DECLARE_PKEY_PARAM_BIGNUM(e);
+#ifdef HAVE_EVP_PKEY_GET_PARAMS
+          EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &n);
+          EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &e);
+#else
+          RSA_get0_key(rsa, &n, &e, NULL);
+#endif /* HAVE_EVP_PKEY_GET_PARAMS */
+          BIO_printf(mem, "%d", n ? BN_num_bits(n) : 0);
+#else
+          BIO_printf(mem, "%d", rsa->n ? BN_num_bits(rsa->n) : 0);
+#endif /* HAVE_OPAQUE_RSA_DSA_DH */
+          push_certinfo("RSA Public Key", i);
+          print_pubkey_BN(rsa, n, i);
+          print_pubkey_BN(rsa, e, i);
+          FREE_PKEY_PARAM_BIGNUM(n);
+          FREE_PKEY_PARAM_BIGNUM(e);
+        }
+
+        break;
+      }
+      case EVP_PKEY_DSA:
+      {
+#ifndef OPENSSL_NO_DSA
+#ifndef HAVE_EVP_PKEY_GET_PARAMS
+        DSA *dsa;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+        dsa = EVP_PKEY_get0_DSA(pubkey);
+#else
+        dsa = pubkey->pkey.dsa;
+#endif /* HAVE_OPAQUE_EVP_PKEY */
+#endif /* !HAVE_EVP_PKEY_GET_PARAMS */
+        {
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+          DECLARE_PKEY_PARAM_BIGNUM(p);
+          DECLARE_PKEY_PARAM_BIGNUM(q);
+          DECLARE_PKEY_PARAM_BIGNUM(g);
+          DECLARE_PKEY_PARAM_BIGNUM(pub_key);
+#ifdef HAVE_EVP_PKEY_GET_PARAMS
+          EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p);
+          EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q);
+          EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g);
+          EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key);
+#else
+          DSA_get0_pqg(dsa, &p, &q, &g);
+          DSA_get0_key(dsa, &pub_key, NULL);
+#endif /* HAVE_EVP_PKEY_GET_PARAMS */
+#endif /* HAVE_OPAQUE_RSA_DSA_DH */
+          print_pubkey_BN(dsa, p, i);
+          print_pubkey_BN(dsa, q, i);
+          print_pubkey_BN(dsa, g, i);
+          print_pubkey_BN(dsa, pub_key, i);
+          FREE_PKEY_PARAM_BIGNUM(p);
+          FREE_PKEY_PARAM_BIGNUM(q);
+          FREE_PKEY_PARAM_BIGNUM(g);
+          FREE_PKEY_PARAM_BIGNUM(pub_key);
+        }
+#endif /* !OPENSSL_NO_DSA */
+        break;
+      }
+      case EVP_PKEY_DH:
+      {
+#ifndef HAVE_EVP_PKEY_GET_PARAMS
+        DH *dh;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+        dh = EVP_PKEY_get0_DH(pubkey);
+#else
+        dh = pubkey->pkey.dh;
+#endif /* HAVE_OPAQUE_EVP_PKEY */
+#endif /* !HAVE_EVP_PKEY_GET_PARAMS */
+        {
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+          DECLARE_PKEY_PARAM_BIGNUM(p);
+          DECLARE_PKEY_PARAM_BIGNUM(q);
+          DECLARE_PKEY_PARAM_BIGNUM(g);
+          DECLARE_PKEY_PARAM_BIGNUM(pub_key);
+#ifdef HAVE_EVP_PKEY_GET_PARAMS
+          EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p);
+          EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q);
+          EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g);
+          EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key);
+#else
+          DH_get0_pqg(dh, &p, &q, &g);
+          DH_get0_key(dh, &pub_key, NULL);
+#endif /* HAVE_EVP_PKEY_GET_PARAMS */
+          print_pubkey_BN(dh, p, i);
+          print_pubkey_BN(dh, q, i);
+          print_pubkey_BN(dh, g, i);
+#else
+          print_pubkey_BN(dh, p, i);
+          print_pubkey_BN(dh, g, i);
+#endif /* HAVE_OPAQUE_RSA_DSA_DH */
+          print_pubkey_BN(dh, pub_key, i);
+          FREE_PKEY_PARAM_BIGNUM(p);
+          FREE_PKEY_PARAM_BIGNUM(q);
+          FREE_PKEY_PARAM_BIGNUM(g);
+          FREE_PKEY_PARAM_BIGNUM(pub_key);
+        }
+        break;
+      }
+      }
+      EVP_PKEY_free(pubkey);
+    }
+
+    if(psig) {
+      for(j = 0; j < psig->length; j++)
+        BIO_printf(mem, "%02x:", psig->data[j]);
+      push_certinfo("Signature", i);
+    }
+
+    PEM_write_bio_X509(mem, x);
+    push_certinfo("Cert", i);
+  }
+
+  BIO_free(mem);
+
+  return CURLE_OK;
+}
+
+#endif /* quiche or OpenSSL */
+
+#ifdef USE_OPENSSL
+
+#if USE_PRE_1_1_API
+#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL
+#define BIO_set_init(x,v)          ((x)->init=(v))
+#define BIO_get_data(x)            ((x)->ptr)
+#define BIO_set_data(x,v)          ((x)->ptr=(v))
+#endif
+#define BIO_get_shutdown(x)        ((x)->shutdown)
+#define BIO_set_shutdown(x,v)      ((x)->shutdown=(v))
+#endif /* USE_PRE_1_1_API */
+
+static int ossl_bio_cf_create(BIO *bio)
+{
+  BIO_set_shutdown(bio, 1);
+  BIO_set_init(bio, 1);
+#if USE_PRE_1_1_API
+  bio->num = -1;
+#endif
+  BIO_set_data(bio, NULL);
+  return 1;
+}
+
+static int ossl_bio_cf_destroy(BIO *bio)
+{
+  if(!bio)
+    return 0;
+  return 1;
+}
+
+static long ossl_bio_cf_ctrl(BIO *bio, int cmd, long num, void *ptr)
+{
+  struct Curl_cfilter *cf = BIO_get_data(bio);
+  long ret = 1;
+
+  (void)cf;
+  (void)ptr;
+  switch(cmd) {
+  case BIO_CTRL_GET_CLOSE:
+    ret = (long)BIO_get_shutdown(bio);
+    break;
+  case BIO_CTRL_SET_CLOSE:
+    BIO_set_shutdown(bio, (int)num);
+    break;
+  case BIO_CTRL_FLUSH:
+    /* we do no delayed writes, but if we ever would, this
+     * needs to trigger it. */
+    ret = 1;
+    break;
+  case BIO_CTRL_DUP:
+    ret = 1;
+    break;
+#ifdef BIO_CTRL_EOF
+  case BIO_CTRL_EOF:
+    /* EOF has been reached on input? */
+    return (!cf->next || !cf->next->connected);
+#endif
+  default:
+    ret = 0;
+    break;
+  }
+  return ret;
+}
+
+static int ossl_bio_cf_out_write(BIO *bio, const char *buf, int blen)
+{
+  struct Curl_cfilter *cf = BIO_get_data(bio);
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ossl_ssl_backend_data *backend =
+    (struct ossl_ssl_backend_data *)connssl->backend;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  ssize_t nwritten;
+  CURLcode result = CURLE_SEND_ERROR;
+
+  DEBUGASSERT(data);
+  nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+  CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, err=%d",
+              blen, (int)nwritten, result);
+  BIO_clear_retry_flags(bio);
+  backend->io_result = result;
+  if(nwritten < 0) {
+    if(CURLE_AGAIN == result)
+      BIO_set_retry_write(bio);
+  }
+  return (int)nwritten;
+}
+
+static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen)
+{
+  struct Curl_cfilter *cf = BIO_get_data(bio);
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ossl_ssl_backend_data *backend =
+    (struct ossl_ssl_backend_data *)connssl->backend;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  ssize_t nread;
+  CURLcode result = CURLE_RECV_ERROR;
+
+  DEBUGASSERT(data);
+  /* OpenSSL catches this case, so should we. */
+  if(!buf)
+    return 0;
+
+  nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+  CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, err=%d",
+              blen, (int)nread, result);
+  BIO_clear_retry_flags(bio);
+  backend->io_result = result;
+  if(nread < 0) {
+    if(CURLE_AGAIN == result)
+      BIO_set_retry_read(bio);
+  }
+  else if(nread == 0) {
+    connssl->peer_closed = TRUE;
+  }
+
+  /* Before returning server replies to the SSL instance, we need
+   * to have setup the x509 store or verification will fail. */
+  if(!backend->x509_store_setup) {
+    result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
+    if(result) {
+      backend->io_result = result;
+      return -1;
+    }
+    backend->x509_store_setup = TRUE;
+  }
+
+  return (int)nread;
+}
+
+#if USE_PRE_1_1_API
+
+static BIO_METHOD ossl_bio_cf_meth_1_0 = {
+  BIO_TYPE_MEM,
+  "OpenSSL CF BIO",
+  ossl_bio_cf_out_write,
+  ossl_bio_cf_in_read,
+  NULL,                    /* puts is never called */
+  NULL,                    /* gets is never called */
+  ossl_bio_cf_ctrl,
+  ossl_bio_cf_create,
+  ossl_bio_cf_destroy,
+  NULL
+};
+
+static BIO_METHOD *ossl_bio_cf_method_create(void)
+{
+  return &ossl_bio_cf_meth_1_0;
+}
+
+#define ossl_bio_cf_method_free(m) Curl_nop_stmt
+
+#else
+
+static BIO_METHOD *ossl_bio_cf_method_create(void)
+{
+  BIO_METHOD *m = BIO_meth_new(BIO_TYPE_MEM, "OpenSSL CF BIO");
+  if(m) {
+    BIO_meth_set_write(m, &ossl_bio_cf_out_write);
+    BIO_meth_set_read(m, &ossl_bio_cf_in_read);
+    BIO_meth_set_ctrl(m, &ossl_bio_cf_ctrl);
+    BIO_meth_set_create(m, &ossl_bio_cf_create);
+    BIO_meth_set_destroy(m, &ossl_bio_cf_destroy);
+  }
+  return m;
+}
+
+static void ossl_bio_cf_method_free(BIO_METHOD *m)
+{
+  if(m)
+    BIO_meth_free(m);
+}
+
+#endif
+
+
+/*
+ * Number of bytes to read from the random number seed file. This must be
+ * a finite value (because some entropy "files" like /dev/urandom have
+ * an infinite length), but must be large enough to provide enough
+ * entropy to properly seed OpenSSL's PRNG.
+ */
+#define RAND_LOAD_LENGTH 1024
+
+#ifdef HAVE_KEYLOG_CALLBACK
+static void ossl_keylog_callback(const SSL *ssl, const char *line)
+{
+  (void)ssl;
+
+  Curl_tls_keylog_write_line(line);
+}
+#else
+/*
+ * ossl_log_tls12_secret is called by libcurl to make the CLIENT_RANDOMs if the
+ * OpenSSL being used doesn't have native support for doing that.
+ */
+static void
+ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done)
+{
+  const SSL_SESSION *session = SSL_get_session(ssl);
+  unsigned char client_random[SSL3_RANDOM_SIZE];
+  unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
+  int master_key_length = 0;
+
+  if(!session || *keylog_done)
+    return;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L &&    \
+  !(defined(LIBRESSL_VERSION_NUMBER) &&         \
+    LIBRESSL_VERSION_NUMBER < 0x20700000L)
+  /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that
+   * we have a valid SSL context if we have a non-NULL session. */
+  SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE);
+  master_key_length = (int)
+    SSL_SESSION_get_master_key(session, master_key, SSL_MAX_MASTER_KEY_LENGTH);
+#else
+  if(ssl->s3 && session->master_key_length > 0) {
+    master_key_length = session->master_key_length;
+    memcpy(master_key, session->master_key, session->master_key_length);
+    memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE);
+  }
+#endif
+
+  /* The handshake has not progressed sufficiently yet, or this is a TLS 1.3
+   * session (when curl was built with older OpenSSL headers and running with
+   * newer OpenSSL runtime libraries). */
+  if(master_key_length <= 0)
+    return;
+
+  *keylog_done = true;
+  Curl_tls_keylog_write("CLIENT_RANDOM", client_random,
+                        master_key, master_key_length);
+}
+#endif /* !HAVE_KEYLOG_CALLBACK */
+
+static const char *SSL_ERROR_to_str(int err)
+{
+  switch(err) {
+  case SSL_ERROR_NONE:
+    return "SSL_ERROR_NONE";
+  case SSL_ERROR_SSL:
+    return "SSL_ERROR_SSL";
+  case SSL_ERROR_WANT_READ:
+    return "SSL_ERROR_WANT_READ";
+  case SSL_ERROR_WANT_WRITE:
+    return "SSL_ERROR_WANT_WRITE";
+  case SSL_ERROR_WANT_X509_LOOKUP:
+    return "SSL_ERROR_WANT_X509_LOOKUP";
+  case SSL_ERROR_SYSCALL:
+    return "SSL_ERROR_SYSCALL";
+  case SSL_ERROR_ZERO_RETURN:
+    return "SSL_ERROR_ZERO_RETURN";
+  case SSL_ERROR_WANT_CONNECT:
+    return "SSL_ERROR_WANT_CONNECT";
+  case SSL_ERROR_WANT_ACCEPT:
+    return "SSL_ERROR_WANT_ACCEPT";
+#if defined(SSL_ERROR_WANT_ASYNC)
+  case SSL_ERROR_WANT_ASYNC:
+    return "SSL_ERROR_WANT_ASYNC";
+#endif
+#if defined(SSL_ERROR_WANT_ASYNC_JOB)
+  case SSL_ERROR_WANT_ASYNC_JOB:
+    return "SSL_ERROR_WANT_ASYNC_JOB";
+#endif
+#if defined(SSL_ERROR_WANT_EARLY)
+  case SSL_ERROR_WANT_EARLY:
+    return "SSL_ERROR_WANT_EARLY";
+#endif
+  default:
+    return "SSL_ERROR unknown";
+  }
+}
+
+static size_t ossl_version(char *buffer, size_t size);
+
+/* Return error string for last OpenSSL error
+ */
+static char *ossl_strerror(unsigned long error, char *buf, size_t size)
+{
+  size_t len;
+  DEBUGASSERT(size);
+  *buf = '\0';
+
+  len = ossl_version(buf, size);
+  DEBUGASSERT(len < (size - 2));
+  if(len < (size - 2)) {
+    buf += len;
+    size -= (len + 2);
+    *buf++ = ':';
+    *buf++ = ' ';
+    *buf = '\0';
+  }
+
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+  ERR_error_string_n((uint32_t)error, buf, size);
+#else
+  ERR_error_string_n(error, buf, size);
+#endif
+
+  if(!*buf) {
+    const char *msg = error ? "Unknown error" : "No error";
+    if(strlen(msg) < size)
+      strcpy(buf, msg);
+  }
+
+  return buf;
+}
+
+static int passwd_callback(char *buf, int num, int encrypting,
+                           void *global_passwd)
+{
+  DEBUGASSERT(0 == encrypting);
+
+  if(!encrypting) {
+    int klen = curlx_uztosi(strlen((char *)global_passwd));
+    if(num > klen) {
+      memcpy(buf, global_passwd, klen + 1);
+      return klen;
+    }
+  }
+  return 0;
+}
+
+/*
+ * rand_enough() returns TRUE if we have seeded the random engine properly.
+ */
+static bool rand_enough(void)
+{
+  return (0 != RAND_status()) ? TRUE : FALSE;
+}
+
+static CURLcode ossl_seed(struct Curl_easy *data)
+{
+  /* This might get called before it has been added to a multi handle */
+  if(data->multi && data->multi->ssl_seeded)
+    return CURLE_OK;
+
+  if(rand_enough()) {
+    /* OpenSSL 1.1.0+ should return here */
+    if(data->multi)
+      data->multi->ssl_seeded = TRUE;
+    return CURLE_OK;
+  }
+#ifdef HAVE_RANDOM_INIT_BY_DEFAULT
+  /* with OpenSSL 1.1.0+, a failed RAND_status is a showstopper */
+  failf(data, "Insufficient randomness");
+  return CURLE_SSL_CONNECT_ERROR;
+#else
+
+#ifdef RANDOM_FILE
+  RAND_load_file(RANDOM_FILE, RAND_LOAD_LENGTH);
+  if(rand_enough())
+    return CURLE_OK;
+#endif
+
+  /* fallback to a custom seeding of the PRNG using a hash based on a current
+     time */
+  do {
+    unsigned char randb[64];
+    size_t len = sizeof(randb);
+    size_t i, i_max;
+    for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) {
+      struct curltime tv = Curl_now();
+      Curl_wait_ms(1);
+      tv.tv_sec *= i + 1;
+      tv.tv_usec *= (unsigned int)i + 2;
+      tv.tv_sec ^= ((Curl_now().tv_sec + Curl_now().tv_usec) *
+                    (i + 3)) << 8;
+      tv.tv_usec ^= (unsigned int) ((Curl_now().tv_sec +
+                                     Curl_now().tv_usec) *
+                                    (i + 4)) << 16;
+      memcpy(&randb[i * sizeof(struct curltime)], &tv,
+             sizeof(struct curltime));
+    }
+    RAND_add(randb, (int)len, (double)len/2);
+  } while(!rand_enough());
+
+  {
+    /* generates a default path for the random seed file */
+    char fname[256];
+    fname[0] = 0; /* blank it first */
+    RAND_file_name(fname, sizeof(fname));
+    if(fname[0]) {
+      /* we got a file name to try */
+      RAND_load_file(fname, RAND_LOAD_LENGTH);
+      if(rand_enough())
+        return CURLE_OK;
+    }
+  }
+
+  infof(data, "libcurl is now using a weak random seed");
+  return (rand_enough() ? CURLE_OK :
+          CURLE_SSL_CONNECT_ERROR /* confusing error code */);
+#endif
+}
+
+#ifndef SSL_FILETYPE_ENGINE
+#define SSL_FILETYPE_ENGINE 42
+#endif
+#ifndef SSL_FILETYPE_PKCS12
+#define SSL_FILETYPE_PKCS12 43
+#endif
+static int do_file_type(const char *type)
+{
+  if(!type || !type[0])
+    return SSL_FILETYPE_PEM;
+  if(strcasecompare(type, "PEM"))
+    return SSL_FILETYPE_PEM;
+  if(strcasecompare(type, "DER"))
+    return SSL_FILETYPE_ASN1;
+  if(strcasecompare(type, "ENG"))
+    return SSL_FILETYPE_ENGINE;
+  if(strcasecompare(type, "P12"))
+    return SSL_FILETYPE_PKCS12;
+  return -1;
+}
+
+#ifdef USE_OPENSSL_ENGINE
+/*
+ * Supply default password to the engine user interface conversation.
+ * The password is passed by OpenSSL engine from ENGINE_load_private_key()
+ * last argument to the ui and can be obtained by UI_get0_user_data(ui) here.
+ */
+static int ssl_ui_reader(UI *ui, UI_STRING *uis)
+{
+  const char *password;
+  switch(UI_get_string_type(uis)) {
+  case UIT_PROMPT:
+  case UIT_VERIFY:
+    password = (const char *)UI_get0_user_data(ui);
+    if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) {
+      UI_set_result(ui, uis, password);
+      return 1;
+    }
+    FALLTHROUGH();
+  default:
+    break;
+  }
+  return (UI_method_get_reader(UI_OpenSSL()))(ui, uis);
+}
+
+/*
+ * Suppress interactive request for a default password if available.
+ */
+static int ssl_ui_writer(UI *ui, UI_STRING *uis)
+{
+  switch(UI_get_string_type(uis)) {
+  case UIT_PROMPT:
+  case UIT_VERIFY:
+    if(UI_get0_user_data(ui) &&
+       (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) {
+      return 1;
+    }
+    FALLTHROUGH();
+  default:
+    break;
+  }
+  return (UI_method_get_writer(UI_OpenSSL()))(ui, uis);
+}
+
+/*
+ * Check if a given string is a PKCS#11 URI
+ */
+static bool is_pkcs11_uri(const char *string)
+{
+  return (string && strncasecompare(string, "pkcs11:", 7));
+}
+
+#endif
+
+static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine);
+
+static int
+SSL_CTX_use_certificate_blob(SSL_CTX *ctx, const struct curl_blob *blob,
+                             int type, const char *key_passwd)
+{
+  int ret = 0;
+  X509 *x = NULL;
+  /* the typecast of blob->len is fine since it is guaranteed to never be
+     larger than CURL_MAX_INPUT_LENGTH */
+  BIO *in = BIO_new_mem_buf(blob->data, (int)(blob->len));
+  if(!in)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(type == SSL_FILETYPE_ASN1) {
+    /* j = ERR_R_ASN1_LIB; */
+    x = d2i_X509_bio(in, NULL);
+  }
+  else if(type == SSL_FILETYPE_PEM) {
+    /* ERR_R_PEM_LIB; */
+    x = PEM_read_bio_X509(in, NULL,
+                          passwd_callback, (void *)key_passwd);
+  }
+  else {
+    ret = 0;
+    goto end;
+  }
+
+  if(!x) {
+    ret = 0;
+    goto end;
+  }
+
+  ret = SSL_CTX_use_certificate(ctx, x);
+end:
+  X509_free(x);
+  BIO_free(in);
+  return ret;
+}
+
+static int
+SSL_CTX_use_PrivateKey_blob(SSL_CTX *ctx, const struct curl_blob *blob,
+                            int type, const char *key_passwd)
+{
+  int ret = 0;
+  EVP_PKEY *pkey = NULL;
+  BIO *in = BIO_new_mem_buf(blob->data, (int)(blob->len));
+  if(!in)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(type == SSL_FILETYPE_PEM)
+    pkey = PEM_read_bio_PrivateKey(in, NULL, passwd_callback,
+                                   (void *)key_passwd);
+  else if(type == SSL_FILETYPE_ASN1)
+    pkey = d2i_PrivateKey_bio(in, NULL);
+  else {
+    ret = 0;
+    goto end;
+  }
+  if(!pkey) {
+    ret = 0;
+    goto end;
+  }
+  ret = SSL_CTX_use_PrivateKey(ctx, pkey);
+  EVP_PKEY_free(pkey);
+end:
+  BIO_free(in);
+  return ret;
+}
+
+static int
+SSL_CTX_use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob,
+                                   const char *key_passwd)
+{
+/* SSL_CTX_add1_chain_cert introduced in OpenSSL 1.0.2 */
+#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* OpenSSL 1.0.2 or later */ \
+  !(defined(LIBRESSL_VERSION_NUMBER) &&                                     \
+    (LIBRESSL_VERSION_NUMBER < 0x2090100fL)) /* LibreSSL 2.9.1 or later */
+  int ret = 0;
+  X509 *x = NULL;
+  void *passwd_callback_userdata = (void *)key_passwd;
+  BIO *in = BIO_new_mem_buf(blob->data, (int)(blob->len));
+  if(!in)
+    return CURLE_OUT_OF_MEMORY;
+
+  ERR_clear_error();
+
+  x = PEM_read_bio_X509_AUX(in, NULL,
+                            passwd_callback, (void *)key_passwd);
+
+  if(!x) {
+    ret = 0;
+    goto end;
+  }
+
+  ret = SSL_CTX_use_certificate(ctx, x);
+
+  if(ERR_peek_error() != 0)
+    ret = 0;
+
+  if(ret) {
+    X509 *ca;
+    sslerr_t err;
+
+    if(!SSL_CTX_clear_chain_certs(ctx)) {
+      ret = 0;
+      goto end;
+    }
+
+    while((ca = PEM_read_bio_X509(in, NULL, passwd_callback,
+                                  passwd_callback_userdata))
+          != NULL) {
+
+      if(!SSL_CTX_add0_chain_cert(ctx, ca)) {
+        X509_free(ca);
+        ret = 0;
+        goto end;
+      }
+    }
+
+    err = ERR_peek_last_error();
+    if((ERR_GET_LIB(err) == ERR_LIB_PEM) &&
+       (ERR_GET_REASON(err) == PEM_R_NO_START_LINE))
+      ERR_clear_error();
+    else
+      ret = 0;
+  }
+
+end:
+  X509_free(x);
+  BIO_free(in);
+  return ret;
+#else
+  (void)ctx; /* unused */
+  (void)blob; /* unused */
+  (void)key_passwd; /* unused */
+  return 0;
+#endif
+}
+
+static
+int cert_stuff(struct Curl_easy *data,
+               SSL_CTX* ctx,
+               char *cert_file,
+               const struct curl_blob *cert_blob,
+               const char *cert_type,
+               char *key_file,
+               const struct curl_blob *key_blob,
+               const char *key_type,
+               char *key_passwd)
+{
+  char error_buffer[256];
+  bool check_privkey = TRUE;
+
+  int file_type = do_file_type(cert_type);
+
+  if(cert_file || cert_blob || (file_type == SSL_FILETYPE_ENGINE)) {
+    SSL *ssl;
+    X509 *x509;
+    int cert_done = 0;
+    int cert_use_result;
+
+    if(key_passwd) {
+      /* set the password in the callback userdata */
+      SSL_CTX_set_default_passwd_cb_userdata(ctx, key_passwd);
+      /* Set passwd callback: */
+      SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
+    }
+
+
+    switch(file_type) {
+    case SSL_FILETYPE_PEM:
+      /* SSL_CTX_use_certificate_chain_file() only works on PEM files */
+      cert_use_result = cert_blob ?
+        SSL_CTX_use_certificate_chain_blob(ctx, cert_blob, key_passwd) :
+        SSL_CTX_use_certificate_chain_file(ctx, cert_file);
+      if(cert_use_result != 1) {
+        failf(data,
+              "could not load PEM client certificate from %s, " OSSL_PACKAGE
+              " error %s, "
+              "(no key found, wrong pass phrase, or wrong file format?)",
+              (cert_blob ? "CURLOPT_SSLCERT_BLOB" : cert_file),
+              ossl_strerror(ERR_get_error(), error_buffer,
+                            sizeof(error_buffer)) );
+        return 0;
+      }
+      break;
+
+    case SSL_FILETYPE_ASN1:
+      /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
+         we use the case above for PEM so this can only be performed with
+         ASN1 files. */
+
+      cert_use_result = cert_blob ?
+        SSL_CTX_use_certificate_blob(ctx, cert_blob,
+                                     file_type, key_passwd) :
+      SSL_CTX_use_certificate_file(ctx, cert_file, file_type);
+      if(cert_use_result != 1) {
+        failf(data,
+              "could not load ASN1 client certificate from %s, " OSSL_PACKAGE
+              " error %s, "
+              "(no key found, wrong pass phrase, or wrong file format?)",
+              (cert_blob ? "CURLOPT_SSLCERT_BLOB" : cert_file),
+              ossl_strerror(ERR_get_error(), error_buffer,
+                            sizeof(error_buffer)) );
+        return 0;
+      }
+      break;
+    case SSL_FILETYPE_ENGINE:
+#if defined(USE_OPENSSL_ENGINE) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME)
+    {
+      /* Implicitly use pkcs11 engine if none was provided and the
+       * cert_file is a PKCS#11 URI */
+      if(!data->state.engine) {
+        if(is_pkcs11_uri(cert_file)) {
+          if(ossl_set_engine(data, "pkcs11") != CURLE_OK) {
+            return 0;
+          }
+        }
+      }
+
+      if(data->state.engine) {
+        const char *cmd_name = "LOAD_CERT_CTRL";
+        struct {
+          const char *cert_id;
+          X509 *cert;
+        } params;
+
+        params.cert_id = cert_file;
+        params.cert = NULL;
+
+        /* Does the engine supports LOAD_CERT_CTRL ? */
+        if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
+                        0, (void *)cmd_name, NULL)) {
+          failf(data, "ssl engine does not support loading certificates");
+          return 0;
+        }
+
+        /* Load the certificate from the engine */
+        if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name,
+                            0, &params, NULL, 1)) {
+          failf(data, "ssl engine cannot load client cert with id"
+                " '%s' [%s]", cert_file,
+                ossl_strerror(ERR_get_error(), error_buffer,
+                              sizeof(error_buffer)));
+          return 0;
+        }
+
+        if(!params.cert) {
+          failf(data, "ssl engine didn't initialized the certificate "
+                "properly.");
+          return 0;
+        }
+
+        if(SSL_CTX_use_certificate(ctx, params.cert) != 1) {
+          failf(data, "unable to set client certificate [%s]",
+                ossl_strerror(ERR_get_error(), error_buffer,
+                              sizeof(error_buffer)));
+          return 0;
+        }
+        X509_free(params.cert); /* we don't need the handle any more... */
+      }
+      else {
+        failf(data, "crypto engine not set, can't load certificate");
+        return 0;
+      }
+    }
+    break;
+#else
+    failf(data, "file type ENG for certificate not implemented");
+    return 0;
+#endif
+
+    case SSL_FILETYPE_PKCS12:
+    {
+      BIO *cert_bio = NULL;
+      PKCS12 *p12 = NULL;
+      EVP_PKEY *pri;
+      STACK_OF(X509) *ca = NULL;
+      if(cert_blob) {
+        cert_bio = BIO_new_mem_buf(cert_blob->data, (int)(cert_blob->len));
+        if(!cert_bio) {
+          failf(data,
+                "BIO_new_mem_buf NULL, " OSSL_PACKAGE
+                " error %s",
+                ossl_strerror(ERR_get_error(), error_buffer,
+                              sizeof(error_buffer)) );
+          return 0;
+        }
+      }
+      else {
+        cert_bio = BIO_new(BIO_s_file());
+        if(!cert_bio) {
+          failf(data,
+                "BIO_new return NULL, " OSSL_PACKAGE
+                " error %s",
+                ossl_strerror(ERR_get_error(), error_buffer,
+                              sizeof(error_buffer)) );
+          return 0;
+        }
+
+        if(BIO_read_filename(cert_bio, cert_file) <= 0) {
+          failf(data, "could not open PKCS12 file '%s'", cert_file);
+          BIO_free(cert_bio);
+          return 0;
+        }
+      }
+
+      p12 = d2i_PKCS12_bio(cert_bio, NULL);
+      BIO_free(cert_bio);
+
+      if(!p12) {
+        failf(data, "error reading PKCS12 file '%s'",
+              cert_blob ? "(memory blob)" : cert_file);
+        return 0;
+      }
+
+      PKCS12_PBE_add();
+
+      if(!PKCS12_parse(p12, key_passwd, &pri, &x509,
+                       &ca)) {
+        failf(data,
+              "could not parse PKCS12 file, check password, " OSSL_PACKAGE
+              " error %s",
+              ossl_strerror(ERR_get_error(), error_buffer,
+                            sizeof(error_buffer)) );
+        PKCS12_free(p12);
+        return 0;
+      }
+
+      PKCS12_free(p12);
+
+      if(SSL_CTX_use_certificate(ctx, x509) != 1) {
+        failf(data,
+              "could not load PKCS12 client certificate, " OSSL_PACKAGE
+              " error %s",
+              ossl_strerror(ERR_get_error(), error_buffer,
+                            sizeof(error_buffer)) );
+        goto fail;
+      }
+
+      if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) {
+        failf(data, "unable to use private key from PKCS12 file '%s'",
+              cert_file);
+        goto fail;
+      }
+
+      if(!SSL_CTX_check_private_key (ctx)) {
+        failf(data, "private key from PKCS12 file '%s' "
+              "does not match certificate in same file", cert_file);
+        goto fail;
+      }
+      /* Set Certificate Verification chain */
+      if(ca) {
+        while(sk_X509_num(ca)) {
+          /*
+           * Note that sk_X509_pop() is used below to make sure the cert is
+           * removed from the stack properly before getting passed to
+           * SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously
+           * we used sk_X509_value() instead, but then we'd clean it in the
+           * subsequent sk_X509_pop_free() call.
+           */
+          X509 *x = sk_X509_pop(ca);
+          if(!SSL_CTX_add_client_CA(ctx, x)) {
+            X509_free(x);
+            failf(data, "cannot add certificate to client CA list");
+            goto fail;
+          }
+          if(!SSL_CTX_add_extra_chain_cert(ctx, x)) {
+            X509_free(x);
+            failf(data, "cannot add certificate to certificate chain");
+            goto fail;
+          }
+        }
+      }
+
+      cert_done = 1;
+fail:
+      EVP_PKEY_free(pri);
+      X509_free(x509);
+      sk_X509_pop_free(ca, X509_free);
+      if(!cert_done)
+        return 0; /* failure! */
+      break;
+    }
+    default:
+      failf(data, "not supported file type '%s' for certificate", cert_type);
+      return 0;
+    }
+
+    if((!key_file) && (!key_blob)) {
+      key_file = cert_file;
+      key_blob = cert_blob;
+    }
+    else
+      file_type = do_file_type(key_type);
+
+    switch(file_type) {
+    case SSL_FILETYPE_PEM:
+      if(cert_done)
+        break;
+      FALLTHROUGH();
+    case SSL_FILETYPE_ASN1:
+      cert_use_result = key_blob ?
+        SSL_CTX_use_PrivateKey_blob(ctx, key_blob, file_type, key_passwd) :
+      SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type);
+      if(cert_use_result != 1) {
+        failf(data, "unable to set private key file: '%s' type %s",
+              key_file?key_file:"(memory blob)", key_type?key_type:"PEM");
+        return 0;
+      }
+      break;
+    case SSL_FILETYPE_ENGINE:
+#ifdef USE_OPENSSL_ENGINE
+    {
+      EVP_PKEY *priv_key = NULL;
+
+      /* Implicitly use pkcs11 engine if none was provided and the
+       * key_file is a PKCS#11 URI */
+      if(!data->state.engine) {
+        if(is_pkcs11_uri(key_file)) {
+          if(ossl_set_engine(data, "pkcs11") != CURLE_OK) {
+            return 0;
+          }
+        }
+      }
+
+      if(data->state.engine) {
+        UI_METHOD *ui_method =
+          UI_create_method((char *)"curl user interface");
+        if(!ui_method) {
+          failf(data, "unable do create " OSSL_PACKAGE
+                " user-interface method");
+          return 0;
+        }
+        UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL()));
+        UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL()));
+        UI_method_set_reader(ui_method, ssl_ui_reader);
+        UI_method_set_writer(ui_method, ssl_ui_writer);
+        priv_key = ENGINE_load_private_key(data->state.engine, key_file,
+                                           ui_method,
+                                           key_passwd);
+        UI_destroy_method(ui_method);
+        if(!priv_key) {
+          failf(data, "failed to load private key from crypto engine");
+          return 0;
+        }
+        if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
+          failf(data, "unable to set private key");
+          EVP_PKEY_free(priv_key);
+          return 0;
+        }
+        EVP_PKEY_free(priv_key);  /* we don't need the handle any more... */
+      }
+      else {
+        failf(data, "crypto engine not set, can't load private key");
+        return 0;
+      }
+    }
+    break;
+#else
+    failf(data, "file type ENG for private key not supported");
+    return 0;
+#endif
+    case SSL_FILETYPE_PKCS12:
+      if(!cert_done) {
+        failf(data, "file type P12 for private key not supported");
+        return 0;
+      }
+      break;
+    default:
+      failf(data, "not supported file type for private key");
+      return 0;
+    }
+
+    ssl = SSL_new(ctx);
+    if(!ssl) {
+      failf(data, "unable to create an SSL structure");
+      return 0;
+    }
+
+    x509 = SSL_get_certificate(ssl);
+
+    /* This version was provided by Evan Jordan and is supposed to not
+       leak memory as the previous version: */
+    if(x509) {
+      EVP_PKEY *pktmp = X509_get_pubkey(x509);
+      EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl));
+      EVP_PKEY_free(pktmp);
+    }
+
+#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) &&       \
+  !defined(OPENSSL_NO_DEPRECATED_3_0)
+    {
+      /* If RSA is used, don't check the private key if its flags indicate
+       * it doesn't support it. */
+      EVP_PKEY *priv_key = SSL_get_privatekey(ssl);
+      int pktype;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+      pktype = EVP_PKEY_id(priv_key);
+#else
+      pktype = priv_key->type;
+#endif
+      if(pktype == EVP_PKEY_RSA) {
+        RSA *rsa = EVP_PKEY_get1_RSA(priv_key);
+        if(RSA_flags(rsa) & RSA_METHOD_FLAG_NO_CHECK)
+          check_privkey = FALSE;
+        RSA_free(rsa); /* Decrement reference count */
+      }
+    }
+#endif
+
+    SSL_free(ssl);
+
+    /* If we are using DSA, we can copy the parameters from
+     * the private key */
+
+    if(check_privkey == TRUE) {
+      /* Now we know that a key and cert have been set against
+       * the SSL context */
+      if(!SSL_CTX_check_private_key(ctx)) {
+        failf(data, "Private key does not match the certificate public key");
+        return 0;
+      }
+    }
+  }
+  return 1;
+}
+
+CURLcode Curl_ossl_set_client_cert(struct Curl_easy *data, SSL_CTX *ctx,
+                                   char *cert_file,
+                                   const struct curl_blob *cert_blob,
+                                   const char *cert_type, char *key_file,
+                                   const struct curl_blob *key_blob,
+                                   const char *key_type, char *key_passwd)
+{
+  int rv = cert_stuff(data, ctx, cert_file, cert_blob, cert_type, key_file,
+                      key_blob, key_type, key_passwd);
+  if(rv != 1) {
+    return CURLE_SSL_CERTPROBLEM;
+  }
+
+  return CURLE_OK;
+}
+
+/* returns non-zero on failure */
+static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
+{
+  BIO *bio_out = BIO_new(BIO_s_mem());
+  BUF_MEM *biomem;
+  int rc;
+
+  if(!bio_out)
+    return 1; /* alloc failed! */
+
+  rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
+  BIO_get_mem_ptr(bio_out, &biomem);
+
+  if((size_t)biomem->length < size)
+    size = biomem->length;
+  else
+    size--; /* don't overwrite the buffer end */
+
+  memcpy(buf, biomem->data, size);
+  buf[size] = 0;
+
+  BIO_free(bio_out);
+
+  return !rc;
+}
+
+/**
+ * Global SSL init
+ *
+ * @retval 0 error initializing SSL
+ * @retval 1 SSL initialized successfully
+ */
+static int ossl_init(void)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) &&  \
+  (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
+  const uint64_t flags =
+#ifdef OPENSSL_INIT_ENGINE_ALL_BUILTIN
+    /* not present in BoringSSL */
+    OPENSSL_INIT_ENGINE_ALL_BUILTIN |
+#endif
+#ifdef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG
+    OPENSSL_INIT_NO_LOAD_CONFIG |
+#else
+    OPENSSL_INIT_LOAD_CONFIG |
+#endif
+    0;
+  OPENSSL_init_ssl(flags, NULL);
+#else
+  OPENSSL_load_builtin_modules();
+
+#ifdef USE_OPENSSL_ENGINE
+  ENGINE_load_builtin_engines();
+#endif
+
+/* CONF_MFLAGS_DEFAULT_SECTION was introduced some time between 0.9.8b and
+   0.9.8e */
+#ifndef CONF_MFLAGS_DEFAULT_SECTION
+#define CONF_MFLAGS_DEFAULT_SECTION 0x0
+#endif
+
+#ifndef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG
+  CONF_modules_load_file(NULL, NULL,
+                         CONF_MFLAGS_DEFAULT_SECTION|
+                         CONF_MFLAGS_IGNORE_MISSING_FILE);
+#endif
+
+  /* Let's get nice error messages */
+  SSL_load_error_strings();
+
+  /* Init the global ciphers and digests */
+  if(!SSLeay_add_ssl_algorithms())
+    return 0;
+
+  OpenSSL_add_all_algorithms();
+#endif
+
+  Curl_tls_keylog_open();
+
+  return 1;
+}
+
+/* Global cleanup */
+static void ossl_cleanup(void)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) &&  \
+  (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
+  /* OpenSSL 1.1 deprecates all these cleanup functions and
+     turns them into no-ops in OpenSSL 1.0 compatibility mode */
+#else
+  /* Free ciphers and digests lists */
+  EVP_cleanup();
+
+#ifdef USE_OPENSSL_ENGINE
+  /* Free engine list */
+  ENGINE_cleanup();
+#endif
+
+  /* Free OpenSSL error strings */
+  ERR_free_strings();
+
+  /* Free thread local error state, destroying hash upon zero refcount */
+#ifdef HAVE_ERR_REMOVE_THREAD_STATE
+  ERR_remove_thread_state(NULL);
+#else
+  ERR_remove_state(0);
+#endif
+
+  /* Free all memory allocated by all configuration modules */
+  CONF_modules_free();
+
+#ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS
+  SSL_COMP_free_compression_methods();
+#endif
+#endif
+
+  Curl_tls_keylog_close();
+}
+
+/* Selects an OpenSSL crypto engine
+ */
+static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine)
+{
+#ifdef USE_OPENSSL_ENGINE
+  ENGINE *e;
+
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+  e = ENGINE_by_id(engine);
+#else
+  /* avoid memory leak */
+  for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
+    const char *e_id = ENGINE_get_id(e);
+    if(!strcmp(engine, e_id))
+      break;
+  }
+#endif
+
+  if(!e) {
+    failf(data, "SSL Engine '%s' not found", engine);
+    return CURLE_SSL_ENGINE_NOTFOUND;
+  }
+
+  if(data->state.engine) {
+    ENGINE_finish(data->state.engine);
+    ENGINE_free(data->state.engine);
+    data->state.engine = NULL;
+  }
+  if(!ENGINE_init(e)) {
+    char buf[256];
+
+    ENGINE_free(e);
+    failf(data, "Failed to initialise SSL Engine '%s': %s",
+          engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf)));
+    return CURLE_SSL_ENGINE_INITFAILED;
+  }
+  data->state.engine = e;
+  return CURLE_OK;
+#else
+  (void)engine;
+  failf(data, "SSL Engine not supported");
+  return CURLE_SSL_ENGINE_NOTFOUND;
+#endif
+}
+
+/* Sets engine as default for all SSL operations
+ */
+static CURLcode ossl_set_engine_default(struct Curl_easy *data)
+{
+#ifdef USE_OPENSSL_ENGINE
+  if(data->state.engine) {
+    if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) {
+      infof(data, "set default crypto engine '%s'",
+            ENGINE_get_id(data->state.engine));
+    }
+    else {
+      failf(data, "set default crypto engine '%s' failed",
+            ENGINE_get_id(data->state.engine));
+      return CURLE_SSL_ENGINE_SETFAILED;
+    }
+  }
+#else
+  (void) data;
+#endif
+  return CURLE_OK;
+}
+
+/* Return list of OpenSSL crypto engine names.
+ */
+static struct curl_slist *ossl_engines_list(struct Curl_easy *data)
+{
+  struct curl_slist *list = NULL;
+#ifdef USE_OPENSSL_ENGINE
+  struct curl_slist *beg;
+  ENGINE *e;
+
+  for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
+    beg = curl_slist_append(list, ENGINE_get_id(e));
+    if(!beg) {
+      curl_slist_free_all(list);
+      return NULL;
+    }
+    list = beg;
+  }
+#endif
+  (void) data;
+  return list;
+}
+
+static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ossl_ssl_backend_data *backend =
+    (struct ossl_ssl_backend_data *)connssl->backend;
+
+  (void)data;
+  DEBUGASSERT(backend);
+
+  if(backend->handle) {
+    /* Send the TLS shutdown if we are still connected *and* if
+     * the peer did not already close the connection. */
+    if(cf->next && cf->next->connected && !connssl->peer_closed) {
+      char buf[1024];
+      int nread, err;
+      long sslerr;
+
+      /* Maybe the server has already sent a close notify alert.
+         Read it to avoid an RST on the TCP connection. */
+      ERR_clear_error();
+      nread = SSL_read(backend->handle, buf, (int)sizeof(buf));
+      err = SSL_get_error(backend->handle, nread);
+      if(!nread && err == SSL_ERROR_ZERO_RETURN) {
+        CURLcode result;
+        ssize_t n;
+        size_t blen = sizeof(buf);
+        CURL_TRC_CF(data, cf, "peer has shutdown TLS");
+        /* SSL_read() will not longer touch the socket, let's receive
+         * directly from the next filter to see if the underlying
+         * connection has also been closed. */
+        n = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+        if(!n) {
+          connssl->peer_closed = TRUE;
+          CURL_TRC_CF(data, cf, "peer closed connection");
+        }
+      }
+      ERR_clear_error();
+      if(connssl->peer_closed) {
+        /* As the peer closed, we do not expect it to read anything more we
+         * may send. It may be harmful, leading to TCP RST and delaying
+         * a lingering close. Just leave. */
+        CURL_TRC_CF(data, cf, "not from sending TLS shutdown on "
+                    "connection closed by peer");
+      }
+      else if(SSL_shutdown(backend->handle) == 1) {
+        CURL_TRC_CF(data, cf, "SSL shutdown finished");
+      }
+      else {
+        nread = SSL_read(backend->handle, buf, (int)sizeof(buf));
+        err = SSL_get_error(backend->handle, nread);
+        switch(err) {
+        case SSL_ERROR_NONE: /* this is not an error */
+        case SSL_ERROR_ZERO_RETURN: /* no more data */
+          CURL_TRC_CF(data, cf, "SSL shutdown, EOF from server");
+          break;
+        case SSL_ERROR_WANT_READ:
+          /* SSL has send its notify and now wants to read the reply
+           * from the server. We are not really interested in that. */
+          CURL_TRC_CF(data, cf, "SSL shutdown sent");
+          break;
+        case SSL_ERROR_WANT_WRITE:
+          CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
+          break;
+        default:
+          sslerr = ERR_get_error();
+          CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s', errno %d",
+                      (sslerr ?
+                       ossl_strerror(sslerr, buf, sizeof(buf)) :
+                       SSL_ERROR_to_str(err)),
+                      SOCKERRNO);
+          break;
+        }
+      }
+
+      ERR_clear_error();
+      SSL_set_connect_state(backend->handle);
+    }
+
+    SSL_free(backend->handle);
+    backend->handle = NULL;
+  }
+  if(backend->ctx) {
+    SSL_CTX_free(backend->ctx);
+    backend->ctx = NULL;
+    backend->x509_store_setup = FALSE;
+  }
+  if(backend->bio_method) {
+    ossl_bio_cf_method_free(backend->bio_method);
+    backend->bio_method = NULL;
+  }
+}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+static int ossl_shutdown(struct Curl_cfilter *cf,
+                         struct Curl_easy *data)
+{
+  int retval = 0;
+  struct ssl_connect_data *connssl = cf->ctx;
+  char buf[256]; /* We will use this for the OpenSSL error buffer, so it has
+                    to be at least 256 bytes long. */
+  unsigned long sslerror;
+  int nread;
+  int buffsize;
+  int err;
+  bool done = FALSE;
+  struct ossl_ssl_backend_data *backend =
+    (struct ossl_ssl_backend_data *)connssl->backend;
+  int loop = 10;
+
+  DEBUGASSERT(backend);
+
+#ifndef CURL_DISABLE_FTP
+  /* This has only been tested on the proftpd server, and the mod_tls code
+     sends a close notify alert without waiting for a close notify alert in
+     response. Thus we wait for a close notify alert from the server, but
+     we do not send one. Let's hope other servers do the same... */
+
+  if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
+    (void)SSL_shutdown(backend->handle);
+#endif
+
+  if(backend->handle) {
+    buffsize = (int)sizeof(buf);
+    while(!done && loop--) {
+      int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
+                                 SSL_SHUTDOWN_TIMEOUT);
+      if(what > 0) {
+        ERR_clear_error();
+
+        /* Something to read, let's do it and hope that it is the close
+           notify alert from the server */
+        nread = SSL_read(backend->handle, buf, buffsize);
+        err = SSL_get_error(backend->handle, nread);
+
+        switch(err) {
+        case SSL_ERROR_NONE: /* this is not an error */
+        case SSL_ERROR_ZERO_RETURN: /* no more data */
+          /* This is the expected response. There was no data but only
+             the close notify alert */
+          done = TRUE;
+          break;
+        case SSL_ERROR_WANT_READ:
+          /* there's data pending, re-invoke SSL_read() */
+          infof(data, "SSL_ERROR_WANT_READ");
+          break;
+        case SSL_ERROR_WANT_WRITE:
+          /* SSL wants a write. Really odd. Let's bail out. */
+          infof(data, "SSL_ERROR_WANT_WRITE");
+          done = TRUE;
+          break;
+        default:
+          /* openssl/ssl.h says "look at error stack/return value/errno" */
+          sslerror = ERR_get_error();
+          failf(data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d",
+                (sslerror ?
+                 ossl_strerror(sslerror, buf, sizeof(buf)) :
+                 SSL_ERROR_to_str(err)),
+                SOCKERRNO);
+          done = TRUE;
+          break;
+        }
+      }
+      else if(0 == what) {
+        /* timeout */
+        failf(data, "SSL shutdown timeout");
+        done = TRUE;
+      }
+      else {
+        /* anything that gets here is fatally bad */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        retval = -1;
+        done = TRUE;
+      }
+    } /* while()-loop for the select() */
+
+    if(data->set.verbose) {
+#ifdef HAVE_SSL_GET_SHUTDOWN
+      switch(SSL_get_shutdown(backend->handle)) {
+      case SSL_SENT_SHUTDOWN:
+        infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN");
+        break;
+      case SSL_RECEIVED_SHUTDOWN:
+        infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN");
+        break;
+      case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
+        infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
+              "SSL_RECEIVED__SHUTDOWN");
+        break;
+      }
+#endif
+    }
+
+    SSL_free(backend->handle);
+    backend->handle = NULL;
+  }
+  return retval;
+}
+
+static void ossl_session_free(void *ptr)
+{
+  /* free the ID */
+  SSL_SESSION_free(ptr);
+}
+
+/*
+ * This function is called when the 'data' struct is going away. Close
+ * down everything and free all resources!
+ */
+static void ossl_close_all(struct Curl_easy *data)
+{
+#ifdef USE_OPENSSL_ENGINE
+  if(data->state.engine) {
+    ENGINE_finish(data->state.engine);
+    ENGINE_free(data->state.engine);
+    data->state.engine = NULL;
+  }
+#else
+  (void)data;
+#endif
+#if !defined(HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED) &&        \
+  defined(HAVE_ERR_REMOVE_THREAD_STATE)
+  /* OpenSSL 1.0.1 and 1.0.2 build an error queue that is stored per-thread
+     so we need to clean it here in case the thread will be killed. All OpenSSL
+     code should extract the error in association with the error so clearing
+     this queue here should be harmless at worst. */
+  ERR_remove_thread_state(NULL);
+#endif
+}
+
+/* ====================================================== */
+
+/*
+ * Match subjectAltName against the host name.
+ */
+static bool subj_alt_hostcheck(struct Curl_easy *data,
+                               const char *match_pattern,
+                               size_t matchlen,
+                               const char *hostname,
+                               size_t hostlen,
+                               const char *dispname)
+{
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)dispname;
+  (void)data;
+#endif
+  if(Curl_cert_hostcheck(match_pattern, matchlen, hostname, hostlen)) {
+    infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"",
+          dispname, match_pattern);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/* Quote from RFC2818 section 3.1 "Server Identity"
+
+   If a subjectAltName extension of type dNSName is present, that MUST
+   be used as the identity. Otherwise, the (most specific) Common Name
+   field in the Subject field of the certificate MUST be used. Although
+   the use of the Common Name is existing practice, it is deprecated and
+   Certification Authorities are encouraged to use the dNSName instead.
+
+   Matching is performed using the matching rules specified by
+   [RFC2459].  If more than one identity of a given type is present in
+   the certificate (e.g., more than one dNSName name, a match in any one
+   of the set is considered acceptable.) Names may contain the wildcard
+   character * which is considered to match any single domain name
+   component or component fragment. E.g., *.a.com matches foo.a.com but
+   not bar.foo.a.com. f*.com matches foo.com but not bar.com.
+
+   In some cases, the URI is specified as an IP address rather than a
+   hostname. In this case, the iPAddress subjectAltName must be present
+   in the certificate and must exactly match the IP in the URI.
+
+   This function is now used from ngtcp2 (QUIC) as well.
+*/
+CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
+                              struct ssl_peer *peer, X509 *server_cert)
+{
+  bool matched = FALSE;
+  int target; /* target type, GEN_DNS or GEN_IPADD */
+  size_t addrlen = 0;
+  STACK_OF(GENERAL_NAME) *altnames;
+#ifdef ENABLE_IPV6
+  struct in6_addr addr;
+#else
+  struct in_addr addr;
+#endif
+  CURLcode result = CURLE_OK;
+  bool dNSName = FALSE; /* if a dNSName field exists in the cert */
+  bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */
+  size_t hostlen;
+
+  (void)conn;
+  hostlen = strlen(peer->hostname);
+  switch(peer->type) {
+  case CURL_SSL_PEER_IPV4:
+    if(!Curl_inet_pton(AF_INET, peer->hostname, &addr))
+      return CURLE_PEER_FAILED_VERIFICATION;
+    target = GEN_IPADD;
+    addrlen = sizeof(struct in_addr);
+    break;
+#ifdef ENABLE_IPV6
+  case CURL_SSL_PEER_IPV6:
+    if(!Curl_inet_pton(AF_INET6, peer->hostname, &addr))
+      return CURLE_PEER_FAILED_VERIFICATION;
+    target = GEN_IPADD;
+    addrlen = sizeof(struct in6_addr);
+    break;
+#endif
+  case CURL_SSL_PEER_DNS:
+    target = GEN_DNS;
+    break;
+  default:
+    DEBUGASSERT(0);
+    failf(data, "unexpected ssl peer type: %d", peer->type);
+    return CURLE_PEER_FAILED_VERIFICATION;
+  }
+
+  /* get a "list" of alternative names */
+  altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);
+
+  if(altnames) {
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+    size_t numalts;
+    size_t i;
+#else
+    int numalts;
+    int i;
+#endif
+    bool dnsmatched = FALSE;
+    bool ipmatched = FALSE;
+
+    /* get amount of alternatives, RFC2459 claims there MUST be at least
+       one, but we don't depend on it... */
+    numalts = sk_GENERAL_NAME_num(altnames);
+
+    /* loop through all alternatives - until a dnsmatch */
+    for(i = 0; (i < numalts) && !dnsmatched; i++) {
+      /* get a handle to alternative name number i */
+      const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
+
+      if(check->type == GEN_DNS)
+        dNSName = TRUE;
+      else if(check->type == GEN_IPADD)
+        iPAddress = TRUE;
+
+      /* only check alternatives of the same type the target is */
+      if(check->type == target) {
+        /* get data and length */
+        const char *altptr = (char *)ASN1_STRING_get0_data(check->d.ia5);
+        size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
+
+        switch(target) {
+        case GEN_DNS: /* name/pattern comparison */
+          /* The OpenSSL man page explicitly says: "In general it cannot be
+             assumed that the data returned by ASN1_STRING_data() is null
+             terminated or does not contain embedded nulls." But also that
+             "The actual format of the data will depend on the actual string
+             type itself: for example for an IA5String the data will be ASCII"
+
+             It has been however verified that in 0.9.6 and 0.9.7, IA5String
+             is always null-terminated.
+          */
+          if((altlen == strlen(altptr)) &&
+             /* if this isn't true, there was an embedded zero in the name
+                string and we cannot match it. */
+             subj_alt_hostcheck(data, altptr, altlen,
+                                peer->hostname, hostlen,
+                                peer->dispname)) {
+            dnsmatched = TRUE;
+          }
+          break;
+
+        case GEN_IPADD: /* IP address comparison */
+          /* compare alternative IP address if the data chunk is the same size
+             our server IP address is */
+          if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) {
+            ipmatched = TRUE;
+            infof(data,
+                  " subjectAltName: host \"%s\" matched cert's IP address!",
+                  peer->dispname);
+          }
+          break;
+        }
+      }
+    }
+    GENERAL_NAMES_free(altnames);
+
+    if(dnsmatched || ipmatched)
+      matched = TRUE;
+  }
+
+  if(matched)
+    /* an alternative name matched */
+    ;
+  else if(dNSName || iPAddress) {
+    const char *tname = (peer->type == CURL_SSL_PEER_DNS) ? "host name" :
+                        (peer->type == CURL_SSL_PEER_IPV4) ?
+                        "ipv4 address" : "ipv6 address";
+    infof(data, " subjectAltName does not match %s %s", tname, peer->dispname);
+    failf(data, "SSL: no alternative certificate subject name matches "
+          "target %s '%s'", tname, peer->dispname);
+    result = CURLE_PEER_FAILED_VERIFICATION;
+  }
+  else {
+    /* we have to look to the last occurrence of a commonName in the
+       distinguished one to get the most significant one. */
+    int i = -1;
+    unsigned char *peer_CN = NULL;
+    int peerlen = 0;
+
+    /* The following is done because of a bug in 0.9.6b */
+    X509_NAME *name = X509_get_subject_name(server_cert);
+    if(name) {
+      int j;
+      while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0)
+        i = j;
+    }
+
+    /* we have the name entry and we will now convert this to a string
+       that we can use for comparison. Doing this we support BMPstring,
+       UTF8, etc. */
+
+    if(i >= 0) {
+      ASN1_STRING *tmp =
+        X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i));
+
+      /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
+         is already UTF-8 encoded. We check for this case and copy the raw
+         string manually to avoid the problem. This code can be made
+         conditional in the future when OpenSSL has been fixed. */
+      if(tmp) {
+        if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+          peerlen = ASN1_STRING_length(tmp);
+          if(peerlen >= 0) {
+            peer_CN = OPENSSL_malloc(peerlen + 1);
+            if(peer_CN) {
+              memcpy(peer_CN, ASN1_STRING_get0_data(tmp), peerlen);
+              peer_CN[peerlen] = '\0';
+            }
+            else
+              result = CURLE_OUT_OF_MEMORY;
+          }
+        }
+        else /* not a UTF8 name */
+          peerlen = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+
+        if(peer_CN && (curlx_uztosi(strlen((char *)peer_CN)) != peerlen)) {
+          /* there was a terminating zero before the end of string, this
+             cannot match and we return failure! */
+          failf(data, "SSL: illegal cert name field");
+          result = CURLE_PEER_FAILED_VERIFICATION;
+        }
+      }
+    }
+
+    if(result)
+      /* error already detected, pass through */
+      ;
+    else if(!peer_CN) {
+      failf(data,
+            "SSL: unable to obtain common name from peer certificate");
+      result = CURLE_PEER_FAILED_VERIFICATION;
+    }
+    else if(!Curl_cert_hostcheck((const char *)peer_CN,
+                                 peerlen, peer->hostname, hostlen)) {
+      failf(data, "SSL: certificate subject name '%s' does not match "
+            "target host name '%s'", peer_CN, peer->dispname);
+      result = CURLE_PEER_FAILED_VERIFICATION;
+    }
+    else {
+      infof(data, " common name: %s (matched)", peer_CN);
+    }
+    if(peer_CN)
+      OPENSSL_free(peer_CN);
+  }
+
+  return result;
+}
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+  !defined(OPENSSL_NO_OCSP)
+static CURLcode verifystatus(struct Curl_cfilter *cf,
+                             struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  int i, ocsp_status;
+#if defined(OPENSSL_IS_AWSLC)
+  const uint8_t *status;
+#else
+  unsigned char *status;
+#endif
+  const unsigned char *p;
+  CURLcode result = CURLE_OK;
+  OCSP_RESPONSE *rsp = NULL;
+  OCSP_BASICRESP *br = NULL;
+  X509_STORE     *st = NULL;
+  STACK_OF(X509) *ch = NULL;
+  struct ossl_ssl_backend_data *backend =
+    (struct ossl_ssl_backend_data *)connssl->backend;
+  X509 *cert;
+  OCSP_CERTID *id = NULL;
+  int cert_status, crl_reason;
+  ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
+  int ret;
+  long len;
+
+  DEBUGASSERT(backend);
+
+  len = SSL_get_tlsext_status_ocsp_resp(backend->handle, &status);
+
+  if(!status) {
+    failf(data, "No OCSP response received");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
+  p = status;
+  rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
+  if(!rsp) {
+    failf(data, "Invalid OCSP response");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
+
+  ocsp_status = OCSP_response_status(rsp);
+  if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+    failf(data, "Invalid OCSP response status: %s (%d)",
+          OCSP_response_status_str(ocsp_status), ocsp_status);
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
+
+  br = OCSP_response_get1_basic(rsp);
+  if(!br) {
+    failf(data, "Invalid OCSP response");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
+
+  ch = SSL_get_peer_cert_chain(backend->handle);
+  if(!ch) {
+    failf(data, "Could not get peer certificate chain");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
+  st = SSL_CTX_get_cert_store(backend->ctx);
+
+#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \
+     (defined(LIBRESSL_VERSION_NUMBER) &&                               \
+      LIBRESSL_VERSION_NUMBER <= 0x2040200fL))
+  /* The authorized responder cert in the OCSP response MUST be signed by the
+     peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert,
+     no problem, but if it's an intermediate cert OpenSSL has a bug where it
+     expects this issuer to be present in the chain embedded in the OCSP
+     response. So we add it if necessary. */
+
+  /* First make sure the peer cert chain includes both a peer and an issuer,
+     and the OCSP response contains a responder cert. */
+  if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) {
+    X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1);
+
+    /* Find issuer of responder cert and add it to the OCSP response chain */
+    for(i = 0; i < sk_X509_num(ch); i++) {
+      X509 *issuer = sk_X509_value(ch, i);
+      if(X509_check_issued(issuer, responder) == X509_V_OK) {
+        if(!OCSP_basic_add1_cert(br, issuer)) {
+          failf(data, "Could not add issuer cert to OCSP response");
+          result = CURLE_SSL_INVALIDCERTSTATUS;
+          goto end;
+        }
+      }
+    }
+  }
+#endif
+
+  if(OCSP_basic_verify(br, ch, st, 0) <= 0) {
+    failf(data, "OCSP response verification failed");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
+
+  /* Compute the certificate's ID */
+  cert = SSL_get1_peer_certificate(backend->handle);
+  if(!cert) {
+    failf(data, "Error getting peer certificate");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
+
+  for(i = 0; i < (int)sk_X509_num(ch); i++) {
+    X509 *issuer = sk_X509_value(ch, i);
+    if(X509_check_issued(issuer, cert) == X509_V_OK) {
+      id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
+      break;
+    }
+  }
+  X509_free(cert);
+
+  if(!id) {
+    failf(data, "Error computing OCSP ID");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
+
+  /* Find the single OCSP response corresponding to the certificate ID */
+  ret = OCSP_resp_find_status(br, id, &cert_status, &crl_reason, &rev,
+                              &thisupd, &nextupd);
+  OCSP_CERTID_free(id);
+  if(ret != 1) {
+    failf(data, "Could not find certificate ID in OCSP response");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
+
+  /* Validate the corresponding single OCSP response */
+  if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
+    failf(data, "OCSP response has expired");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
+
+  infof(data, "SSL certificate status: %s (%d)",
+        OCSP_cert_status_str(cert_status), cert_status);
+
+  switch(cert_status) {
+  case V_OCSP_CERTSTATUS_GOOD:
+    break;
+
+  case V_OCSP_CERTSTATUS_REVOKED:
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    failf(data, "SSL certificate revocation reason: %s (%d)",
+          OCSP_crl_reason_str(crl_reason), crl_reason);
+    goto end;
+
+  case V_OCSP_CERTSTATUS_UNKNOWN:
+  default:
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
+
+end:
+  if(br)
+    OCSP_BASICRESP_free(br);
+  OCSP_RESPONSE_free(rsp);
+
+  return result;
+}
+#endif
+
+#endif /* USE_OPENSSL */
+
+/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions
+   and thus this cannot be done there. */
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+
+static const char *ssl_msg_type(int ssl_ver, int msg)
+{
+#ifdef SSL2_VERSION_MAJOR
+  if(ssl_ver == SSL2_VERSION_MAJOR) {
+    switch(msg) {
+    case SSL2_MT_ERROR:
+      return "Error";
+    case SSL2_MT_CLIENT_HELLO:
+      return "Client hello";
+    case SSL2_MT_CLIENT_MASTER_KEY:
+      return "Client key";
+    case SSL2_MT_CLIENT_FINISHED:
+      return "Client finished";
+    case SSL2_MT_SERVER_HELLO:
+      return "Server hello";
+    case SSL2_MT_SERVER_VERIFY:
+      return "Server verify";
+    case SSL2_MT_SERVER_FINISHED:
+      return "Server finished";
+    case SSL2_MT_REQUEST_CERTIFICATE:
+      return "Request CERT";
+    case SSL2_MT_CLIENT_CERTIFICATE:
+      return "Client CERT";
+    }
+  }
+  else
+#endif
+  if(ssl_ver == SSL3_VERSION_MAJOR) {
+    switch(msg) {
+    case SSL3_MT_HELLO_REQUEST:
+      return "Hello request";
+    case SSL3_MT_CLIENT_HELLO:
+      return "Client hello";
+    case SSL3_MT_SERVER_HELLO:
+      return "Server hello";
+#ifdef SSL3_MT_NEWSESSION_TICKET
+    case SSL3_MT_NEWSESSION_TICKET:
+      return "Newsession Ticket";
+#endif
+    case SSL3_MT_CERTIFICATE:
+      return "Certificate";
+    case SSL3_MT_SERVER_KEY_EXCHANGE:
+      return "Server key exchange";
+    case SSL3_MT_CLIENT_KEY_EXCHANGE:
+      return "Client key exchange";
+    case SSL3_MT_CERTIFICATE_REQUEST:
+      return "Request CERT";
+    case SSL3_MT_SERVER_DONE:
+      return "Server finished";
+    case SSL3_MT_CERTIFICATE_VERIFY:
+      return "CERT verify";
+    case SSL3_MT_FINISHED:
+      return "Finished";
+#ifdef SSL3_MT_CERTIFICATE_STATUS
+    case SSL3_MT_CERTIFICATE_STATUS:
+      return "Certificate Status";
+#endif
+#ifdef SSL3_MT_ENCRYPTED_EXTENSIONS
+    case SSL3_MT_ENCRYPTED_EXTENSIONS:
+      return "Encrypted Extensions";
+#endif
+#ifdef SSL3_MT_SUPPLEMENTAL_DATA
+    case SSL3_MT_SUPPLEMENTAL_DATA:
+      return "Supplemental data";
+#endif
+#ifdef SSL3_MT_END_OF_EARLY_DATA
+    case SSL3_MT_END_OF_EARLY_DATA:
+      return "End of early data";
+#endif
+#ifdef SSL3_MT_KEY_UPDATE
+    case SSL3_MT_KEY_UPDATE:
+      return "Key update";
+#endif
+#ifdef SSL3_MT_NEXT_PROTO
+    case SSL3_MT_NEXT_PROTO:
+      return "Next protocol";
+#endif
+#ifdef SSL3_MT_MESSAGE_HASH
+    case SSL3_MT_MESSAGE_HASH:
+      return "Message hash";
+#endif
+    }
+  }
+  return "Unknown";
+}
+
+static const char *tls_rt_type(int type)
+{
+  switch(type) {
+#ifdef SSL3_RT_HEADER
+  case SSL3_RT_HEADER:
+    return "TLS header";
+#endif
+  case SSL3_RT_CHANGE_CIPHER_SPEC:
+    return "TLS change cipher";
+  case SSL3_RT_ALERT:
+    return "TLS alert";
+  case SSL3_RT_HANDSHAKE:
+    return "TLS handshake";
+  case SSL3_RT_APPLICATION_DATA:
+    return "TLS app data";
+  default:
+    return "TLS Unknown";
+  }
+}
+
+/*
+ * Our callback from the SSL/TLS layers.
+ */
+static void ossl_trace(int direction, int ssl_ver, int content_type,
+                       const void *buf, size_t len, SSL *ssl,
+                       void *userp)
+{
+  const char *verstr = "???";
+  struct Curl_cfilter *cf = userp;
+  struct Curl_easy *data = NULL;
+  char unknown[32];
+
+  if(!cf)
+    return;
+  data = CF_DATA_CURRENT(cf);
+  if(!data || !data->set.fdebug || (direction && direction != 1))
+    return;
+
+  switch(ssl_ver) {
+#ifdef SSL2_VERSION /* removed in recent versions */
+  case SSL2_VERSION:
+    verstr = "SSLv2";
+    break;
+#endif
+#ifdef SSL3_VERSION
+  case SSL3_VERSION:
+    verstr = "SSLv3";
+    break;
+#endif
+  case TLS1_VERSION:
+    verstr = "TLSv1.0";
+    break;
+#ifdef TLS1_1_VERSION
+  case TLS1_1_VERSION:
+    verstr = "TLSv1.1";
+    break;
+#endif
+#ifdef TLS1_2_VERSION
+  case TLS1_2_VERSION:
+    verstr = "TLSv1.2";
+    break;
+#endif
+#ifdef TLS1_3_VERSION
+  case TLS1_3_VERSION:
+    verstr = "TLSv1.3";
+    break;
+#endif
+  case 0:
+    break;
+  default:
+    msnprintf(unknown, sizeof(unknown), "(%x)", ssl_ver);
+    verstr = unknown;
+    break;
+  }
+
+  /* Log progress for interesting records only (like Handshake or Alert), skip
+   * all raw record headers (content_type == SSL3_RT_HEADER or ssl_ver == 0).
+   * For TLS 1.3, skip notification of the decrypted inner Content-Type.
+   */
+  if(ssl_ver
+#ifdef SSL3_RT_HEADER
+     && content_type != SSL3_RT_HEADER
+#endif
+#ifdef SSL3_RT_INNER_CONTENT_TYPE
+     && content_type != SSL3_RT_INNER_CONTENT_TYPE
+#endif
+    ) {
+    const char *msg_name, *tls_rt_name;
+    char ssl_buf[1024];
+    int msg_type, txt_len;
+
+    /* the info given when the version is zero is not that useful for us */
+
+    ssl_ver >>= 8; /* check the upper 8 bits only below */
+
+    /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
+     * always pass-up content-type as 0. But the interesting message-type
+     * is at 'buf[0]'.
+     */
+    if(ssl_ver == SSL3_VERSION_MAJOR && content_type)
+      tls_rt_name = tls_rt_type(content_type);
+    else
+      tls_rt_name = "";
+
+    if(content_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
+      msg_type = *(char *)buf;
+      msg_name = "Change cipher spec";
+    }
+    else if(content_type == SSL3_RT_ALERT) {
+      msg_type = (((char *)buf)[0] << 8) + ((char *)buf)[1];
+      msg_name = SSL_alert_desc_string_long(msg_type);
+    }
+    else {
+      msg_type = *(char *)buf;
+      msg_name = ssl_msg_type(ssl_ver, msg_type);
+    }
+
+    txt_len = msnprintf(ssl_buf, sizeof(ssl_buf),
+                        "%s (%s), %s, %s (%d):\n",
+                        verstr, direction?"OUT":"IN",
+                        tls_rt_name, msg_name, msg_type);
+    if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) {
+      Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len);
+    }
+  }
+
+  Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
+             CURLINFO_SSL_DATA_IN, (char *)buf, len);
+  (void) ssl;
+}
+#endif
+
+#ifdef USE_OPENSSL
+/* ====================================================== */
+
+/* Check for OpenSSL 1.0.2 which has ALPN support. */
+#undef HAS_ALPN
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L       \
+  && !defined(OPENSSL_NO_TLSEXT)
+#  define HAS_ALPN 1
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */
+static CURLcode
+ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx)
+{
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  /* first, TLS min version... */
+  long curl_ssl_version_min = conn_config->version;
+  long curl_ssl_version_max;
+
+  /* convert curl min SSL version option to OpenSSL constant */
+#if (defined(OPENSSL_IS_BORINGSSL)  || \
+     defined(OPENSSL_IS_AWSLC)      || \
+     defined(LIBRESSL_VERSION_NUMBER))
+  uint16_t ossl_ssl_version_min = 0;
+  uint16_t ossl_ssl_version_max = 0;
+#else
+  long ossl_ssl_version_min = 0;
+  long ossl_ssl_version_max = 0;
+#endif
+  switch(curl_ssl_version_min) {
+  case CURL_SSLVERSION_TLSv1: /* TLS 1.x */
+  case CURL_SSLVERSION_TLSv1_0:
+    ossl_ssl_version_min = TLS1_VERSION;
+    break;
+  case CURL_SSLVERSION_TLSv1_1:
+    ossl_ssl_version_min = TLS1_1_VERSION;
+    break;
+  case CURL_SSLVERSION_TLSv1_2:
+    ossl_ssl_version_min = TLS1_2_VERSION;
+    break;
+  case CURL_SSLVERSION_TLSv1_3:
+#ifdef TLS1_3_VERSION
+    ossl_ssl_version_min = TLS1_3_VERSION;
+    break;
+#else
+    return CURLE_NOT_BUILT_IN;
+#endif
+  }
+
+  /* CURL_SSLVERSION_DEFAULT means that no option was selected.
+     We don't want to pass 0 to SSL_CTX_set_min_proto_version as
+     it would enable all versions down to the lowest supported by
+     the library.
+     So we skip this, and stay with the library default
+  */
+  if(curl_ssl_version_min != CURL_SSLVERSION_DEFAULT) {
+    if(!SSL_CTX_set_min_proto_version(ctx, ossl_ssl_version_min)) {
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+
+  /* ... then, TLS max version */
+  curl_ssl_version_max = conn_config->version_max;
+
+  /* convert curl max SSL version option to OpenSSL constant */
+  switch(curl_ssl_version_max) {
+  case CURL_SSLVERSION_MAX_TLSv1_0:
+    ossl_ssl_version_max = TLS1_VERSION;
+    break;
+  case CURL_SSLVERSION_MAX_TLSv1_1:
+    ossl_ssl_version_max = TLS1_1_VERSION;
+    break;
+  case CURL_SSLVERSION_MAX_TLSv1_2:
+    ossl_ssl_version_max = TLS1_2_VERSION;
+    break;
+#ifdef TLS1_3_VERSION
+  case CURL_SSLVERSION_MAX_TLSv1_3:
+    ossl_ssl_version_max = TLS1_3_VERSION;
+    break;
+#endif
+  case CURL_SSLVERSION_MAX_NONE:  /* none selected */
+  case CURL_SSLVERSION_MAX_DEFAULT:  /* max selected */
+  default:
+    /* SSL_CTX_set_max_proto_version states that:
+       setting the maximum to 0 will enable
+       protocol versions up to the highest version
+       supported by the library */
+    ossl_ssl_version_max = 0;
+    break;
+  }
+
+  if(!SSL_CTX_set_max_proto_version(ctx, ossl_ssl_version_max)) {
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  return CURLE_OK;
+}
+#endif
+
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+typedef uint32_t ctx_option_t;
+#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
+typedef uint64_t ctx_option_t;
+#else
+typedef long ctx_option_t;
+#endif
+
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) /* 1.1.0 */
+static CURLcode
+ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
+                                       struct Curl_cfilter *cf,
+                                       struct Curl_easy *data)
+{
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  long ssl_version = conn_config->version;
+  long ssl_version_max = conn_config->version_max;
+
+  (void) data; /* In case it's unused. */
+
+  switch(ssl_version) {
+  case CURL_SSLVERSION_TLSv1_3:
+#ifdef TLS1_3_VERSION
+  {
+    struct ssl_connect_data *connssl = cf->ctx;
+    struct ossl_ssl_backend_data *backend =
+      (struct ossl_ssl_backend_data *)connssl->backend;
+    DEBUGASSERT(backend);
+    SSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION);
+    *ctx_options |= SSL_OP_NO_TLSv1_2;
+  }
+#else
+  (void)ctx_options;
+  failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
+  return CURLE_NOT_BUILT_IN;
+#endif
+  FALLTHROUGH();
+  case CURL_SSLVERSION_TLSv1_2:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+    *ctx_options |= SSL_OP_NO_TLSv1_1;
+#else
+    failf(data, OSSL_PACKAGE " was built without TLS 1.2 support");
+    return CURLE_NOT_BUILT_IN;
+#endif
+    FALLTHROUGH();
+  case CURL_SSLVERSION_TLSv1_1:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+    *ctx_options |= SSL_OP_NO_TLSv1;
+#else
+    failf(data, OSSL_PACKAGE " was built without TLS 1.1 support");
+    return CURLE_NOT_BUILT_IN;
+#endif
+    FALLTHROUGH();
+  case CURL_SSLVERSION_TLSv1_0:
+  case CURL_SSLVERSION_TLSv1:
+    break;
+  }
+
+  switch(ssl_version_max) {
+  case CURL_SSLVERSION_MAX_TLSv1_0:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+    *ctx_options |= SSL_OP_NO_TLSv1_1;
+#endif
+    FALLTHROUGH();
+  case CURL_SSLVERSION_MAX_TLSv1_1:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+    *ctx_options |= SSL_OP_NO_TLSv1_2;
+#endif
+    FALLTHROUGH();
+  case CURL_SSLVERSION_MAX_TLSv1_2:
+#ifdef TLS1_3_VERSION
+    *ctx_options |= SSL_OP_NO_TLSv1_3;
+#endif
+    break;
+  case CURL_SSLVERSION_MAX_TLSv1_3:
+#ifdef TLS1_3_VERSION
+    break;
+#else
+    failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
+    return CURLE_NOT_BUILT_IN;
+#endif
+  }
+  return CURLE_OK;
+}
+#endif
+
+/* The "new session" callback must return zero if the session can be removed
+ * or non-zero if the session has been put into the session cache.
+ */
+static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
+{
+  int res = 0;
+  struct Curl_easy *data;
+  struct Curl_cfilter *cf;
+  const struct ssl_config_data *config;
+  struct ssl_connect_data *connssl;
+  bool isproxy;
+
+  cf = (struct Curl_cfilter*) SSL_get_app_data(ssl);
+  connssl = cf? cf->ctx : NULL;
+  data = connssl? CF_DATA_CURRENT(cf) : NULL;
+  /* The sockindex has been stored as a pointer to an array element */
+  if(!cf || !data)
+    return 0;
+
+  isproxy = Curl_ssl_cf_is_proxy(cf);
+
+  config = Curl_ssl_cf_get_config(cf, data);
+  if(config->primary.sessionid) {
+    bool incache;
+    bool added = FALSE;
+    void *old_ssl_sessionid = NULL;
+
+    Curl_ssl_sessionid_lock(data);
+    if(isproxy)
+      incache = FALSE;
+    else
+      incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
+    if(incache) {
+      if(old_ssl_sessionid != ssl_sessionid) {
+        infof(data, "old SSL session ID is stale, removing");
+        Curl_ssl_delsessionid(data, old_ssl_sessionid);
+        incache = FALSE;
+      }
+    }
+
+    if(!incache) {
+      if(!Curl_ssl_addsessionid(cf, data, ssl_sessionid,
+                                0 /* unknown size */, &added)) {
+        if(added) {
+          /* the session has been put into the session cache */
+          res = 1;
+        }
+      }
+      else
+        failf(data, "failed to store ssl session");
+    }
+    Curl_ssl_sessionid_unlock(data);
+  }
+
+  return res;
+}
+
+static CURLcode load_cacert_from_memory(X509_STORE *store,
+                                        const struct curl_blob *ca_info_blob)
+{
+  /* these need to be freed at the end */
+  BIO *cbio = NULL;
+  STACK_OF(X509_INFO) *inf = NULL;
+
+  /* everything else is just a reference */
+  int i, count = 0;
+  X509_INFO *itmp = NULL;
+
+  if(ca_info_blob->len > (size_t)INT_MAX)
+    return CURLE_SSL_CACERT_BADFILE;
+
+  cbio = BIO_new_mem_buf(ca_info_blob->data, (int)ca_info_blob->len);
+  if(!cbio)
+    return CURLE_OUT_OF_MEMORY;
+
+  inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL);
+  if(!inf) {
+    BIO_free(cbio);
+    return CURLE_SSL_CACERT_BADFILE;
+  }
+
+  /* add each entry from PEM file to x509_store */
+  for(i = 0; i < (int)sk_X509_INFO_num(inf); ++i) {
+    itmp = sk_X509_INFO_value(inf, i);
+    if(itmp->x509) {
+      if(X509_STORE_add_cert(store, itmp->x509)) {
+        ++count;
+      }
+      else {
+        /* set count to 0 to return an error */
+        count = 0;
+        break;
+      }
+    }
+    if(itmp->crl) {
+      if(X509_STORE_add_crl(store, itmp->crl)) {
+        ++count;
+      }
+      else {
+        /* set count to 0 to return an error */
+        count = 0;
+        break;
+      }
+    }
+  }
+
+  sk_X509_INFO_pop_free(inf, X509_INFO_free);
+  BIO_free(cbio);
+
+  /* if we didn't end up importing anything, treat that as an error */
+  return (count > 0) ? CURLE_OK : CURLE_SSL_CACERT_BADFILE;
+}
+
+#if defined(USE_WIN32_CRYPTO)
+static CURLcode import_windows_cert_store(struct Curl_easy *data,
+                                          const char *name,
+                                          X509_STORE *store,
+                                          bool *imported)
+{
+  CURLcode result = CURLE_OK;
+  HCERTSTORE hStore;
+
+  *imported = false;
+
+  hStore = CertOpenSystemStoreA(0, name);
+  if(hStore) {
+    PCCERT_CONTEXT pContext = NULL;
+    /* The array of enhanced key usage OIDs will vary per certificate and
+       is declared outside of the loop so that rather than malloc/free each
+       iteration we can grow it with realloc, when necessary. */
+    CERT_ENHKEY_USAGE *enhkey_usage = NULL;
+    DWORD enhkey_usage_size = 0;
+
+    /* This loop makes a best effort to import all valid certificates from
+       the MS root store. If a certificate cannot be imported it is
+       skipped. 'result' is used to store only hard-fail conditions (such
+       as out of memory) that cause an early break. */
+    result = CURLE_OK;
+    for(;;) {
+      X509 *x509;
+      FILETIME now;
+      BYTE key_usage[2];
+      DWORD req_size;
+      const unsigned char *encoded_cert;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+      char cert_name[256];
+#endif
+
+      pContext = CertEnumCertificatesInStore(hStore, pContext);
+      if(!pContext)
+        break;
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+      if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
+                             NULL, cert_name, sizeof(cert_name))) {
+        strcpy(cert_name, "Unknown");
+      }
+      infof(data, "SSL: Checking cert \"%s\"", cert_name);
+#endif
+      encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
+      if(!encoded_cert)
+        continue;
+
+      GetSystemTimeAsFileTime(&now);
+      if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 ||
+         CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0)
+        continue;
+
+      /* If key usage exists check for signing attribute */
+      if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType,
+                                 pContext->pCertInfo,
+                                 key_usage, sizeof(key_usage))) {
+        if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE))
+          continue;
+      }
+      else if(GetLastError())
+        continue;
+
+      /* If enhanced key usage exists check for server auth attribute.
+       *
+       * Note "In a Microsoft environment, a certificate might also have
+       * EKU extended properties that specify valid uses for the
+       * certificate."  The call below checks both, and behavior varies
+       * depending on what is found. For more details see
+       * CertGetEnhancedKeyUsage doc.
+       */
+      if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) {
+        if(req_size && req_size > enhkey_usage_size) {
+          void *tmp = realloc(enhkey_usage, req_size);
+
+          if(!tmp) {
+            failf(data, "SSL: Out of memory allocating for OID list");
+            result = CURLE_OUT_OF_MEMORY;
+            break;
+          }
+
+          enhkey_usage = (CERT_ENHKEY_USAGE *)tmp;
+          enhkey_usage_size = req_size;
+        }
+
+        if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) {
+          if(!enhkey_usage->cUsageIdentifier) {
+            /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate
+               is good for all uses. If it returns zero, the certificate
+               has no valid uses." */
+            if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND)
+              continue;
+          }
+          else {
+            DWORD i;
+            bool found = false;
+
+            for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) {
+              if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */,
+                         enhkey_usage->rgpszUsageIdentifier[i])) {
+                found = true;
+                break;
+              }
+            }
+
+            if(!found)
+              continue;
+          }
+        }
+        else
+          continue;
+      }
+      else
+        continue;
+
+      x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
+      if(!x509)
+        continue;
+
+      /* Try to import the certificate. This may fail for legitimate
+         reasons such as duplicate certificate, which is allowed by MS but
+         not OpenSSL. */
+      if(X509_STORE_add_cert(store, x509) == 1) {
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+        infof(data, "SSL: Imported cert \"%s\"", cert_name);
+#endif
+        *imported = true;
+      }
+      X509_free(x509);
+    }
+
+    free(enhkey_usage);
+    CertFreeCertificateContext(pContext);
+    CertCloseStore(hStore, 0);
+
+    if(result)
+      return result;
+  }
+
+  return result;
+}
+#endif
+
+static CURLcode populate_x509_store(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    X509_STORE *store)
+{
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  CURLcode result = CURLE_OK;
+  X509_LOOKUP *lookup = NULL;
+  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+  const char * const ssl_cafile =
+    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+    (ca_info_blob ? NULL : conn_config->CAfile);
+  const char * const ssl_capath = conn_config->CApath;
+  const char * const ssl_crlfile = ssl_config->primary.CRLfile;
+  const bool verifypeer = conn_config->verifypeer;
+  bool imported_native_ca = false;
+  bool imported_ca_info_blob = false;
+
+  CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
+              ssl_cafile? ssl_cafile : "none", !!ca_info_blob);
+  if(!store)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(verifypeer) {
+#if defined(USE_WIN32_CRYPTO)
+    /* Import certificates from the Windows root certificate store if
+       requested.
+       https://stackoverflow.com/questions/9507184/
+       https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037
+       https://datatracker.ietf.org/doc/html/rfc5280 */
+    if(ssl_config->native_ca_store) {
+      const char *storeNames[] = {
+        "ROOT",   /* Trusted Root Certification Authorities */
+        "CA"      /* Intermediate Certification Authorities */
+      };
+      size_t i;
+      for(i = 0; i < ARRAYSIZE(storeNames); ++i) {
+        bool imported = false;
+        result = import_windows_cert_store(data, storeNames[i], store,
+                                           &imported);
+        if(result)
+          return result;
+        if(imported) {
+          infof(data, "successfully imported Windows %s store", storeNames[i]);
+          imported_native_ca = true;
+        }
+        else
+          infof(data, "error importing Windows %s store, continuing anyway",
+                storeNames[i]);
+      }
+    }
+#endif
+    if(ca_info_blob) {
+      result = load_cacert_from_memory(store, ca_info_blob);
+      if(result) {
+        failf(data, "error importing CA certificate blob");
+        return result;
+      }
+      else {
+        imported_ca_info_blob = true;
+        infof(data, "successfully imported CA certificate blob");
+      }
+    }
+
+    if(ssl_cafile || ssl_capath) {
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+      /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
+      if(ssl_cafile && !X509_STORE_load_file(store, ssl_cafile)) {
+        if(!imported_native_ca && !imported_ca_info_blob) {
+          /* Fail if we insist on successfully verifying the server. */
+          failf(data, "error setting certificate file: %s", ssl_cafile);
+          return CURLE_SSL_CACERT_BADFILE;
+        }
+        else
+          infof(data, "error setting certificate file, continuing anyway");
+      }
+      if(ssl_capath && !X509_STORE_load_path(store, ssl_capath)) {
+        if(!imported_native_ca && !imported_ca_info_blob) {
+          /* Fail if we insist on successfully verifying the server. */
+          failf(data, "error setting certificate path: %s", ssl_capath);
+          return CURLE_SSL_CACERT_BADFILE;
+        }
+        else
+          infof(data, "error setting certificate path, continuing anyway");
+      }
+#else
+      /* tell OpenSSL where to find CA certificates that are used to verify the
+         server's certificate. */
+      if(!X509_STORE_load_locations(store, ssl_cafile, ssl_capath)) {
+        if(!imported_native_ca && !imported_ca_info_blob) {
+          /* Fail if we insist on successfully verifying the server. */
+          failf(data, "error setting certificate verify locations:"
+                "  CAfile: %s CApath: %s",
+                ssl_cafile ? ssl_cafile : "none",
+                ssl_capath ? ssl_capath : "none");
+          return CURLE_SSL_CACERT_BADFILE;
+        }
+        else {
+          infof(data, "error setting certificate verify locations,"
+                " continuing anyway");
+        }
+      }
+#endif
+      infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
+      infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
+    }
+
+#ifdef CURL_CA_FALLBACK
+    if(!ssl_cafile && !ssl_capath &&
+       !imported_native_ca && !imported_ca_info_blob) {
+      /* verifying the peer without any CA certificates won't
+         work so use openssl's built-in default as fallback */
+      X509_STORE_set_default_paths(store);
+    }
+#endif
+  }
+
+  if(ssl_crlfile) {
+    /* tell OpenSSL where to find CRL file that is used to check certificate
+     * revocation */
+    lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
+    if(!lookup ||
+       (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) {
+      failf(data, "error loading CRL file: %s", ssl_crlfile);
+      return CURLE_SSL_CRL_BADFILE;
+    }
+    /* Everything is fine. */
+    infof(data, "successfully loaded CRL file:");
+    X509_STORE_set_flags(store,
+                         X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+
+    infof(data, "  CRLfile: %s", ssl_crlfile);
+  }
+
+  if(verifypeer) {
+    /* Try building a chain using issuers in the trusted store first to avoid
+       problems with server-sent legacy intermediates.  Newer versions of
+       OpenSSL do alternate chain checking by default but we do not know how to
+       determine that in a reliable manner.
+       https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
+    */
+#if defined(X509_V_FLAG_TRUSTED_FIRST)
+    X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST);
+#endif
+#ifdef X509_V_FLAG_PARTIAL_CHAIN
+    if(!ssl_config->no_partialchain && !ssl_crlfile) {
+      /* Have intermediate certificates in the trust store be treated as
+         trust-anchors, in the same way as self-signed root CA certificates
+         are. This allows users to verify servers using the intermediate cert
+         only, instead of needing the whole chain.
+
+         Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we
+         cannot do partial chains with a CRL check.
+      */
+      X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN);
+    }
+#endif
+  }
+
+  return result;
+}
+
+#if defined(HAVE_SSL_X509_STORE_SHARE)
+static bool cached_x509_store_expired(const struct Curl_easy *data,
+                                      const struct multi_ssl_backend_data *mb)
+{
+  const struct ssl_general_config *cfg = &data->set.general_ssl;
+  struct curltime now = Curl_now();
+  timediff_t elapsed_ms = Curl_timediff(now, mb->time);
+  timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
+
+  if(timeout_ms < 0)
+    return false;
+
+  return elapsed_ms >= timeout_ms;
+}
+
+static bool cached_x509_store_different(
+  struct Curl_cfilter *cf,
+  const struct multi_ssl_backend_data *mb)
+{
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  if(!mb->CAfile || !conn_config->CAfile)
+    return mb->CAfile != conn_config->CAfile;
+
+  return strcmp(mb->CAfile, conn_config->CAfile);
+}
+
+static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
+                                         const struct Curl_easy *data)
+{
+  struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+  X509_STORE *store = NULL;
+
+  DEBUGASSERT(multi);
+  if(multi &&
+     multi->ssl_backend_data &&
+     multi->ssl_backend_data->store &&
+     !cached_x509_store_expired(data, multi->ssl_backend_data) &&
+     !cached_x509_store_different(cf, multi->ssl_backend_data)) {
+    store = multi->ssl_backend_data->store;
+  }
+
+  return store;
+}
+
+static void set_cached_x509_store(struct Curl_cfilter *cf,
+                                  const struct Curl_easy *data,
+                                  X509_STORE *store)
+{
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+  struct multi_ssl_backend_data *mbackend;
+
+  DEBUGASSERT(multi);
+  if(!multi)
+    return;
+
+  if(!multi->ssl_backend_data) {
+    multi->ssl_backend_data = calloc(1, sizeof(struct multi_ssl_backend_data));
+    if(!multi->ssl_backend_data)
+      return;
+  }
+
+  mbackend = multi->ssl_backend_data;
+
+  if(X509_STORE_up_ref(store)) {
+    char *CAfile = NULL;
+
+    if(conn_config->CAfile) {
+      CAfile = strdup(conn_config->CAfile);
+      if(!CAfile) {
+        X509_STORE_free(store);
+        return;
+      }
+    }
+
+    if(mbackend->store) {
+      X509_STORE_free(mbackend->store);
+      free(mbackend->CAfile);
+    }
+
+    mbackend->time = Curl_now();
+    mbackend->store = store;
+    mbackend->CAfile = CAfile;
+  }
+}
+
+CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   SSL_CTX *ssl_ctx)
+{
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  CURLcode result = CURLE_OK;
+  X509_STORE *cached_store;
+  bool cache_criteria_met;
+
+  /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
+     or no source is provided and we are falling back to openssl's built-in
+     default. */
+  cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
+    conn_config->verifypeer &&
+    !conn_config->CApath &&
+    !conn_config->ca_info_blob &&
+    !ssl_config->primary.CRLfile &&
+    !ssl_config->native_ca_store;
+
+  cached_store = get_cached_x509_store(cf, data);
+  if(cached_store && cache_criteria_met && X509_STORE_up_ref(cached_store)) {
+    SSL_CTX_set_cert_store(ssl_ctx, cached_store);
+  }
+  else {
+    X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
+
+    result = populate_x509_store(cf, data, store);
+    if(result == CURLE_OK && cache_criteria_met) {
+      set_cached_x509_store(cf, data, store);
+    }
+  }
+
+  return result;
+}
+#else /* HAVE_SSL_X509_STORE_SHARE */
+CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   SSL_CTX *ssl_ctx)
+{
+  X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx);
+
+  return populate_x509_store(cf, data, store);
+}
+#endif /* HAVE_SSL_X509_STORE_SHARE */
+
+static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  char *ciphers;
+  SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
+  struct ssl_connect_data *connssl = cf->ctx;
+  ctx_option_t ctx_options = 0;
+  void *ssl_sessionid = NULL;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  BIO *bio;
+  const long int ssl_version = conn_config->version;
+  char * const ssl_cert = ssl_config->primary.clientcert;
+  const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
+  const char * const ssl_cert_type = ssl_config->cert_type;
+  const bool verifypeer = conn_config->verifypeer;
+  char error_buffer[256];
+  struct ossl_ssl_backend_data *backend =
+    (struct ossl_ssl_backend_data *)connssl->backend;
+
+  DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
+  DEBUGASSERT(backend);
+
+  /* Make funny stuff to get random input */
+  result = ossl_seed(data);
+  if(result)
+    return result;
+
+  ssl_config->certverifyresult = !X509_V_OK;
+
+  /* check to see if we've been told to use an explicit SSL/TLS version */
+
+  switch(ssl_version) {
+  case CURL_SSLVERSION_DEFAULT:
+  case CURL_SSLVERSION_TLSv1:
+  case CURL_SSLVERSION_TLSv1_0:
+  case CURL_SSLVERSION_TLSv1_1:
+  case CURL_SSLVERSION_TLSv1_2:
+  case CURL_SSLVERSION_TLSv1_3:
+    /* it will be handled later with the context options */
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+    req_method = TLS_client_method();
+#else
+    req_method = SSLv23_client_method();
+#endif
+    break;
+  case CURL_SSLVERSION_SSLv2:
+    failf(data, "No SSLv2 support");
+    return CURLE_NOT_BUILT_IN;
+  case CURL_SSLVERSION_SSLv3:
+    failf(data, "No SSLv3 support");
+    return CURLE_NOT_BUILT_IN;
+  default:
+    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  if(backend->ctx) {
+    /* This happens when an error was encountered before in this
+     * step and we are called to do it again. Get rid of any leftover
+     * from the previous call. */
+    ossl_close(cf, data);
+  }
+  backend->ctx = SSL_CTX_new(req_method);
+
+  if(!backend->ctx) {
+    failf(data, "SSL: couldn't create a context: %s",
+          ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer)));
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+#ifdef SSL_MODE_RELEASE_BUFFERS
+  SSL_CTX_set_mode(backend->ctx, SSL_MODE_RELEASE_BUFFERS);
+#endif
+
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+  if(data->set.fdebug && data->set.verbose) {
+    /* the SSL trace callback is only used for verbose logging */
+    SSL_CTX_set_msg_callback(backend->ctx, ossl_trace);
+    SSL_CTX_set_msg_callback_arg(backend->ctx, cf);
+  }
+#endif
+
+  /* OpenSSL contains code to work around lots of bugs and flaws in various
+     SSL-implementations. SSL_CTX_set_options() is used to enabled those
+     work-arounds. The man page for this option states that SSL_OP_ALL enables
+     all the work-arounds and that "It is usually safe to use SSL_OP_ALL to
+     enable the bug workaround options if compatibility with somewhat broken
+     implementations is desired."
+
+     The "-no_ticket" option was introduced in OpenSSL 0.9.8j. It's a flag to
+     disable "rfc4507bis session ticket support". rfc4507bis was later turned
+     into the proper RFC5077: https://datatracker.ietf.org/doc/html/rfc5077
+
+     The enabled extension concerns the session management. I wonder how often
+     libcurl stops a connection and then resumes a TLS session. Also, sending
+     the session data is some overhead. I suggest that you just use your
+     proposed patch (which explicitly disables TICKET).
+
+     If someone writes an application with libcurl and OpenSSL who wants to
+     enable the feature, one can do this in the SSL callback.
+
+     SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper
+     interoperability with web server Netscape Enterprise Server 2.0.1 which
+     was released back in 1996.
+
+     Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has
+     become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate
+     CVE-2010-4180 when using previous OpenSSL versions we no longer enable
+     this option regardless of OpenSSL version and SSL_OP_ALL definition.
+
+     OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability
+     (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to
+     SSL_OP_ALL that _disables_ that work-around despite the fact that
+     SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to
+     keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit
+     must not be set.
+  */
+
+  ctx_options = SSL_OP_ALL;
+
+#ifdef SSL_OP_NO_TICKET
+  ctx_options |= SSL_OP_NO_TICKET;
+#endif
+
+#ifdef SSL_OP_NO_COMPRESSION
+  ctx_options |= SSL_OP_NO_COMPRESSION;
+#endif
+
+#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
+  /* mitigate CVE-2010-4180 */
+  ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
+#endif
+
+#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
+  /* unless the user explicitly asks to allow the protocol vulnerability we
+     use the work-around */
+  if(!ssl_config->enable_beast)
+    ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+#endif
+
+  switch(ssl_version) {
+  case CURL_SSLVERSION_SSLv2:
+  case CURL_SSLVERSION_SSLv3:
+    return CURLE_NOT_BUILT_IN;
+
+    /* "--tlsv<x.y>" options mean TLS >= version <x.y> */
+  case CURL_SSLVERSION_DEFAULT:
+  case CURL_SSLVERSION_TLSv1: /* TLS >= version 1.0 */
+  case CURL_SSLVERSION_TLSv1_0: /* TLS >= version 1.0 */
+  case CURL_SSLVERSION_TLSv1_1: /* TLS >= version 1.1 */
+  case CURL_SSLVERSION_TLSv1_2: /* TLS >= version 1.2 */
+  case CURL_SSLVERSION_TLSv1_3: /* TLS >= version 1.3 */
+    /* asking for any TLS version as the minimum, means no SSL versions
+       allowed */
+    ctx_options |= SSL_OP_NO_SSLv2;
+    ctx_options |= SSL_OP_NO_SSLv3;
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */
+    result = ossl_set_ssl_version_min_max(cf, backend->ctx);
+#else
+    result = ossl_set_ssl_version_min_max_legacy(&ctx_options, cf, data);
+#endif
+    if(result != CURLE_OK)
+      return result;
+    break;
+
+  default:
+    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  SSL_CTX_set_options(backend->ctx, ctx_options);
+
+#ifdef HAS_ALPN
+  if(connssl->alpn) {
+    struct alpn_proto_buf proto;
+
+    result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
+    if(result ||
+       SSL_CTX_set_alpn_protos(backend->ctx, proto.data, proto.len)) {
+      failf(data, "Error setting ALPN");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    Curl_alpn_to_proto_str(&proto, connssl->alpn);
+    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+  }
+#endif
+
+  if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
+    if(!result &&
+       !cert_stuff(data, backend->ctx,
+                   ssl_cert, ssl_cert_blob, ssl_cert_type,
+                   ssl_config->key, ssl_config->key_blob,
+                   ssl_config->key_type, ssl_config->key_passwd))
+      result = CURLE_SSL_CERTPROBLEM;
+    if(result)
+      /* failf() is already done in cert_stuff() */
+      return result;
+  }
+
+  ciphers = conn_config->cipher_list;
+  if(!ciphers)
+    ciphers = (char *)DEFAULT_CIPHER_SELECTION;
+  if(ciphers) {
+    if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
+      failf(data, "failed setting cipher list: %s", ciphers);
+      return CURLE_SSL_CIPHER;
+    }
+    infof(data, "Cipher selection: %s", ciphers);
+  }
+
+#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
+  {
+    char *ciphers13 = conn_config->cipher_list13;
+    if(ciphers13) {
+      if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) {
+        failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13);
+        return CURLE_SSL_CIPHER;
+      }
+      infof(data, "TLS 1.3 cipher selection: %s", ciphers13);
+    }
+  }
+#endif
+
+#ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
+  /* OpenSSL 1.1.1 requires clients to opt-in for PHA */
+  SSL_CTX_set_post_handshake_auth(backend->ctx, 1);
+#endif
+
+#ifdef HAVE_SSL_CTX_SET_EC_CURVES
+  {
+    char *curves = conn_config->curves;
+    if(curves) {
+      if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
+        failf(data, "failed setting curves list: '%s'", curves);
+        return CURLE_SSL_CIPHER;
+      }
+    }
+  }
+#endif
+
+#ifdef USE_OPENSSL_SRP
+  if(ssl_config->primary.username && Curl_auth_allowed_to_host(data)) {
+    char * const ssl_username = ssl_config->primary.username;
+    char * const ssl_password = ssl_config->primary.password;
+    infof(data, "Using TLS-SRP username: %s", ssl_username);
+
+    if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) {
+      failf(data, "Unable to set SRP user name");
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+    if(!SSL_CTX_set_srp_password(backend->ctx, ssl_password)) {
+      failf(data, "failed setting SRP password");
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+    if(!conn_config->cipher_list) {
+      infof(data, "Setting cipher list SRP");
+
+      if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) {
+        failf(data, "failed setting SRP cipher list");
+        return CURLE_SSL_CIPHER;
+      }
+    }
+  }
+#endif
+
+  /* OpenSSL always tries to verify the peer, this only says whether it should
+   * fail to connect if the verification fails, or if it should continue
+   * anyway. In the latter case the result of the verification is checked with
+   * SSL_get_verify_result() below. */
+  SSL_CTX_set_verify(backend->ctx,
+                     verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
+
+  /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */
+#ifdef HAVE_KEYLOG_CALLBACK
+  if(Curl_tls_keylog_enabled()) {
+    SSL_CTX_set_keylog_callback(backend->ctx, ossl_keylog_callback);
+  }
+#endif
+
+  /* Enable the session cache because it's a prerequisite for the "new session"
+   * callback. Use the "external storage" mode to prevent OpenSSL from creating
+   * an internal session cache.
+   */
+  SSL_CTX_set_session_cache_mode(backend->ctx,
+                                 SSL_SESS_CACHE_CLIENT |
+                                 SSL_SESS_CACHE_NO_INTERNAL);
+  SSL_CTX_sess_set_new_cb(backend->ctx, ossl_new_session_cb);
+
+  /* give application a chance to interfere with SSL set up. */
+  if(data->set.ssl.fsslctx) {
+    /* When a user callback is installed to modify the SSL_CTX,
+     * we need to do the full initialization before calling it.
+     * See: #11800 */
+    if(!backend->x509_store_setup) {
+      result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
+      if(result)
+        return result;
+      backend->x509_store_setup = TRUE;
+    }
+    Curl_set_in_callback(data, true);
+    result = (*data->set.ssl.fsslctx)(data, backend->ctx,
+                                      data->set.ssl.fsslctxp);
+    Curl_set_in_callback(data, false);
+    if(result) {
+      failf(data, "error signaled by ssl ctx callback");
+      return result;
+    }
+  }
+
+  /* Let's make an SSL structure */
+  if(backend->handle)
+    SSL_free(backend->handle);
+  backend->handle = SSL_new(backend->ctx);
+  if(!backend->handle) {
+    failf(data, "SSL: couldn't create a context (handle)");
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  SSL_set_app_data(backend->handle, cf);
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+  !defined(OPENSSL_NO_OCSP)
+  if(conn_config->verifystatus)
+    SSL_set_tlsext_status_type(backend->handle, TLSEXT_STATUSTYPE_ocsp);
+#endif
+
+#if (defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)) && \
+    defined(ALLOW_RENEG)
+  SSL_set_renegotiate_mode(backend->handle, ssl_renegotiate_freely);
+#endif
+
+  SSL_set_connect_state(backend->handle);
+
+  backend->server_cert = 0x0;
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+  if(connssl->peer.sni) {
+    if(!SSL_set_tlsext_host_name(backend->handle, connssl->peer.sni)) {
+      failf(data, "Failed set SNI");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+#endif
+
+  SSL_set_app_data(backend->handle, cf);
+
+  connssl->reused_session = FALSE;
+  if(ssl_config->primary.sessionid) {
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
+      /* we got a session id, use it! */
+      if(!SSL_set_session(backend->handle, ssl_sessionid)) {
+        Curl_ssl_sessionid_unlock(data);
+        failf(data, "SSL: SSL_set_session failed: %s",
+              ossl_strerror(ERR_get_error(), error_buffer,
+                            sizeof(error_buffer)));
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      /* Informational message */
+      infof(data, "SSL reusing session ID");
+      connssl->reused_session = TRUE;
+    }
+    Curl_ssl_sessionid_unlock(data);
+  }
+
+  backend->bio_method = ossl_bio_cf_method_create();
+  if(!backend->bio_method)
+    return CURLE_OUT_OF_MEMORY;
+  bio = BIO_new(backend->bio_method);
+  if(!bio)
+    return CURLE_OUT_OF_MEMORY;
+
+  BIO_set_data(bio, cf);
+#ifdef HAVE_SSL_SET0_WBIO
+  /* with OpenSSL v1.1.1 we get an alternative to SSL_set_bio() that works
+   * without backward compat quirks. Every call takes one reference, so we
+   * up it and pass. SSL* then owns it and will free.
+   * We check on the function in configure, since libressl and friends
+   * each have their own versions to add support for this. */
+  BIO_up_ref(bio);
+  SSL_set0_rbio(backend->handle, bio);
+  SSL_set0_wbio(backend->handle, bio);
+#else
+  SSL_set_bio(backend->handle, bio, bio);
+#endif
+  connssl->connecting_state = ssl_connect_2;
+
+  return CURLE_OK;
+}
+
+static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data)
+{
+  int err;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ossl_ssl_backend_data *backend =
+    (struct ossl_ssl_backend_data *)connssl->backend;
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
+              || ssl_connect_2_reading == connssl->connecting_state
+              || ssl_connect_2_writing == connssl->connecting_state);
+  DEBUGASSERT(backend);
+
+  ERR_clear_error();
+
+  err = SSL_connect(backend->handle);
+
+  if(!backend->x509_store_setup) {
+    /* After having send off the ClientHello, we prepare the x509
+     * store to verify the coming certificate from the server */
+    CURLcode result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
+    if(result)
+      return result;
+    backend->x509_store_setup = TRUE;
+  }
+
+#ifndef HAVE_KEYLOG_CALLBACK
+  if(Curl_tls_keylog_enabled()) {
+    /* If key logging is enabled, wait for the handshake to complete and then
+     * proceed with logging secrets (for TLS 1.2 or older).
+     */
+    ossl_log_tls12_secret(backend->handle, &backend->keylog_done);
+  }
+#endif
+
+  /* 1  is fine
+     0  is "not successful but was shut down controlled"
+     <0 is "handshake was not successful, because a fatal error occurred" */
+  if(1 != err) {
+    int detail = SSL_get_error(backend->handle, err);
+
+    if(SSL_ERROR_WANT_READ == detail) {
+      connssl->connecting_state = ssl_connect_2_reading;
+      return CURLE_OK;
+    }
+    if(SSL_ERROR_WANT_WRITE == detail) {
+      connssl->connecting_state = ssl_connect_2_writing;
+      return CURLE_OK;
+    }
+#ifdef SSL_ERROR_WANT_ASYNC
+    if(SSL_ERROR_WANT_ASYNC == detail) {
+      connssl->connecting_state = ssl_connect_2;
+      return CURLE_OK;
+    }
+#endif
+#ifdef SSL_ERROR_WANT_RETRY_VERIFY
+    if(SSL_ERROR_WANT_RETRY_VERIFY == detail) {
+      connssl->connecting_state = ssl_connect_2;
+      return CURLE_OK;
+    }
+#endif
+    if(backend->io_result == CURLE_AGAIN) {
+      return CURLE_OK;
+    }
+    else {
+      /* untreated error */
+      sslerr_t errdetail;
+      char error_buffer[256]="";
+      CURLcode result;
+      long lerr;
+      int lib;
+      int reason;
+
+      /* the connection failed, we're not waiting for anything else. */
+      connssl->connecting_state = ssl_connect_2;
+
+      /* Get the earliest error code from the thread's error queue and remove
+         the entry. */
+      errdetail = ERR_get_error();
+
+      /* Extract which lib and reason */
+      lib = ERR_GET_LIB(errdetail);
+      reason = ERR_GET_REASON(errdetail);
+
+      if((lib == ERR_LIB_SSL) &&
+         ((reason == SSL_R_CERTIFICATE_VERIFY_FAILED) ||
+          (reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) {
+        result = CURLE_PEER_FAILED_VERIFICATION;
+
+        lerr = SSL_get_verify_result(backend->handle);
+        if(lerr != X509_V_OK) {
+          ssl_config->certverifyresult = lerr;
+          msnprintf(error_buffer, sizeof(error_buffer),
+                    "SSL certificate problem: %s",
+                    X509_verify_cert_error_string(lerr));
+        }
+        else
+          /* strcpy() is fine here as long as the string fits within
+             error_buffer */
+          strcpy(error_buffer, "SSL certificate verification failed");
+      }
+#if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)
+      /* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on
+         OpenSSL version above v1.1.1, not LibreSSL, BoringSSL, or AWS-LC */
+      else if((lib == ERR_LIB_SSL) &&
+              (reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)) {
+        /* If client certificate is required, communicate the
+           error to client */
+        result = CURLE_SSL_CLIENTCERT;
+        ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
+      }
+#endif
+      else {
+        result = CURLE_SSL_CONNECT_ERROR;
+        ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
+      }
+
+      /* detail is already set to the SSL error above */
+
+      /* If we e.g. use SSLv2 request-method and the server doesn't like us
+       * (RST connection, etc.), OpenSSL gives no explanation whatsoever and
+       * the SO_ERROR is also lost.
+       */
+      if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
+        char extramsg[80]="";
+        int sockerr = SOCKERRNO;
+
+        if(sockerr && detail == SSL_ERROR_SYSCALL)
+          Curl_strerror(sockerr, extramsg, sizeof(extramsg));
+        failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ",
+              extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
+              connssl->peer.hostname, connssl->port);
+        return result;
+      }
+
+      /* Could be a CERT problem */
+      failf(data, "%s", error_buffer);
+
+      return result;
+    }
+  }
+  else {
+    int psigtype_nid = NID_undef;
+    const char *negotiated_group_name = NULL;
+
+    /* we connected fine, we're not waiting for anything else. */
+    connssl->connecting_state = ssl_connect_3;
+
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+    SSL_get_peer_signature_type_nid(backend->handle, &psigtype_nid);
+#if (OPENSSL_VERSION_NUMBER >= 0x30200000L)
+    negotiated_group_name = SSL_get0_group_name(backend->handle);
+#else
+    negotiated_group_name =
+      OBJ_nid2sn(SSL_get_negotiated_group(backend->handle) & 0x0000FFFF);
+#endif
+#endif
+
+    /* Informational message */
+    infof(data, "SSL connection using %s / %s / %s / %s",
+          SSL_get_version(backend->handle),
+          SSL_get_cipher(backend->handle),
+          negotiated_group_name? negotiated_group_name : "[blank]",
+          OBJ_nid2sn(psigtype_nid));
+
+#ifdef HAS_ALPN
+    /* Sets data and len to negotiated protocol, len is 0 if no protocol was
+     * negotiated
+     */
+    if(connssl->alpn) {
+      const unsigned char *neg_protocol;
+      unsigned int len;
+      SSL_get0_alpn_selected(backend->handle, &neg_protocol, &len);
+
+      return Curl_alpn_set_negotiated(cf, data, neg_protocol, len);
+    }
+#endif
+
+    return CURLE_OK;
+  }
+}
+
+/*
+ * Heavily modified from:
+ * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL
+ */
+static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
+                                         const char *pinnedpubkey)
+{
+  /* Scratch */
+  int len1 = 0, len2 = 0;
+  unsigned char *buff1 = NULL, *temp = NULL;
+
+  /* Result is returned to caller */
+  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+  /* if a path wasn't specified, don't pin */
+  if(!pinnedpubkey)
+    return CURLE_OK;
+
+  if(!cert)
+    return result;
+
+  do {
+    /* Begin Gyrations to get the subjectPublicKeyInfo     */
+    /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */
+
+    /* https://groups.google.com/group/mailing.openssl.users/browse_thread
+       /thread/d61858dae102c6c7 */
+    len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
+    if(len1 < 1)
+      break; /* failed */
+
+    buff1 = temp = malloc(len1);
+    if(!buff1)
+      break; /* failed */
+
+    /* https://www.openssl.org/docs/crypto/d2i_X509.html */
+    len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp);
+
+    /*
+     * These checks are verifying we got back the same values as when we
+     * sized the buffer. It's pretty weak since they should always be the
+     * same. But it gives us something to test.
+     */
+    if((len1 != len2) || !temp || ((temp - buff1) != len1))
+      break; /* failed */
+
+    /* End Gyrations */
+
+    /* The one good exit point */
+    result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
+  } while(0);
+
+  if(buff1)
+    free(buff1);
+
+  return result;
+}
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) &&  \
+  !(defined(LIBRESSL_VERSION_NUMBER) && \
+    LIBRESSL_VERSION_NUMBER < 0x3060000fL) && \
+  !defined(OPENSSL_IS_BORINGSSL) && \
+  !defined(OPENSSL_IS_AWSLC) && \
+  !defined(CURL_DISABLE_VERBOSE_STRINGS)
+static void infof_certstack(struct Curl_easy *data, const SSL *ssl)
+{
+  STACK_OF(X509) *certstack;
+  long verify_result;
+  int num_cert_levels;
+  int cert_level;
+
+  verify_result = SSL_get_verify_result(ssl);
+  if(verify_result != X509_V_OK)
+    certstack = SSL_get_peer_cert_chain(ssl);
+  else
+    certstack = SSL_get0_verified_chain(ssl);
+  num_cert_levels = sk_X509_num(certstack);
+
+  for(cert_level = 0; cert_level < num_cert_levels; cert_level++) {
+    char cert_algorithm[80] = "";
+    char group_name_final[80] = "";
+    const X509_ALGOR *palg_cert = NULL;
+    const ASN1_OBJECT *paobj_cert = NULL;
+    X509 *current_cert;
+    EVP_PKEY *current_pkey;
+    int key_bits;
+    int key_sec_bits;
+    int get_group_name;
+    const char *type_name;
+
+    current_cert = sk_X509_value(certstack, cert_level);
+
+    X509_get0_signature(NULL, &palg_cert, current_cert);
+    X509_ALGOR_get0(&paobj_cert, NULL, NULL, palg_cert);
+    OBJ_obj2txt(cert_algorithm, sizeof(cert_algorithm), paobj_cert, 0);
+
+    current_pkey = X509_get0_pubkey(current_cert);
+    key_bits = EVP_PKEY_bits(current_pkey);
+#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
+#define EVP_PKEY_get_security_bits EVP_PKEY_security_bits
+#endif
+    key_sec_bits = EVP_PKEY_get_security_bits(current_pkey);
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+    {
+      char group_name[80] = "";
+      get_group_name = EVP_PKEY_get_group_name(current_pkey, group_name,
+                                               sizeof(group_name), NULL);
+      msnprintf(group_name_final, sizeof(group_name_final), "/%s", group_name);
+    }
+    type_name = EVP_PKEY_get0_type_name(current_pkey);
+#else
+    get_group_name = 0;
+    type_name = NULL;
+#endif
+
+    infof(data,
+          "  Certificate level %d: "
+          "Public key type %s%s (%d/%d Bits/secBits), signed using %s",
+          cert_level, type_name ? type_name : "?",
+          get_group_name == 0 ? "" : group_name_final,
+          key_bits, key_sec_bits, cert_algorithm);
+  }
+}
+#else
+#define infof_certstack(data, ssl)
+#endif
+
+/*
+ * Get the server cert, verify it and show it, etc., only call failf() if the
+ * 'strict' argument is TRUE as otherwise all this is for informational
+ * purposes only!
+ *
+ * We check certificates to authenticate the server; otherwise we risk
+ * man-in-the-middle attack.
+ */
+static CURLcode servercert(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           bool strict)
+{
+  struct connectdata *conn = cf->conn;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  CURLcode result = CURLE_OK;
+  int rc;
+  long lerr;
+  X509 *issuer;
+  BIO *fp = NULL;
+  char error_buffer[256]="";
+  char buffer[2048];
+  const char *ptr;
+  BIO *mem = BIO_new(BIO_s_mem());
+  struct ossl_ssl_backend_data *backend =
+    (struct ossl_ssl_backend_data *)connssl->backend;
+
+  DEBUGASSERT(backend);
+
+  if(!mem) {
+    failf(data,
+          "BIO_new return NULL, " OSSL_PACKAGE
+          " error %s",
+          ossl_strerror(ERR_get_error(), error_buffer,
+                        sizeof(error_buffer)) );
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(data->set.ssl.certinfo)
+    /* asked to gather certificate info */
+    (void)Curl_ossl_certchain(data, backend->handle);
+
+  backend->server_cert = SSL_get1_peer_certificate(backend->handle);
+  if(!backend->server_cert) {
+    BIO_free(mem);
+    if(!strict)
+      return CURLE_OK;
+
+    failf(data, "SSL: couldn't get peer certificate");
+    return CURLE_PEER_FAILED_VERIFICATION;
+  }
+
+  infof(data, "%s certificate:",
+        Curl_ssl_cf_is_proxy(cf)? "Proxy" : "Server");
+
+  rc = x509_name_oneline(X509_get_subject_name(backend->server_cert),
+                         buffer, sizeof(buffer));
+  infof(data, " subject: %s", rc?"[NONE]":buffer);
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  {
+    long len;
+    ASN1_TIME_print(mem, X509_get0_notBefore(backend->server_cert));
+    len = BIO_get_mem_data(mem, (char **) &ptr);
+    infof(data, " start date: %.*s", (int)len, ptr);
+    (void)BIO_reset(mem);
+
+    ASN1_TIME_print(mem, X509_get0_notAfter(backend->server_cert));
+    len = BIO_get_mem_data(mem, (char **) &ptr);
+    infof(data, " expire date: %.*s", (int)len, ptr);
+    (void)BIO_reset(mem);
+  }
+#endif
+
+  BIO_free(mem);
+
+  if(conn_config->verifyhost) {
+    result = Curl_ossl_verifyhost(data, conn, &connssl->peer,
+                                  backend->server_cert);
+    if(result) {
+      X509_free(backend->server_cert);
+      backend->server_cert = NULL;
+      return result;
+    }
+  }
+
+  rc = x509_name_oneline(X509_get_issuer_name(backend->server_cert),
+                         buffer, sizeof(buffer));
+  if(rc) {
+    if(strict)
+      failf(data, "SSL: couldn't get X509-issuer name");
+    result = CURLE_PEER_FAILED_VERIFICATION;
+  }
+  else {
+    infof(data, " issuer: %s", buffer);
+
+    /* We could do all sorts of certificate verification stuff here before
+       deallocating the certificate. */
+
+    /* e.g. match issuer name with provided issuer certificate */
+    if(conn_config->issuercert || conn_config->issuercert_blob) {
+      if(conn_config->issuercert_blob) {
+        fp = BIO_new_mem_buf(conn_config->issuercert_blob->data,
+                             (int)conn_config->issuercert_blob->len);
+        if(!fp) {
+          failf(data,
+                "BIO_new_mem_buf NULL, " OSSL_PACKAGE
+                " error %s",
+                ossl_strerror(ERR_get_error(), error_buffer,
+                              sizeof(error_buffer)) );
+          X509_free(backend->server_cert);
+          backend->server_cert = NULL;
+          return CURLE_OUT_OF_MEMORY;
+        }
+      }
+      else {
+        fp = BIO_new(BIO_s_file());
+        if(!fp) {
+          failf(data,
+                "BIO_new return NULL, " OSSL_PACKAGE
+                " error %s",
+                ossl_strerror(ERR_get_error(), error_buffer,
+                              sizeof(error_buffer)) );
+          X509_free(backend->server_cert);
+          backend->server_cert = NULL;
+          return CURLE_OUT_OF_MEMORY;
+        }
+
+        if(BIO_read_filename(fp, conn_config->issuercert) <= 0) {
+          if(strict)
+            failf(data, "SSL: Unable to open issuer cert (%s)",
+                  conn_config->issuercert);
+          BIO_free(fp);
+          X509_free(backend->server_cert);
+          backend->server_cert = NULL;
+          return CURLE_SSL_ISSUER_ERROR;
+        }
+      }
+
+      issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL);
+      if(!issuer) {
+        if(strict)
+          failf(data, "SSL: Unable to read issuer cert (%s)",
+                conn_config->issuercert);
+        BIO_free(fp);
+        X509_free(issuer);
+        X509_free(backend->server_cert);
+        backend->server_cert = NULL;
+        return CURLE_SSL_ISSUER_ERROR;
+      }
+
+      if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) {
+        if(strict)
+          failf(data, "SSL: Certificate issuer check failed (%s)",
+                conn_config->issuercert);
+        BIO_free(fp);
+        X509_free(issuer);
+        X509_free(backend->server_cert);
+        backend->server_cert = NULL;
+        return CURLE_SSL_ISSUER_ERROR;
+      }
+
+      infof(data, " SSL certificate issuer check ok (%s)",
+            conn_config->issuercert);
+      BIO_free(fp);
+      X509_free(issuer);
+    }
+
+    lerr = SSL_get_verify_result(backend->handle);
+    ssl_config->certverifyresult = lerr;
+    if(lerr != X509_V_OK) {
+      if(conn_config->verifypeer) {
+        /* We probably never reach this, because SSL_connect() will fail
+           and we return earlier if verifypeer is set? */
+        if(strict)
+          failf(data, "SSL certificate verify result: %s (%ld)",
+                X509_verify_cert_error_string(lerr), lerr);
+        result = CURLE_PEER_FAILED_VERIFICATION;
+      }
+      else
+        infof(data, " SSL certificate verify result: %s (%ld),"
+              " continuing anyway.",
+              X509_verify_cert_error_string(lerr), lerr);
+    }
+    else
+      infof(data, " SSL certificate verify ok.");
+  }
+
+  infof_certstack(data, backend->handle);
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+  !defined(OPENSSL_NO_OCSP)
+  if(conn_config->verifystatus && !connssl->reused_session) {
+    /* don't do this after Session ID reuse */
+    result = verifystatus(cf, data);
+    if(result) {
+      /* when verifystatus failed, remove the session id from the cache again
+         if present */
+      if(!Curl_ssl_cf_is_proxy(cf)) {
+        void *old_ssl_sessionid = NULL;
+        bool incache;
+        Curl_ssl_sessionid_lock(data);
+        incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
+        if(incache) {
+          infof(data, "Remove session ID again from cache");
+          Curl_ssl_delsessionid(data, old_ssl_sessionid);
+        }
+        Curl_ssl_sessionid_unlock(data);
+      }
+
+      X509_free(backend->server_cert);
+      backend->server_cert = NULL;
+      return result;
+    }
+  }
+#endif
+
+  if(!strict)
+    /* when not strict, we don't bother about the verify cert problems */
+    result = CURLE_OK;
+
+  ptr = Curl_ssl_cf_is_proxy(cf)?
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+  if(!result && ptr) {
+    result = ossl_pkp_pin_peer_pubkey(data, backend->server_cert, ptr);
+    if(result)
+      failf(data, "SSL: public key does not match pinned public key");
+  }
+
+  X509_free(backend->server_cert);
+  backend->server_cert = NULL;
+  connssl->connecting_state = ssl_connect_done;
+
+  return result;
+}
+
+static CURLcode ossl_connect_step3(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+
+  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+  /*
+   * We check certificates to authenticate the server; otherwise we risk
+   * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to
+   * verify the peer, ignore faults and failures from the server cert
+   * operations.
+   */
+
+  result = servercert(cf, data, conn_config->verifypeer ||
+                      conn_config->verifyhost);
+
+  if(!result)
+    connssl->connecting_state = ssl_connect_done;
+
+  return result;
+}
+
+static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    bool nonblocking,
+                                    bool *done)
+{
+  CURLcode result = CURLE_OK;
+  struct ssl_connect_data *connssl = cf->ctx;
+  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+  int what;
+
+  /* check if the connection has already been established */
+  if(ssl_connection_complete == connssl->state) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  if(ssl_connect_1 == connssl->connecting_state) {
+    /* Find out how much more time we're allowed */
+    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time is already up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    result = ossl_connect_step1(cf, data);
+    if(result)
+      goto out;
+  }
+
+  while(ssl_connect_2 == connssl->connecting_state ||
+        ssl_connect_2_reading == connssl->connecting_state ||
+        ssl_connect_2_writing == connssl->connecting_state) {
+
+    /* check allowed time left */
+    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      result = CURLE_OPERATION_TIMEDOUT;
+      goto out;
+    }
+
+    /* if ssl is expecting something, check if it's available. */
+    if(!nonblocking &&
+       (connssl->connecting_state == ssl_connect_2_reading ||
+        connssl->connecting_state == ssl_connect_2_writing)) {
+
+      curl_socket_t writefd = ssl_connect_2_writing ==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+      curl_socket_t readfd = ssl_connect_2_reading ==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+                               timeout_ms);
+      if(what < 0) {
+        /* fatal error */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        result = CURLE_SSL_CONNECT_ERROR;
+        goto out;
+      }
+      if(0 == what) {
+        /* timeout */
+        failf(data, "SSL connection timeout");
+        result = CURLE_OPERATION_TIMEDOUT;
+        goto out;
+      }
+      /* socket is readable or writable */
+    }
+
+    /* Run transaction, and return to the caller if it failed or if this
+     * connection is done nonblocking and this loop would execute again. This
+     * permits the owner of a multi handle to abort a connection attempt
+     * before step2 has completed while ensuring that a client using select()
+     * or epoll() will always have a valid fdset to wait on.
+     */
+    result = ossl_connect_step2(cf, data);
+    if(result || (nonblocking &&
+                  (ssl_connect_2 == connssl->connecting_state ||
+                   ssl_connect_2_reading == connssl->connecting_state ||
+                   ssl_connect_2_writing == connssl->connecting_state)))
+      goto out;
+
+  } /* repeat step2 until all transactions are done. */
+
+  if(ssl_connect_3 == connssl->connecting_state) {
+    result = ossl_connect_step3(cf, data);
+    if(result)
+      goto out;
+  }
+
+  if(ssl_connect_done == connssl->connecting_state) {
+    connssl->state = ssl_connection_complete;
+    *done = TRUE;
+  }
+  else
+    *done = FALSE;
+
+  /* Reset our connect state machine */
+  connssl->connecting_state = ssl_connect_1;
+
+out:
+  return result;
+}
+
+static CURLcode ossl_connect_nonblocking(struct Curl_cfilter *cf,
+                                         struct Curl_easy *data,
+                                         bool *done)
+{
+  return ossl_connect_common(cf, data, TRUE, done);
+}
+
+static CURLcode ossl_connect(struct Curl_cfilter *cf,
+                             struct Curl_easy *data)
+{
+  CURLcode result;
+  bool done = FALSE;
+
+  result = ossl_connect_common(cf, data, FALSE, &done);
+  if(result)
+    return result;
+
+  DEBUGASSERT(done);
+
+  return CURLE_OK;
+}
+
+static bool ossl_data_pending(struct Curl_cfilter *cf,
+                              const struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ossl_ssl_backend_data *backend =
+    (struct ossl_ssl_backend_data *)connssl->backend;
+
+  (void)data;
+  DEBUGASSERT(connssl && backend);
+  if(backend->handle && SSL_pending(backend->handle))
+    return TRUE;
+  return FALSE;
+}
+
+static ssize_t ossl_send(struct Curl_cfilter *cf,
+                         struct Curl_easy *data,
+                         const void *mem,
+                         size_t len,
+                         CURLcode *curlcode)
+{
+  /* SSL_write() is said to return 'int' while write() and send() returns
+     'size_t' */
+  int err;
+  char error_buffer[256];
+  sslerr_t sslerror;
+  int memlen;
+  int rc;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ossl_ssl_backend_data *backend =
+    (struct ossl_ssl_backend_data *)connssl->backend;
+
+  (void)data;
+  DEBUGASSERT(backend);
+
+  ERR_clear_error();
+
+  memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
+  rc = SSL_write(backend->handle, mem, memlen);
+
+  if(rc <= 0) {
+    err = SSL_get_error(backend->handle, rc);
+
+    switch(err) {
+    case SSL_ERROR_WANT_READ:
+    case SSL_ERROR_WANT_WRITE:
+      /* The operation did not complete; the same TLS/SSL I/O function
+         should be called again later. This is basically an EWOULDBLOCK
+         equivalent. */
+      *curlcode = CURLE_AGAIN;
+      rc = -1;
+      goto out;
+    case SSL_ERROR_SYSCALL:
+    {
+      int sockerr = SOCKERRNO;
+
+      if(backend->io_result == CURLE_AGAIN) {
+        *curlcode = CURLE_AGAIN;
+        rc = -1;
+        goto out;
+      }
+      sslerror = ERR_get_error();
+      if(sslerror)
+        ossl_strerror(sslerror, error_buffer, sizeof(error_buffer));
+      else if(sockerr)
+        Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
+      else
+        msnprintf(error_buffer, sizeof(error_buffer), "%s",
+                  SSL_ERROR_to_str(err));
+
+      failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
+            error_buffer, sockerr);
+      *curlcode = CURLE_SEND_ERROR;
+      rc = -1;
+      goto out;
+    }
+    case SSL_ERROR_SSL: {
+      /*  A failure in the SSL library occurred, usually a protocol error.
+          The OpenSSL error queue contains more information on the error. */
+      sslerror = ERR_get_error();
+      failf(data, "SSL_write() error: %s",
+            ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
+      *curlcode = CURLE_SEND_ERROR;
+      rc = -1;
+      goto out;
+    }
+    default:
+      /* a true error */
+      failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
+            SSL_ERROR_to_str(err), SOCKERRNO);
+      *curlcode = CURLE_SEND_ERROR;
+      rc = -1;
+      goto out;
+    }
+  }
+  *curlcode = CURLE_OK;
+
+out:
+  return (ssize_t)rc; /* number of bytes */
+}
+
+static ssize_t ossl_recv(struct Curl_cfilter *cf,
+                         struct Curl_easy *data,   /* transfer */
+                         char *buf,                /* store read data here */
+                         size_t buffersize,        /* max amount to read */
+                         CURLcode *curlcode)
+{
+  char error_buffer[256];
+  unsigned long sslerror;
+  ssize_t nread;
+  int buffsize;
+  struct connectdata *conn = cf->conn;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ossl_ssl_backend_data *backend =
+    (struct ossl_ssl_backend_data *)connssl->backend;
+
+  (void)data;
+  DEBUGASSERT(backend);
+
+  ERR_clear_error();
+
+  buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
+  nread = (ssize_t)SSL_read(backend->handle, buf, buffsize);
+
+  if(nread <= 0) {
+    /* failed SSL_read */
+    int err = SSL_get_error(backend->handle, (int)nread);
+
+    switch(err) {
+    case SSL_ERROR_NONE: /* this is not an error */
+      break;
+    case SSL_ERROR_ZERO_RETURN: /* no more data */
+      /* close_notify alert */
+      if(cf->sockindex == FIRSTSOCKET)
+        /* mark the connection for close if it is indeed the control
+           connection */
+        connclose(conn, "TLS close_notify");
+      break;
+    case SSL_ERROR_WANT_READ:
+    case SSL_ERROR_WANT_WRITE:
+      /* there's data pending, re-invoke SSL_read() */
+      *curlcode = CURLE_AGAIN;
+      nread = -1;
+      goto out;
+    default:
+      /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
+         value/errno" */
+      /* https://www.openssl.org/docs/crypto/ERR_get_error.html */
+      if(backend->io_result == CURLE_AGAIN) {
+        *curlcode = CURLE_AGAIN;
+        nread = -1;
+        goto out;
+      }
+      sslerror = ERR_get_error();
+      if((nread < 0) || sslerror) {
+        /* If the return code was negative or there actually is an error in the
+           queue */
+        int sockerr = SOCKERRNO;
+        if(sslerror)
+          ossl_strerror(sslerror, error_buffer, sizeof(error_buffer));
+        else if(sockerr && err == SSL_ERROR_SYSCALL)
+          Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
+        else
+          msnprintf(error_buffer, sizeof(error_buffer), "%s",
+                    SSL_ERROR_to_str(err));
+        failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d",
+              error_buffer, sockerr);
+        *curlcode = CURLE_RECV_ERROR;
+        nread = -1;
+        goto out;
+      }
+      /* For debug builds be a little stricter and error on any
+         SSL_ERROR_SYSCALL. For example a server may have closed the connection
+         abruptly without a close_notify alert. For compatibility with older
+         peers we don't do this by default. #4624
+
+         We can use this to gauge how many users may be affected, and
+         if it goes ok eventually transition to allow in dev and release with
+         the newest OpenSSL: #if (OPENSSL_VERSION_NUMBER >= 0x10101000L) */
+#ifdef DEBUGBUILD
+      if(err == SSL_ERROR_SYSCALL) {
+        int sockerr = SOCKERRNO;
+        if(sockerr)
+          Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
+        else {
+          msnprintf(error_buffer, sizeof(error_buffer),
+                    "Connection closed abruptly");
+        }
+        failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d"
+              " (Fatal because this is a curl debug build)",
+              error_buffer, sockerr);
+        *curlcode = CURLE_RECV_ERROR;
+        nread = -1;
+        goto out;
+      }
+#endif
+    }
+  }
+
+out:
+  return nread;
+}
+
+static size_t ossl_version(char *buffer, size_t size)
+{
+#ifdef LIBRESSL_VERSION_NUMBER
+#ifdef HAVE_OPENSSL_VERSION
+  char *p;
+  int count;
+  const char *ver = OpenSSL_version(OPENSSL_VERSION);
+  const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */
+  if(strncasecompare(ver, expected, sizeof(expected) - 1)) {
+    ver += sizeof(expected) - 1;
+  }
+  count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver);
+  for(p = buffer; *p; ++p) {
+    if(ISBLANK(*p))
+      *p = '_';
+  }
+  return count;
+#else
+  return msnprintf(buffer, size, "%s/%lx.%lx.%lx",
+                   OSSL_PACKAGE,
+                   (LIBRESSL_VERSION_NUMBER>>28)&0xf,
+                   (LIBRESSL_VERSION_NUMBER>>20)&0xff,
+                   (LIBRESSL_VERSION_NUMBER>>12)&0xff);
+#endif
+#elif defined(OPENSSL_IS_BORINGSSL)
+#ifdef CURL_BORINGSSL_VERSION
+  return msnprintf(buffer, size, "%s/%s",
+                   OSSL_PACKAGE,
+                   CURL_BORINGSSL_VERSION);
+#else
+  return msnprintf(buffer, size, OSSL_PACKAGE);
+#endif
+#elif defined(OPENSSL_IS_AWSLC)
+  return msnprintf(buffer, size, "%s/%s",
+                   OSSL_PACKAGE,
+                   AWSLC_VERSION_NUMBER_STRING);
+#elif defined(HAVE_OPENSSL_VERSION) && defined(OPENSSL_VERSION_STRING)
+  return msnprintf(buffer, size, "%s/%s",
+                   OSSL_PACKAGE, OpenSSL_version(OPENSSL_VERSION_STRING));
+#else
+  /* not LibreSSL, BoringSSL and not using OpenSSL_version */
+
+  char sub[3];
+  unsigned long ssleay_value;
+  sub[2]='\0';
+  sub[1]='\0';
+  ssleay_value = OpenSSL_version_num();
+  if(ssleay_value < 0x906000) {
+    ssleay_value = SSLEAY_VERSION_NUMBER;
+    sub[0]='\0';
+  }
+  else {
+    if(ssleay_value&0xff0) {
+      int minor_ver = (ssleay_value >> 4) & 0xff;
+      if(minor_ver > 26) {
+        /* handle extended version introduced for 0.9.8za */
+        sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1);
+        sub[0] = 'z';
+      }
+      else {
+        sub[0] = (char) (minor_ver + 'a' - 1);
+      }
+    }
+    else
+      sub[0]='\0';
+  }
+
+  return msnprintf(buffer, size, "%s/%lx.%lx.%lx%s"
+#ifdef OPENSSL_FIPS
+                   "-fips"
+#endif
+                   ,
+                   OSSL_PACKAGE,
+                   (ssleay_value>>28)&0xf,
+                   (ssleay_value>>20)&0xff,
+                   (ssleay_value>>12)&0xff,
+                   sub);
+#endif /* OPENSSL_IS_BORINGSSL */
+}
+
+/* can be called with data == NULL */
+static CURLcode ossl_random(struct Curl_easy *data,
+                            unsigned char *entropy, size_t length)
+{
+  int rc;
+  if(data) {
+    if(ossl_seed(data)) /* Initiate the seed if not already done */
+      return CURLE_FAILED_INIT; /* couldn't seed for some reason */
+  }
+  else {
+    if(!rand_enough())
+      return CURLE_FAILED_INIT;
+  }
+  /* RAND_bytes() returns 1 on success, 0 otherwise.  */
+  rc = RAND_bytes(entropy, curlx_uztosi(length));
+  return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT);
+}
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+static CURLcode ossl_sha256sum(const unsigned char *tmp, /* input */
+                               size_t tmplen,
+                               unsigned char *sha256sum /* output */,
+                               size_t unused)
+{
+  EVP_MD_CTX *mdctx;
+  unsigned int len = 0;
+  (void) unused;
+
+  mdctx = EVP_MD_CTX_create();
+  if(!mdctx)
+    return CURLE_OUT_OF_MEMORY;
+  if(!EVP_DigestInit(mdctx, EVP_sha256())) {
+    EVP_MD_CTX_destroy(mdctx);
+    return CURLE_FAILED_INIT;
+  }
+  EVP_DigestUpdate(mdctx, tmp, tmplen);
+  EVP_DigestFinal_ex(mdctx, sha256sum, &len);
+  EVP_MD_CTX_destroy(mdctx);
+  return CURLE_OK;
+}
+#endif
+
+static bool ossl_cert_status_request(void)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+  !defined(OPENSSL_NO_OCSP)
+  return TRUE;
+#else
+  return FALSE;
+#endif
+}
+
+static void *ossl_get_internals(struct ssl_connect_data *connssl,
+                                CURLINFO info)
+{
+  /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
+  struct ossl_ssl_backend_data *backend =
+    (struct ossl_ssl_backend_data *)connssl->backend;
+  DEBUGASSERT(backend);
+  return info == CURLINFO_TLS_SESSION ?
+    (void *)backend->ctx : (void *)backend->handle;
+}
+
+static void ossl_free_multi_ssl_backend_data(
+  struct multi_ssl_backend_data *mbackend)
+{
+#if defined(HAVE_SSL_X509_STORE_SHARE)
+  if(mbackend->store) {
+    X509_STORE_free(mbackend->store);
+  }
+  free(mbackend->CAfile);
+  free(mbackend);
+#else /* HAVE_SSL_X509_STORE_SHARE */
+  (void)mbackend;
+#endif /* HAVE_SSL_X509_STORE_SHARE */
+}
+
+const struct Curl_ssl Curl_ssl_openssl = {
+  { CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */
+
+  SSLSUPP_CA_PATH |
+  SSLSUPP_CAINFO_BLOB |
+  SSLSUPP_CERTINFO |
+  SSLSUPP_PINNEDPUBKEY |
+  SSLSUPP_SSL_CTX |
+#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
+  SSLSUPP_TLS13_CIPHERSUITES |
+#endif
+  SSLSUPP_HTTPS_PROXY,
+
+  sizeof(struct ossl_ssl_backend_data),
+
+  ossl_init,                /* init */
+  ossl_cleanup,             /* cleanup */
+  ossl_version,             /* version */
+  Curl_none_check_cxn,      /* check_cxn */
+  ossl_shutdown,            /* shutdown */
+  ossl_data_pending,        /* data_pending */
+  ossl_random,              /* random */
+  ossl_cert_status_request, /* cert_status_request */
+  ossl_connect,             /* connect */
+  ossl_connect_nonblocking, /* connect_nonblocking */
+  Curl_ssl_adjust_pollset,  /* adjust_pollset */
+  ossl_get_internals,       /* get_internals */
+  ossl_close,               /* close_one */
+  ossl_close_all,           /* close_all */
+  ossl_session_free,        /* session_free */
+  ossl_set_engine,          /* set_engine */
+  ossl_set_engine_default,  /* set_engine_default */
+  ossl_engines_list,        /* engines_list */
+  Curl_none_false_start,    /* false_start */
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+  ossl_sha256sum,           /* sha256sum */
+#else
+  NULL,                     /* sha256sum */
+#endif
+  NULL,                     /* use of data in this connection */
+  NULL,                     /* remote of data from this connection */
+  ossl_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
+  ossl_recv,                /* recv decrypted data */
+  ossl_send,                /* send data to encrypt */
+};
+
+#endif /* USE_OPENSSL */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/openssl.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/openssl.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/openssl.h	(revision 104083)
@@ -0,0 +1,70 @@
+#ifndef HEADER_CURL_SSLUSE_H
+#define HEADER_CURL_SSLUSE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_OPENSSL
+/*
+ * This header should only be needed to get included by vtls.c, openssl.c
+ * and ngtcp2.c
+ */
+#include <openssl/ossl_typ.h>
+#include <openssl/ssl.h>
+
+#include "urldata.h"
+
+#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
+#define SSL_get1_peer_certificate SSL_get_peer_certificate
+#endif
+
+CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
+                              struct ssl_peer *peer, X509 *server_cert);
+extern const struct Curl_ssl Curl_ssl_openssl;
+
+CURLcode Curl_ossl_set_client_cert(struct Curl_easy *data,
+                                   SSL_CTX *ctx, char *cert_file,
+                                   const struct curl_blob *cert_blob,
+                                   const char *cert_type, char *key_file,
+                                   const struct curl_blob *key_blob,
+                                   const char *key_type, char *key_passwd);
+
+CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl);
+
+/**
+ * Setup the OpenSSL X509_STORE in `ssl_ctx` for the cfilter `cf` and
+ * easy handle `data`. Will allow reuse of a shared cache if suitable
+ * and configured.
+ */
+CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   SSL_CTX *ssl_ctx);
+
+CURLcode Curl_ossl_ctx_configure(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 SSL_CTX *ssl_ctx);
+
+#endif /* USE_OPENSSL */
+#endif /* HEADER_CURL_SSLUSE_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/rustls.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/rustls.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/rustls.c	(revision 104083)
@@ -0,0 +1,759 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Jacob Hoffman-Andrews,
+ * <github@hoffman-andrews.com>
+ * Copyright (C) kpcyrd, <kpcyrd@archlinux.org>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_RUSTLS
+
+#include "curl_printf.h"
+
+#include <errno.h>
+#include <rustls.h>
+
+#include "inet_pton.h"
+#include "urldata.h"
+#include "sendf.h"
+#include "vtls.h"
+#include "vtls_int.h"
+#include "select.h"
+#include "strerror.h"
+#include "multiif.h"
+#include "connect.h" /* for the connect timeout */
+
+struct rustls_ssl_backend_data
+{
+  const struct rustls_client_config *config;
+  struct rustls_connection *conn;
+  bool data_pending;
+};
+
+/* For a given rustls_result error code, return the best-matching CURLcode. */
+static CURLcode map_error(rustls_result r)
+{
+  if(rustls_result_is_cert_error(r)) {
+    return CURLE_PEER_FAILED_VERIFICATION;
+  }
+  switch(r) {
+    case RUSTLS_RESULT_OK:
+      return CURLE_OK;
+    case RUSTLS_RESULT_NULL_PARAMETER:
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    default:
+      return CURLE_READ_ERROR;
+  }
+}
+
+static bool
+cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
+{
+  struct ssl_connect_data *ctx = cf->ctx;
+  struct rustls_ssl_backend_data *backend;
+
+  (void)data;
+  DEBUGASSERT(ctx && ctx->backend);
+  backend = (struct rustls_ssl_backend_data *)ctx->backend;
+  return backend->data_pending;
+}
+
+struct io_ctx {
+  struct Curl_cfilter *cf;
+  struct Curl_easy *data;
+};
+
+static int
+read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
+{
+  struct io_ctx *io_ctx = userdata;
+  struct ssl_connect_data *const connssl = io_ctx->cf->ctx;
+  CURLcode result;
+  int ret = 0;
+  ssize_t nread = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data,
+                                    (char *)buf, len, &result);
+  if(nread < 0) {
+    nread = 0;
+    if(CURLE_AGAIN == result)
+      ret = EAGAIN;
+    else
+      ret = EINVAL;
+  }
+  else if(nread == 0)
+    connssl->peer_closed = TRUE;
+  *out_n = (int)nread;
+  return ret;
+}
+
+static int
+write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
+{
+  struct io_ctx *io_ctx = userdata;
+  CURLcode result;
+  int ret = 0;
+  ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
+                                       (const char *)buf, len, &result);
+  if(nwritten < 0) {
+    nwritten = 0;
+    if(CURLE_AGAIN == result)
+      ret = EAGAIN;
+    else
+      ret = EINVAL;
+  }
+  *out_n = (int)nwritten;
+  /*
+  CURL_TRC_CFX(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
+                len, nwritten, result));
+  */
+  return ret;
+}
+
+static ssize_t tls_recv_more(struct Curl_cfilter *cf,
+                             struct Curl_easy *data, CURLcode *err)
+{
+  struct ssl_connect_data *const connssl = cf->ctx;
+  struct rustls_ssl_backend_data *const backend =
+    (struct rustls_ssl_backend_data *)connssl->backend;
+  struct io_ctx io_ctx;
+  size_t tls_bytes_read = 0;
+  rustls_io_result io_error;
+  rustls_result rresult = 0;
+
+  io_ctx.cf = cf;
+  io_ctx.data = data;
+  io_error = rustls_connection_read_tls(backend->conn, read_cb, &io_ctx,
+                                        &tls_bytes_read);
+  if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+  else if(io_error) {
+    char buffer[STRERROR_LEN];
+    failf(data, "reading from socket: %s",
+          Curl_strerror(io_error, buffer, sizeof(buffer)));
+    *err = CURLE_READ_ERROR;
+    return -1;
+  }
+
+  rresult = rustls_connection_process_new_packets(backend->conn);
+  if(rresult != RUSTLS_RESULT_OK) {
+    char errorbuf[255];
+    size_t errorlen;
+    rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
+    failf(data, "rustls_connection_process_new_packets: %.*s",
+      (int)errorlen, errorbuf);
+    *err = map_error(rresult);
+    return -1;
+  }
+
+  backend->data_pending = TRUE;
+  *err = CURLE_OK;
+  return (ssize_t)tls_bytes_read;
+}
+
+/*
+ * On each run:
+ *  - Read a chunk of bytes from the socket into rustls' TLS input buffer.
+ *  - Tell rustls to process any new packets.
+ *  - Read out as many plaintext bytes from rustls as possible, until hitting
+ *    error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up.
+ *
+ * It's okay to call this function with plainbuf == NULL and plainlen == 0.
+ * In that case, it will copy bytes from the socket into rustls' TLS input
+ * buffer, and process packets, but won't consume bytes from rustls' plaintext
+ * output buffer.
+ */
+static ssize_t
+cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+            char *plainbuf, size_t plainlen, CURLcode *err)
+{
+  struct ssl_connect_data *const connssl = cf->ctx;
+  struct rustls_ssl_backend_data *const backend =
+    (struct rustls_ssl_backend_data *)connssl->backend;
+  struct rustls_connection *rconn = NULL;
+  size_t n = 0;
+  size_t plain_bytes_copied = 0;
+  rustls_result rresult = 0;
+  ssize_t nread;
+  bool eof = FALSE;
+
+  DEBUGASSERT(backend);
+  rconn = backend->conn;
+
+  while(plain_bytes_copied < plainlen) {
+    if(!backend->data_pending) {
+      if(tls_recv_more(cf, data, err) < 0) {
+        if(*err != CURLE_AGAIN) {
+          nread = -1;
+          goto out;
+        }
+        break;
+      }
+    }
+
+    rresult = rustls_connection_read(rconn,
+      (uint8_t *)plainbuf + plain_bytes_copied,
+      plainlen - plain_bytes_copied,
+      &n);
+    if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
+      backend->data_pending = FALSE;
+    }
+    else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) {
+      failf(data, "rustls: peer closed TCP connection "
+        "without first closing TLS connection");
+      *err = CURLE_READ_ERROR;
+      nread = -1;
+      goto out;
+    }
+    else if(rresult != RUSTLS_RESULT_OK) {
+      /* n always equals 0 in this case, don't need to check it */
+      char errorbuf[255];
+      size_t errorlen;
+      rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
+      failf(data, "rustls_connection_read: %.*s", (int)errorlen, errorbuf);
+      *err = CURLE_READ_ERROR;
+      nread = -1;
+      goto out;
+    }
+    else if(n == 0) {
+      /* n == 0 indicates clean EOF, but we may have read some other
+         plaintext bytes before we reached this. Break out of the loop
+         so we can figure out whether to return success or EOF. */
+      eof = TRUE;
+      break;
+    }
+    else {
+      plain_bytes_copied += n;
+    }
+  }
+
+  if(plain_bytes_copied) {
+    *err = CURLE_OK;
+    nread = (ssize_t)plain_bytes_copied;
+  }
+  else if(eof) {
+    *err = CURLE_OK;
+    nread = 0;
+  }
+  else {
+    *err = CURLE_AGAIN;
+    nread = -1;
+  }
+
+out:
+  CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d",
+              plainlen, nread, *err);
+  return nread;
+}
+
+/*
+ * On each call:
+ *  - Copy `plainlen` bytes into rustls' plaintext input buffer (if > 0).
+ *  - Fully drain rustls' plaintext output buffer into the socket until
+ *    we get either an error or EAGAIN/EWOULDBLOCK.
+ *
+ * It's okay to call this function with plainbuf == NULL and plainlen == 0.
+ * In that case, it won't read anything into rustls' plaintext input buffer.
+ * It will only drain rustls' plaintext output buffer into the socket.
+ */
+static ssize_t
+cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+        const void *plainbuf, size_t plainlen, CURLcode *err)
+{
+  struct ssl_connect_data *const connssl = cf->ctx;
+  struct rustls_ssl_backend_data *const backend =
+    (struct rustls_ssl_backend_data *)connssl->backend;
+  struct rustls_connection *rconn = NULL;
+  struct io_ctx io_ctx;
+  size_t plainwritten = 0;
+  size_t tlswritten = 0;
+  size_t tlswritten_total = 0;
+  rustls_result rresult;
+  rustls_io_result io_error;
+  char errorbuf[256];
+  size_t errorlen;
+
+  DEBUGASSERT(backend);
+  rconn = backend->conn;
+
+  CURL_TRC_CF(data, cf, "cf_send: %zu plain bytes", plainlen);
+
+  io_ctx.cf = cf;
+  io_ctx.data = data;
+
+  if(plainlen > 0) {
+    rresult = rustls_connection_write(rconn, plainbuf, plainlen,
+                                      &plainwritten);
+    if(rresult != RUSTLS_RESULT_OK) {
+      rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
+      failf(data, "rustls_connection_write: %.*s", (int)errorlen, errorbuf);
+      *err = CURLE_WRITE_ERROR;
+      return -1;
+    }
+    else if(plainwritten == 0) {
+      failf(data, "rustls_connection_write: EOF");
+      *err = CURLE_WRITE_ERROR;
+      return -1;
+    }
+  }
+
+  while(rustls_connection_wants_write(rconn)) {
+    io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
+                                           &tlswritten);
+    if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
+      CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
+                  tlswritten_total);
+      *err = CURLE_AGAIN;
+      return -1;
+    }
+    else if(io_error) {
+      char buffer[STRERROR_LEN];
+      failf(data, "writing to socket: %s",
+            Curl_strerror(io_error, buffer, sizeof(buffer)));
+      *err = CURLE_WRITE_ERROR;
+      return -1;
+    }
+    if(tlswritten == 0) {
+      failf(data, "EOF in swrite");
+      *err = CURLE_WRITE_ERROR;
+      return -1;
+    }
+    CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
+    tlswritten_total += tlswritten;
+  }
+
+  return plainwritten;
+}
+
+/* A server certificate verify callback for rustls that always returns
+   RUSTLS_RESULT_OK, or in other words disable certificate verification. */
+static uint32_t
+cr_verify_none(void *userdata UNUSED_PARAM,
+               const rustls_verify_server_cert_params *params UNUSED_PARAM)
+{
+  return RUSTLS_RESULT_OK;
+}
+
+static bool
+cr_hostname_is_ip(const char *hostname)
+{
+  struct in_addr in;
+#ifdef ENABLE_IPV6
+  struct in6_addr in6;
+  if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) {
+    return true;
+  }
+#endif /* ENABLE_IPV6 */
+  if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
+    return true;
+  }
+  return false;
+}
+
+static CURLcode
+cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
+                struct rustls_ssl_backend_data *const backend)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct rustls_connection *rconn = NULL;
+  struct rustls_client_config_builder *config_builder = NULL;
+  const struct rustls_root_cert_store *roots = NULL;
+  struct rustls_root_cert_store_builder *roots_builder = NULL;
+  struct rustls_web_pki_server_cert_verifier_builder *verifier_builder = NULL;
+  struct rustls_server_cert_verifier *server_cert_verifier = NULL;
+  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+  const char * const ssl_cafile =
+    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+    (ca_info_blob ? NULL : conn_config->CAfile);
+  const bool verifypeer = conn_config->verifypeer;
+  const char *hostname = connssl->peer.hostname;
+  char errorbuf[256];
+  size_t errorlen;
+  int result;
+
+  DEBUGASSERT(backend);
+  rconn = backend->conn;
+
+  config_builder = rustls_client_config_builder_new();
+  if(connssl->alpn) {
+    struct alpn_proto_buf proto;
+    rustls_slice_bytes alpn[ALPN_ENTRIES_MAX];
+    size_t i;
+
+    for(i = 0; i < connssl->alpn->count; ++i) {
+      alpn[i].data = (const uint8_t *)connssl->alpn->entries[i];
+      alpn[i].len = strlen(connssl->alpn->entries[i]);
+    }
+    rustls_client_config_builder_set_alpn_protocols(config_builder, alpn,
+                                                    connssl->alpn->count);
+    Curl_alpn_to_proto_str(&proto, connssl->alpn);
+    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+  }
+  if(!verifypeer) {
+    rustls_client_config_builder_dangerous_set_certificate_verifier(
+      config_builder, cr_verify_none);
+    /* rustls doesn't support IP addresses (as of 0.19.0), and will reject
+     * connections created with an IP address, even when certificate
+     * verification is turned off. Set a placeholder hostname and disable
+     * SNI. */
+    if(cr_hostname_is_ip(hostname)) {
+      rustls_client_config_builder_set_enable_sni(config_builder, false);
+      hostname = "example.invalid";
+    }
+  }
+  else if(ca_info_blob || ssl_cafile) {
+    roots_builder = rustls_root_cert_store_builder_new();
+
+    if(ca_info_blob) {
+      /* Enable strict parsing only if verification isn't disabled. */
+      result = rustls_root_cert_store_builder_add_pem(roots_builder,
+                                                      ca_info_blob->data,
+                                                      ca_info_blob->len,
+                                                      verifypeer);
+      if(result != RUSTLS_RESULT_OK) {
+        failf(data, "rustls: failed to parse trusted certificates from blob");
+        rustls_root_cert_store_builder_free(roots_builder);
+        rustls_client_config_free(
+          rustls_client_config_builder_build(config_builder));
+        return CURLE_SSL_CACERT_BADFILE;
+      }
+    }
+    else if(ssl_cafile) {
+      /* Enable strict parsing only if verification isn't disabled. */
+      result = rustls_root_cert_store_builder_load_roots_from_file(
+        roots_builder, ssl_cafile, verifypeer);
+      if(result != RUSTLS_RESULT_OK) {
+        failf(data, "rustls: failed to load trusted certificates");
+        rustls_root_cert_store_builder_free(roots_builder);
+        rustls_client_config_free(
+          rustls_client_config_builder_build(config_builder));
+        return CURLE_SSL_CACERT_BADFILE;
+      }
+    }
+
+    result = rustls_root_cert_store_builder_build(roots_builder, &roots);
+    rustls_root_cert_store_builder_free(roots_builder);
+    if(result != RUSTLS_RESULT_OK) {
+      failf(data, "rustls: failed to load trusted certificates");
+      rustls_client_config_free(
+        rustls_client_config_builder_build(config_builder));
+      return CURLE_SSL_CACERT_BADFILE;
+    }
+
+    verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(roots);
+
+    result = rustls_web_pki_server_cert_verifier_builder_build(
+      verifier_builder, &server_cert_verifier);
+    rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
+    if(result != RUSTLS_RESULT_OK) {
+      failf(data, "rustls: failed to load trusted certificates");
+      rustls_server_cert_verifier_free(server_cert_verifier);
+      rustls_client_config_free(
+        rustls_client_config_builder_build(config_builder));
+      return CURLE_SSL_CACERT_BADFILE;
+    }
+
+    rustls_client_config_builder_set_server_verifier(config_builder,
+                                                     server_cert_verifier);
+  }
+
+  backend->config = rustls_client_config_builder_build(config_builder);
+  DEBUGASSERT(rconn == NULL);
+  {
+    /* rustls claims to manage ip address hostnames as well here. So,
+     * if we have an SNI, we use it, otherwise we pass the hostname */
+    char *server = connssl->peer.sni?
+                   connssl->peer.sni : connssl->peer.hostname;
+    result = rustls_client_connection_new(backend->config, server, &rconn);
+  }
+  if(result != RUSTLS_RESULT_OK) {
+    rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
+    failf(data, "rustls_client_connection_new: %.*s", (int)errorlen, errorbuf);
+    return CURLE_COULDNT_CONNECT;
+  }
+  rustls_connection_set_userdata(rconn, backend);
+  backend->conn = rconn;
+  return CURLE_OK;
+}
+
+static void
+cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data,
+  const struct rustls_connection *rconn)
+{
+  const uint8_t *protocol = NULL;
+  size_t len = 0;
+
+  rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
+  Curl_alpn_set_negotiated(cf, data, protocol, len);
+}
+
+/* Given an established network connection, do a TLS handshake.
+ *
+ * If `blocking` is true, this function will block until the handshake is
+ * complete. Otherwise it will return as soon as I/O would block.
+ *
+ * For the non-blocking I/O case, this function will set `*done` to true
+ * once the handshake is complete. This function never reads the value of
+ * `*done*`.
+ */
+static CURLcode
+cr_connect_common(struct Curl_cfilter *cf,
+                  struct Curl_easy *data,
+                  bool blocking,
+                  bool *done)
+{
+  struct ssl_connect_data *const connssl = cf->ctx;
+  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+  struct rustls_ssl_backend_data *const backend =
+    (struct rustls_ssl_backend_data *)connssl->backend;
+  struct rustls_connection *rconn = NULL;
+  CURLcode tmperr = CURLE_OK;
+  int result;
+  int what;
+  bool wants_read;
+  bool wants_write;
+  curl_socket_t writefd;
+  curl_socket_t readfd;
+  timediff_t timeout_ms;
+  timediff_t socket_check_timeout;
+
+  DEBUGASSERT(backend);
+
+  if(ssl_connection_none == connssl->state) {
+    result = cr_init_backend(cf, data,
+               (struct rustls_ssl_backend_data *)connssl->backend);
+    if(result != CURLE_OK) {
+      return result;
+    }
+    connssl->state = ssl_connection_negotiating;
+  }
+
+  rconn = backend->conn;
+
+  /* Read/write data until the handshake is done or the socket would block. */
+  for(;;) {
+    /*
+    * Connection has been established according to rustls. Set send/recv
+    * handlers, and update the state machine.
+    */
+    if(!rustls_connection_is_handshaking(rconn)) {
+      infof(data, "Done handshaking");
+      /* Done with the handshake. Set up callbacks to send/receive data. */
+      connssl->state = ssl_connection_complete;
+
+      cr_set_negotiated_alpn(cf, data, rconn);
+
+      *done = TRUE;
+      return CURLE_OK;
+    }
+
+    wants_read = rustls_connection_wants_read(rconn);
+    wants_write = rustls_connection_wants_write(rconn);
+    DEBUGASSERT(wants_read || wants_write);
+    writefd = wants_write?sockfd:CURL_SOCKET_BAD;
+    readfd = wants_read?sockfd:CURL_SOCKET_BAD;
+
+    /* check allowed time left */
+    timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "rustls: operation timed out before socket check");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    socket_check_timeout = blocking?timeout_ms:0;
+
+    what = Curl_socket_check(
+      readfd, CURL_SOCKET_BAD, writefd, socket_check_timeout);
+    if(what < 0) {
+      /* fatal error */
+      failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    if(blocking && 0 == what) {
+      failf(data, "rustls connection timeout after %"
+        CURL_FORMAT_TIMEDIFF_T " ms", socket_check_timeout);
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+    if(0 == what) {
+      infof(data, "Curl_socket_check: %s would block",
+            wants_read&&wants_write ? "writing and reading" :
+            wants_write ? "writing" : "reading");
+      *done = FALSE;
+      return CURLE_OK;
+    }
+    /* socket is readable or writable */
+
+    if(wants_write) {
+      infof(data, "rustls_connection wants us to write_tls.");
+      cr_send(cf, data, NULL, 0, &tmperr);
+      if(tmperr == CURLE_AGAIN) {
+        infof(data, "writing would block");
+        /* fall through */
+      }
+      else if(tmperr != CURLE_OK) {
+        return tmperr;
+      }
+    }
+
+    if(wants_read) {
+      infof(data, "rustls_connection wants us to read_tls.");
+
+      if(tls_recv_more(cf, data, &tmperr) < 0) {
+        if(tmperr == CURLE_AGAIN) {
+          infof(data, "reading would block");
+          /* fall through */
+        }
+        else if(tmperr == CURLE_READ_ERROR) {
+          return CURLE_SSL_CONNECT_ERROR;
+        }
+        else {
+          return tmperr;
+        }
+      }
+    }
+  }
+
+  /* We should never fall through the loop. We should return either because
+     the handshake is done or because we can't read/write without blocking. */
+  DEBUGASSERT(false);
+}
+
+static CURLcode
+cr_connect_nonblocking(struct Curl_cfilter *cf,
+                       struct Curl_easy *data, bool *done)
+{
+  return cr_connect_common(cf, data, false, done);
+}
+
+static CURLcode
+cr_connect_blocking(struct Curl_cfilter *cf UNUSED_PARAM,
+           struct Curl_easy *data UNUSED_PARAM)
+{
+  bool done; /* unused */
+  return cr_connect_common(cf, data, true, &done);
+}
+
+static void cr_adjust_pollset(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              struct easy_pollset *ps)
+{
+  if(!cf->connected) {
+    curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
+    struct ssl_connect_data *const connssl = cf->ctx;
+    struct rustls_ssl_backend_data *const backend =
+      (struct rustls_ssl_backend_data *)connssl->backend;
+    struct rustls_connection *rconn = NULL;
+
+    (void)data;
+    DEBUGASSERT(backend);
+    rconn = backend->conn;
+
+    if(rustls_connection_wants_write(rconn)) {
+      Curl_pollset_add_out(data, ps, sock);
+    }
+    if(rustls_connection_wants_read(rconn)) {
+      Curl_pollset_add_in(data, ps, sock);
+    }
+  }
+}
+
+static void *
+cr_get_internals(struct ssl_connect_data *connssl,
+                 CURLINFO info UNUSED_PARAM)
+{
+  struct rustls_ssl_backend_data *backend =
+    (struct rustls_ssl_backend_data *)connssl->backend;
+  DEBUGASSERT(backend);
+  return &backend->conn;
+}
+
+static void
+cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct rustls_ssl_backend_data *backend =
+    (struct rustls_ssl_backend_data *)connssl->backend;
+  CURLcode tmperr = CURLE_OK;
+  ssize_t n = 0;
+
+  DEBUGASSERT(backend);
+
+  if(backend->conn && !connssl->peer_closed) {
+    rustls_connection_send_close_notify(backend->conn);
+    n = cr_send(cf, data, NULL, 0, &tmperr);
+    if(n < 0) {
+      failf(data, "rustls: error sending close_notify: %d", tmperr);
+    }
+
+    rustls_connection_free(backend->conn);
+    backend->conn = NULL;
+  }
+  if(backend->config) {
+    rustls_client_config_free(backend->config);
+    backend->config = NULL;
+  }
+}
+
+static size_t cr_version(char *buffer, size_t size)
+{
+  struct rustls_str ver = rustls_version();
+  return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data);
+}
+
+const struct Curl_ssl Curl_ssl_rustls = {
+  { CURLSSLBACKEND_RUSTLS, "rustls" },
+  SSLSUPP_CAINFO_BLOB |            /* supports */
+  SSLSUPP_TLS13_CIPHERSUITES |
+  SSLSUPP_HTTPS_PROXY,
+  sizeof(struct rustls_ssl_backend_data),
+
+  Curl_none_init,                  /* init */
+  Curl_none_cleanup,               /* cleanup */
+  cr_version,                      /* version */
+  Curl_none_check_cxn,             /* check_cxn */
+  Curl_none_shutdown,              /* shutdown */
+  cr_data_pending,                 /* data_pending */
+  Curl_none_random,                /* random */
+  Curl_none_cert_status_request,   /* cert_status_request */
+  cr_connect_blocking,             /* connect */
+  cr_connect_nonblocking,          /* connect_nonblocking */
+  cr_adjust_pollset,               /* adjust_pollset */
+  cr_get_internals,                /* get_internals */
+  cr_close,                        /* close_one */
+  Curl_none_close_all,             /* close_all */
+  Curl_none_session_free,          /* session_free */
+  Curl_none_set_engine,            /* set_engine */
+  Curl_none_set_engine_default,    /* set_engine_default */
+  Curl_none_engines_list,          /* engines_list */
+  Curl_none_false_start,           /* false_start */
+  NULL,                            /* sha256sum */
+  NULL,                            /* associate_connection */
+  NULL,                            /* disassociate_connection */
+  NULL,                            /* free_multi_ssl_backend_data */
+  cr_recv,                         /* recv decrypted data */
+  cr_send,                         /* send data to encrypt */
+};
+
+#endif /* USE_RUSTLS */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/rustls.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/rustls.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/rustls.h	(revision 104083)
@@ -0,0 +1,35 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Jacob Hoffman-Andrews,
+ * <github@hoffman-andrews.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#ifndef HEADER_CURL_RUSTLS_H
+#define HEADER_CURL_RUSTLS_H
+
+#include "curl_setup.h"
+
+#ifdef USE_RUSTLS
+
+extern const struct Curl_ssl Curl_ssl_rustls;
+
+#endif /* USE_RUSTLS */
+#endif /* HEADER_CURL_RUSTLS_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/schannel.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/schannel.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/schannel.c	(revision 104083)
@@ -0,0 +1,2933 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Marc Hoersken, <info@marc-hoersken.de>
+ * Copyright (C) Mark Salisbury, <mark.salisbury@hp.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all Schannel-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_SCHANNEL
+
+#ifndef USE_WINDOWS_SSPI
+#  error "Can't compile SCHANNEL support without SSPI."
+#endif
+
+#include "schannel.h"
+#include "schannel_int.h"
+#include "vtls.h"
+#include "vtls_int.h"
+#include "strcase.h"
+#include "sendf.h"
+#include "connect.h" /* for the connect timeout */
+#include "strerror.h"
+#include "select.h" /* for the socket readiness */
+#include "inet_pton.h" /* for IP addr SNI check */
+#include "curl_multibyte.h"
+#include "warnless.h"
+#include "x509asn1.h"
+#include "curl_printf.h"
+#include "multiif.h"
+#include "version_win32.h"
+#include "rand.h"
+
+/* The last #include file should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* ALPN requires version 8.1 of the Windows SDK, which was
+   shipped with Visual Studio 2013, aka _MSC_VER 1800:
+
+   https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
+*/
+#if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
+#  define HAS_ALPN 1
+#endif
+
+#ifndef BCRYPT_CHACHA20_POLY1305_ALGORITHM
+#define BCRYPT_CHACHA20_POLY1305_ALGORITHM L"CHACHA20_POLY1305"
+#endif
+
+#ifndef BCRYPT_CHAIN_MODE_CCM
+#define BCRYPT_CHAIN_MODE_CCM L"ChainingModeCCM"
+#endif
+
+#ifndef BCRYPT_CHAIN_MODE_GCM
+#define BCRYPT_CHAIN_MODE_GCM L"ChainingModeGCM"
+#endif
+
+#ifndef BCRYPT_AES_ALGORITHM
+#define BCRYPT_AES_ALGORITHM L"AES"
+#endif
+
+#ifndef BCRYPT_SHA256_ALGORITHM
+#define BCRYPT_SHA256_ALGORITHM L"SHA256"
+#endif
+
+#ifndef BCRYPT_SHA384_ALGORITHM
+#define BCRYPT_SHA384_ALGORITHM L"SHA384"
+#endif
+
+#ifdef HAS_CLIENT_CERT_PATH
+#ifdef UNICODE
+#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W
+#else
+#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A
+#endif
+#endif
+
+#ifndef SP_PROT_TLS1_0_CLIENT
+#define SP_PROT_TLS1_0_CLIENT           SP_PROT_TLS1_CLIENT
+#endif
+
+#ifndef SP_PROT_TLS1_1_CLIENT
+#define SP_PROT_TLS1_1_CLIENT           0x00000200
+#endif
+
+#ifndef SP_PROT_TLS1_2_CLIENT
+#define SP_PROT_TLS1_2_CLIENT           0x00000800
+#endif
+
+#ifndef SP_PROT_TLS1_3_CLIENT
+#define SP_PROT_TLS1_3_CLIENT           0x00002000
+#endif
+
+#ifndef SCH_USE_STRONG_CRYPTO
+#define SCH_USE_STRONG_CRYPTO           0x00400000
+#endif
+
+#ifndef SECBUFFER_ALERT
+#define SECBUFFER_ALERT                 17
+#endif
+
+/* Both schannel buffer sizes must be > 0 */
+#define CURL_SCHANNEL_BUFFER_INIT_SIZE   4096
+#define CURL_SCHANNEL_BUFFER_FREE_SIZE   1024
+
+#define CERT_THUMBPRINT_STR_LEN 40
+#define CERT_THUMBPRINT_DATA_LEN 20
+
+/* Uncomment to force verbose output
+ * #define infof(x, y, ...) printf(y, __VA_ARGS__)
+ * #define failf(x, y, ...) printf(y, __VA_ARGS__)
+ */
+
+#ifndef CALG_SHA_256
+#  define CALG_SHA_256 0x0000800c
+#endif
+
+#ifndef PKCS12_NO_PERSIST_KEY
+#define PKCS12_NO_PERSIST_KEY 0x00008000
+#endif
+
+static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
+                                             struct Curl_easy *data,
+                                             const char *pinnedpubkey);
+
+static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
+                          void *BufDataPtr, unsigned long BufByteSize)
+{
+  buffer->cbBuffer = BufByteSize;
+  buffer->BufferType = BufType;
+  buffer->pvBuffer = BufDataPtr;
+}
+
+static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
+                              unsigned long NumArrElem)
+{
+  desc->ulVersion = SECBUFFER_VERSION;
+  desc->pBuffers = BufArr;
+  desc->cBuffers = NumArrElem;
+}
+
+static CURLcode
+schannel_set_ssl_version_min_max(DWORD *enabled_protocols,
+                                 struct Curl_cfilter *cf,
+                                 struct Curl_easy *data)
+{
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  long ssl_version = conn_config->version;
+  long ssl_version_max = conn_config->version_max;
+  long i = ssl_version;
+
+  switch(ssl_version_max) {
+  case CURL_SSLVERSION_MAX_NONE:
+  case CURL_SSLVERSION_MAX_DEFAULT:
+
+    /* Windows Server 2022 and newer (including Windows 11) support TLS 1.3
+       built-in. Previous builds of Windows 10 had broken TLS 1.3
+       implementations that could be enabled via registry.
+    */
+    if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT,
+                                    VERSION_GREATER_THAN_EQUAL)) {
+      ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
+    }
+    else /* Windows 10 and older */
+      ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+
+    break;
+  }
+
+  for(; i <= (ssl_version_max >> 16); ++i) {
+    switch(i) {
+    case CURL_SSLVERSION_TLSv1_0:
+      (*enabled_protocols) |= SP_PROT_TLS1_0_CLIENT;
+      break;
+    case CURL_SSLVERSION_TLSv1_1:
+      (*enabled_protocols) |= SP_PROT_TLS1_1_CLIENT;
+      break;
+    case CURL_SSLVERSION_TLSv1_2:
+      (*enabled_protocols) |= SP_PROT_TLS1_2_CLIENT;
+      break;
+    case CURL_SSLVERSION_TLSv1_3:
+
+      /* Windows Server 2022 and newer */
+      if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT,
+                                      VERSION_GREATER_THAN_EQUAL)) {
+        (*enabled_protocols) |= SP_PROT_TLS1_3_CLIENT;
+        break;
+      }
+      else { /* Windows 10 and older */
+        failf(data, "schannel: TLS 1.3 not supported on Windows prior to 11");
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+    }
+  }
+  return CURLE_OK;
+}
+
+/* longest is 26, buffer is slightly bigger */
+#define LONGEST_ALG_ID 32
+#define CIPHEROPTION(x) {#x, x}
+
+struct algo {
+  const char *name;
+  int id;
+};
+
+static const struct algo algs[]= {
+  CIPHEROPTION(CALG_MD2),
+  CIPHEROPTION(CALG_MD4),
+  CIPHEROPTION(CALG_MD5),
+  CIPHEROPTION(CALG_SHA),
+  CIPHEROPTION(CALG_SHA1),
+  CIPHEROPTION(CALG_MAC),
+  CIPHEROPTION(CALG_RSA_SIGN),
+  CIPHEROPTION(CALG_DSS_SIGN),
+/* ifdefs for the options that are defined conditionally in wincrypt.h */
+#ifdef CALG_NO_SIGN
+  CIPHEROPTION(CALG_NO_SIGN),
+#endif
+  CIPHEROPTION(CALG_RSA_KEYX),
+  CIPHEROPTION(CALG_DES),
+#ifdef CALG_3DES_112
+  CIPHEROPTION(CALG_3DES_112),
+#endif
+  CIPHEROPTION(CALG_3DES),
+  CIPHEROPTION(CALG_DESX),
+  CIPHEROPTION(CALG_RC2),
+  CIPHEROPTION(CALG_RC4),
+  CIPHEROPTION(CALG_SEAL),
+#ifdef CALG_DH_SF
+  CIPHEROPTION(CALG_DH_SF),
+#endif
+  CIPHEROPTION(CALG_DH_EPHEM),
+#ifdef CALG_AGREEDKEY_ANY
+  CIPHEROPTION(CALG_AGREEDKEY_ANY),
+#endif
+#ifdef CALG_HUGHES_MD5
+  CIPHEROPTION(CALG_HUGHES_MD5),
+#endif
+  CIPHEROPTION(CALG_SKIPJACK),
+#ifdef CALG_TEK
+  CIPHEROPTION(CALG_TEK),
+#endif
+  CIPHEROPTION(CALG_CYLINK_MEK),
+  CIPHEROPTION(CALG_SSL3_SHAMD5),
+#ifdef CALG_SSL3_MASTER
+  CIPHEROPTION(CALG_SSL3_MASTER),
+#endif
+#ifdef CALG_SCHANNEL_MASTER_HASH
+  CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH),
+#endif
+#ifdef CALG_SCHANNEL_MAC_KEY
+  CIPHEROPTION(CALG_SCHANNEL_MAC_KEY),
+#endif
+#ifdef CALG_SCHANNEL_ENC_KEY
+  CIPHEROPTION(CALG_SCHANNEL_ENC_KEY),
+#endif
+#ifdef CALG_PCT1_MASTER
+  CIPHEROPTION(CALG_PCT1_MASTER),
+#endif
+#ifdef CALG_SSL2_MASTER
+  CIPHEROPTION(CALG_SSL2_MASTER),
+#endif
+#ifdef CALG_TLS1_MASTER
+  CIPHEROPTION(CALG_TLS1_MASTER),
+#endif
+#ifdef CALG_RC5
+  CIPHEROPTION(CALG_RC5),
+#endif
+#ifdef CALG_HMAC
+  CIPHEROPTION(CALG_HMAC),
+#endif
+#ifdef CALG_TLS1PRF
+  CIPHEROPTION(CALG_TLS1PRF),
+#endif
+#ifdef CALG_HASH_REPLACE_OWF
+  CIPHEROPTION(CALG_HASH_REPLACE_OWF),
+#endif
+#ifdef CALG_AES_128
+  CIPHEROPTION(CALG_AES_128),
+#endif
+#ifdef CALG_AES_192
+  CIPHEROPTION(CALG_AES_192),
+#endif
+#ifdef CALG_AES_256
+  CIPHEROPTION(CALG_AES_256),
+#endif
+#ifdef CALG_AES
+  CIPHEROPTION(CALG_AES),
+#endif
+#ifdef CALG_SHA_256
+  CIPHEROPTION(CALG_SHA_256),
+#endif
+#ifdef CALG_SHA_384
+  CIPHEROPTION(CALG_SHA_384),
+#endif
+#ifdef CALG_SHA_512
+  CIPHEROPTION(CALG_SHA_512),
+#endif
+#ifdef CALG_ECDH
+  CIPHEROPTION(CALG_ECDH),
+#endif
+#ifdef CALG_ECMQV
+  CIPHEROPTION(CALG_ECMQV),
+#endif
+#ifdef CALG_ECDSA
+  CIPHEROPTION(CALG_ECDSA),
+#endif
+#ifdef CALG_ECDH_EPHEM
+  CIPHEROPTION(CALG_ECDH_EPHEM),
+#endif
+  {NULL, 0},
+};
+
+static int
+get_alg_id_by_name(char *name)
+{
+  char *nameEnd = strchr(name, ':');
+  size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name);
+  int i;
+
+  for(i = 0; algs[i].name; i++) {
+    if((n == strlen(algs[i].name) && !strncmp(algs[i].name, name, n)))
+      return algs[i].id;
+  }
+  return 0; /* not found */
+}
+
+#define NUM_CIPHERS 47 /* There are 47 options listed above */
+
+static CURLcode
+set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
+                ALG_ID *algIds)
+{
+  char *startCur = ciphers;
+  int algCount = 0;
+  while(startCur && (0 != *startCur) && (algCount < NUM_CIPHERS)) {
+    long alg = strtol(startCur, 0, 0);
+    if(!alg)
+      alg = get_alg_id_by_name(startCur);
+    if(alg)
+      algIds[algCount++] = alg;
+    else if(!strncmp(startCur, "USE_STRONG_CRYPTO",
+                     sizeof("USE_STRONG_CRYPTO") - 1) ||
+            !strncmp(startCur, "SCH_USE_STRONG_CRYPTO",
+                     sizeof("SCH_USE_STRONG_CRYPTO") - 1))
+      schannel_cred->dwFlags |= SCH_USE_STRONG_CRYPTO;
+    else
+      return CURLE_SSL_CIPHER;
+    startCur = strchr(startCur, ':');
+    if(startCur)
+      startCur++;
+  }
+  schannel_cred->palgSupportedAlgs = algIds;
+  schannel_cred->cSupportedAlgs = algCount;
+  return CURLE_OK;
+}
+
+#ifdef HAS_CLIENT_CERT_PATH
+
+/* Function allocates memory for store_path only if CURLE_OK is returned */
+static CURLcode
+get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
+                  TCHAR **thumbprint)
+{
+  TCHAR *sep;
+  TCHAR *store_path_start;
+  size_t store_name_len;
+
+  sep = _tcschr(path, TEXT('\\'));
+  if(!sep)
+    return CURLE_SSL_CERTPROBLEM;
+
+  store_name_len = sep - path;
+
+  if(_tcsncmp(path, TEXT("CurrentUser"), store_name_len) == 0)
+    *store_name = CERT_SYSTEM_STORE_CURRENT_USER;
+  else if(_tcsncmp(path, TEXT("LocalMachine"), store_name_len) == 0)
+    *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE;
+  else if(_tcsncmp(path, TEXT("CurrentService"), store_name_len) == 0)
+    *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE;
+  else if(_tcsncmp(path, TEXT("Services"), store_name_len) == 0)
+    *store_name = CERT_SYSTEM_STORE_SERVICES;
+  else if(_tcsncmp(path, TEXT("Users"), store_name_len) == 0)
+    *store_name = CERT_SYSTEM_STORE_USERS;
+  else if(_tcsncmp(path, TEXT("CurrentUserGroupPolicy"),
+                   store_name_len) == 0)
+    *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
+  else if(_tcsncmp(path, TEXT("LocalMachineGroupPolicy"),
+                   store_name_len) == 0)
+    *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
+  else if(_tcsncmp(path, TEXT("LocalMachineEnterprise"),
+                   store_name_len) == 0)
+    *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
+  else
+    return CURLE_SSL_CERTPROBLEM;
+
+  store_path_start = sep + 1;
+
+  sep = _tcschr(store_path_start, TEXT('\\'));
+  if(!sep)
+    return CURLE_SSL_CERTPROBLEM;
+
+  *thumbprint = sep + 1;
+  if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
+    return CURLE_SSL_CERTPROBLEM;
+
+  *sep = TEXT('\0');
+  *store_path = _tcsdup(store_path_start);
+  *sep = TEXT('\\');
+  if(!*store_path)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+#endif
+
+static bool algo(const char *check, char *namep, size_t nlen)
+{
+  return (strlen(check) == nlen) && !strncmp(check, namep, nlen);
+}
+
+static CURLcode
+schannel_acquire_credential_handle(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+
+#ifdef HAS_CLIENT_CERT_PATH
+  PCCERT_CONTEXT client_certs[1] = { NULL };
+  HCERTSTORE client_cert_store = NULL;
+#endif
+  SECURITY_STATUS sspi_status = SEC_E_OK;
+  CURLcode result;
+
+  /* setup Schannel API options */
+  DWORD flags = 0;
+  DWORD enabled_protocols = 0;
+
+  struct schannel_ssl_backend_data *backend =
+    (struct schannel_ssl_backend_data *)(connssl->backend);
+
+  DEBUGASSERT(backend);
+
+  if(conn_config->verifypeer) {
+#ifdef HAS_MANUAL_VERIFY_API
+    if(backend->use_manual_cred_validation)
+      flags = SCH_CRED_MANUAL_CRED_VALIDATION;
+    else
+#endif
+      flags = SCH_CRED_AUTO_CRED_VALIDATION;
+
+    if(ssl_config->no_revoke) {
+      flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+        SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+
+      DEBUGF(infof(data, "schannel: disabled server certificate revocation "
+                   "checks"));
+    }
+    else if(ssl_config->revoke_best_effort) {
+      flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+        SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
+
+      DEBUGF(infof(data, "schannel: ignore revocation offline errors"));
+    }
+    else {
+      flags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
+
+      DEBUGF(infof(data,
+                   "schannel: checking server certificate revocation"));
+    }
+  }
+  else {
+    flags = SCH_CRED_MANUAL_CRED_VALIDATION |
+      SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+      SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+    DEBUGF(infof(data,
+                 "schannel: disabled server cert revocation checks"));
+  }
+
+  if(!conn_config->verifyhost) {
+    flags |= SCH_CRED_NO_SERVERNAME_CHECK;
+    DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
+                 "comparing the supplied target name with the subject "
+                 "names in server certificates."));
+  }
+
+  if(!ssl_config->auto_client_cert) {
+    flags &= ~SCH_CRED_USE_DEFAULT_CREDS;
+    flags |= SCH_CRED_NO_DEFAULT_CREDS;
+    infof(data, "schannel: disabled automatic use of client certificate");
+  }
+  else
+    infof(data, "schannel: enabled automatic use of client certificate");
+
+  switch(conn_config->version) {
+  case CURL_SSLVERSION_DEFAULT:
+  case CURL_SSLVERSION_TLSv1:
+  case CURL_SSLVERSION_TLSv1_0:
+  case CURL_SSLVERSION_TLSv1_1:
+  case CURL_SSLVERSION_TLSv1_2:
+  case CURL_SSLVERSION_TLSv1_3:
+  {
+    result = schannel_set_ssl_version_min_max(&enabled_protocols, cf, data);
+    if(result != CURLE_OK)
+      return result;
+    break;
+  }
+  case CURL_SSLVERSION_SSLv3:
+  case CURL_SSLVERSION_SSLv2:
+    failf(data, "SSL versions not supported");
+    return CURLE_NOT_BUILT_IN;
+  default:
+    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+#ifdef HAS_CLIENT_CERT_PATH
+  /* client certificate */
+  if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
+    DWORD cert_store_name = 0;
+    TCHAR *cert_store_path = NULL;
+    TCHAR *cert_thumbprint_str = NULL;
+    CRYPT_HASH_BLOB cert_thumbprint;
+    BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
+    HCERTSTORE cert_store = NULL;
+    FILE *fInCert = NULL;
+    void *certdata = NULL;
+    size_t certsize = 0;
+    bool blob = data->set.ssl.primary.cert_blob != NULL;
+    TCHAR *cert_path = NULL;
+    if(blob) {
+      certdata = data->set.ssl.primary.cert_blob->data;
+      certsize = data->set.ssl.primary.cert_blob->len;
+    }
+    else {
+      cert_path = curlx_convert_UTF8_to_tchar(
+        data->set.ssl.primary.clientcert);
+      if(!cert_path)
+        return CURLE_OUT_OF_MEMORY;
+
+      result = get_cert_location(cert_path, &cert_store_name,
+                                 &cert_store_path, &cert_thumbprint_str);
+
+      if(result && (data->set.ssl.primary.clientcert[0]!='\0'))
+        fInCert = fopen(data->set.ssl.primary.clientcert, "rb");
+
+      if(result && !fInCert) {
+        failf(data, "schannel: Failed to get certificate location"
+              " or file for %s",
+              data->set.ssl.primary.clientcert);
+        curlx_unicodefree(cert_path);
+        return result;
+      }
+    }
+
+    if((fInCert || blob) && (data->set.ssl.cert_type) &&
+       (!strcasecompare(data->set.ssl.cert_type, "P12"))) {
+      failf(data, "schannel: certificate format compatibility error "
+            " for %s",
+            blob ? "(memory blob)" : data->set.ssl.primary.clientcert);
+      curlx_unicodefree(cert_path);
+      return CURLE_SSL_CERTPROBLEM;
+    }
+
+    if(fInCert || blob) {
+      /* Reading a .P12 or .pfx file, like the example at bottom of
+         https://social.msdn.microsoft.com/Forums/windowsdesktop/
+         en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
+      */
+      CRYPT_DATA_BLOB datablob;
+      WCHAR* pszPassword;
+      size_t pwd_len = 0;
+      int str_w_len = 0;
+      const char *cert_showfilename_error = blob ?
+        "(memory blob)" : data->set.ssl.primary.clientcert;
+      curlx_unicodefree(cert_path);
+      if(fInCert) {
+        long cert_tell = 0;
+        bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
+        if(continue_reading)
+          cert_tell = ftell(fInCert);
+        if(cert_tell < 0)
+          continue_reading = FALSE;
+        else
+          certsize = (size_t)cert_tell;
+        if(continue_reading)
+          continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
+        if(continue_reading)
+          certdata = malloc(certsize + 1);
+        if((!certdata) ||
+           ((int) fread(certdata, certsize, 1, fInCert) != 1))
+          continue_reading = FALSE;
+        fclose(fInCert);
+        if(!continue_reading) {
+          failf(data, "schannel: Failed to read cert file %s",
+                data->set.ssl.primary.clientcert);
+          free(certdata);
+          return CURLE_SSL_CERTPROBLEM;
+        }
+      }
+
+      /* Convert key-pair data to the in-memory certificate store */
+      datablob.pbData = (BYTE*)certdata;
+      datablob.cbData = (DWORD)certsize;
+
+      if(data->set.ssl.key_passwd)
+        pwd_len = strlen(data->set.ssl.key_passwd);
+      pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
+      if(pszPassword) {
+        if(pwd_len > 0)
+          str_w_len = MultiByteToWideChar(CP_UTF8,
+                                          MB_ERR_INVALID_CHARS,
+                                          data->set.ssl.key_passwd,
+                                          (int)pwd_len,
+                                          pszPassword, (int)(pwd_len + 1));
+
+        if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
+          pszPassword[str_w_len] = 0;
+        else
+          pszPassword[0] = 0;
+
+        if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
+                                        VERSION_GREATER_THAN_EQUAL))
+          cert_store = PFXImportCertStore(&datablob, pszPassword,
+                                          PKCS12_NO_PERSIST_KEY);
+        else
+          cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
+
+        free(pszPassword);
+      }
+      if(!blob)
+        free(certdata);
+      if(!cert_store) {
+        DWORD errorcode = GetLastError();
+        if(errorcode == ERROR_INVALID_PASSWORD)
+          failf(data, "schannel: Failed to import cert file %s, "
+                "password is bad",
+                cert_showfilename_error);
+        else
+          failf(data, "schannel: Failed to import cert file %s, "
+                "last error is 0x%lx",
+                cert_showfilename_error, errorcode);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+
+      client_certs[0] = CertFindCertificateInStore(
+        cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
+        CERT_FIND_ANY, NULL, NULL);
+
+      if(!client_certs[0]) {
+        failf(data, "schannel: Failed to get certificate from file %s"
+              ", last error is 0x%lx",
+              cert_showfilename_error, GetLastError());
+        CertCloseStore(cert_store, 0);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+    }
+    else {
+      cert_store =
+        CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
+                      (HCRYPTPROV)NULL,
+                      CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
+                      cert_store_path);
+      if(!cert_store) {
+        char *path_utf8 =
+          curlx_convert_tchar_to_UTF8(cert_store_path);
+        failf(data, "schannel: Failed to open cert store %lx %s, "
+              "last error is 0x%lx",
+              cert_store_name,
+              (path_utf8 ? path_utf8 : "(unknown)"),
+              GetLastError());
+        free(cert_store_path);
+        curlx_unicodefree(path_utf8);
+        curlx_unicodefree(cert_path);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+      free(cert_store_path);
+
+      cert_thumbprint.pbData = cert_thumbprint_data;
+      cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
+
+      if(!CryptStringToBinary(cert_thumbprint_str,
+                              CERT_THUMBPRINT_STR_LEN,
+                              CRYPT_STRING_HEX,
+                              cert_thumbprint_data,
+                              &cert_thumbprint.cbData,
+                              NULL, NULL)) {
+        curlx_unicodefree(cert_path);
+        CertCloseStore(cert_store, 0);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+
+      client_certs[0] = CertFindCertificateInStore(
+        cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
+        CERT_FIND_HASH, &cert_thumbprint, NULL);
+
+      curlx_unicodefree(cert_path);
+
+      if(!client_certs[0]) {
+        /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
+        CertCloseStore(cert_store, 0);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+    }
+    client_cert_store = cert_store;
+  }
+#else
+  if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
+    failf(data, "schannel: client cert support not built in");
+    return CURLE_NOT_BUILT_IN;
+  }
+#endif
+
+  /* allocate memory for the reusable credential handle */
+  backend->cred = (struct Curl_schannel_cred *)
+    calloc(1, sizeof(struct Curl_schannel_cred));
+  if(!backend->cred) {
+    failf(data, "schannel: unable to allocate memory");
+
+#ifdef HAS_CLIENT_CERT_PATH
+    if(client_certs[0])
+      CertFreeCertificateContext(client_certs[0]);
+    if(client_cert_store)
+      CertCloseStore(client_cert_store, 0);
+#endif
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+  backend->cred->refcount = 1;
+
+#ifdef HAS_CLIENT_CERT_PATH
+  /* Since we did not persist the key, we need to extend the store's
+   * lifetime until the end of the connection
+   */
+  backend->cred->client_cert_store = client_cert_store;
+#endif
+
+  /* We support TLS 1.3 starting in Windows 10 version 1809 (OS build 17763) as
+     long as the user did not set a legacy algorithm list
+     (CURLOPT_SSL_CIPHER_LIST). */
+  if(!conn_config->cipher_list &&
+     curlx_verify_windows_version(10, 0, 17763, PLATFORM_WINNT,
+                                  VERSION_GREATER_THAN_EQUAL)) {
+
+    char *ciphers13 = 0;
+
+    bool disable_aes_gcm_sha384 = FALSE;
+    bool disable_aes_gcm_sha256 = FALSE;
+    bool disable_chacha_poly = FALSE;
+    bool disable_aes_ccm_8_sha256 = FALSE;
+    bool disable_aes_ccm_sha256 = FALSE;
+
+    SCH_CREDENTIALS credentials = { 0 };
+    TLS_PARAMETERS tls_parameters = { 0 };
+    CRYPTO_SETTINGS crypto_settings[4] = { { 0 } };
+    UNICODE_STRING blocked_ccm_modes[1] = { { 0 } };
+    UNICODE_STRING blocked_gcm_modes[1] = { { 0 } };
+
+    int crypto_settings_idx = 0;
+
+
+    /* If TLS 1.3 ciphers are explicitly listed, then
+     * disable all the ciphers and re-enable which
+     * ciphers the user has provided.
+     */
+    ciphers13 = conn_config->cipher_list13;
+    if(ciphers13) {
+      const int remaining_ciphers = 5;
+
+      /* detect which remaining ciphers to enable
+         and then disable everything else.
+      */
+
+      char *startCur = ciphers13;
+      int algCount = 0;
+      char *nameEnd;
+
+      disable_aes_gcm_sha384 = TRUE;
+      disable_aes_gcm_sha256 = TRUE;
+      disable_chacha_poly = TRUE;
+      disable_aes_ccm_8_sha256 = TRUE;
+      disable_aes_ccm_sha256 = TRUE;
+
+      while(startCur && (0 != *startCur) && (algCount < remaining_ciphers)) {
+        size_t n;
+        char *namep;
+        nameEnd = strchr(startCur, ':');
+        n = nameEnd ? (size_t)(nameEnd - startCur) : strlen(startCur);
+        namep = startCur;
+
+        if(disable_aes_gcm_sha384 &&
+           algo("TLS_AES_256_GCM_SHA384", namep, n)) {
+          disable_aes_gcm_sha384 = FALSE;
+        }
+        else if(disable_aes_gcm_sha256
+                && algo("TLS_AES_128_GCM_SHA256", namep, n)) {
+          disable_aes_gcm_sha256 = FALSE;
+        }
+        else if(disable_chacha_poly
+                && algo("TLS_CHACHA20_POLY1305_SHA256", namep, n)) {
+          disable_chacha_poly = FALSE;
+        }
+        else if(disable_aes_ccm_8_sha256
+                && algo("TLS_AES_128_CCM_8_SHA256", namep, n)) {
+          disable_aes_ccm_8_sha256 = FALSE;
+        }
+        else if(disable_aes_ccm_sha256
+                && algo("TLS_AES_128_CCM_SHA256", namep, n)) {
+          disable_aes_ccm_sha256 = FALSE;
+        }
+        else {
+          failf(data, "schannel: Unknown TLS 1.3 cipher: %.*s", (int)n, namep);
+          return CURLE_SSL_CIPHER;
+        }
+
+        startCur = nameEnd;
+        if(startCur)
+          startCur++;
+
+        algCount++;
+      }
+    }
+
+    if(disable_aes_gcm_sha384 && disable_aes_gcm_sha256
+       && disable_chacha_poly && disable_aes_ccm_8_sha256
+       && disable_aes_ccm_sha256) {
+      failf(data, "schannel: All available TLS 1.3 ciphers were disabled");
+      return CURLE_SSL_CIPHER;
+    }
+
+    /* Disable TLS_AES_128_CCM_8_SHA256 and/or TLS_AES_128_CCM_SHA256 */
+    if(disable_aes_ccm_8_sha256 || disable_aes_ccm_sha256) {
+      /*
+        Disallow AES_CCM algorithm.
+      */
+      blocked_ccm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_CCM);
+      blocked_ccm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_CCM);
+      blocked_ccm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_CCM;
+
+      crypto_settings[crypto_settings_idx].eAlgorithmUsage =
+        TlsParametersCngAlgUsageCipher;
+      crypto_settings[crypto_settings_idx].rgstrChainingModes =
+        blocked_ccm_modes;
+      crypto_settings[crypto_settings_idx].cChainingModes =
+        ARRAYSIZE(blocked_ccm_modes);
+      crypto_settings[crypto_settings_idx].strCngAlgId.Length =
+        sizeof(BCRYPT_AES_ALGORITHM);
+      crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
+        sizeof(BCRYPT_AES_ALGORITHM);
+      crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
+        (PWSTR)BCRYPT_AES_ALGORITHM;
+
+      /* only disabling one of the CCM modes */
+      if(disable_aes_ccm_8_sha256 != disable_aes_ccm_sha256) {
+        if(disable_aes_ccm_8_sha256)
+          crypto_settings[crypto_settings_idx].dwMinBitLength = 128;
+        else /* disable_aes_ccm_sha256 */
+          crypto_settings[crypto_settings_idx].dwMaxBitLength = 64;
+      }
+
+      crypto_settings_idx++;
+    }
+
+    /* Disable TLS_AES_256_GCM_SHA384 and/or TLS_AES_128_GCM_SHA256 */
+    if(disable_aes_gcm_sha384 || disable_aes_gcm_sha256) {
+
+      /*
+        Disallow AES_GCM algorithm
+      */
+      blocked_gcm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_GCM);
+      blocked_gcm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_GCM);
+      blocked_gcm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_GCM;
+
+      /* if only one is disabled, then explicitly disable the
+         digest cipher suite (sha384 or sha256) */
+      if(disable_aes_gcm_sha384 != disable_aes_gcm_sha256) {
+        crypto_settings[crypto_settings_idx].eAlgorithmUsage =
+          TlsParametersCngAlgUsageDigest;
+        crypto_settings[crypto_settings_idx].strCngAlgId.Length =
+          sizeof(disable_aes_gcm_sha384 ?
+                 BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
+        crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
+          sizeof(disable_aes_gcm_sha384 ?
+                 BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
+        crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
+          (PWSTR)(disable_aes_gcm_sha384 ?
+                  BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
+      }
+      else { /* Disable both AES_GCM ciphers */
+        crypto_settings[crypto_settings_idx].eAlgorithmUsage =
+          TlsParametersCngAlgUsageCipher;
+        crypto_settings[crypto_settings_idx].strCngAlgId.Length =
+          sizeof(BCRYPT_AES_ALGORITHM);
+        crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
+          sizeof(BCRYPT_AES_ALGORITHM);
+        crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
+          (PWSTR)BCRYPT_AES_ALGORITHM;
+      }
+
+      crypto_settings[crypto_settings_idx].rgstrChainingModes =
+        blocked_gcm_modes;
+      crypto_settings[crypto_settings_idx].cChainingModes = 1;
+
+      crypto_settings_idx++;
+    }
+
+    /*
+      Disable ChaCha20-Poly1305.
+    */
+    if(disable_chacha_poly) {
+      crypto_settings[crypto_settings_idx].eAlgorithmUsage =
+        TlsParametersCngAlgUsageCipher;
+      crypto_settings[crypto_settings_idx].strCngAlgId.Length =
+        sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM);
+      crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
+        sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM);
+      crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
+        (PWSTR)BCRYPT_CHACHA20_POLY1305_ALGORITHM;
+      crypto_settings_idx++;
+    }
+
+    tls_parameters.pDisabledCrypto = crypto_settings;
+
+    /* The number of blocked suites */
+    tls_parameters.cDisabledCrypto = crypto_settings_idx;
+    credentials.pTlsParameters = &tls_parameters;
+    credentials.cTlsParameters = 1;
+
+    credentials.dwVersion = SCH_CREDENTIALS_VERSION;
+    credentials.dwFlags = flags | SCH_USE_STRONG_CRYPTO;
+
+    credentials.pTlsParameters->grbitDisabledProtocols =
+      (DWORD)~enabled_protocols;
+
+#ifdef HAS_CLIENT_CERT_PATH
+    if(client_certs[0]) {
+      credentials.cCreds = 1;
+      credentials.paCred = client_certs;
+    }
+#endif
+
+    sspi_status =
+      s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
+                                         SECPKG_CRED_OUTBOUND, NULL,
+                                         &credentials, NULL, NULL,
+                                         &backend->cred->cred_handle,
+                                         &backend->cred->time_stamp);
+  }
+  else {
+    /* Pre-Windows 10 1809 or the user set a legacy algorithm list. Although MS
+       doesn't document it, currently Schannel will not negotiate TLS 1.3 when
+       SCHANNEL_CRED is used. */
+    ALG_ID algIds[NUM_CIPHERS];
+    char *ciphers = conn_config->cipher_list;
+    SCHANNEL_CRED schannel_cred = { 0 };
+    schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
+    schannel_cred.dwFlags = flags;
+    schannel_cred.grbitEnabledProtocols = enabled_protocols;
+
+    if(ciphers) {
+      if((enabled_protocols & SP_PROT_TLS1_3_CLIENT)) {
+        infof(data, "schannel: WARNING: This version of Schannel may "
+              "negotiate a less-secure TLS version than TLS 1.3 because the "
+              "user set an algorithm cipher list.");
+      }
+      if(conn_config->cipher_list13) {
+        failf(data, "schannel: This version of Schannel does not support "
+              "setting an algorithm cipher list and TLS 1.3 cipher list at "
+              "the same time");
+        return CURLE_SSL_CIPHER;
+      }
+      result = set_ssl_ciphers(&schannel_cred, ciphers, algIds);
+      if(CURLE_OK != result) {
+        failf(data, "schannel: Failed setting algorithm cipher list");
+        return result;
+      }
+    }
+    else {
+      schannel_cred.dwFlags = flags | SCH_USE_STRONG_CRYPTO;
+    }
+
+#ifdef HAS_CLIENT_CERT_PATH
+    if(client_certs[0]) {
+      schannel_cred.cCreds = 1;
+      schannel_cred.paCred = client_certs;
+    }
+#endif
+
+    sspi_status =
+      s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
+                                         SECPKG_CRED_OUTBOUND, NULL,
+                                         &schannel_cred, NULL, NULL,
+                                         &backend->cred->cred_handle,
+                                         &backend->cred->time_stamp);
+  }
+
+#ifdef HAS_CLIENT_CERT_PATH
+  if(client_certs[0])
+    CertFreeCertificateContext(client_certs[0]);
+#endif
+
+  if(sspi_status != SEC_E_OK) {
+    char buffer[STRERROR_LEN];
+    failf(data, "schannel: AcquireCredentialsHandle failed: %s",
+          Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+    Curl_safefree(backend->cred);
+    switch(sspi_status) {
+    case SEC_E_INSUFFICIENT_MEMORY:
+      return CURLE_OUT_OF_MEMORY;
+    case SEC_E_NO_CREDENTIALS:
+    case SEC_E_SECPKG_NOT_FOUND:
+    case SEC_E_NOT_OWNER:
+    case SEC_E_UNKNOWN_CREDENTIALS:
+    case SEC_E_INTERNAL_ERROR:
+    default:
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  ssize_t written = -1;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct schannel_ssl_backend_data *backend =
+    (struct schannel_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  SecBuffer outbuf;
+  SecBufferDesc outbuf_desc;
+  SecBuffer inbuf;
+  SecBufferDesc inbuf_desc;
+#ifdef HAS_ALPN
+  unsigned char alpn_buffer[128];
+#endif
+  SECURITY_STATUS sspi_status = SEC_E_OK;
+  struct Curl_schannel_cred *old_cred = NULL;
+  CURLcode result;
+
+  DEBUGASSERT(backend);
+  DEBUGF(infof(data,
+               "schannel: SSL/TLS connection with %s port %d (step 1/3)",
+               connssl->peer.hostname, connssl->port));
+
+  if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
+                                  VERSION_LESS_THAN_EQUAL)) {
+    /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
+       algorithms that may not be supported by all servers. */
+    infof(data, "schannel: Windows version is old and may not be able to "
+          "connect to some servers due to lack of SNI, algorithms, etc.");
+  }
+
+#ifdef HAS_ALPN
+  /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
+     Also it doesn't seem to be supported for Wine, see curl bug #983. */
+  backend->use_alpn = connssl->alpn &&
+    !GetProcAddress(GetModuleHandle(TEXT("ntdll")),
+                    "wine_get_version") &&
+    curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
+                                 VERSION_GREATER_THAN_EQUAL);
+#else
+  backend->use_alpn = false;
+#endif
+
+#ifdef _WIN32_WCE
+#ifdef HAS_MANUAL_VERIFY_API
+  /* certificate validation on CE doesn't seem to work right; we'll
+   * do it following a more manual process. */
+  backend->use_manual_cred_validation = true;
+#else
+#error "compiler too old to support requisite manual cert verify for Win CE"
+#endif
+#else
+#ifdef HAS_MANUAL_VERIFY_API
+  if(conn_config->CAfile || conn_config->ca_info_blob) {
+    if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
+                                    VERSION_GREATER_THAN_EQUAL)) {
+      backend->use_manual_cred_validation = true;
+    }
+    else {
+      failf(data, "schannel: this version of Windows is too old to support "
+            "certificate verification via CA bundle file.");
+      return CURLE_SSL_CACERT_BADFILE;
+    }
+  }
+  else
+    backend->use_manual_cred_validation = false;
+#else
+  if(conn_config->CAfile || conn_config->ca_info_blob) {
+    failf(data, "schannel: CA cert support not built in");
+    return CURLE_NOT_BUILT_IN;
+  }
+#endif
+#endif
+
+  backend->cred = NULL;
+
+  /* check for an existing reusable credential handle */
+  if(ssl_config->primary.sessionid) {
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)) {
+      backend->cred = old_cred;
+      DEBUGF(infof(data, "schannel: reusing existing credential handle"));
+
+      /* increment the reference counter of the credential/session handle */
+      backend->cred->refcount++;
+      DEBUGF(infof(data,
+                   "schannel: incremented credential handle refcount = %d",
+                   backend->cred->refcount));
+    }
+    Curl_ssl_sessionid_unlock(data);
+  }
+
+  if(!backend->cred) {
+    char *snihost;
+    result = schannel_acquire_credential_handle(cf, data);
+    if(result)
+      return result;
+    /* schannel_acquire_credential_handle() sets backend->cred accordingly or
+       it returns error otherwise. */
+
+    /* A hostname associated with the credential is needed by
+       InitializeSecurityContext for SNI and other reasons. */
+    snihost = connssl->peer.sni? connssl->peer.sni : connssl->peer.hostname;
+    backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost);
+    if(!backend->cred->sni_hostname)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Warn if SNI is disabled due to use of an IP address */
+  if(connssl->peer.type != CURL_SSL_PEER_DNS) {
+    infof(data, "schannel: using IP address, SNI is not supported by OS.");
+  }
+
+#ifdef HAS_ALPN
+  if(backend->use_alpn) {
+    int cur = 0;
+    int list_start_index = 0;
+    unsigned int *extension_len = NULL;
+    unsigned short* list_len = NULL;
+    struct alpn_proto_buf proto;
+
+    /* The first four bytes will be an unsigned int indicating number
+       of bytes of data in the rest of the buffer. */
+    extension_len = (unsigned int *)(void *)(&alpn_buffer[cur]);
+    cur += (int)sizeof(unsigned int);
+
+    /* The next four bytes are an indicator that this buffer will contain
+       ALPN data, as opposed to NPN, for example. */
+    *(unsigned int *)(void *)&alpn_buffer[cur] =
+      SecApplicationProtocolNegotiationExt_ALPN;
+    cur += (int)sizeof(unsigned int);
+
+    /* The next two bytes will be an unsigned short indicating the number
+       of bytes used to list the preferred protocols. */
+    list_len = (unsigned short*)(void *)(&alpn_buffer[cur]);
+    cur += (int)sizeof(unsigned short);
+
+    list_start_index = cur;
+
+    result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
+    if(result) {
+      failf(data, "Error setting ALPN");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    memcpy(&alpn_buffer[cur], proto.data, proto.len);
+    cur += proto.len;
+
+    *list_len = curlx_uitous(cur - list_start_index);
+    *extension_len = (unsigned int)(*list_len +
+      sizeof(unsigned int) + sizeof(unsigned short));
+
+    InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
+    InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
+
+    Curl_alpn_to_proto_str(&proto, connssl->alpn);
+    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+  }
+  else {
+    InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
+    InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
+  }
+#else /* HAS_ALPN */
+  InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
+  InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
+#endif
+
+  /* setup output buffer */
+  InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
+  InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
+
+  /* security request flags */
+  backend->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
+    ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
+    ISC_REQ_STREAM;
+
+  if(!ssl_config->auto_client_cert) {
+    backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
+  }
+
+  /* allocate memory for the security context handle */
+  backend->ctxt = (struct Curl_schannel_ctxt *)
+    calloc(1, sizeof(struct Curl_schannel_ctxt));
+  if(!backend->ctxt) {
+    failf(data, "schannel: unable to allocate memory");
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Schannel InitializeSecurityContext:
+     https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
+
+     At the moment we don't pass inbuf unless we're using ALPN since we only
+     use it for that, and Wine (for which we currently disable ALPN) is giving
+     us problems with inbuf regardless. https://github.com/curl/curl/issues/983
+  */
+  sspi_status = s_pSecFn->InitializeSecurityContext(
+    &backend->cred->cred_handle, NULL, backend->cred->sni_hostname,
+    backend->req_flags, 0, 0,
+    (backend->use_alpn ? &inbuf_desc : NULL),
+    0, &backend->ctxt->ctxt_handle,
+    &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
+
+  if(sspi_status != SEC_I_CONTINUE_NEEDED) {
+    char buffer[STRERROR_LEN];
+    Curl_safefree(backend->ctxt);
+    switch(sspi_status) {
+    case SEC_E_INSUFFICIENT_MEMORY:
+      failf(data, "schannel: initial InitializeSecurityContext failed: %s",
+            Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+      return CURLE_OUT_OF_MEMORY;
+    case SEC_E_WRONG_PRINCIPAL:
+      failf(data, "schannel: SNI or certificate check failed: %s",
+            Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+      return CURLE_PEER_FAILED_VERIFICATION;
+      /*
+        case SEC_E_INVALID_HANDLE:
+        case SEC_E_INVALID_TOKEN:
+        case SEC_E_LOGON_DENIED:
+        case SEC_E_TARGET_UNKNOWN:
+        case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+        case SEC_E_INTERNAL_ERROR:
+        case SEC_E_NO_CREDENTIALS:
+        case SEC_E_UNSUPPORTED_FUNCTION:
+        case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
+      */
+    default:
+      failf(data, "schannel: initial InitializeSecurityContext failed: %s",
+            Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+
+  DEBUGF(infof(data, "schannel: sending initial handshake data: "
+               "sending %lu bytes.", outbuf.cbBuffer));
+
+  /* send initial handshake data which is now stored in output buffer */
+  written = Curl_conn_cf_send(cf->next, data,
+                              outbuf.pvBuffer, outbuf.cbBuffer,
+                              &result);
+  s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
+  if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
+    failf(data, "schannel: failed to send initial handshake data: "
+          "sent %zd of %lu bytes", written, outbuf.cbBuffer);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  DEBUGF(infof(data, "schannel: sent initial handshake data: "
+               "sent %zd bytes", written));
+
+  backend->recv_unrecoverable_err = CURLE_OK;
+  backend->recv_sspi_close_notify = false;
+  backend->recv_connection_closed = false;
+  backend->recv_renegotiating = false;
+  backend->encdata_is_incomplete = false;
+
+  /* continue to second handshake step */
+  connssl->connecting_state = ssl_connect_2;
+
+  return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct schannel_ssl_backend_data *backend =
+    (struct schannel_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  int i;
+  ssize_t nread = -1, written = -1;
+  unsigned char *reallocated_buffer;
+  SecBuffer outbuf[3];
+  SecBufferDesc outbuf_desc;
+  SecBuffer inbuf[2];
+  SecBufferDesc inbuf_desc;
+  SECURITY_STATUS sspi_status = SEC_E_OK;
+  CURLcode result;
+  bool doread;
+  const char *pubkey_ptr;
+
+  DEBUGASSERT(backend);
+
+  doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
+
+  DEBUGF(infof(data,
+               "schannel: SSL/TLS connection with %s port %d (step 2/3)",
+               connssl->peer.hostname, connssl->port));
+
+  if(!backend->cred || !backend->ctxt)
+    return CURLE_SSL_CONNECT_ERROR;
+
+  /* buffer to store previously received and decrypted data */
+  if(!backend->decdata_buffer) {
+    backend->decdata_offset = 0;
+    backend->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
+    backend->decdata_buffer = malloc(backend->decdata_length);
+    if(!backend->decdata_buffer) {
+      failf(data, "schannel: unable to allocate memory");
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  /* buffer to store previously received and encrypted data */
+  if(!backend->encdata_buffer) {
+    backend->encdata_is_incomplete = false;
+    backend->encdata_offset = 0;
+    backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
+    backend->encdata_buffer = malloc(backend->encdata_length);
+    if(!backend->encdata_buffer) {
+      failf(data, "schannel: unable to allocate memory");
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  /* if we need a bigger buffer to read a full message, increase buffer now */
+  if(backend->encdata_length - backend->encdata_offset <
+     CURL_SCHANNEL_BUFFER_FREE_SIZE) {
+    /* increase internal encrypted data buffer */
+    size_t reallocated_length = backend->encdata_offset +
+      CURL_SCHANNEL_BUFFER_FREE_SIZE;
+    reallocated_buffer = realloc(backend->encdata_buffer,
+                                 reallocated_length);
+
+    if(!reallocated_buffer) {
+      failf(data, "schannel: unable to re-allocate memory");
+      return CURLE_OUT_OF_MEMORY;
+    }
+    else {
+      backend->encdata_buffer = reallocated_buffer;
+      backend->encdata_length = reallocated_length;
+    }
+  }
+
+  for(;;) {
+    if(doread) {
+      /* read encrypted handshake data from socket */
+      nread = Curl_conn_cf_recv(cf->next, data,
+                               (char *) (backend->encdata_buffer +
+                                         backend->encdata_offset),
+                               backend->encdata_length -
+                               backend->encdata_offset,
+                               &result);
+      if(result == CURLE_AGAIN) {
+        if(connssl->connecting_state != ssl_connect_2_writing)
+          connssl->connecting_state = ssl_connect_2_reading;
+        DEBUGF(infof(data, "schannel: failed to receive handshake, "
+                     "need more data"));
+        return CURLE_OK;
+      }
+      else if((result != CURLE_OK) || (nread == 0)) {
+        failf(data, "schannel: failed to receive handshake, "
+              "SSL/TLS connection failed");
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+
+      /* increase encrypted data buffer offset */
+      backend->encdata_offset += nread;
+      backend->encdata_is_incomplete = false;
+      DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
+    }
+
+    DEBUGF(infof(data,
+                 "schannel: encrypted data buffer: offset %zu length %zu",
+                 backend->encdata_offset, backend->encdata_length));
+
+    /* setup input buffers */
+    InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset),
+                  curlx_uztoul(backend->encdata_offset));
+    InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
+    InitSecBufferDesc(&inbuf_desc, inbuf, 2);
+
+    /* setup output buffers */
+    InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
+    InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
+    InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
+    InitSecBufferDesc(&outbuf_desc, outbuf, 3);
+
+    if(!inbuf[0].pvBuffer) {
+      failf(data, "schannel: unable to allocate memory");
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    /* copy received handshake data into input buffer */
+    memcpy(inbuf[0].pvBuffer, backend->encdata_buffer,
+           backend->encdata_offset);
+
+    sspi_status = s_pSecFn->InitializeSecurityContext(
+      &backend->cred->cred_handle, &backend->ctxt->ctxt_handle,
+      backend->cred->sni_hostname, backend->req_flags,
+      0, 0, &inbuf_desc, 0, NULL,
+      &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
+
+    /* free buffer for received handshake data */
+    Curl_safefree(inbuf[0].pvBuffer);
+
+    /* check if the handshake was incomplete */
+    if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
+      backend->encdata_is_incomplete = true;
+      connssl->connecting_state = ssl_connect_2_reading;
+      DEBUGF(infof(data,
+                   "schannel: received incomplete message, need more data"));
+      return CURLE_OK;
+    }
+
+    /* If the server has requested a client certificate, attempt to continue
+       the handshake without one. This will allow connections to servers which
+       request a client certificate but do not require it. */
+    if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
+       !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
+      backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
+      connssl->connecting_state = ssl_connect_2_writing;
+      DEBUGF(infof(data,
+                   "schannel: a client certificate has been requested"));
+      return CURLE_OK;
+    }
+
+    /* check if the handshake needs to be continued */
+    if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
+      for(i = 0; i < 3; i++) {
+        /* search for handshake tokens that need to be send */
+        if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
+          DEBUGF(infof(data, "schannel: sending next handshake data: "
+                       "sending %lu bytes.", outbuf[i].cbBuffer));
+
+          /* send handshake token to server */
+          written = Curl_conn_cf_send(cf->next, data,
+                                      outbuf[i].pvBuffer, outbuf[i].cbBuffer,
+                                      &result);
+          if((result != CURLE_OK) ||
+             (outbuf[i].cbBuffer != (size_t) written)) {
+            failf(data, "schannel: failed to send next handshake data: "
+                  "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
+            return CURLE_SSL_CONNECT_ERROR;
+          }
+        }
+
+        /* free obsolete buffer */
+        if(outbuf[i].pvBuffer) {
+          s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
+        }
+      }
+    }
+    else {
+      char buffer[STRERROR_LEN];
+      switch(sspi_status) {
+      case SEC_E_INSUFFICIENT_MEMORY:
+        failf(data, "schannel: next InitializeSecurityContext failed: %s",
+              Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+        return CURLE_OUT_OF_MEMORY;
+      case SEC_E_WRONG_PRINCIPAL:
+        failf(data, "schannel: SNI or certificate check failed: %s",
+              Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+        return CURLE_PEER_FAILED_VERIFICATION;
+      case SEC_E_UNTRUSTED_ROOT:
+        failf(data, "schannel: %s",
+              Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+        return CURLE_PEER_FAILED_VERIFICATION;
+        /*
+          case SEC_E_INVALID_HANDLE:
+          case SEC_E_INVALID_TOKEN:
+          case SEC_E_LOGON_DENIED:
+          case SEC_E_TARGET_UNKNOWN:
+          case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+          case SEC_E_INTERNAL_ERROR:
+          case SEC_E_NO_CREDENTIALS:
+          case SEC_E_UNSUPPORTED_FUNCTION:
+          case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
+        */
+      default:
+        failf(data, "schannel: next InitializeSecurityContext failed: %s",
+              Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+    }
+
+    /* check if there was additional remaining encrypted data */
+    if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
+      DEBUGF(infof(data, "schannel: encrypted data length: %lu",
+                   inbuf[1].cbBuffer));
+      /*
+        There are two cases where we could be getting extra data here:
+        1) If we're renegotiating a connection and the handshake is already
+        complete (from the server perspective), it can encrypted app data
+        (not handshake data) in an extra buffer at this point.
+        2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
+        connection and this extra data is part of the handshake.
+        We should process the data immediately; waiting for the socket to
+        be ready may fail since the server is done sending handshake data.
+      */
+      /* check if the remaining data is less than the total amount
+         and therefore begins after the already processed data */
+      if(backend->encdata_offset > inbuf[1].cbBuffer) {
+        memmove(backend->encdata_buffer,
+                (backend->encdata_buffer + backend->encdata_offset) -
+                inbuf[1].cbBuffer, inbuf[1].cbBuffer);
+        backend->encdata_offset = inbuf[1].cbBuffer;
+        if(sspi_status == SEC_I_CONTINUE_NEEDED) {
+          doread = FALSE;
+          continue;
+        }
+      }
+    }
+    else {
+      backend->encdata_offset = 0;
+    }
+    break;
+  }
+
+  /* check if the handshake needs to be continued */
+  if(sspi_status == SEC_I_CONTINUE_NEEDED) {
+    connssl->connecting_state = ssl_connect_2_reading;
+    return CURLE_OK;
+  }
+
+  /* check if the handshake is complete */
+  if(sspi_status == SEC_E_OK) {
+    connssl->connecting_state = ssl_connect_3;
+    DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
+  }
+
+  pubkey_ptr = Curl_ssl_cf_is_proxy(cf)?
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+  if(pubkey_ptr) {
+    result = schannel_pkp_pin_peer_pubkey(cf, data, pubkey_ptr);
+    if(result) {
+      failf(data, "SSL: public key does not match pinned public key");
+      return result;
+    }
+  }
+
+#ifdef HAS_MANUAL_VERIFY_API
+  if(conn_config->verifypeer && backend->use_manual_cred_validation) {
+    /* Certificate verification also verifies the hostname if verifyhost */
+    return Curl_verify_certificate(cf, data);
+  }
+#endif
+
+  /* Verify the hostname manually when certificate verification is disabled,
+     because in that case Schannel won't verify it. */
+  if(!conn_config->verifypeer && conn_config->verifyhost)
+    return Curl_verify_host(cf, data);
+
+  return CURLE_OK;
+}
+
+static bool
+valid_cert_encoding(const CERT_CONTEXT *cert_context)
+{
+  return (cert_context != NULL) &&
+    ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
+    (cert_context->pbCertEncoded != NULL) &&
+    (cert_context->cbCertEncoded > 0);
+}
+
+typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context,
+                             bool reverse_order, void *arg);
+
+static void
+traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
+                    void *arg)
+{
+  const CERT_CONTEXT *current_context = NULL;
+  bool should_continue = true;
+  bool first = true;
+  bool reverse_order = false;
+  while(should_continue &&
+        (current_context = CertEnumCertificatesInStore(
+          context->hCertStore,
+          current_context)) != NULL) {
+    /* Windows 11 22H2 OS Build 22621.674 or higher enumerates certificates in
+       leaf-to-root order while all previous versions of Windows enumerate
+       certificates in root-to-leaf order. Determine the order of enumeration
+       by comparing SECPKG_ATTR_REMOTE_CERT_CONTEXT's pbCertContext with the
+       first certificate's pbCertContext. */
+    if(first && context->pbCertEncoded != current_context->pbCertEncoded)
+      reverse_order = true;
+    should_continue = func(current_context, reverse_order, arg);
+    first = false;
+  }
+
+  if(current_context)
+    CertFreeCertificateContext(current_context);
+}
+
+static bool
+cert_counter_callback(const CERT_CONTEXT *ccert_context, bool reverse_order,
+                      void *certs_count)
+{
+  (void)reverse_order; /* unused */
+  if(valid_cert_encoding(ccert_context))
+    (*(int *)certs_count)++;
+  return true;
+}
+
+struct Adder_args
+{
+  struct Curl_easy *data;
+  CURLcode result;
+  int idx;
+  int certs_count;
+};
+
+static bool
+add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, bool reverse_order,
+                     void *raw_arg)
+{
+  struct Adder_args *args = (struct Adder_args*)raw_arg;
+  args->result = CURLE_OK;
+  if(valid_cert_encoding(ccert_context)) {
+    const char *beg = (const char *) ccert_context->pbCertEncoded;
+    const char *end = beg + ccert_context->cbCertEncoded;
+    int insert_index = reverse_order ? (args->certs_count - 1) - args->idx :
+                       args->idx;
+    args->result = Curl_extract_certinfo(args->data, insert_index,
+                                         beg, end);
+    args->idx++;
+  }
+  return args->result == CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct schannel_ssl_backend_data *backend =
+    (struct schannel_ssl_backend_data *)connssl->backend;
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  CURLcode result = CURLE_OK;
+  SECURITY_STATUS sspi_status = SEC_E_OK;
+  CERT_CONTEXT *ccert_context = NULL;
+#ifdef HAS_ALPN
+  SecPkgContext_ApplicationProtocol alpn_result;
+#endif
+
+  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+  DEBUGASSERT(backend);
+
+  DEBUGF(infof(data,
+               "schannel: SSL/TLS connection with %s port %d (step 3/3)",
+               connssl->peer.hostname, connssl->port));
+
+  if(!backend->cred)
+    return CURLE_SSL_CONNECT_ERROR;
+
+  /* check if the required context attributes are met */
+  if(backend->ret_flags != backend->req_flags) {
+    if(!(backend->ret_flags & ISC_RET_SEQUENCE_DETECT))
+      failf(data, "schannel: failed to setup sequence detection");
+    if(!(backend->ret_flags & ISC_RET_REPLAY_DETECT))
+      failf(data, "schannel: failed to setup replay detection");
+    if(!(backend->ret_flags & ISC_RET_CONFIDENTIALITY))
+      failf(data, "schannel: failed to setup confidentiality");
+    if(!(backend->ret_flags & ISC_RET_ALLOCATED_MEMORY))
+      failf(data, "schannel: failed to setup memory allocation");
+    if(!(backend->ret_flags & ISC_RET_STREAM))
+      failf(data, "schannel: failed to setup stream orientation");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+#ifdef HAS_ALPN
+  if(backend->use_alpn) {
+    sspi_status =
+      s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
+                                       SECPKG_ATTR_APPLICATION_PROTOCOL,
+                                       &alpn_result);
+
+    if(sspi_status != SEC_E_OK) {
+      failf(data, "schannel: failed to retrieve ALPN result");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+
+    if(alpn_result.ProtoNegoStatus ==
+       SecApplicationProtocolNegotiationStatus_Success) {
+      unsigned char prev_alpn = cf->conn->alpn;
+
+      Curl_alpn_set_negotiated(cf, data, alpn_result.ProtocolId,
+                               alpn_result.ProtocolIdSize);
+      if(backend->recv_renegotiating) {
+        if(prev_alpn != cf->conn->alpn &&
+           prev_alpn != CURL_HTTP_VERSION_NONE) {
+          /* Renegotiation selected a different protocol now, we cannot
+           * deal with this */
+          failf(data, "schannel: server selected an ALPN protocol too late");
+          return CURLE_SSL_CONNECT_ERROR;
+        }
+      }
+    }
+    else {
+      if(!backend->recv_renegotiating)
+        Curl_alpn_set_negotiated(cf, data, NULL, 0);
+    }
+  }
+#endif
+
+  /* save the current session data for possible reuse */
+  if(ssl_config->primary.sessionid) {
+    bool incache;
+    bool added = FALSE;
+    struct Curl_schannel_cred *old_cred = NULL;
+
+    Curl_ssl_sessionid_lock(data);
+    incache = !(Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL));
+    if(incache) {
+      if(old_cred != backend->cred) {
+        DEBUGF(infof(data,
+                     "schannel: old credential handle is stale, removing"));
+        /* we're not taking old_cred ownership here, no refcount++ is needed */
+        Curl_ssl_delsessionid(data, (void *)old_cred);
+        incache = FALSE;
+      }
+    }
+    if(!incache) {
+      result = Curl_ssl_addsessionid(cf, data, backend->cred,
+                                     sizeof(struct Curl_schannel_cred),
+                                     &added);
+      if(result) {
+        Curl_ssl_sessionid_unlock(data);
+        failf(data, "schannel: failed to store credential handle");
+        return result;
+      }
+      else if(added) {
+        /* this cred session is now also referenced by sessionid cache */
+        backend->cred->refcount++;
+        DEBUGF(infof(data,
+                     "schannel: stored credential handle in session cache"));
+      }
+    }
+    Curl_ssl_sessionid_unlock(data);
+  }
+
+  if(data->set.ssl.certinfo) {
+    int certs_count = 0;
+    sspi_status =
+      s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
+                                       SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+                                       &ccert_context);
+
+    if((sspi_status != SEC_E_OK) || !ccert_context) {
+      failf(data, "schannel: failed to retrieve remote cert context");
+      return CURLE_PEER_FAILED_VERIFICATION;
+    }
+
+    traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
+
+    result = Curl_ssl_init_certinfo(data, certs_count);
+    if(!result) {
+      struct Adder_args args;
+      args.data = data;
+      args.idx = 0;
+      args.certs_count = certs_count;
+      traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
+      result = args.result;
+    }
+    CertFreeCertificateContext(ccert_context);
+    if(result)
+      return result;
+  }
+
+  connssl->connecting_state = ssl_connect_done;
+
+  return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_common(struct Curl_cfilter *cf,
+                        struct Curl_easy *data,
+                        bool nonblocking, bool *done)
+{
+  CURLcode result;
+  struct ssl_connect_data *connssl = cf->ctx;
+  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+  timediff_t timeout_ms;
+  int what;
+
+  /* check if the connection has already been established */
+  if(ssl_connection_complete == connssl->state) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  if(ssl_connect_1 == connssl->connecting_state) {
+    /* check out how much more time we're allowed */
+    timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL/TLS connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    result = schannel_connect_step1(cf, data);
+    if(result)
+      return result;
+  }
+
+  while(ssl_connect_2 == connssl->connecting_state ||
+        ssl_connect_2_reading == connssl->connecting_state ||
+        ssl_connect_2_writing == connssl->connecting_state) {
+
+    /* check out how much more time we're allowed */
+    timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL/TLS connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    /* if ssl is expecting something, check if it's available. */
+    if(connssl->connecting_state == ssl_connect_2_reading
+       || connssl->connecting_state == ssl_connect_2_writing) {
+
+      curl_socket_t writefd = ssl_connect_2_writing ==
+        connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
+      curl_socket_t readfd = ssl_connect_2_reading ==
+        connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
+
+      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+                               nonblocking ? 0 : timeout_ms);
+      if(what < 0) {
+        /* fatal error */
+        failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      else if(0 == what) {
+        if(nonblocking) {
+          *done = FALSE;
+          return CURLE_OK;
+        }
+        else {
+          /* timeout */
+          failf(data, "SSL/TLS connection timeout");
+          return CURLE_OPERATION_TIMEDOUT;
+        }
+      }
+      /* socket is readable or writable */
+    }
+
+    /* Run transaction, and return to the caller if it failed or if
+     * this connection is part of a multi handle and this loop would
+     * execute again. This permits the owner of a multi handle to
+     * abort a connection attempt before step2 has completed while
+     * ensuring that a client using select() or epoll() will always
+     * have a valid fdset to wait on.
+     */
+    result = schannel_connect_step2(cf, data);
+    if(result || (nonblocking &&
+                  (ssl_connect_2 == connssl->connecting_state ||
+                   ssl_connect_2_reading == connssl->connecting_state ||
+                   ssl_connect_2_writing == connssl->connecting_state)))
+      return result;
+
+  } /* repeat step2 until all transactions are done. */
+
+  if(ssl_connect_3 == connssl->connecting_state) {
+    result = schannel_connect_step3(cf, data);
+    if(result)
+      return result;
+  }
+
+  if(ssl_connect_done == connssl->connecting_state) {
+    connssl->state = ssl_connection_complete;
+
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+    /* When SSPI is used in combination with Schannel
+     * we need the Schannel context to create the Schannel
+     * binding to pass the IIS extended protection checks.
+     * Available on Windows 7 or later.
+     */
+    {
+      struct schannel_ssl_backend_data *backend =
+        (struct schannel_ssl_backend_data *)connssl->backend;
+      DEBUGASSERT(backend);
+      cf->conn->sslContext = &backend->ctxt->ctxt_handle;
+    }
+#endif
+
+    *done = TRUE;
+  }
+  else
+    *done = FALSE;
+
+  /* reset our connection state machine */
+  connssl->connecting_state = ssl_connect_1;
+
+  return CURLE_OK;
+}
+
+static ssize_t
+schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+              const void *buf, size_t len, CURLcode *err)
+{
+  ssize_t written = -1;
+  size_t data_len = 0;
+  unsigned char *ptr = NULL;
+  struct ssl_connect_data *connssl = cf->ctx;
+  SecBuffer outbuf[4];
+  SecBufferDesc outbuf_desc;
+  SECURITY_STATUS sspi_status = SEC_E_OK;
+  CURLcode result;
+  struct schannel_ssl_backend_data *backend =
+    (struct schannel_ssl_backend_data *)connssl->backend;
+
+  DEBUGASSERT(backend);
+
+  /* check if the maximum stream sizes were queried */
+  if(backend->stream_sizes.cbMaximumMessage == 0) {
+    sspi_status = s_pSecFn->QueryContextAttributes(
+      &backend->ctxt->ctxt_handle,
+      SECPKG_ATTR_STREAM_SIZES,
+      &backend->stream_sizes);
+    if(sspi_status != SEC_E_OK) {
+      *err = CURLE_SEND_ERROR;
+      return -1;
+    }
+  }
+
+  /* check if the buffer is longer than the maximum message length */
+  if(len > backend->stream_sizes.cbMaximumMessage) {
+    len = backend->stream_sizes.cbMaximumMessage;
+  }
+
+  /* calculate the complete message length and allocate a buffer for it */
+  data_len = backend->stream_sizes.cbHeader + len +
+    backend->stream_sizes.cbTrailer;
+  ptr = (unsigned char *) malloc(data_len);
+  if(!ptr) {
+    *err = CURLE_OUT_OF_MEMORY;
+    return -1;
+  }
+
+  /* setup output buffers (header, data, trailer, empty) */
+  InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
+                ptr, backend->stream_sizes.cbHeader);
+  InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
+                ptr + backend->stream_sizes.cbHeader, curlx_uztoul(len));
+  InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
+                ptr + backend->stream_sizes.cbHeader + len,
+                backend->stream_sizes.cbTrailer);
+  InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
+  InitSecBufferDesc(&outbuf_desc, outbuf, 4);
+
+  /* copy data into output buffer */
+  memcpy(outbuf[1].pvBuffer, buf, len);
+
+  /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
+  sspi_status = s_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0,
+                                         &outbuf_desc, 0);
+
+  /* check if the message was encrypted */
+  if(sspi_status == SEC_E_OK) {
+    written = 0;
+
+    /* send the encrypted message including header, data and trailer */
+    len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
+
+    /*
+      It's important to send the full message which includes the header,
+      encrypted payload, and trailer.  Until the client receives all the
+      data a coherent message has not been delivered and the client
+      can't read any of it.
+
+      If we wanted to buffer the unwritten encrypted bytes, we would
+      tell the client that all data it has requested to be sent has been
+      sent. The unwritten encrypted bytes would be the first bytes to
+      send on the next invocation.
+      Here's the catch with this - if we tell the client that all the
+      bytes have been sent, will the client call this method again to
+      send the buffered data?  Looking at who calls this function, it
+      seems the answer is NO.
+    */
+
+    /* send entire message or fail */
+    while(len > (size_t)written) {
+      ssize_t this_write = 0;
+      int what;
+      timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE);
+      if(timeout_ms < 0) {
+        /* we already got the timeout */
+        failf(data, "schannel: timed out sending data "
+              "(bytes sent: %zd)", written);
+        *err = CURLE_OPERATION_TIMEDOUT;
+        written = -1;
+        break;
+      }
+      else if(!timeout_ms)
+        timeout_ms = TIMEDIFF_T_MAX;
+      what = SOCKET_WRITABLE(Curl_conn_cf_get_socket(cf, data), timeout_ms);
+      if(what < 0) {
+        /* fatal error */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        *err = CURLE_SEND_ERROR;
+        written = -1;
+        break;
+      }
+      else if(0 == what) {
+        failf(data, "schannel: timed out sending data "
+              "(bytes sent: %zd)", written);
+        *err = CURLE_OPERATION_TIMEDOUT;
+        written = -1;
+        break;
+      }
+      /* socket is writable */
+
+       this_write = Curl_conn_cf_send(cf->next, data,
+                                      ptr + written, len - written,
+                                      &result);
+      if(result == CURLE_AGAIN)
+        continue;
+      else if(result != CURLE_OK) {
+        *err = result;
+        written = -1;
+        break;
+      }
+
+      written += this_write;
+    }
+  }
+  else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
+    *err = CURLE_OUT_OF_MEMORY;
+  }
+  else{
+    *err = CURLE_SEND_ERROR;
+  }
+
+  Curl_safefree(ptr);
+
+  if(len == (size_t)written)
+    /* Encrypted message including header, data and trailer entirely sent.
+       The return value is the number of unencrypted bytes that were sent. */
+    written = outbuf[1].cbBuffer;
+
+  return written;
+}
+
+static ssize_t
+schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+              char *buf, size_t len, CURLcode *err)
+{
+  size_t size = 0;
+  ssize_t nread = -1;
+  struct ssl_connect_data *connssl = cf->ctx;
+  unsigned char *reallocated_buffer;
+  size_t reallocated_length;
+  bool done = FALSE;
+  SecBuffer inbuf[4];
+  SecBufferDesc inbuf_desc;
+  SECURITY_STATUS sspi_status = SEC_E_OK;
+  /* we want the length of the encrypted buffer to be at least large enough
+     that it can hold all the bytes requested and some TLS record overhead. */
+  size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
+  struct schannel_ssl_backend_data *backend =
+    (struct schannel_ssl_backend_data *)connssl->backend;
+
+  DEBUGASSERT(backend);
+
+  /****************************************************************************
+   * Don't return or set backend->recv_unrecoverable_err unless in the cleanup.
+   * The pattern for return error is set *err, optional infof, goto cleanup.
+   *
+   * Our priority is to always return as much decrypted data to the caller as
+   * possible, even if an error occurs. The state of the decrypted buffer must
+   * always be valid. Transfer of decrypted data to the caller's buffer is
+   * handled in the cleanup.
+   */
+
+  DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
+  *err = CURLE_OK;
+
+  if(len && len <= backend->decdata_offset) {
+    infof(data, "schannel: enough decrypted data is already available");
+    goto cleanup;
+  }
+  else if(backend->recv_unrecoverable_err) {
+    *err = backend->recv_unrecoverable_err;
+    infof(data, "schannel: an unrecoverable error occurred in a prior call");
+    goto cleanup;
+  }
+  else if(backend->recv_sspi_close_notify) {
+    /* once a server has indicated shutdown there is no more encrypted data */
+    infof(data, "schannel: server indicated shutdown in a prior call");
+    goto cleanup;
+  }
+  /* It's debatable what to return when !len. Regardless we can't return
+     immediately because there may be data to decrypt (in the case we want to
+     decrypt all encrypted cached data) so handle !len later in cleanup.
+  */
+  else if(len && !backend->recv_connection_closed) {
+    /* increase enc buffer in order to fit the requested amount of data */
+    size = backend->encdata_length - backend->encdata_offset;
+    if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
+       backend->encdata_length < min_encdata_length) {
+      reallocated_length = backend->encdata_offset +
+        CURL_SCHANNEL_BUFFER_FREE_SIZE;
+      if(reallocated_length < min_encdata_length) {
+        reallocated_length = min_encdata_length;
+      }
+      reallocated_buffer = realloc(backend->encdata_buffer,
+                                   reallocated_length);
+      if(!reallocated_buffer) {
+        *err = CURLE_OUT_OF_MEMORY;
+        failf(data, "schannel: unable to re-allocate memory");
+        goto cleanup;
+      }
+
+      backend->encdata_buffer = reallocated_buffer;
+      backend->encdata_length = reallocated_length;
+      size = backend->encdata_length - backend->encdata_offset;
+      DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
+                   backend->encdata_length));
+    }
+
+    DEBUGF(infof(data,
+                 "schannel: encrypted data buffer: offset %zu length %zu",
+                 backend->encdata_offset, backend->encdata_length));
+
+    /* read encrypted data from socket */
+    nread = Curl_conn_cf_recv(cf->next, data,
+                              (char *)(backend->encdata_buffer +
+                                    backend->encdata_offset),
+                              size, err);
+    if(*err) {
+      nread = -1;
+      if(*err == CURLE_AGAIN)
+        DEBUGF(infof(data,
+                     "schannel: recv returned CURLE_AGAIN"));
+      else if(*err == CURLE_RECV_ERROR)
+        infof(data, "schannel: recv returned CURLE_RECV_ERROR");
+      else
+        infof(data, "schannel: recv returned error %d", *err);
+    }
+    else if(nread == 0) {
+      backend->recv_connection_closed = true;
+      DEBUGF(infof(data, "schannel: server closed the connection"));
+    }
+    else if(nread > 0) {
+      backend->encdata_offset += (size_t)nread;
+      backend->encdata_is_incomplete = false;
+      DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
+    }
+  }
+
+  DEBUGF(infof(data,
+               "schannel: encrypted data buffer: offset %zu length %zu",
+               backend->encdata_offset, backend->encdata_length));
+
+  /* decrypt loop */
+  while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK &&
+        (!len || backend->decdata_offset < len ||
+         backend->recv_connection_closed)) {
+    /* prepare data buffer for DecryptMessage call */
+    InitSecBuffer(&inbuf[0], SECBUFFER_DATA, backend->encdata_buffer,
+                  curlx_uztoul(backend->encdata_offset));
+
+    /* we need 3 more empty input buffers for possible output */
+    InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
+    InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
+    InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
+    InitSecBufferDesc(&inbuf_desc, inbuf, 4);
+
+    /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
+     */
+    sspi_status = s_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle,
+                                           &inbuf_desc, 0, NULL);
+
+    /* check if everything went fine (server may want to renegotiate
+       or shutdown the connection context) */
+    if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
+       sspi_status == SEC_I_CONTEXT_EXPIRED) {
+      /* check for successfully decrypted data, even before actual
+         renegotiation or shutdown of the connection context */
+      if(inbuf[1].BufferType == SECBUFFER_DATA) {
+        DEBUGF(infof(data, "schannel: decrypted data length: %lu",
+                     inbuf[1].cbBuffer));
+
+        /* increase buffer in order to fit the received amount of data */
+        size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
+          inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
+        if(backend->decdata_length - backend->decdata_offset < size ||
+           backend->decdata_length < len) {
+          /* increase internal decrypted data buffer */
+          reallocated_length = backend->decdata_offset + size;
+          /* make sure that the requested amount of data fits */
+          if(reallocated_length < len) {
+            reallocated_length = len;
+          }
+          reallocated_buffer = realloc(backend->decdata_buffer,
+                                       reallocated_length);
+          if(!reallocated_buffer) {
+            *err = CURLE_OUT_OF_MEMORY;
+            failf(data, "schannel: unable to re-allocate memory");
+            goto cleanup;
+          }
+          backend->decdata_buffer = reallocated_buffer;
+          backend->decdata_length = reallocated_length;
+        }
+
+        /* copy decrypted data to internal buffer */
+        size = inbuf[1].cbBuffer;
+        if(size) {
+          memcpy(backend->decdata_buffer + backend->decdata_offset,
+                 inbuf[1].pvBuffer, size);
+          backend->decdata_offset += size;
+        }
+
+        DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
+        DEBUGF(infof(data,
+                     "schannel: decrypted cached: offset %zu length %zu",
+                     backend->decdata_offset, backend->decdata_length));
+      }
+
+      /* check for remaining encrypted data */
+      if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
+        DEBUGF(infof(data, "schannel: encrypted data length: %lu",
+                     inbuf[3].cbBuffer));
+
+        /* check if the remaining data is less than the total amount
+         * and therefore begins after the already processed data
+         */
+        if(backend->encdata_offset > inbuf[3].cbBuffer) {
+          /* move remaining encrypted data forward to the beginning of
+             buffer */
+          memmove(backend->encdata_buffer,
+                  (backend->encdata_buffer + backend->encdata_offset) -
+                  inbuf[3].cbBuffer, inbuf[3].cbBuffer);
+          backend->encdata_offset = inbuf[3].cbBuffer;
+        }
+
+        DEBUGF(infof(data,
+                     "schannel: encrypted cached: offset %zu length %zu",
+                     backend->encdata_offset, backend->encdata_length));
+      }
+      else {
+        /* reset encrypted buffer offset, because there is no data remaining */
+        backend->encdata_offset = 0;
+      }
+
+      /* check if server wants to renegotiate the connection context */
+      if(sspi_status == SEC_I_RENEGOTIATE) {
+        infof(data, "schannel: remote party requests renegotiation");
+        if(*err && *err != CURLE_AGAIN) {
+          infof(data, "schannel: can't renegotiate, an error is pending");
+          goto cleanup;
+        }
+
+        /* begin renegotiation */
+        infof(data, "schannel: renegotiating SSL/TLS connection");
+        connssl->state = ssl_connection_negotiating;
+        connssl->connecting_state = ssl_connect_2_writing;
+        backend->recv_renegotiating = true;
+        *err = schannel_connect_common(cf, data, FALSE, &done);
+        backend->recv_renegotiating = false;
+        if(*err) {
+          infof(data, "schannel: renegotiation failed");
+          goto cleanup;
+        }
+        /* now retry receiving data */
+        sspi_status = SEC_E_OK;
+        infof(data, "schannel: SSL/TLS connection renegotiated");
+        continue;
+      }
+      /* check if the server closed the connection */
+      else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
+        /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
+           returned so we have to work around that in cleanup. */
+        backend->recv_sspi_close_notify = true;
+        if(!backend->recv_connection_closed)
+          backend->recv_connection_closed = true;
+        infof(data,
+              "schannel: server close notification received (close_notify)");
+        goto cleanup;
+      }
+    }
+    else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
+      backend->encdata_is_incomplete = true;
+      if(!*err)
+        *err = CURLE_AGAIN;
+      infof(data, "schannel: failed to decrypt data, need more data");
+      goto cleanup;
+    }
+    else {
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+      char buffer[STRERROR_LEN];
+      infof(data, "schannel: failed to read data from server: %s",
+            Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+#endif
+      *err = CURLE_RECV_ERROR;
+      goto cleanup;
+    }
+  }
+
+  DEBUGF(infof(data,
+               "schannel: encrypted data buffer: offset %zu length %zu",
+               backend->encdata_offset, backend->encdata_length));
+
+  DEBUGF(infof(data,
+               "schannel: decrypted data buffer: offset %zu length %zu",
+               backend->decdata_offset, backend->decdata_length));
+
+cleanup:
+  /* Warning- there is no guarantee the encdata state is valid at this point */
+  DEBUGF(infof(data, "schannel: schannel_recv cleanup"));
+
+  /* Error if the connection has closed without a close_notify.
+
+     The behavior here is a matter of debate. We don't want to be vulnerable
+     to a truncation attack however there's some browser precedent for
+     ignoring the close_notify for compatibility reasons.
+
+     Additionally, Windows 2000 (v5.0) is a special case since it seems it
+     doesn't return close_notify. In that case if the connection was closed we
+     assume it was graceful (close_notify) since there doesn't seem to be a
+     way to tell.
+  */
+  if(len && !backend->decdata_offset && backend->recv_connection_closed &&
+     !backend->recv_sspi_close_notify) {
+    bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
+                                                VERSION_EQUAL);
+
+    if(isWin2k && sspi_status == SEC_E_OK)
+      backend->recv_sspi_close_notify = true;
+    else {
+      *err = CURLE_RECV_ERROR;
+      infof(data, "schannel: server closed abruptly (missing close_notify)");
+    }
+  }
+
+  /* Any error other than CURLE_AGAIN is an unrecoverable error. */
+  if(*err && *err != CURLE_AGAIN)
+    backend->recv_unrecoverable_err = *err;
+
+  size = len < backend->decdata_offset ? len : backend->decdata_offset;
+  if(size) {
+    memcpy(buf, backend->decdata_buffer, size);
+    memmove(backend->decdata_buffer, backend->decdata_buffer + size,
+            backend->decdata_offset - size);
+    backend->decdata_offset -= size;
+    DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
+    DEBUGF(infof(data,
+                 "schannel: decrypted data buffer: offset %zu length %zu",
+                 backend->decdata_offset, backend->decdata_length));
+    *err = CURLE_OK;
+    return (ssize_t)size;
+  }
+
+  if(!*err && !backend->recv_connection_closed)
+    *err = CURLE_AGAIN;
+
+  /* It's debatable what to return when !len. We could return whatever error
+     we got from decryption but instead we override here so the return is
+     consistent.
+  */
+  if(!len)
+    *err = CURLE_OK;
+
+  return *err ? -1 : 0;
+}
+
+static CURLcode schannel_connect_nonblocking(struct Curl_cfilter *cf,
+                                             struct Curl_easy *data,
+                                             bool *done)
+{
+  return schannel_connect_common(cf, data, TRUE, done);
+}
+
+static CURLcode schannel_connect(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data)
+{
+  CURLcode result;
+  bool done = FALSE;
+
+  result = schannel_connect_common(cf, data, FALSE, &done);
+  if(result)
+    return result;
+
+  DEBUGASSERT(done);
+
+  return CURLE_OK;
+}
+
+static bool schannel_data_pending(struct Curl_cfilter *cf,
+                                  const struct Curl_easy *data)
+{
+  const struct ssl_connect_data *connssl = cf->ctx;
+  struct schannel_ssl_backend_data *backend =
+    (struct schannel_ssl_backend_data *)connssl->backend;
+
+  (void)data;
+  DEBUGASSERT(backend);
+
+  if(backend->ctxt) /* SSL/TLS is in use */
+    return (backend->decdata_offset > 0 ||
+            (backend->encdata_offset > 0 && !backend->encdata_is_incomplete) ||
+            backend->recv_connection_closed ||
+            backend->recv_sspi_close_notify ||
+            backend->recv_unrecoverable_err);
+  else
+    return FALSE;
+}
+
+static void schannel_session_free(void *ptr)
+{
+  /* this is expected to be called under sessionid lock */
+  struct Curl_schannel_cred *cred = ptr;
+
+  if(cred) {
+    cred->refcount--;
+    if(cred->refcount == 0) {
+      s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+      curlx_unicodefree(cred->sni_hostname);
+#ifdef HAS_CLIENT_CERT_PATH
+      if(cred->client_cert_store) {
+        CertCloseStore(cred->client_cert_store, 0);
+        cred->client_cert_store = NULL;
+      }
+#endif
+      Curl_safefree(cred);
+    }
+  }
+}
+
+/* shut down the SSL connection and clean up related memory.
+   this function can be called multiple times on the same connection including
+   if the SSL connection failed (eg connection made but failed handshake). */
+static int schannel_shutdown(struct Curl_cfilter *cf,
+                             struct Curl_easy *data)
+{
+  /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
+   * Shutting Down an Schannel Connection
+   */
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct schannel_ssl_backend_data *backend =
+    (struct schannel_ssl_backend_data *)connssl->backend;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(backend);
+
+  if(backend->ctxt) {
+    infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
+          connssl->peer.hostname, connssl->port);
+  }
+
+  if(backend->cred && backend->ctxt) {
+    SecBufferDesc BuffDesc;
+    SecBuffer Buffer;
+    SECURITY_STATUS sspi_status;
+    SecBuffer outbuf;
+    SecBufferDesc outbuf_desc;
+    CURLcode result;
+    DWORD dwshut = SCHANNEL_SHUTDOWN;
+
+    InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
+    InitSecBufferDesc(&BuffDesc, &Buffer, 1);
+
+    sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
+                                              &BuffDesc);
+
+    if(sspi_status != SEC_E_OK) {
+      char buffer[STRERROR_LEN];
+      failf(data, "schannel: ApplyControlToken failure: %s",
+            Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+    }
+
+    /* setup output buffer */
+    InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
+    InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
+
+    sspi_status = s_pSecFn->InitializeSecurityContext(
+      &backend->cred->cred_handle,
+      &backend->ctxt->ctxt_handle,
+      backend->cred->sni_hostname,
+      backend->req_flags,
+      0,
+      0,
+      NULL,
+      0,
+      &backend->ctxt->ctxt_handle,
+      &outbuf_desc,
+      &backend->ret_flags,
+      &backend->ctxt->time_stamp);
+
+    if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
+      /* send close message which is in output buffer */
+      ssize_t written = Curl_conn_cf_send(cf->next, data,
+                                          outbuf.pvBuffer, outbuf.cbBuffer,
+                                          &result);
+      s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
+      if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
+        infof(data, "schannel: failed to send close msg: %s"
+              " (bytes written: %zd)", curl_easy_strerror(result), written);
+      }
+    }
+  }
+
+  /* free SSPI Schannel API security context handle */
+  if(backend->ctxt) {
+    DEBUGF(infof(data, "schannel: clear security context handle"));
+    s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
+    Curl_safefree(backend->ctxt);
+  }
+
+  /* free SSPI Schannel API credential handle */
+  if(backend->cred) {
+    Curl_ssl_sessionid_lock(data);
+    schannel_session_free(backend->cred);
+    Curl_ssl_sessionid_unlock(data);
+    backend->cred = NULL;
+  }
+
+  /* free internal buffer for received encrypted data */
+  if(backend->encdata_buffer) {
+    Curl_safefree(backend->encdata_buffer);
+    backend->encdata_length = 0;
+    backend->encdata_offset = 0;
+    backend->encdata_is_incomplete = false;
+  }
+
+  /* free internal buffer for received decrypted data */
+  if(backend->decdata_buffer) {
+    Curl_safefree(backend->decdata_buffer);
+    backend->decdata_length = 0;
+    backend->decdata_offset = 0;
+  }
+
+  return CURLE_OK;
+}
+
+static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  schannel_shutdown(cf, data);
+}
+
+static int schannel_init(void)
+{
+  return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
+}
+
+static void schannel_cleanup(void)
+{
+  Curl_sspi_global_cleanup();
+}
+
+static size_t schannel_version(char *buffer, size_t size)
+{
+  size = msnprintf(buffer, size, "Schannel");
+
+  return size;
+}
+
+static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
+                                unsigned char *entropy, size_t length)
+{
+  (void)data;
+
+  return Curl_win32_random(entropy, length);
+}
+
+static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
+                                             struct Curl_easy *data,
+                                             const char *pinnedpubkey)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct schannel_ssl_backend_data *backend =
+    (struct schannel_ssl_backend_data *)connssl->backend;
+  CERT_CONTEXT *pCertContextServer = NULL;
+
+  /* Result is returned to caller */
+  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+  DEBUGASSERT(backend);
+
+  /* if a path wasn't specified, don't pin */
+  if(!pinnedpubkey)
+    return CURLE_OK;
+
+  do {
+    SECURITY_STATUS sspi_status;
+    const char *x509_der;
+    DWORD x509_der_len;
+    struct Curl_X509certificate x509_parsed;
+    struct Curl_asn1Element *pubkey;
+
+    sspi_status =
+      s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
+                                       SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+                                       &pCertContextServer);
+
+    if((sspi_status != SEC_E_OK) || !pCertContextServer) {
+      char buffer[STRERROR_LEN];
+      failf(data, "schannel: Failed to read remote certificate context: %s",
+            Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+      break; /* failed */
+    }
+
+
+    if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
+         (pCertContextServer->cbCertEncoded > 0)))
+      break;
+
+    x509_der = (const char *)pCertContextServer->pbCertEncoded;
+    x509_der_len = pCertContextServer->cbCertEncoded;
+    memset(&x509_parsed, 0, sizeof(x509_parsed));
+    if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
+      break;
+
+    pubkey = &x509_parsed.subjectPublicKeyInfo;
+    if(!pubkey->header || pubkey->end <= pubkey->header) {
+      failf(data, "SSL: failed retrieving public key from server certificate");
+      break;
+    }
+
+    result = Curl_pin_peer_pubkey(data,
+                                  pinnedpubkey,
+                                  (const unsigned char *)pubkey->header,
+                                  (size_t)(pubkey->end - pubkey->header));
+    if(result) {
+      failf(data, "SSL: public key does not match pinned public key");
+    }
+  } while(0);
+
+  if(pCertContextServer)
+    CertFreeCertificateContext(pCertContextServer);
+
+  return result;
+}
+
+static void schannel_checksum(const unsigned char *input,
+                              size_t inputlen,
+                              unsigned char *checksum,
+                              size_t checksumlen,
+                              DWORD provType,
+                              const unsigned int algId)
+{
+  HCRYPTPROV hProv = 0;
+  HCRYPTHASH hHash = 0;
+  DWORD cbHashSize = 0;
+  DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
+  DWORD dwChecksumLen = (DWORD)checksumlen;
+
+  /* since this can fail in multiple ways, zero memory first so we never
+   * return old data
+   */
+  memset(checksum, 0, checksumlen);
+
+  if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
+                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+    return; /* failed */
+
+  do {
+    if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
+      break; /* failed */
+
+    if(!CryptHashData(hHash, input, (DWORD)inputlen, 0))
+      break; /* failed */
+
+    /* get hash size */
+    if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
+                          &dwHashSizeLen, 0))
+      break; /* failed */
+
+    /* check hash size */
+    if(checksumlen < cbHashSize)
+      break; /* failed */
+
+    if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
+      break; /* failed */
+  } while(0);
+
+  if(hHash)
+    CryptDestroyHash(hHash);
+
+  if(hProv)
+    CryptReleaseContext(hProv, 0);
+}
+
+static CURLcode schannel_sha256sum(const unsigned char *input,
+                                   size_t inputlen,
+                                   unsigned char *sha256sum,
+                                   size_t sha256len)
+{
+  schannel_checksum(input, inputlen, sha256sum, sha256len,
+                    PROV_RSA_AES, CALG_SHA_256);
+  return CURLE_OK;
+}
+
+static void *schannel_get_internals(struct ssl_connect_data *connssl,
+                                    CURLINFO info UNUSED_PARAM)
+{
+  struct schannel_ssl_backend_data *backend =
+    (struct schannel_ssl_backend_data *)connssl->backend;
+  (void)info;
+  DEBUGASSERT(backend);
+  return &backend->ctxt->ctxt_handle;
+}
+
+HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
+                                               const struct Curl_easy *data)
+{
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+  struct schannel_multi_ssl_backend_data *mbackend;
+  const struct ssl_general_config *cfg = &data->set.general_ssl;
+  timediff_t timeout_ms;
+  timediff_t elapsed_ms;
+  struct curltime now;
+  unsigned char info_blob_digest[CURL_SHA256_DIGEST_LENGTH];
+
+  DEBUGASSERT(multi);
+
+  if(!multi || !multi->ssl_backend_data) {
+    return NULL;
+  }
+
+  mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;
+  if(!mbackend->cert_store) {
+    return NULL;
+  }
+
+  /* zero ca_cache_timeout completely disables caching */
+  if(!cfg->ca_cache_timeout) {
+    return NULL;
+  }
+
+  /* check for cache timeout by using the cached_x509_store_expired timediff
+     calculation pattern from openssl.c.
+     negative timeout means retain forever. */
+  timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
+  if(timeout_ms >= 0) {
+    now = Curl_now();
+    elapsed_ms = Curl_timediff(now, mbackend->time);
+    if(elapsed_ms >= timeout_ms) {
+      return NULL;
+    }
+  }
+
+  if(ca_info_blob) {
+    if(!mbackend->CAinfo_blob_digest) {
+      return NULL;
+    }
+    if(mbackend->CAinfo_blob_size != ca_info_blob->len) {
+      return NULL;
+    }
+    schannel_sha256sum((const unsigned char *)ca_info_blob->data,
+                       ca_info_blob->len,
+                       info_blob_digest,
+                       CURL_SHA256_DIGEST_LENGTH);
+    if(memcmp(mbackend->CAinfo_blob_digest,
+              info_blob_digest,
+              CURL_SHA256_DIGEST_LENGTH)) {
+        return NULL;
+    }
+  }
+  else {
+    if(!conn_config->CAfile || !mbackend->CAfile ||
+       strcmp(mbackend->CAfile, conn_config->CAfile)) {
+      return NULL;
+    }
+  }
+
+  return mbackend->cert_store;
+}
+
+bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
+                                         const struct Curl_easy *data,
+                                         HCERTSTORE cert_store)
+{
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+  struct schannel_multi_ssl_backend_data *mbackend;
+  unsigned char *CAinfo_blob_digest = NULL;
+  size_t CAinfo_blob_size = 0;
+  char *CAfile = NULL;
+
+  DEBUGASSERT(multi);
+
+  if(!multi) {
+    return false;
+  }
+
+  if(!multi->ssl_backend_data) {
+    multi->ssl_backend_data =
+      calloc(1, sizeof(struct schannel_multi_ssl_backend_data));
+    if(!multi->ssl_backend_data) {
+      return false;
+    }
+  }
+
+  mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;
+
+
+  if(ca_info_blob) {
+    CAinfo_blob_digest = malloc(CURL_SHA256_DIGEST_LENGTH);
+    if(!CAinfo_blob_digest) {
+      return false;
+    }
+    schannel_sha256sum((const unsigned char *)ca_info_blob->data,
+                       ca_info_blob->len,
+                       CAinfo_blob_digest,
+                       CURL_SHA256_DIGEST_LENGTH);
+    CAinfo_blob_size = ca_info_blob->len;
+  }
+  else {
+    if(conn_config->CAfile) {
+      CAfile = strdup(conn_config->CAfile);
+      if(!CAfile) {
+        return false;
+      }
+    }
+  }
+
+  /* free old cache data */
+  if(mbackend->cert_store) {
+    CertCloseStore(mbackend->cert_store, 0);
+  }
+  free(mbackend->CAinfo_blob_digest);
+  free(mbackend->CAfile);
+
+  mbackend->time = Curl_now();
+  mbackend->cert_store = cert_store;
+  mbackend->CAinfo_blob_digest = CAinfo_blob_digest;
+  mbackend->CAinfo_blob_size = CAinfo_blob_size;
+  mbackend->CAfile = CAfile;
+  return true;
+}
+
+static void schannel_free_multi_ssl_backend_data(
+  struct multi_ssl_backend_data *msbd)
+{
+  struct schannel_multi_ssl_backend_data *mbackend =
+    (struct schannel_multi_ssl_backend_data*)msbd;
+  if(mbackend->cert_store) {
+    CertCloseStore(mbackend->cert_store, 0);
+  }
+  free(mbackend->CAinfo_blob_digest);
+  free(mbackend->CAfile);
+  free(mbackend);
+}
+
+const struct Curl_ssl Curl_ssl_schannel = {
+  { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
+
+  SSLSUPP_CERTINFO |
+#ifdef HAS_MANUAL_VERIFY_API
+  SSLSUPP_CAINFO_BLOB |
+#endif
+  SSLSUPP_PINNEDPUBKEY |
+  SSLSUPP_TLS13_CIPHERSUITES |
+  SSLSUPP_HTTPS_PROXY,
+
+  sizeof(struct schannel_ssl_backend_data),
+
+  schannel_init,                     /* init */
+  schannel_cleanup,                  /* cleanup */
+  schannel_version,                  /* version */
+  Curl_none_check_cxn,               /* check_cxn */
+  schannel_shutdown,                 /* shutdown */
+  schannel_data_pending,             /* data_pending */
+  schannel_random,                   /* random */
+  Curl_none_cert_status_request,     /* cert_status_request */
+  schannel_connect,                  /* connect */
+  schannel_connect_nonblocking,      /* connect_nonblocking */
+  Curl_ssl_adjust_pollset,           /* adjust_pollset */
+  schannel_get_internals,            /* get_internals */
+  schannel_close,                    /* close_one */
+  Curl_none_close_all,               /* close_all */
+  schannel_session_free,             /* session_free */
+  Curl_none_set_engine,              /* set_engine */
+  Curl_none_set_engine_default,      /* set_engine_default */
+  Curl_none_engines_list,            /* engines_list */
+  Curl_none_false_start,             /* false_start */
+  schannel_sha256sum,                /* sha256sum */
+  NULL,                              /* associate_connection */
+  NULL,                              /* disassociate_connection */
+  schannel_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
+  schannel_recv,                     /* recv decrypted data */
+  schannel_send,                     /* send data to encrypt */
+};
+
+#endif /* USE_SCHANNEL */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/schannel.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/schannel.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/schannel.h	(revision 104083)
@@ -0,0 +1,86 @@
+#ifndef HEADER_CURL_SCHANNEL_H
+#define HEADER_CURL_SCHANNEL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Marc Hoersken, <info@marc-hoersken.de>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_SCHANNEL
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4201)
+#endif
+#include <subauth.h>
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+/* Wincrypt must be included before anything that could include OpenSSL. */
+#if defined(USE_WIN32_CRYPTO)
+#include <wincrypt.h>
+/* Undefine wincrypt conflicting symbols for BoringSSL. */
+#undef X509_NAME
+#undef X509_EXTENSIONS
+#undef PKCS7_ISSUER_AND_SERIAL
+#undef PKCS7_SIGNER_INFO
+#undef OCSP_REQUEST
+#undef OCSP_RESPONSE
+#endif
+
+#include <schnlsp.h>
+#include <schannel.h>
+#include "curl_sspi.h"
+
+#include "cfilters.h"
+#include "urldata.h"
+
+/* <wincrypt.h> has been included via the above <schnlsp.h>.
+ * Or in case of ldap.c, it was included via <winldap.h>.
+ * And since <wincrypt.h> has this:
+ *   #define X509_NAME  ((LPCSTR) 7)
+ *
+ * And in BoringSSL's <openssl/base.h> there is:
+ *  typedef struct X509_name_st X509_NAME;
+ *  etc.
+ *
+ * this will cause all kinds of C-preprocessing paste errors in
+ * BoringSSL's <openssl/x509.h>: So just undefine those defines here
+ * (and only here).
+ */
+#if defined(OPENSSL_IS_BORINGSSL)
+# undef X509_NAME
+# undef X509_CERT_PAIR
+# undef X509_EXTENSIONS
+#endif
+
+extern const struct Curl_ssl Curl_ssl_schannel;
+
+CURLcode Curl_verify_host(struct Curl_cfilter *cf,
+                          struct Curl_easy *data);
+
+CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data);
+
+#endif /* USE_SCHANNEL */
+#endif /* HEADER_CURL_SCHANNEL_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/schannel_int.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/schannel_int.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/schannel_int.h	(revision 104083)
@@ -0,0 +1,170 @@
+#ifndef HEADER_CURL_SCHANNEL_INT_H
+#define HEADER_CURL_SCHANNEL_INT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Marc Hoersken, <info@marc-hoersken.de>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_SCHANNEL
+
+#if defined(__MINGW32__) || defined(CERT_CHAIN_REVOCATION_CHECK_CHAIN)
+#define HAS_MANUAL_VERIFY_API
+#endif
+
+#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX)   \
+  && !defined(DISABLE_SCHANNEL_CLIENT_CERT)
+#define HAS_CLIENT_CERT_PATH
+#endif
+
+#ifndef CRYPT_DECODE_NOCOPY_FLAG
+#define CRYPT_DECODE_NOCOPY_FLAG 0x1
+#endif
+
+#ifndef CRYPT_DECODE_ALLOC_FLAG
+#define CRYPT_DECODE_ALLOC_FLAG 0x8000
+#endif
+
+#ifndef CERT_ALT_NAME_DNS_NAME
+#define CERT_ALT_NAME_DNS_NAME 3
+#endif
+
+#ifndef CERT_ALT_NAME_IP_ADDRESS
+#define CERT_ALT_NAME_IP_ADDRESS 8
+#endif
+
+
+#ifndef SCH_CREDENTIALS_VERSION
+
+#define SCH_CREDENTIALS_VERSION  0x00000005
+
+typedef enum _eTlsAlgorithmUsage
+{
+    TlsParametersCngAlgUsageKeyExchange,
+    TlsParametersCngAlgUsageSignature,
+    TlsParametersCngAlgUsageCipher,
+    TlsParametersCngAlgUsageDigest,
+    TlsParametersCngAlgUsageCertSig
+} eTlsAlgorithmUsage;
+
+typedef struct _CRYPTO_SETTINGS
+{
+    eTlsAlgorithmUsage  eAlgorithmUsage;
+    UNICODE_STRING      strCngAlgId;
+    DWORD               cChainingModes;
+    PUNICODE_STRING     rgstrChainingModes;
+    DWORD               dwMinBitLength;
+    DWORD               dwMaxBitLength;
+} CRYPTO_SETTINGS, * PCRYPTO_SETTINGS;
+
+typedef struct _TLS_PARAMETERS
+{
+    DWORD               cAlpnIds;
+    PUNICODE_STRING     rgstrAlpnIds;
+    DWORD               grbitDisabledProtocols;
+    DWORD               cDisabledCrypto;
+    PCRYPTO_SETTINGS    pDisabledCrypto;
+    DWORD               dwFlags;
+} TLS_PARAMETERS, * PTLS_PARAMETERS;
+
+typedef struct _SCH_CREDENTIALS
+{
+    DWORD               dwVersion;
+    DWORD               dwCredFormat;
+    DWORD               cCreds;
+    PCCERT_CONTEXT* paCred;
+    HCERTSTORE          hRootStore;
+
+    DWORD               cMappers;
+    struct _HMAPPER **aphMappers;
+
+    DWORD               dwSessionLifespan;
+    DWORD               dwFlags;
+    DWORD               cTlsParameters;
+    PTLS_PARAMETERS     pTlsParameters;
+} SCH_CREDENTIALS, * PSCH_CREDENTIALS;
+
+#define SCH_CRED_MAX_SUPPORTED_PARAMETERS 16
+#define SCH_CRED_MAX_SUPPORTED_ALPN_IDS 16
+#define SCH_CRED_MAX_SUPPORTED_CRYPTO_SETTINGS 16
+#define SCH_CRED_MAX_SUPPORTED_CHAINING_MODES 16
+
+#endif /* SCH_CREDENTIALS_VERSION */
+
+struct Curl_schannel_cred {
+  CredHandle cred_handle;
+  TimeStamp time_stamp;
+  TCHAR *sni_hostname;
+#ifdef HAS_CLIENT_CERT_PATH
+  HCERTSTORE client_cert_store;
+#endif
+  int refcount;
+};
+
+struct Curl_schannel_ctxt {
+  CtxtHandle ctxt_handle;
+  TimeStamp time_stamp;
+};
+
+struct schannel_ssl_backend_data {
+  struct Curl_schannel_cred *cred;
+  struct Curl_schannel_ctxt *ctxt;
+  SecPkgContext_StreamSizes stream_sizes;
+  size_t encdata_length, decdata_length;
+  size_t encdata_offset, decdata_offset;
+  unsigned char *encdata_buffer, *decdata_buffer;
+  /* encdata_is_incomplete: if encdata contains only a partial record that
+     can't be decrypted without another recv() (that is, status is
+     SEC_E_INCOMPLETE_MESSAGE) then set this true. after an recv() adds
+     more bytes into encdata then set this back to false. */
+  bool encdata_is_incomplete;
+  unsigned long req_flags, ret_flags;
+  CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
+  bool recv_sspi_close_notify; /* true if connection closed by close_notify */
+  bool recv_connection_closed; /* true if connection closed, regardless how */
+  bool recv_renegotiating;     /* true if recv is doing renegotiation */
+  bool use_alpn; /* true if ALPN is used for this connection */
+#ifdef HAS_MANUAL_VERIFY_API
+  bool use_manual_cred_validation; /* true if manual cred validation is used */
+#endif
+};
+
+struct schannel_multi_ssl_backend_data {
+  unsigned char *CAinfo_blob_digest; /* CA info blob digest */
+  size_t CAinfo_blob_size;           /* CA info blob size */
+  char *CAfile;                      /* CAfile path used to generate
+                                        certificate store */
+  HCERTSTORE cert_store;             /* cached certificate store or
+                                        NULL if none */
+  struct curltime time;              /* when the cached store was created */
+};
+
+HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
+                                               const struct Curl_easy *data);
+
+bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
+                                         const struct Curl_easy *data,
+                                         HCERTSTORE cert_store);
+
+#endif /* USE_SCHANNEL */
+#endif /* HEADER_CURL_SCHANNEL_INT_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/schannel_verify.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/schannel_verify.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/schannel_verify.c	(revision 104083)
@@ -0,0 +1,787 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Marc Hoersken, <info@marc-hoersken.de>
+ * Copyright (C) Mark Salisbury, <mark.salisbury@hp.com>
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for Schannel-specific certificate verification. This code should
+ * only be invoked by code in schannel.c.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_SCHANNEL
+#ifndef USE_WINDOWS_SSPI
+#  error "Can't compile SCHANNEL support without SSPI."
+#endif
+
+#include "schannel.h"
+#include "schannel_int.h"
+
+#include "vtls.h"
+#include "vtls_int.h"
+#include "sendf.h"
+#include "strerror.h"
+#include "curl_multibyte.h"
+#include "curl_printf.h"
+#include "hostcheck.h"
+#include "version_win32.h"
+
+/* The last #include file should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define BACKEND ((struct schannel_ssl_backend_data *)connssl->backend)
+
+
+#ifdef HAS_MANUAL_VERIFY_API
+
+#define MAX_CAFILE_SIZE 1048576 /* 1 MiB */
+#define BEGIN_CERT "-----BEGIN CERTIFICATE-----"
+#define END_CERT "\n-----END CERTIFICATE-----"
+
+struct cert_chain_engine_config_win7 {
+  DWORD cbSize;
+  HCERTSTORE hRestrictedRoot;
+  HCERTSTORE hRestrictedTrust;
+  HCERTSTORE hRestrictedOther;
+  DWORD cAdditionalStore;
+  HCERTSTORE *rghAdditionalStore;
+  DWORD dwFlags;
+  DWORD dwUrlRetrievalTimeout;
+  DWORD MaximumCachedCertificates;
+  DWORD CycleDetectionModulus;
+  HCERTSTORE hExclusiveRoot;
+  HCERTSTORE hExclusiveTrustedPeople;
+};
+
+static int is_cr_or_lf(char c)
+{
+  return c == '\r' || c == '\n';
+}
+
+/* Search the substring needle,needlelen into string haystack,haystacklen
+ * Strings don't need to be terminated by a '\0'.
+ * Similar of OSX/Linux memmem (not available on Visual Studio).
+ * Return position of beginning of first occurrence or NULL if not found
+ */
+static const char *c_memmem(const void *haystack, size_t haystacklen,
+                            const void *needle, size_t needlelen)
+{
+  const char *p;
+  char first;
+  const char *str_limit = (const char *)haystack + haystacklen;
+  if(!needlelen || needlelen > haystacklen)
+    return NULL;
+  first = *(const char *)needle;
+  for(p = (const char *)haystack; p <= (str_limit - needlelen); p++)
+    if(((*p) == first) && (memcmp(p, needle, needlelen) == 0))
+      return p;
+
+  return NULL;
+}
+
+static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
+                                        const char *ca_buffer,
+                                        size_t ca_buffer_size,
+                                        const char *ca_file_text,
+                                        struct Curl_easy *data)
+{
+  const size_t begin_cert_len = strlen(BEGIN_CERT);
+  const size_t end_cert_len = strlen(END_CERT);
+  CURLcode result = CURLE_OK;
+  int num_certs = 0;
+  bool more_certs = 1;
+  const char *current_ca_file_ptr = ca_buffer;
+  const char *ca_buffer_limit = ca_buffer + ca_buffer_size;
+
+  while(more_certs && (current_ca_file_ptr<ca_buffer_limit)) {
+    const char *begin_cert_ptr = c_memmem(current_ca_file_ptr,
+                                          ca_buffer_limit-current_ca_file_ptr,
+                                          BEGIN_CERT,
+                                          begin_cert_len);
+    if(!begin_cert_ptr || !is_cr_or_lf(begin_cert_ptr[begin_cert_len])) {
+      more_certs = 0;
+    }
+    else {
+      const char *end_cert_ptr = c_memmem(begin_cert_ptr,
+                                          ca_buffer_limit-begin_cert_ptr,
+                                          END_CERT,
+                                          end_cert_len);
+      if(!end_cert_ptr) {
+        failf(data,
+              "schannel: CA file '%s' is not correctly formatted",
+              ca_file_text);
+        result = CURLE_SSL_CACERT_BADFILE;
+        more_certs = 0;
+      }
+      else {
+        CERT_BLOB cert_blob;
+        CERT_CONTEXT *cert_context = NULL;
+        BOOL add_cert_result = FALSE;
+        DWORD actual_content_type = 0;
+        DWORD cert_size = (DWORD)
+          ((end_cert_ptr + end_cert_len) - begin_cert_ptr);
+
+        cert_blob.pbData = (BYTE *)begin_cert_ptr;
+        cert_blob.cbData = cert_size;
+        if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
+                             &cert_blob,
+                             CERT_QUERY_CONTENT_FLAG_CERT,
+                             CERT_QUERY_FORMAT_FLAG_ALL,
+                             0,
+                             NULL,
+                             &actual_content_type,
+                             NULL,
+                             NULL,
+                             NULL,
+                             (const void **)&cert_context)) {
+          char buffer[STRERROR_LEN];
+          failf(data,
+                "schannel: failed to extract certificate from CA file "
+                "'%s': %s",
+                ca_file_text,
+                Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+          result = CURLE_SSL_CACERT_BADFILE;
+          more_certs = 0;
+        }
+        else {
+          current_ca_file_ptr = begin_cert_ptr + cert_size;
+
+          /* Sanity check that the cert_context object is the right type */
+          if(CERT_QUERY_CONTENT_CERT != actual_content_type) {
+            failf(data,
+                  "schannel: unexpected content type '%lu' when extracting "
+                  "certificate from CA file '%s'",
+                  actual_content_type, ca_file_text);
+            result = CURLE_SSL_CACERT_BADFILE;
+            more_certs = 0;
+          }
+          else {
+            add_cert_result =
+              CertAddCertificateContextToStore(trust_store,
+                                               cert_context,
+                                               CERT_STORE_ADD_ALWAYS,
+                                               NULL);
+            CertFreeCertificateContext(cert_context);
+            if(!add_cert_result) {
+              char buffer[STRERROR_LEN];
+              failf(data,
+                    "schannel: failed to add certificate from CA file '%s' "
+                    "to certificate store: %s",
+                    ca_file_text,
+                    Curl_winapi_strerror(GetLastError(), buffer,
+                                         sizeof(buffer)));
+              result = CURLE_SSL_CACERT_BADFILE;
+              more_certs = 0;
+            }
+            else {
+              num_certs++;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  if(result == CURLE_OK) {
+    if(!num_certs) {
+      infof(data,
+            "schannel: did not add any certificates from CA file '%s'",
+            ca_file_text);
+    }
+    else {
+      infof(data,
+            "schannel: added %d certificate(s) from CA file '%s'",
+            num_certs, ca_file_text);
+    }
+  }
+  return result;
+}
+
+static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
+                                        const char *ca_file,
+                                        struct Curl_easy *data)
+{
+  CURLcode result;
+  HANDLE ca_file_handle = INVALID_HANDLE_VALUE;
+  LARGE_INTEGER file_size;
+  char *ca_file_buffer = NULL;
+  TCHAR *ca_file_tstr = NULL;
+  size_t ca_file_bufsize = 0;
+  DWORD total_bytes_read = 0;
+
+  ca_file_tstr = curlx_convert_UTF8_to_tchar((char *)ca_file);
+  if(!ca_file_tstr) {
+    char buffer[STRERROR_LEN];
+    failf(data,
+          "schannel: invalid path name for CA file '%s': %s",
+          ca_file,
+          Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+    result = CURLE_SSL_CACERT_BADFILE;
+    goto cleanup;
+  }
+
+  /*
+   * Read the CA file completely into memory before parsing it. This
+   * optimizes for the common case where the CA file will be relatively
+   * small ( < 1 MiB ).
+   */
+  ca_file_handle = CreateFile(ca_file_tstr,
+                              GENERIC_READ,
+                              FILE_SHARE_READ,
+                              NULL,
+                              OPEN_EXISTING,
+                              FILE_ATTRIBUTE_NORMAL,
+                              NULL);
+  if(ca_file_handle == INVALID_HANDLE_VALUE) {
+    char buffer[STRERROR_LEN];
+    failf(data,
+          "schannel: failed to open CA file '%s': %s",
+          ca_file,
+          Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+    result = CURLE_SSL_CACERT_BADFILE;
+    goto cleanup;
+  }
+
+  if(!GetFileSizeEx(ca_file_handle, &file_size)) {
+    char buffer[STRERROR_LEN];
+    failf(data,
+          "schannel: failed to determine size of CA file '%s': %s",
+          ca_file,
+          Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+    result = CURLE_SSL_CACERT_BADFILE;
+    goto cleanup;
+  }
+
+  if(file_size.QuadPart > MAX_CAFILE_SIZE) {
+    failf(data,
+          "schannel: CA file exceeds max size of %u bytes",
+          MAX_CAFILE_SIZE);
+    result = CURLE_SSL_CACERT_BADFILE;
+    goto cleanup;
+  }
+
+  ca_file_bufsize = (size_t)file_size.QuadPart;
+  ca_file_buffer = (char *)malloc(ca_file_bufsize + 1);
+  if(!ca_file_buffer) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto cleanup;
+  }
+
+  while(total_bytes_read < ca_file_bufsize) {
+    DWORD bytes_to_read = (DWORD)(ca_file_bufsize - total_bytes_read);
+    DWORD bytes_read = 0;
+
+    if(!ReadFile(ca_file_handle, ca_file_buffer + total_bytes_read,
+                 bytes_to_read, &bytes_read, NULL)) {
+      char buffer[STRERROR_LEN];
+      failf(data,
+            "schannel: failed to read from CA file '%s': %s",
+            ca_file,
+            Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+      result = CURLE_SSL_CACERT_BADFILE;
+      goto cleanup;
+    }
+    if(bytes_read == 0) {
+      /* Premature EOF -- adjust the bufsize to the new value */
+      ca_file_bufsize = total_bytes_read;
+    }
+    else {
+      total_bytes_read += bytes_read;
+    }
+  }
+
+  /* Null terminate the buffer */
+  ca_file_buffer[ca_file_bufsize] = '\0';
+
+  result = add_certs_data_to_store(trust_store,
+                                   ca_file_buffer, ca_file_bufsize,
+                                   ca_file,
+                                   data);
+
+cleanup:
+  if(ca_file_handle != INVALID_HANDLE_VALUE) {
+    CloseHandle(ca_file_handle);
+  }
+  Curl_safefree(ca_file_buffer);
+  curlx_unicodefree(ca_file_tstr);
+
+  return result;
+}
+
+#endif /* HAS_MANUAL_VERIFY_API */
+
+/*
+ * Returns the number of characters necessary to populate all the host_names.
+ * If host_names is not NULL, populate it with all the host names. Each string
+ * in the host_names is null-terminated and the last string is double
+ * null-terminated. If no DNS names are found, a single null-terminated empty
+ * string is returned.
+ */
+static DWORD cert_get_name_string(struct Curl_easy *data,
+                                  CERT_CONTEXT *cert_context,
+                                  LPTSTR host_names,
+                                  DWORD length)
+{
+  DWORD actual_length = 0;
+  BOOL compute_content = FALSE;
+  CERT_INFO *cert_info = NULL;
+  CERT_EXTENSION *extension = NULL;
+  CRYPT_DECODE_PARA decode_para = {0, 0, 0};
+  CERT_ALT_NAME_INFO *alt_name_info = NULL;
+  DWORD alt_name_info_size = 0;
+  BOOL ret_val = FALSE;
+  LPTSTR current_pos = NULL;
+  DWORD i;
+
+#ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
+  /* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */
+  if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT,
+                                  VERSION_GREATER_THAN_EQUAL)) {
+    /* CertGetNameString will provide the 8-bit character string without
+     * any decoding */
+    DWORD name_flags =
+      CERT_NAME_DISABLE_IE4_UTF8_FLAG | CERT_NAME_SEARCH_ALL_NAMES_FLAG;
+    actual_length = CertGetNameString(cert_context,
+                                      CERT_NAME_DNS_TYPE,
+                                      name_flags,
+                                      NULL,
+                                      host_names,
+                                      length);
+    return actual_length;
+  }
+#endif
+
+  compute_content = host_names != NULL && length != 0;
+
+  /* Initialize default return values. */
+  actual_length = 1;
+  if(compute_content) {
+    *host_names = '\0';
+  }
+
+  if(!cert_context) {
+    failf(data, "schannel: Null certificate context.");
+    return actual_length;
+  }
+
+  cert_info = cert_context->pCertInfo;
+  if(!cert_info) {
+    failf(data, "schannel: Null certificate info.");
+    return actual_length;
+  }
+
+  extension = CertFindExtension(szOID_SUBJECT_ALT_NAME2,
+                                cert_info->cExtension,
+                                cert_info->rgExtension);
+  if(!extension) {
+    failf(data, "schannel: CertFindExtension() returned no extension.");
+    return actual_length;
+  }
+
+  decode_para.cbSize = sizeof(CRYPT_DECODE_PARA);
+
+  ret_val =
+    CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+                        szOID_SUBJECT_ALT_NAME2,
+                        extension->Value.pbData,
+                        extension->Value.cbData,
+                        CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
+                        &decode_para,
+                        &alt_name_info,
+                        &alt_name_info_size);
+  if(!ret_val) {
+    failf(data,
+          "schannel: CryptDecodeObjectEx() returned no alternate name "
+          "information.");
+    return actual_length;
+  }
+
+  current_pos = host_names;
+
+  /* Iterate over the alternate names and populate host_names. */
+  for(i = 0; i < alt_name_info->cAltEntry; i++) {
+    const CERT_ALT_NAME_ENTRY *entry = &alt_name_info->rgAltEntry[i];
+    wchar_t *dns_w = NULL;
+    size_t current_length = 0;
+
+    if(entry->dwAltNameChoice != CERT_ALT_NAME_DNS_NAME) {
+      continue;
+    }
+    if(!entry->pwszDNSName) {
+      infof(data, "schannel: Empty DNS name.");
+      continue;
+    }
+    current_length = wcslen(entry->pwszDNSName) + 1;
+    if(!compute_content) {
+      actual_length += (DWORD)current_length;
+      continue;
+    }
+    /* Sanity check to prevent buffer overrun. */
+    if((actual_length + current_length) > length) {
+      failf(data, "schannel: Not enough memory to list all host names.");
+      break;
+    }
+    dns_w = entry->pwszDNSName;
+    /* pwszDNSName is in ia5 string format and hence doesn't contain any
+     * non-ascii characters. */
+    while(*dns_w != '\0') {
+      *current_pos++ = (char)(*dns_w++);
+    }
+    *current_pos++ = '\0';
+    actual_length += (DWORD)current_length;
+  }
+  if(compute_content) {
+    /* Last string has double null-terminator. */
+    *current_pos = '\0';
+  }
+  return actual_length;
+}
+
+/* Verify the server's hostname */
+CURLcode Curl_verify_host(struct Curl_cfilter *cf,
+                          struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  SECURITY_STATUS sspi_status;
+  CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
+  CERT_CONTEXT *pCertContextServer = NULL;
+  TCHAR *cert_hostname_buff = NULL;
+  size_t cert_hostname_buff_index = 0;
+  const char *conn_hostname = connssl->peer.hostname;
+  size_t hostlen = strlen(conn_hostname);
+  DWORD len = 0;
+  DWORD actual_len = 0;
+
+  sspi_status =
+    s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+                                     SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+                                     &pCertContextServer);
+
+  if((sspi_status != SEC_E_OK) || !pCertContextServer) {
+    char buffer[STRERROR_LEN];
+    failf(data, "schannel: Failed to read remote certificate context: %s",
+          Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+    result = CURLE_PEER_FAILED_VERIFICATION;
+    goto cleanup;
+  }
+
+  /* Determine the size of the string needed for the cert hostname */
+  len = cert_get_name_string(data, pCertContextServer, NULL, 0);
+  if(len == 0) {
+    failf(data,
+          "schannel: CertGetNameString() returned no "
+          "certificate name information");
+    result = CURLE_PEER_FAILED_VERIFICATION;
+    goto cleanup;
+  }
+
+  /* CertGetNameString guarantees that the returned name will not contain
+   * embedded null bytes. This appears to be undocumented behavior.
+   */
+  cert_hostname_buff = (LPTSTR)malloc(len * sizeof(TCHAR));
+  if(!cert_hostname_buff) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto cleanup;
+  }
+  actual_len = cert_get_name_string(
+    data, pCertContextServer, (LPTSTR)cert_hostname_buff, len);
+
+  /* Sanity check */
+  if(actual_len != len) {
+    failf(data,
+          "schannel: CertGetNameString() returned certificate "
+          "name information of unexpected size");
+    result = CURLE_PEER_FAILED_VERIFICATION;
+    goto cleanup;
+  }
+
+  /* cert_hostname_buff contains all DNS names, where each name is
+   * null-terminated and the last DNS name is double null-terminated. Due to
+   * this encoding, use the length of the buffer to iterate over all names.
+   */
+  result = CURLE_PEER_FAILED_VERIFICATION;
+  while(cert_hostname_buff_index < len &&
+        cert_hostname_buff[cert_hostname_buff_index] != TEXT('\0') &&
+        result == CURLE_PEER_FAILED_VERIFICATION) {
+
+    char *cert_hostname;
+
+    /* Comparing the cert name and the connection hostname encoded as UTF-8
+     * is acceptable since both values are assumed to use ASCII
+     * (or some equivalent) encoding
+     */
+    cert_hostname = curlx_convert_tchar_to_UTF8(
+      &cert_hostname_buff[cert_hostname_buff_index]);
+    if(!cert_hostname) {
+      result = CURLE_OUT_OF_MEMORY;
+    }
+    else {
+      if(Curl_cert_hostcheck(cert_hostname, strlen(cert_hostname),
+                             conn_hostname, hostlen)) {
+        infof(data,
+              "schannel: connection hostname (%s) validated "
+              "against certificate name (%s)",
+              conn_hostname, cert_hostname);
+        result = CURLE_OK;
+      }
+      else {
+        size_t cert_hostname_len;
+
+        infof(data,
+              "schannel: connection hostname (%s) did not match "
+              "against certificate name (%s)",
+              conn_hostname, cert_hostname);
+
+        cert_hostname_len =
+          _tcslen(&cert_hostname_buff[cert_hostname_buff_index]);
+
+        /* Move on to next cert name */
+        cert_hostname_buff_index += cert_hostname_len + 1;
+
+        result = CURLE_PEER_FAILED_VERIFICATION;
+      }
+      curlx_unicodefree(cert_hostname);
+    }
+  }
+
+  if(result == CURLE_PEER_FAILED_VERIFICATION) {
+    failf(data,
+          "schannel: CertGetNameString() failed to match "
+          "connection hostname (%s) against server certificate names",
+          conn_hostname);
+  }
+  else if(result != CURLE_OK)
+    failf(data, "schannel: server certificate name verification failed");
+
+cleanup:
+  Curl_safefree(cert_hostname_buff);
+
+  if(pCertContextServer)
+    CertFreeCertificateContext(pCertContextServer);
+
+  return result;
+}
+
+
+#ifdef HAS_MANUAL_VERIFY_API
+/* Verify the server's certificate and hostname */
+CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  SECURITY_STATUS sspi_status;
+  CURLcode result = CURLE_OK;
+  CERT_CONTEXT *pCertContextServer = NULL;
+  const CERT_CHAIN_CONTEXT *pChainContext = NULL;
+  HCERTCHAINENGINE cert_chain_engine = NULL;
+  HCERTSTORE trust_store = NULL;
+  HCERTSTORE own_trust_store = NULL;
+
+  DEBUGASSERT(BACKEND);
+
+  sspi_status =
+    s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+                                     SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+                                     &pCertContextServer);
+
+  if((sspi_status != SEC_E_OK) || !pCertContextServer) {
+    char buffer[STRERROR_LEN];
+    failf(data, "schannel: Failed to read remote certificate context: %s",
+          Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+    result = CURLE_PEER_FAILED_VERIFICATION;
+  }
+
+  if(result == CURLE_OK &&
+      (conn_config->CAfile || conn_config->ca_info_blob) &&
+      BACKEND->use_manual_cred_validation) {
+    /*
+     * Create a chain engine that uses the certificates in the CA file as
+     * trusted certificates. This is only supported on Windows 7+.
+     */
+
+    if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
+                                    VERSION_LESS_THAN)) {
+      failf(data, "schannel: this version of Windows is too old to support "
+            "certificate verification via CA bundle file.");
+      result = CURLE_SSL_CACERT_BADFILE;
+    }
+    else {
+      /* try cache */
+      trust_store = Curl_schannel_get_cached_cert_store(cf, data);
+
+      if(trust_store) {
+        infof(data, "schannel: reusing certificate store from cache");
+      }
+      else {
+        /* Open the certificate store */
+        trust_store = CertOpenStore(CERT_STORE_PROV_MEMORY,
+                                    0,
+                                    (HCRYPTPROV)NULL,
+                                    CERT_STORE_CREATE_NEW_FLAG,
+                                    NULL);
+        if(!trust_store) {
+          char buffer[STRERROR_LEN];
+          failf(data, "schannel: failed to create certificate store: %s",
+                Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+          result = CURLE_SSL_CACERT_BADFILE;
+        }
+        else {
+          const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+          own_trust_store = trust_store;
+
+          if(ca_info_blob) {
+            result = add_certs_data_to_store(trust_store,
+                                              (const char *)ca_info_blob->data,
+                                              ca_info_blob->len,
+                                              "(memory blob)",
+                                              data);
+          }
+          else {
+            result = add_certs_file_to_store(trust_store,
+                                              conn_config->CAfile,
+                                              data);
+          }
+          if(result == CURLE_OK) {
+            if(Curl_schannel_set_cached_cert_store(cf, data, trust_store)) {
+              own_trust_store = NULL;
+            }
+          }
+        }
+      }
+    }
+
+    if(result == CURLE_OK) {
+      struct cert_chain_engine_config_win7 engine_config;
+      BOOL create_engine_result;
+
+      memset(&engine_config, 0, sizeof(engine_config));
+      engine_config.cbSize = sizeof(engine_config);
+      engine_config.hExclusiveRoot = trust_store;
+
+      /* CertCreateCertificateChainEngine will check the expected size of the
+       * CERT_CHAIN_ENGINE_CONFIG structure and fail if the specified size
+       * does not match the expected size. When this occurs, it indicates that
+       * CAINFO is not supported on the version of Windows in use.
+       */
+      create_engine_result =
+        CertCreateCertificateChainEngine(
+          (CERT_CHAIN_ENGINE_CONFIG *)&engine_config, &cert_chain_engine);
+      if(!create_engine_result) {
+        char buffer[STRERROR_LEN];
+        failf(data,
+              "schannel: failed to create certificate chain engine: %s",
+              Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+        result = CURLE_SSL_CACERT_BADFILE;
+      }
+    }
+  }
+
+  if(result == CURLE_OK) {
+    CERT_CHAIN_PARA ChainPara;
+
+    memset(&ChainPara, 0, sizeof(ChainPara));
+    ChainPara.cbSize = sizeof(ChainPara);
+
+    if(!CertGetCertificateChain(cert_chain_engine,
+                                pCertContextServer,
+                                NULL,
+                                pCertContextServer->hCertStore,
+                                &ChainPara,
+                                (ssl_config->no_revoke ? 0 :
+                                 CERT_CHAIN_REVOCATION_CHECK_CHAIN),
+                                NULL,
+                                &pChainContext)) {
+      char buffer[STRERROR_LEN];
+      failf(data, "schannel: CertGetCertificateChain failed: %s",
+            Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+      pChainContext = NULL;
+      result = CURLE_PEER_FAILED_VERIFICATION;
+    }
+
+    if(result == CURLE_OK) {
+      CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
+      DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
+      dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
+
+      if(data->set.ssl.revoke_best_effort) {
+        /* Ignore errors when root certificates are missing the revocation
+         * list URL, or when the list could not be downloaded because the
+         * server is currently unreachable. */
+        dwTrustErrorMask &= ~(DWORD)(CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
+          CERT_TRUST_IS_OFFLINE_REVOCATION);
+      }
+
+      if(dwTrustErrorMask) {
+        if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
+          failf(data, "schannel: CertGetCertificateChain trust error"
+                " CERT_TRUST_IS_REVOKED");
+        else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
+          failf(data, "schannel: CertGetCertificateChain trust error"
+                " CERT_TRUST_IS_PARTIAL_CHAIN");
+        else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
+          failf(data, "schannel: CertGetCertificateChain trust error"
+                " CERT_TRUST_IS_UNTRUSTED_ROOT");
+        else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
+          failf(data, "schannel: CertGetCertificateChain trust error"
+                " CERT_TRUST_IS_NOT_TIME_VALID");
+        else if(dwTrustErrorMask & CERT_TRUST_REVOCATION_STATUS_UNKNOWN)
+          failf(data, "schannel: CertGetCertificateChain trust error"
+                " CERT_TRUST_REVOCATION_STATUS_UNKNOWN");
+        else
+          failf(data, "schannel: CertGetCertificateChain error mask: 0x%08lx",
+                dwTrustErrorMask);
+        result = CURLE_PEER_FAILED_VERIFICATION;
+      }
+    }
+  }
+
+  if(result == CURLE_OK) {
+    if(conn_config->verifyhost) {
+      result = Curl_verify_host(cf, data);
+    }
+  }
+
+  if(cert_chain_engine) {
+    CertFreeCertificateChainEngine(cert_chain_engine);
+  }
+
+  if(own_trust_store) {
+    CertCloseStore(own_trust_store, 0);
+  }
+
+  if(pChainContext)
+    CertFreeCertificateChain(pChainContext);
+
+  if(pCertContextServer)
+    CertFreeCertificateContext(pCertContextServer);
+
+  return result;
+}
+
+#endif /* HAS_MANUAL_VERIFY_API */
+#endif /* USE_SCHANNEL */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/sectransp.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/sectransp.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/sectransp.c	(revision 104083)
@@ -0,0 +1,3493 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Nick Zitzmann, <nickzman@gmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all iOS and macOS SecureTransport-specific code for the
+ * TLS/SSL layer. No code but vtls.c should ever call or use these functions.
+ */
+
+#include "curl_setup.h"
+
+#include "urldata.h" /* for the Curl_easy definition */
+#include "curl_base64.h"
+#include "strtok.h"
+#include "multiif.h"
+#include "strcase.h"
+#include "x509asn1.h"
+#include "strerror.h"
+
+#ifdef USE_SECTRANSP
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
+#endif /* __clang__ */
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Waddress"
+#pragma GCC diagnostic ignored "-Wundef"
+#pragma GCC diagnostic ignored "-Wunreachable-code"
+#endif
+
+#include <limits.h>
+
+#include <Security/Security.h>
+/* For some reason, when building for iOS, the omnibus header above does
+ * not include SecureTransport.h as of iOS SDK 5.1. */
+#include <Security/SecureTransport.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CommonCrypto/CommonDigest.h>
+
+/* The Security framework has changed greatly between iOS and different macOS
+   versions, and we will try to support as many of them as we can (back to
+   Leopard and iOS 5) by using macros and weak-linking.
+
+   In general, you want to build this using the most recent OS SDK, since some
+   features require curl to be built against the latest SDK. TLS 1.1 and 1.2
+   support, for instance, require the macOS 10.8 SDK or later. TLS 1.3
+   requires the macOS 10.13 or iOS 11 SDK or later. */
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
+#error "The Secure Transport back-end requires Leopard or later."
+#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */
+
+#define CURL_BUILD_IOS 0
+#define CURL_BUILD_IOS_7 0
+#define CURL_BUILD_IOS_9 0
+#define CURL_BUILD_IOS_11 0
+#define CURL_BUILD_IOS_13 0
+#define CURL_BUILD_MAC 1
+/* This is the maximum API level we are allowed to use when building: */
+#define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
+#define CURL_BUILD_MAC_10_6 MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+#define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+#define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+#define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
+#define CURL_BUILD_MAC_10_11 MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
+#define CURL_BUILD_MAC_10_13 MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
+#define CURL_BUILD_MAC_10_15 MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
+/* These macros mean "the following code is present to allow runtime backward
+   compatibility with at least this cat or earlier":
+   (You set this at build-time using the compiler command line option
+   "-mmacosx-version-min.") */
+#define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
+#define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060
+#define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
+#define CURL_SUPPORT_MAC_10_8 MAC_OS_X_VERSION_MIN_REQUIRED <= 1080
+#define CURL_SUPPORT_MAC_10_9 MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
+
+#elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
+#define CURL_BUILD_IOS 1
+#define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
+#define CURL_BUILD_IOS_9 __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
+#define CURL_BUILD_IOS_11 __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
+#define CURL_BUILD_IOS_13 __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
+#define CURL_BUILD_MAC 0
+#define CURL_BUILD_MAC_10_5 0
+#define CURL_BUILD_MAC_10_6 0
+#define CURL_BUILD_MAC_10_7 0
+#define CURL_BUILD_MAC_10_8 0
+#define CURL_BUILD_MAC_10_9 0
+#define CURL_BUILD_MAC_10_11 0
+#define CURL_BUILD_MAC_10_13 0
+#define CURL_BUILD_MAC_10_15 0
+#define CURL_SUPPORT_MAC_10_5 0
+#define CURL_SUPPORT_MAC_10_6 0
+#define CURL_SUPPORT_MAC_10_7 0
+#define CURL_SUPPORT_MAC_10_8 0
+#define CURL_SUPPORT_MAC_10_9 0
+
+#else
+#error "The Secure Transport back-end requires iOS or macOS."
+#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
+
+#if CURL_BUILD_MAC
+#include <sys/sysctl.h>
+#endif /* CURL_BUILD_MAC */
+
+#include "sendf.h"
+#include "inet_pton.h"
+#include "connect.h"
+#include "select.h"
+#include "vtls.h"
+#include "vtls_int.h"
+#include "sectransp.h"
+#include "curl_printf.h"
+#include "strdup.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+
+/* From MacTypes.h (which we can't include because it isn't present in iOS: */
+#define ioErr -36
+#define paramErr -50
+
+struct st_ssl_backend_data {
+  SSLContextRef ssl_ctx;
+  bool ssl_direction; /* true if writing, false if reading */
+  size_t ssl_write_buffered_length;
+};
+
+struct st_cipher {
+  const char *name; /* Cipher suite IANA name. It starts with "TLS_" prefix */
+  const char *alias_name; /* Alias name is the same as OpenSSL cipher name */
+  SSLCipherSuite num; /* Cipher suite code/number defined in IANA registry */
+  bool weak; /* Flag to mark cipher as weak based on previous implementation
+                of Secure Transport back-end by CURL */
+};
+
+/* Macro to initialize st_cipher data structure: stringify id to name, cipher
+   number/id, 'weak' suite flag
+ */
+#define CIPHER_DEF(num, alias, weak) \
+  { #num, alias, num, weak }
+
+/*
+ Macro to initialize st_cipher data structure with name, code (IANA cipher
+ number/id value), and 'weak' suite flag. The first 28 cipher suite numbers
+ have the same IANA code for both SSL and TLS standards: numbers 0x0000 to
+ 0x001B. They have different names though. The first 4 letters of the cipher
+ suite name are the protocol name: "SSL_" or "TLS_", rest of the IANA name is
+ the same for both SSL and TLS cipher suite name.
+ The second part of the problem is that macOS/iOS SDKs don't define all TLS
+ codes but only 12 of them. The SDK defines all SSL codes though, i.e. SSL_NUM
+ constant is always defined for those 28 ciphers while TLS_NUM is defined only
+ for 12 of the first 28 ciphers. Those 12 TLS cipher codes match to
+ corresponding SSL enum value and represent the same cipher suite. Therefore
+ we'll use the SSL enum value for those cipher suites because it is defined
+ for all 28 of them.
+ We make internal data consistent and based on TLS names, i.e. all st_cipher
+ item names start with the "TLS_" prefix.
+ Summarizing all the above, those 28 first ciphers are presented in our table
+ with both TLS and SSL names. Their cipher numbers are assigned based on the
+ SDK enum value for the SSL cipher, which matches to IANA TLS number.
+ */
+#define CIPHER_DEF_SSLTLS(num_wo_prefix, alias, weak) \
+  { "TLS_" #num_wo_prefix, alias, SSL_##num_wo_prefix, weak }
+
+/*
+ Cipher suites were marked as weak based on the following:
+ RC4 encryption - rfc7465, the document contains a list of deprecated ciphers.
+     Marked in the code below as weak.
+ RC2 encryption - many mentions, was found vulnerable to a relatively easy
+     attack https://link.springer.com/chapter/10.1007%2F3-540-69710-1_14
+     Marked in the code below as weak.
+ DES and IDEA encryption - rfc5469, has a list of deprecated ciphers.
+     Marked in the code below as weak.
+ Anonymous Diffie-Hellman authentication and anonymous elliptic curve
+     Diffie-Hellman - vulnerable to a man-in-the-middle attack. Deprecated by
+     RFC 4346 aka TLS 1.1 (section A.5, page 60)
+ Null bulk encryption suites - not encrypted communication
+ Export ciphers, i.e. ciphers with restrictions to be used outside the US for
+     software exported to some countries, they were excluded from TLS 1.1
+     version. More precisely, they were noted as ciphers which MUST NOT be
+     negotiated in RFC 4346 aka TLS 1.1 (section A.5, pages 60 and 61).
+     All of those filters were considered weak because they contain a weak
+     algorithm like DES, RC2 or RC4, and already considered weak by other
+     criteria.
+ 3DES - NIST deprecated it and is going to retire it by 2023
+ https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA
+     OpenSSL https://www.openssl.org/blog/blog/2016/08/24/sweet32/ also
+     deprecated those ciphers. Some other libraries also consider it
+     vulnerable or at least not strong enough.
+
+ CBC ciphers are vulnerable with SSL3.0 and TLS1.0:
+ https://www.cisco.com/c/en/us/support/docs/security/email-security-appliance
+ /118518-technote-esa-00.html
+     We don't take care of this issue because it is resolved by later TLS
+     versions and for us, it requires more complicated checks, we need to
+     check a protocol version also. Vulnerability doesn't look very critical
+     and we do not filter out those cipher suites.
+ */
+
+#define CIPHER_WEAK_NOT_ENCRYPTED   TRUE
+#define CIPHER_WEAK_RC_ENCRYPTION   TRUE
+#define CIPHER_WEAK_DES_ENCRYPTION  TRUE
+#define CIPHER_WEAK_IDEA_ENCRYPTION TRUE
+#define CIPHER_WEAK_ANON_AUTH       TRUE
+#define CIPHER_WEAK_3DES_ENCRYPTION TRUE
+#define CIPHER_STRONG_ENOUGH        FALSE
+
+/* Please do not change the order of the first ciphers available for SSL.
+   Do not insert and do not delete any of them. Code below
+   depends on their order and continuity.
+   If you add a new cipher, please maintain order by number, i.e.
+   insert in between existing items to appropriate place based on
+   cipher suite IANA number
+*/
+static const struct st_cipher ciphertable[] = {
+  /* SSL version 3.0 and initial TLS 1.0 cipher suites.
+     Defined since SDK 10.2.8 */
+  CIPHER_DEF_SSLTLS(NULL_WITH_NULL_NULL,                           /* 0x0000 */
+                    NULL,
+                    CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF_SSLTLS(RSA_WITH_NULL_MD5,                             /* 0x0001 */
+                    "NULL-MD5",
+                    CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF_SSLTLS(RSA_WITH_NULL_SHA,                             /* 0x0002 */
+                    "NULL-SHA",
+                    CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_RC4_40_MD5,                    /* 0x0003 */
+                    "EXP-RC4-MD5",
+                    CIPHER_WEAK_RC_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(RSA_WITH_RC4_128_MD5,                          /* 0x0004 */
+                    "RC4-MD5",
+                    CIPHER_WEAK_RC_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(RSA_WITH_RC4_128_SHA,                          /* 0x0005 */
+                    "RC4-SHA",
+                    CIPHER_WEAK_RC_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_RC2_CBC_40_MD5,                /* 0x0006 */
+                    "EXP-RC2-CBC-MD5",
+                    CIPHER_WEAK_RC_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(RSA_WITH_IDEA_CBC_SHA,                         /* 0x0007 */
+                    "IDEA-CBC-SHA",
+                    CIPHER_WEAK_IDEA_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_DES40_CBC_SHA,                 /* 0x0008 */
+                    "EXP-DES-CBC-SHA",
+                    CIPHER_WEAK_DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(RSA_WITH_DES_CBC_SHA,                          /* 0x0009 */
+                    "DES-CBC-SHA",
+                    CIPHER_WEAK_DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(RSA_WITH_3DES_EDE_CBC_SHA,                     /* 0x000A */
+                    "DES-CBC3-SHA",
+                    CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DH_DSS_EXPORT_WITH_DES40_CBC_SHA,              /* 0x000B */
+                    "EXP-DH-DSS-DES-CBC-SHA",
+                    CIPHER_WEAK_DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DH_DSS_WITH_DES_CBC_SHA,                       /* 0x000C */
+                    "DH-DSS-DES-CBC-SHA",
+                    CIPHER_WEAK_DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DH_DSS_WITH_3DES_EDE_CBC_SHA,                  /* 0x000D */
+                    "DH-DSS-DES-CBC3-SHA",
+                    CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DH_RSA_EXPORT_WITH_DES40_CBC_SHA,              /* 0x000E */
+                    "EXP-DH-RSA-DES-CBC-SHA",
+                    CIPHER_WEAK_DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DH_RSA_WITH_DES_CBC_SHA,                       /* 0x000F */
+                    "DH-RSA-DES-CBC-SHA",
+                    CIPHER_WEAK_DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DH_RSA_WITH_3DES_EDE_CBC_SHA,                  /* 0x0010 */
+                    "DH-RSA-DES-CBC3-SHA",
+                    CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,             /* 0x0011 */
+                    "EXP-EDH-DSS-DES-CBC-SHA",
+                    CIPHER_WEAK_DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DHE_DSS_WITH_DES_CBC_SHA,                      /* 0x0012 */
+                    "EDH-DSS-CBC-SHA",
+                    CIPHER_WEAK_DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DHE_DSS_WITH_3DES_EDE_CBC_SHA,                 /* 0x0013 */
+                    "DHE-DSS-DES-CBC3-SHA",
+                    CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,             /* 0x0014 */
+                    "EXP-EDH-RSA-DES-CBC-SHA",
+                    CIPHER_WEAK_DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DHE_RSA_WITH_DES_CBC_SHA,                      /* 0x0015 */
+                    "EDH-RSA-DES-CBC-SHA",
+                    CIPHER_WEAK_DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DHE_RSA_WITH_3DES_EDE_CBC_SHA,                 /* 0x0016 */
+                    "DHE-RSA-DES-CBC3-SHA",
+                    CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF_SSLTLS(DH_anon_EXPORT_WITH_RC4_40_MD5,                /* 0x0017 */
+                    "EXP-ADH-RC4-MD5",
+                    CIPHER_WEAK_ANON_AUTH),
+  CIPHER_DEF_SSLTLS(DH_anon_WITH_RC4_128_MD5,                      /* 0x0018 */
+                    "ADH-RC4-MD5",
+                    CIPHER_WEAK_ANON_AUTH),
+  CIPHER_DEF_SSLTLS(DH_anon_EXPORT_WITH_DES40_CBC_SHA,             /* 0x0019 */
+                    "EXP-ADH-DES-CBC-SHA",
+                    CIPHER_WEAK_ANON_AUTH),
+  CIPHER_DEF_SSLTLS(DH_anon_WITH_DES_CBC_SHA,                      /* 0x001A */
+                    "ADH-DES-CBC-SHA",
+                    CIPHER_WEAK_ANON_AUTH),
+  CIPHER_DEF_SSLTLS(DH_anon_WITH_3DES_EDE_CBC_SHA,                 /* 0x001B */
+                    "ADH-DES-CBC3-SHA",
+                    CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF(SSL_FORTEZZA_DMS_WITH_NULL_SHA,                       /* 0x001C */
+             NULL,
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA,               /* 0x001D */
+             NULL,
+             CIPHER_STRONG_ENOUGH),
+
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+  /* RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption */
+  CIPHER_DEF(TLS_PSK_WITH_NULL_SHA,                                /* 0x002C */
+             "PSK-NULL-SHA",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA,                            /* 0x002D */
+             "DHE-PSK-NULL-SHA",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA,                            /* 0x002E */
+             "RSA-PSK-NULL-SHA",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+
+  /* TLS addenda using AES, per RFC 3268. Defined since SDK 10.4u */
+  CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA,                         /* 0x002F */
+             "AES128-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_CBC_SHA,                      /* 0x0030 */
+             "DH-DSS-AES128-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_CBC_SHA,                      /* 0x0031 */
+             "DH-RSA-AES128-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_CBC_SHA,                     /* 0x0032 */
+             "DHE-DSS-AES128-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_CBC_SHA,                     /* 0x0033 */
+             "DHE-RSA-AES128-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_anon_WITH_AES_128_CBC_SHA,                     /* 0x0034 */
+             "ADH-AES128-SHA",
+             CIPHER_WEAK_ANON_AUTH),
+  CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA,                         /* 0x0035 */
+             "AES256-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_CBC_SHA,                      /* 0x0036 */
+             "DH-DSS-AES256-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_CBC_SHA,                      /* 0x0037 */
+             "DH-RSA-AES256-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_CBC_SHA,                     /* 0x0038 */
+             "DHE-DSS-AES256-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_CBC_SHA,                     /* 0x0039 */
+             "DHE-RSA-AES256-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_anon_WITH_AES_256_CBC_SHA,                     /* 0x003A */
+             "ADH-AES256-SHA",
+             CIPHER_WEAK_ANON_AUTH),
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+  /* TLS 1.2 addenda, RFC 5246 */
+  /* Server provided RSA certificate for key exchange. */
+  CIPHER_DEF(TLS_RSA_WITH_NULL_SHA256,                             /* 0x003B */
+             "NULL-SHA256",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA256,                      /* 0x003C */
+             "AES128-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA256,                      /* 0x003D */
+             "AES256-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  /* Server-authenticated (and optionally client-authenticated)
+     Diffie-Hellman. */
+  CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_CBC_SHA256,                   /* 0x003E */
+             "DH-DSS-AES128-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_CBC_SHA256,                   /* 0x003F */
+             "DH-RSA-AES128-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,                  /* 0x0040 */
+             "DHE-DSS-AES128-SHA256",
+             CIPHER_STRONG_ENOUGH),
+
+  /* TLS 1.2 addenda, RFC 5246 */
+  CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,                  /* 0x0067 */
+             "DHE-RSA-AES128-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_CBC_SHA256,                   /* 0x0068 */
+             "DH-DSS-AES256-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_CBC_SHA256,                   /* 0x0069 */
+             "DH-RSA-AES256-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,                  /* 0x006A */
+             "DHE-DSS-AES256-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,                  /* 0x006B */
+             "DHE-RSA-AES256-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_anon_WITH_AES_128_CBC_SHA256,                  /* 0x006C */
+             "ADH-AES128-SHA256",
+             CIPHER_WEAK_ANON_AUTH),
+  CIPHER_DEF(TLS_DH_anon_WITH_AES_256_CBC_SHA256,                  /* 0x006D */
+             "ADH-AES256-SHA256",
+             CIPHER_WEAK_ANON_AUTH),
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+  /* Addendum from RFC 4279, TLS PSK */
+  CIPHER_DEF(TLS_PSK_WITH_RC4_128_SHA,                             /* 0x008A */
+             "PSK-RC4-SHA",
+             CIPHER_WEAK_RC_ENCRYPTION),
+  CIPHER_DEF(TLS_PSK_WITH_3DES_EDE_CBC_SHA,                        /* 0x008B */
+             "PSK-3DES-EDE-CBC-SHA",
+             CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF(TLS_PSK_WITH_AES_128_CBC_SHA,                         /* 0x008C */
+             "PSK-AES128-CBC-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_PSK_WITH_AES_256_CBC_SHA,                         /* 0x008D */
+             "PSK-AES256-CBC-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_PSK_WITH_RC4_128_SHA,                         /* 0x008E */
+             "DHE-PSK-RC4-SHA",
+             CIPHER_WEAK_RC_ENCRYPTION),
+  CIPHER_DEF(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,                    /* 0x008F */
+             "DHE-PSK-3DES-EDE-CBC-SHA",
+             CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_CBC_SHA,                     /* 0x0090 */
+             "DHE-PSK-AES128-CBC-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_CBC_SHA,                     /* 0x0091 */
+             "DHE-PSK-AES256-CBC-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_RSA_PSK_WITH_RC4_128_SHA,                         /* 0x0092 */
+             "RSA-PSK-RC4-SHA",
+             CIPHER_WEAK_RC_ENCRYPTION),
+  CIPHER_DEF(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,                    /* 0x0093 */
+             "RSA-PSK-3DES-EDE-CBC-SHA",
+             CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_CBC_SHA,                     /* 0x0094 */
+             "RSA-PSK-AES128-CBC-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_CBC_SHA,                     /* 0x0095 */
+             "RSA-PSK-AES256-CBC-SHA",
+             CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+  /* Addenda from rfc 5288 AES Galois Counter Mode (GCM) Cipher Suites
+     for TLS. */
+  CIPHER_DEF(TLS_RSA_WITH_AES_128_GCM_SHA256,                      /* 0x009C */
+             "AES128-GCM-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_RSA_WITH_AES_256_GCM_SHA384,                      /* 0x009D */
+             "AES256-GCM-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,                  /* 0x009E */
+             "DHE-RSA-AES128-GCM-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,                  /* 0x009F */
+             "DHE-RSA-AES256-GCM-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_GCM_SHA256,                   /* 0x00A0 */
+             "DH-RSA-AES128-GCM-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_GCM_SHA384,                   /* 0x00A1 */
+             "DH-RSA-AES256-GCM-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,                  /* 0x00A2 */
+             "DHE-DSS-AES128-GCM-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,                  /* 0x00A3 */
+             "DHE-DSS-AES256-GCM-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_GCM_SHA256,                   /* 0x00A4 */
+             "DH-DSS-AES128-GCM-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_GCM_SHA384,                   /* 0x00A5 */
+             "DH-DSS-AES256-GCM-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DH_anon_WITH_AES_128_GCM_SHA256,                  /* 0x00A6 */
+             "ADH-AES128-GCM-SHA256",
+             CIPHER_WEAK_ANON_AUTH),
+  CIPHER_DEF(TLS_DH_anon_WITH_AES_256_GCM_SHA384,                  /* 0x00A7 */
+             "ADH-AES256-GCM-SHA384",
+             CIPHER_WEAK_ANON_AUTH),
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+  /* RFC 5487 - PSK with SHA-256/384 and AES GCM */
+  CIPHER_DEF(TLS_PSK_WITH_AES_128_GCM_SHA256,                      /* 0x00A8 */
+             "PSK-AES128-GCM-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_PSK_WITH_AES_256_GCM_SHA384,                      /* 0x00A9 */
+             "PSK-AES256-GCM-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,                  /* 0x00AA */
+             "DHE-PSK-AES128-GCM-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,                  /* 0x00AB */
+             "DHE-PSK-AES256-GCM-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,                  /* 0x00AC */
+             "RSA-PSK-AES128-GCM-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,                  /* 0x00AD */
+             "RSA-PSK-AES256-GCM-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_PSK_WITH_AES_128_CBC_SHA256,                      /* 0x00AE */
+             "PSK-AES128-CBC-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_PSK_WITH_AES_256_CBC_SHA384,                      /* 0x00AF */
+             "PSK-AES256-CBC-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_PSK_WITH_NULL_SHA256,                             /* 0x00B0 */
+             "PSK-NULL-SHA256",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(TLS_PSK_WITH_NULL_SHA384,                             /* 0x00B1 */
+             "PSK-NULL-SHA384",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,                  /* 0x00B2 */
+             "DHE-PSK-AES128-CBC-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,                  /* 0x00B3 */
+             "DHE-PSK-AES256-CBC-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA256,                         /* 0x00B4 */
+             "DHE-PSK-NULL-SHA256",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA384,                         /* 0x00B5 */
+             "DHE-PSK-NULL-SHA384",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,                  /* 0x00B6 */
+             "RSA-PSK-AES128-CBC-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,                  /* 0x00B7 */
+             "RSA-PSK-AES256-CBC-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA256,                         /* 0x00B8 */
+             "RSA-PSK-NULL-SHA256",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA384,                         /* 0x00B9 */
+             "RSA-PSK-NULL-SHA384",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+
+  /* RFC 5746 - Secure Renegotiation. This is not a real suite,
+     it is a response to initiate negotiation again */
+  CIPHER_DEF(TLS_EMPTY_RENEGOTIATION_INFO_SCSV,                    /* 0x00FF */
+             NULL,
+             CIPHER_STRONG_ENOUGH),
+
+#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
+  /* TLS 1.3 standard cipher suites for ChaCha20+Poly1305.
+     Note: TLS 1.3 ciphersuites do not specify the key exchange
+     algorithm -- they only specify the symmetric ciphers.
+     Cipher alias name matches to OpenSSL cipher name, and for
+     TLS 1.3 ciphers */
+  CIPHER_DEF(TLS_AES_128_GCM_SHA256,                               /* 0x1301 */
+             NULL,  /* The OpenSSL cipher name matches to the IANA name */
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_AES_256_GCM_SHA384,                               /* 0x1302 */
+             NULL,  /* The OpenSSL cipher name matches to the IANA name */
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_CHACHA20_POLY1305_SHA256,                         /* 0x1303 */
+             NULL,  /* The OpenSSL cipher name matches to the IANA name */
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_AES_128_CCM_SHA256,                               /* 0x1304 */
+             NULL,  /* The OpenSSL cipher name matches to the IANA name */
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_AES_128_CCM_8_SHA256,                             /* 0x1305 */
+             NULL,  /* The OpenSSL cipher name matches to the IANA name */
+             CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
+
+#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
+  /* ECDSA addenda, RFC 4492 */
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_NULL_SHA,                         /* 0xC001 */
+             "ECDH-ECDSA-NULL-SHA",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_RC4_128_SHA,                      /* 0xC002 */
+             "ECDH-ECDSA-RC4-SHA",
+             CIPHER_WEAK_RC_ENCRYPTION),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,                 /* 0xC003 */
+             "ECDH-ECDSA-DES-CBC3-SHA",
+             CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,                  /* 0xC004 */
+             "ECDH-ECDSA-AES128-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,                  /* 0xC005 */
+             "ECDH-ECDSA-AES256-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_NULL_SHA,                        /* 0xC006 */
+             "ECDHE-ECDSA-NULL-SHA",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,                     /* 0xC007 */
+             "ECDHE-ECDSA-RC4-SHA",
+             CIPHER_WEAK_RC_ENCRYPTION),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,                /* 0xC008 */
+             "ECDHE-ECDSA-DES-CBC3-SHA",
+             CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,                 /* 0xC009 */
+             "ECDHE-ECDSA-AES128-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,                 /* 0xC00A */
+             "ECDHE-ECDSA-AES256-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_NULL_SHA,                           /* 0xC00B */
+             "ECDH-RSA-NULL-SHA",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_RC4_128_SHA,                        /* 0xC00C */
+             "ECDH-RSA-RC4-SHA",
+             CIPHER_WEAK_RC_ENCRYPTION),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,                   /* 0xC00D */
+             "ECDH-RSA-DES-CBC3-SHA",
+             CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,                    /* 0xC00E */
+             "ECDH-RSA-AES128-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,                    /* 0xC00F */
+             "ECDH-RSA-AES256-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_NULL_SHA,                          /* 0xC010 */
+             "ECDHE-RSA-NULL-SHA",
+             CIPHER_WEAK_NOT_ENCRYPTED),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_RC4_128_SHA,                       /* 0xC011 */
+             "ECDHE-RSA-RC4-SHA",
+             CIPHER_WEAK_RC_ENCRYPTION),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,                  /* 0xC012 */
+             "ECDHE-RSA-DES-CBC3-SHA",
+             CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,                   /* 0xC013 */
+             "ECDHE-RSA-AES128-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,                   /* 0xC014 */
+             "ECDHE-RSA-AES256-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDH_anon_WITH_NULL_SHA,                          /* 0xC015 */
+             "AECDH-NULL-SHA",
+             CIPHER_WEAK_ANON_AUTH),
+  CIPHER_DEF(TLS_ECDH_anon_WITH_RC4_128_SHA,                       /* 0xC016 */
+             "AECDH-RC4-SHA",
+             CIPHER_WEAK_ANON_AUTH),
+  CIPHER_DEF(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,                  /* 0xC017 */
+             "AECDH-DES-CBC3-SHA",
+             CIPHER_WEAK_3DES_ENCRYPTION),
+  CIPHER_DEF(TLS_ECDH_anon_WITH_AES_128_CBC_SHA,                   /* 0xC018 */
+             "AECDH-AES128-SHA",
+             CIPHER_WEAK_ANON_AUTH),
+  CIPHER_DEF(TLS_ECDH_anon_WITH_AES_256_CBC_SHA,                   /* 0xC019 */
+             "AECDH-AES256-SHA",
+             CIPHER_WEAK_ANON_AUTH),
+#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+  /* Addenda from rfc 5289  Elliptic Curve Cipher Suites with
+     HMAC SHA-256/384. */
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,              /* 0xC023 */
+             "ECDHE-ECDSA-AES128-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,              /* 0xC024 */
+             "ECDHE-ECDSA-AES256-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,               /* 0xC025 */
+             "ECDH-ECDSA-AES128-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,               /* 0xC026 */
+             "ECDH-ECDSA-AES256-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,                /* 0xC027 */
+             "ECDHE-RSA-AES128-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,                /* 0xC028 */
+             "ECDHE-RSA-AES256-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,                 /* 0xC029 */
+             "ECDH-RSA-AES128-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,                 /* 0xC02A */
+             "ECDH-RSA-AES256-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  /* Addenda from rfc 5289  Elliptic Curve Cipher Suites with
+     SHA-256/384 and AES Galois Counter Mode (GCM) */
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,              /* 0xC02B */
+             "ECDHE-ECDSA-AES128-GCM-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,              /* 0xC02C */
+             "ECDHE-ECDSA-AES256-GCM-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,               /* 0xC02D */
+             "ECDH-ECDSA-AES128-GCM-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,               /* 0xC02E */
+             "ECDH-ECDSA-AES256-GCM-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,                /* 0xC02F */
+             "ECDHE-RSA-AES128-GCM-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,                /* 0xC030 */
+             "ECDHE-RSA-AES256-GCM-SHA384",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,                 /* 0xC031 */
+             "ECDH-RSA-AES128-GCM-SHA256",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,                 /* 0xC032 */
+             "ECDH-RSA-AES256-GCM-SHA384",
+             CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+
+#if CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13
+  /* ECDHE_PSK Cipher Suites for Transport Layer Security (TLS), RFC 5489 */
+  CIPHER_DEF(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,                   /* 0xC035 */
+             "ECDHE-PSK-AES128-CBC-SHA",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA,                   /* 0xC036 */
+             "ECDHE-PSK-AES256-CBC-SHA",
+             CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 */
+
+#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
+  /* Addenda from rfc 7905  ChaCha20-Poly1305 Cipher Suites for
+     Transport Layer Security (TLS). */
+  CIPHER_DEF(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,          /* 0xCCA8 */
+             "ECDHE-RSA-CHACHA20-POLY1305",
+             CIPHER_STRONG_ENOUGH),
+  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,        /* 0xCCA9 */
+             "ECDHE-ECDSA-CHACHA20-POLY1305",
+             CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
+
+#if CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13
+  /* ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS),
+     RFC 7905 */
+  CIPHER_DEF(TLS_PSK_WITH_CHACHA20_POLY1305_SHA256,                /* 0xCCAB */
+             "PSK-CHACHA20-POLY1305",
+             CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 */
+
+  /* Tags for SSL 2 cipher kinds which are not specified for SSL 3.
+     Defined since SDK 10.2.8 */
+  CIPHER_DEF(SSL_RSA_WITH_RC2_CBC_MD5,                             /* 0xFF80 */
+             NULL,
+             CIPHER_WEAK_RC_ENCRYPTION),
+  CIPHER_DEF(SSL_RSA_WITH_IDEA_CBC_MD5,                            /* 0xFF81 */
+             NULL,
+             CIPHER_WEAK_IDEA_ENCRYPTION),
+  CIPHER_DEF(SSL_RSA_WITH_DES_CBC_MD5,                             /* 0xFF82 */
+             NULL,
+             CIPHER_WEAK_DES_ENCRYPTION),
+  CIPHER_DEF(SSL_RSA_WITH_3DES_EDE_CBC_MD5,                        /* 0xFF83 */
+             NULL,
+             CIPHER_WEAK_3DES_ENCRYPTION),
+};
+
+#define NUM_OF_CIPHERS sizeof(ciphertable)/sizeof(ciphertable[0])
+
+
+/* pinned public key support tests */
+
+/* version 1 supports macOS 10.12+ and iOS 10+ */
+#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \
+    (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED  >= 101200))
+#define SECTRANSP_PINNEDPUBKEY_V1 1
+#endif
+
+/* version 2 supports MacOSX 10.7+ */
+#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)
+#define SECTRANSP_PINNEDPUBKEY_V2 1
+#endif
+
+#if defined(SECTRANSP_PINNEDPUBKEY_V1) || defined(SECTRANSP_PINNEDPUBKEY_V2)
+/* this backend supports CURLOPT_PINNEDPUBLICKEY */
+#define SECTRANSP_PINNEDPUBKEY 1
+#endif /* SECTRANSP_PINNEDPUBKEY */
+
+#ifdef SECTRANSP_PINNEDPUBKEY
+/* both new and old APIs return rsa keys missing the spki header (not DER) */
+static const unsigned char rsa4096SpkiHeader[] = {
+                                       0x30, 0x82, 0x02, 0x22, 0x30, 0x0d,
+                                       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+                                       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+                                       0x00, 0x03, 0x82, 0x02, 0x0f, 0x00};
+
+static const unsigned char rsa2048SpkiHeader[] = {
+                                       0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
+                                       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+                                       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+                                       0x00, 0x03, 0x82, 0x01, 0x0f, 0x00};
+#ifdef SECTRANSP_PINNEDPUBKEY_V1
+/* the *new* version doesn't return DER encoded ecdsa certs like the old... */
+static const unsigned char ecDsaSecp256r1SpkiHeader[] = {
+                                       0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
+                                       0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+                                       0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
+                                       0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
+                                       0x42, 0x00};
+
+static const unsigned char ecDsaSecp384r1SpkiHeader[] = {
+                                       0x30, 0x76, 0x30, 0x10, 0x06, 0x07,
+                                       0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+                                       0x01, 0x06, 0x05, 0x2b, 0x81, 0x04,
+                                       0x00, 0x22, 0x03, 0x62, 0x00};
+#endif /* SECTRANSP_PINNEDPUBKEY_V1 */
+#endif /* SECTRANSP_PINNEDPUBKEY */
+
+static OSStatus sectransp_bio_cf_in_read(SSLConnectionRef connection,
+                                         void *buf,
+                                         size_t *dataLength)  /* IN/OUT */
+{
+  struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct st_ssl_backend_data *backend =
+    (struct st_ssl_backend_data *)connssl->backend;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  ssize_t nread;
+  CURLcode result;
+  OSStatus rtn = noErr;
+
+  DEBUGASSERT(data);
+  nread = Curl_conn_cf_recv(cf->next, data, buf, *dataLength, &result);
+  CURL_TRC_CF(data, cf, "bio_read(len=%zu) -> %zd, result=%d",
+              *dataLength, nread, result);
+  if(nread < 0) {
+    switch(result) {
+      case CURLE_OK:
+      case CURLE_AGAIN:
+        rtn = errSSLWouldBlock;
+        backend->ssl_direction = false;
+        break;
+      default:
+        rtn = ioErr;
+        break;
+    }
+    nread = 0;
+  }
+  else if(nread == 0) {
+    rtn = errSSLClosedGraceful;
+  }
+  else if((size_t)nread < *dataLength) {
+    rtn = errSSLWouldBlock;
+  }
+  *dataLength = nread;
+  return rtn;
+}
+
+static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection,
+                                           const void *buf,
+                                           size_t *dataLength)  /* IN/OUT */
+{
+  struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct st_ssl_backend_data *backend =
+    (struct st_ssl_backend_data *)connssl->backend;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  ssize_t nwritten;
+  CURLcode result;
+  OSStatus rtn = noErr;
+
+  DEBUGASSERT(data);
+  nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, &result);
+  CURL_TRC_CF(data, cf, "bio_send(len=%zu) -> %zd, result=%d",
+              *dataLength, nwritten, result);
+  if(nwritten <= 0) {
+    if(result == CURLE_AGAIN) {
+      rtn = errSSLWouldBlock;
+      backend->ssl_direction = true;
+    }
+    else {
+      rtn = ioErr;
+    }
+    nwritten = 0;
+  }
+  else if((size_t)nwritten < *dataLength) {
+    rtn = errSSLWouldBlock;
+  }
+  *dataLength = nwritten;
+  return rtn;
+}
+
+CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher)
+{
+  /* The first ciphers in the ciphertable are continuous. Here we do small
+     optimization and instead of loop directly get SSL name by cipher number.
+  */
+  size_t i;
+  if(cipher <= SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA) {
+    return ciphertable[cipher].name;
+  }
+  /* Iterate through the rest of the ciphers */
+  for(i = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA + 1; i < NUM_OF_CIPHERS;
+      ++i) {
+    if(ciphertable[i].num == cipher) {
+      return ciphertable[i].name;
+    }
+  }
+  return ciphertable[SSL_NULL_WITH_NULL_NULL].name;
+}
+
+#if CURL_BUILD_MAC
+CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
+{
+  int mib[2];
+  char *os_version;
+  size_t os_version_len;
+  char *os_version_major, *os_version_minor;
+  char *tok_buf;
+
+  /* Get the Darwin kernel version from the kernel using sysctl(): */
+  mib[0] = CTL_KERN;
+  mib[1] = KERN_OSRELEASE;
+  if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1)
+    return;
+  os_version = malloc(os_version_len*sizeof(char));
+  if(!os_version)
+    return;
+  if(sysctl(mib, 2, os_version, &os_version_len, NULL, 0) == -1) {
+    free(os_version);
+    return;
+  }
+
+  /* Parse the version: */
+  os_version_major = strtok_r(os_version, ".", &tok_buf);
+  os_version_minor = strtok_r(NULL, ".", &tok_buf);
+  *major = atoi(os_version_major);
+  *minor = atoi(os_version_minor);
+  free(os_version);
+}
+#endif /* CURL_BUILD_MAC */
+
+/* Apple provides a myriad of ways of getting information about a certificate
+   into a string. Some aren't available under iOS or newer cats. So here's
+   a unified function for getting a string describing the certificate that
+   ought to work in all cats starting with Leopard. */
+CF_INLINE CFStringRef getsubject(SecCertificateRef cert)
+{
+  CFStringRef server_cert_summary = CFSTR("(null)");
+
+#if CURL_BUILD_IOS
+  /* iOS: There's only one way to do this. */
+  server_cert_summary = SecCertificateCopySubjectSummary(cert);
+#else
+#if CURL_BUILD_MAC_10_7
+  /* Lion & later: Get the long description if we can. */
+  if(SecCertificateCopyLongDescription)
+    server_cert_summary =
+      SecCertificateCopyLongDescription(NULL, cert, NULL);
+  else
+#endif /* CURL_BUILD_MAC_10_7 */
+#if CURL_BUILD_MAC_10_6
+  /* Snow Leopard: Get the certificate summary. */
+  if(SecCertificateCopySubjectSummary)
+    server_cert_summary = SecCertificateCopySubjectSummary(cert);
+  else
+#endif /* CURL_BUILD_MAC_10_6 */
+  /* Leopard is as far back as we go... */
+  (void)SecCertificateCopyCommonName(cert, &server_cert_summary);
+#endif /* CURL_BUILD_IOS */
+  return server_cert_summary;
+}
+
+static CURLcode CopyCertSubject(struct Curl_easy *data,
+                                SecCertificateRef cert, char **certp)
+{
+  CFStringRef c = getsubject(cert);
+  CURLcode result = CURLE_OK;
+  const char *direct;
+  char *cbuf = NULL;
+  *certp = NULL;
+
+  if(!c) {
+    failf(data, "SSL: invalid CA certificate subject");
+    return CURLE_PEER_FAILED_VERIFICATION;
+  }
+
+  /* If the subject is already available as UTF-8 encoded (ie 'direct') then
+     use that, else convert it. */
+  direct = CFStringGetCStringPtr(c, kCFStringEncodingUTF8);
+  if(direct) {
+    *certp = strdup(direct);
+    if(!*certp) {
+      failf(data, "SSL: out of memory");
+      result = CURLE_OUT_OF_MEMORY;
+    }
+  }
+  else {
+    size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1;
+    cbuf = calloc(1, cbuf_size);
+    if(cbuf) {
+      if(!CFStringGetCString(c, cbuf, cbuf_size,
+                             kCFStringEncodingUTF8)) {
+        failf(data, "SSL: invalid CA certificate subject");
+        result = CURLE_PEER_FAILED_VERIFICATION;
+      }
+      else
+        /* pass back the buffer */
+        *certp = cbuf;
+    }
+    else {
+      failf(data, "SSL: couldn't allocate %zu bytes of memory", cbuf_size);
+      result = CURLE_OUT_OF_MEMORY;
+    }
+  }
+  if(result)
+    free(cbuf);
+  CFRelease(c);
+  return result;
+}
+
+#if CURL_SUPPORT_MAC_10_6
+/* The SecKeychainSearch API was deprecated in Lion, and using it will raise
+   deprecation warnings, so let's not compile this unless it's necessary: */
+static OSStatus CopyIdentityWithLabelOldSchool(char *label,
+                                               SecIdentityRef *out_c_a_k)
+{
+  OSStatus status = errSecItemNotFound;
+  SecKeychainAttributeList attr_list;
+  SecKeychainAttribute attr;
+  SecKeychainSearchRef search = NULL;
+  SecCertificateRef cert = NULL;
+
+  /* Set up the attribute list: */
+  attr_list.count = 1L;
+  attr_list.attr = &attr;
+
+  /* Set up our lone search criterion: */
+  attr.tag = kSecLabelItemAttr;
+  attr.data = label;
+  attr.length = (UInt32)strlen(label);
+
+  /* Start searching: */
+  status = SecKeychainSearchCreateFromAttributes(NULL,
+                                                 kSecCertificateItemClass,
+                                                 &attr_list,
+                                                 &search);
+  if(status == noErr) {
+    status = SecKeychainSearchCopyNext(search,
+                                       (SecKeychainItemRef *)&cert);
+    if(status == noErr && cert) {
+      /* If we found a certificate, does it have a private key? */
+      status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k);
+      CFRelease(cert);
+    }
+  }
+
+  if(search)
+    CFRelease(search);
+  return status;
+}
+#endif /* CURL_SUPPORT_MAC_10_6 */
+
+static OSStatus CopyIdentityWithLabel(char *label,
+                                      SecIdentityRef *out_cert_and_key)
+{
+  OSStatus status = errSecItemNotFound;
+
+#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
+  CFArrayRef keys_list;
+  CFIndex keys_list_count;
+  CFIndex i;
+
+  /* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
+     kSecClassIdentity was introduced in Lion. If both exist, let's use them
+     to find the certificate. */
+  if(SecItemCopyMatching && kSecClassIdentity) {
+    CFTypeRef keys[5];
+    CFTypeRef values[5];
+    CFDictionaryRef query_dict;
+    CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
+      kCFStringEncodingUTF8);
+
+    /* Set up our search criteria and expected results: */
+    values[0] = kSecClassIdentity; /* we want a certificate and a key */
+    keys[0] = kSecClass;
+    values[1] = kCFBooleanTrue;    /* we want a reference */
+    keys[1] = kSecReturnRef;
+    values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the
+                                    * label matching below worked correctly */
+    keys[2] = kSecMatchLimit;
+    /* identity searches need a SecPolicyRef in order to work */
+    values[3] = SecPolicyCreateSSL(false, NULL);
+    keys[3] = kSecMatchPolicy;
+    /* match the name of the certificate (doesn't work in macOS 10.12.1) */
+    values[4] = label_cf;
+    keys[4] = kSecAttrLabel;
+    query_dict = CFDictionaryCreate(NULL, (const void **)keys,
+                                    (const void **)values, 5L,
+                                    &kCFCopyStringDictionaryKeyCallBacks,
+                                    &kCFTypeDictionaryValueCallBacks);
+    CFRelease(values[3]);
+
+    /* Do we have a match? */
+    status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list);
+
+    /* Because kSecAttrLabel matching doesn't work with kSecClassIdentity,
+     * we need to find the correct identity ourselves */
+    if(status == noErr) {
+      keys_list_count = CFArrayGetCount(keys_list);
+      *out_cert_and_key = NULL;
+      status = 1;
+      for(i = 0; i<keys_list_count; i++) {
+        OSStatus err = noErr;
+        SecCertificateRef cert = NULL;
+        SecIdentityRef identity =
+          (SecIdentityRef) CFArrayGetValueAtIndex(keys_list, i);
+        err = SecIdentityCopyCertificate(identity, &cert);
+        if(err == noErr) {
+          CFStringRef common_name = NULL;
+          OSStatus copy_status = noErr;
+#if CURL_BUILD_IOS
+          common_name = SecCertificateCopySubjectSummary(cert);
+#elif CURL_BUILD_MAC_10_7
+          copy_status = SecCertificateCopyCommonName(cert, &common_name);
+#endif
+          if(copy_status == noErr &&
+            CFStringCompare(common_name, label_cf, 0) == kCFCompareEqualTo) {
+            CFRelease(cert);
+            CFRelease(common_name);
+            CFRetain(identity);
+            *out_cert_and_key = identity;
+            status = noErr;
+            break;
+          }
+          if(common_name)
+            CFRelease(common_name);
+        }
+        CFRelease(cert);
+      }
+    }
+
+    if(keys_list)
+      CFRelease(keys_list);
+    CFRelease(query_dict);
+    CFRelease(label_cf);
+  }
+  else {
+#if CURL_SUPPORT_MAC_10_6
+    /* On Leopard and Snow Leopard, fall back to SecKeychainSearch. */
+    status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
+#endif /* CURL_SUPPORT_MAC_10_6 */
+  }
+#elif CURL_SUPPORT_MAC_10_6
+  /* For developers building on older cats, we have no choice but to fall back
+     to SecKeychainSearch. */
+  status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
+#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
+  return status;
+}
+
+static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
+                                           const struct curl_blob *blob,
+                                           const char *cPassword,
+                                           SecIdentityRef *out_cert_and_key)
+{
+  OSStatus status = errSecItemNotFound;
+  CFURLRef pkcs_url = NULL;
+  CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
+    cPassword, kCFStringEncodingUTF8) : NULL;
+  CFDataRef pkcs_data = NULL;
+
+  /* We can import P12 files on iOS or OS X 10.7 or later: */
+  /* These constants are documented as having first appeared in 10.6 but they
+     raise linker errors when used on that cat for some reason. */
+#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
+  bool resource_imported;
+
+  if(blob) {
+    pkcs_data = CFDataCreate(kCFAllocatorDefault,
+                             (const unsigned char *)blob->data, blob->len);
+    status = (pkcs_data != NULL) ? errSecSuccess : errSecAllocate;
+    resource_imported = (pkcs_data != NULL);
+  }
+  else {
+    pkcs_url =
+      CFURLCreateFromFileSystemRepresentation(NULL,
+                                              (const UInt8 *)cPath,
+                                              strlen(cPath), false);
+    resource_imported =
+      CFURLCreateDataAndPropertiesFromResource(NULL,
+                                               pkcs_url, &pkcs_data,
+                                               NULL, NULL, &status);
+  }
+
+  if(resource_imported) {
+    CFArrayRef items = NULL;
+
+  /* On iOS SecPKCS12Import will never add the client certificate to the
+   * Keychain.
+   *
+   * It gives us back a SecIdentityRef that we can use directly. */
+#if CURL_BUILD_IOS
+    const void *cKeys[] = {kSecImportExportPassphrase};
+    const void *cValues[] = {password};
+    CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
+      password ? 1L : 0L, NULL, NULL);
+
+    if(options) {
+      status = SecPKCS12Import(pkcs_data, options, &items);
+      CFRelease(options);
+    }
+
+
+  /* On macOS SecPKCS12Import will always add the client certificate to
+   * the Keychain.
+   *
+   * As this doesn't match iOS, and apps may not want to see their client
+   * certificate saved in the user's keychain, we use SecItemImport
+   * with a NULL keychain to avoid importing it.
+   *
+   * This returns a SecCertificateRef from which we can construct a
+   * SecIdentityRef.
+   */
+#elif CURL_BUILD_MAC_10_7
+    SecItemImportExportKeyParameters keyParams;
+    SecExternalFormat inputFormat = kSecFormatPKCS12;
+    SecExternalItemType inputType = kSecItemTypeCertificate;
+
+    memset(&keyParams, 0x00, sizeof(keyParams));
+    keyParams.version    = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
+    keyParams.passphrase = password;
+
+    status = SecItemImport(pkcs_data, NULL, &inputFormat, &inputType,
+                           0, &keyParams, NULL, &items);
+#endif
+
+
+    /* Extract the SecIdentityRef */
+    if(status == errSecSuccess && items && CFArrayGetCount(items)) {
+      CFIndex i, count;
+      count = CFArrayGetCount(items);
+
+      for(i = 0; i < count; i++) {
+        CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(items, i);
+        CFTypeID  itemID = CFGetTypeID(item);
+
+        if(itemID == CFDictionaryGetTypeID()) {
+          CFTypeRef identity = (CFTypeRef) CFDictionaryGetValue(
+                                                 (CFDictionaryRef) item,
+                                                 kSecImportItemIdentity);
+          CFRetain(identity);
+          *out_cert_and_key = (SecIdentityRef) identity;
+          break;
+        }
+#if CURL_BUILD_MAC_10_7
+        else if(itemID == SecCertificateGetTypeID()) {
+          status = SecIdentityCreateWithCertificate(NULL,
+                                                 (SecCertificateRef) item,
+                                                 out_cert_and_key);
+          break;
+        }
+#endif
+      }
+    }
+
+    if(items)
+      CFRelease(items);
+    CFRelease(pkcs_data);
+  }
+#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
+  if(password)
+    CFRelease(password);
+  if(pkcs_url)
+    CFRelease(pkcs_url);
+  return status;
+}
+
+/* This code was borrowed from nss.c, with some modifications:
+ * Determine whether the nickname passed in is a filename that needs to
+ * be loaded as a PEM or a nickname.
+ *
+ * returns 1 for a file
+ * returns 0 for not a file
+ */
+CF_INLINE bool is_file(const char *filename)
+{
+  struct_stat st;
+
+  if(!filename)
+    return false;
+
+  if(stat(filename, &st) == 0)
+    return S_ISREG(st.st_mode);
+  return false;
+}
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+static CURLcode sectransp_version_from_curl(SSLProtocol *darwinver,
+                                            long ssl_version)
+{
+  switch(ssl_version) {
+    case CURL_SSLVERSION_TLSv1_0:
+      *darwinver = kTLSProtocol1;
+      return CURLE_OK;
+    case CURL_SSLVERSION_TLSv1_1:
+      *darwinver = kTLSProtocol11;
+      return CURLE_OK;
+    case CURL_SSLVERSION_TLSv1_2:
+      *darwinver = kTLSProtocol12;
+      return CURLE_OK;
+    case CURL_SSLVERSION_TLSv1_3:
+      /* TLS 1.3 support first appeared in iOS 11 and macOS 10.13 */
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+      if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
+        *darwinver = kTLSProtocol13;
+        return CURLE_OK;
+      }
+#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
+          HAVE_BUILTIN_AVAILABLE == 1 */
+      break;
+  }
+  return CURLE_SSL_CONNECT_ERROR;
+}
+#endif
+
+static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf,
+                                        struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct st_ssl_backend_data *backend =
+    (struct st_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  long ssl_version = conn_config->version;
+  long ssl_version_max = conn_config->version_max;
+  long max_supported_version_by_os;
+
+  DEBUGASSERT(backend);
+
+  /* macOS 10.5-10.7 supported TLS 1.0 only.
+     macOS 10.8 and later, and iOS 5 and later, added TLS 1.1 and 1.2.
+     macOS 10.13 and later, and iOS 11 and later, added TLS 1.3. */
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+  if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
+    max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_3;
+  }
+  else {
+    max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2;
+  }
+#else
+  max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2;
+#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
+          HAVE_BUILTIN_AVAILABLE == 1 */
+
+  switch(ssl_version) {
+    case CURL_SSLVERSION_DEFAULT:
+    case CURL_SSLVERSION_TLSv1:
+      ssl_version = CURL_SSLVERSION_TLSv1_0;
+      break;
+  }
+
+  switch(ssl_version_max) {
+    case CURL_SSLVERSION_MAX_NONE:
+    case CURL_SSLVERSION_MAX_DEFAULT:
+      ssl_version_max = max_supported_version_by_os;
+      break;
+  }
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+  if(SSLSetProtocolVersionMax) {
+    SSLProtocol darwin_ver_min = kTLSProtocol1;
+    SSLProtocol darwin_ver_max = kTLSProtocol1;
+    CURLcode result = sectransp_version_from_curl(&darwin_ver_min,
+                                                  ssl_version);
+    if(result) {
+      failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
+      return result;
+    }
+    result = sectransp_version_from_curl(&darwin_ver_max,
+                                         ssl_version_max >> 16);
+    if(result) {
+      failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
+      return result;
+    }
+
+    (void)SSLSetProtocolVersionMin(backend->ssl_ctx, darwin_ver_min);
+    (void)SSLSetProtocolVersionMax(backend->ssl_ctx, darwin_ver_max);
+    return result;
+  }
+  else {
+#if CURL_SUPPORT_MAC_10_8
+    long i = ssl_version;
+    (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+                                       kSSLProtocolAll,
+                                       false);
+    for(; i <= (ssl_version_max >> 16); i++) {
+      switch(i) {
+        case CURL_SSLVERSION_TLSv1_0:
+          (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+                                            kTLSProtocol1,
+                                            true);
+          break;
+        case CURL_SSLVERSION_TLSv1_1:
+          (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+                                            kTLSProtocol11,
+                                            true);
+          break;
+        case CURL_SSLVERSION_TLSv1_2:
+          (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+                                            kTLSProtocol12,
+                                            true);
+          break;
+        case CURL_SSLVERSION_TLSv1_3:
+          failf(data, "Your version of the OS does not support TLSv1.3");
+          return CURLE_SSL_CONNECT_ERROR;
+      }
+    }
+    return CURLE_OK;
+#endif  /* CURL_SUPPORT_MAC_10_8 */
+  }
+#endif  /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+  failf(data, "Secure Transport: cannot set SSL protocol");
+  return CURLE_SSL_CONNECT_ERROR;
+}
+
+static bool is_cipher_suite_strong(SSLCipherSuite suite_num)
+{
+  size_t i;
+  for(i = 0; i < NUM_OF_CIPHERS; ++i) {
+    if(ciphertable[i].num == suite_num) {
+      return !ciphertable[i].weak;
+    }
+  }
+  /* If the cipher is not in our list, assume it is a new one
+     and therefore strong. Previous implementation was the same,
+     if cipher suite is not in the list, it was considered strong enough */
+  return true;
+}
+
+static bool is_separator(char c)
+{
+  /* Return whether character is a cipher list separator. */
+  switch(c) {
+  case ' ':
+  case '\t':
+  case ':':
+  case ',':
+  case ';':
+    return true;
+  }
+  return false;
+}
+
+static CURLcode sectransp_set_default_ciphers(struct Curl_easy *data,
+                                              SSLContextRef ssl_ctx)
+{
+  size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i;
+  SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL;
+  OSStatus err = noErr;
+
+#if CURL_BUILD_MAC
+  int darwinver_maj = 0, darwinver_min = 0;
+
+  GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
+#endif /* CURL_BUILD_MAC */
+
+  /* Disable cipher suites that ST supports but are not safe. These ciphers
+     are unlikely to be used in any case since ST gives other ciphers a much
+     higher priority, but it's probably better that we not connect at all than
+     to give the user a false sense of security if the server only supports
+     insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */
+  err = SSLGetNumberSupportedCiphers(ssl_ctx, &all_ciphers_count);
+  if(err != noErr) {
+    failf(data, "SSL: SSLGetNumberSupportedCiphers() failed: OSStatus %d",
+          err);
+    return CURLE_SSL_CIPHER;
+  }
+  all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+  if(!all_ciphers) {
+    failf(data, "SSL: Failed to allocate memory for all ciphers");
+    return CURLE_OUT_OF_MEMORY;
+  }
+  allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+  if(!allowed_ciphers) {
+    Curl_safefree(all_ciphers);
+    failf(data, "SSL: Failed to allocate memory for allowed ciphers");
+    return CURLE_OUT_OF_MEMORY;
+  }
+  err = SSLGetSupportedCiphers(ssl_ctx, all_ciphers,
+                               &all_ciphers_count);
+  if(err != noErr) {
+    Curl_safefree(all_ciphers);
+    Curl_safefree(allowed_ciphers);
+    return CURLE_SSL_CIPHER;
+  }
+  for(i = 0UL ; i < all_ciphers_count ; i++) {
+#if CURL_BUILD_MAC
+   /* There's a known bug in early versions of Mountain Lion where ST's ECC
+      ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
+      Work around the problem here by disabling those ciphers if we are
+      running in an affected version of OS X. */
+    if(darwinver_maj == 12 && darwinver_min <= 3 &&
+       all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
+      continue;
+    }
+#endif /* CURL_BUILD_MAC */
+    if(is_cipher_suite_strong(all_ciphers[i])) {
+      allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i];
+    }
+  }
+  err = SSLSetEnabledCiphers(ssl_ctx, allowed_ciphers,
+                             allowed_ciphers_count);
+  Curl_safefree(all_ciphers);
+  Curl_safefree(allowed_ciphers);
+  if(err != noErr) {
+    failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
+    return CURLE_SSL_CIPHER;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
+                                               SSLContextRef ssl_ctx,
+                                               const char *ciphers)
+{
+  size_t ciphers_count = 0;
+  const char *cipher_start = ciphers;
+  OSStatus err = noErr;
+  SSLCipherSuite selected_ciphers[NUM_OF_CIPHERS];
+
+  if(!ciphers)
+    return CURLE_OK;
+
+  while(is_separator(*ciphers))     /* Skip initial separators. */
+    ciphers++;
+  if(!*ciphers)
+    return CURLE_OK;
+
+  cipher_start = ciphers;
+  while(*cipher_start && ciphers_count < NUM_OF_CIPHERS) {
+    bool cipher_found = FALSE;
+    size_t cipher_len = 0;
+    const char *cipher_end = NULL;
+    bool tls_name = FALSE;
+    size_t i;
+
+    /* Skip separators */
+    while(is_separator(*cipher_start))
+      cipher_start++;
+    if(*cipher_start == '\0') {
+      break;
+    }
+    /* Find last position of a cipher in the ciphers string */
+    cipher_end = cipher_start;
+    while(*cipher_end != '\0' && !is_separator(*cipher_end)) {
+      ++cipher_end;
+    }
+
+    /* IANA cipher names start with the TLS_ or SSL_ prefix.
+       If the 4th symbol of the cipher is '_' we look for a cipher in the
+       table by its (TLS) name.
+       Otherwise, we try to match cipher by an alias. */
+    if(cipher_start[3] == '_') {
+      tls_name = TRUE;
+    }
+    /* Iterate through the cipher table and look for the cipher, starting
+       the cipher number 0x01 because the 0x00 is not the real cipher */
+    cipher_len = cipher_end - cipher_start;
+    for(i = 1; i < NUM_OF_CIPHERS; ++i) {
+      const char *table_cipher_name = NULL;
+      if(tls_name) {
+        table_cipher_name = ciphertable[i].name;
+      }
+      else if(ciphertable[i].alias_name) {
+        table_cipher_name = ciphertable[i].alias_name;
+      }
+      else {
+        continue;
+      }
+      /* Compare a part of the string between separators with a cipher name
+         in the table and make sure we matched the whole cipher name */
+      if(strncmp(cipher_start, table_cipher_name, cipher_len) == 0
+          && table_cipher_name[cipher_len] == '\0') {
+        selected_ciphers[ciphers_count] = ciphertable[i].num;
+        ++ciphers_count;
+        cipher_found = TRUE;
+        break;
+      }
+    }
+    if(!cipher_found) {
+      /* It would be more human-readable if we print the wrong cipher name
+         but we don't want to allocate any additional memory and copy the name
+         into it, then add it into logs.
+         Also, we do not modify an original cipher list string. We just point
+         to positions where cipher starts and ends in the cipher list string.
+         The message is a bit cryptic and longer than necessary but can be
+         understood by humans. */
+      failf(data, "SSL: cipher string \"%s\" contains unsupported cipher name"
+            " starting position %zd and ending position %zd",
+            ciphers,
+            cipher_start - ciphers,
+            cipher_end - ciphers);
+      return CURLE_SSL_CIPHER;
+    }
+    if(*cipher_end) {
+      cipher_start = cipher_end + 1;
+    }
+    else {
+      break;
+    }
+  }
+  /* All cipher suites in the list are found. Report to logs as-is */
+  infof(data, "SSL: Setting cipher suites list \"%s\"", ciphers);
+
+  err = SSLSetEnabledCiphers(ssl_ctx, selected_ciphers, ciphers_count);
+  if(err != noErr) {
+    failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
+    return CURLE_SSL_CIPHER;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
+                                        struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct st_ssl_backend_data *backend =
+    (struct st_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  const struct curl_blob *ssl_cablob = conn_config->ca_info_blob;
+  const char * const ssl_cafile =
+    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+    (ssl_cablob ? NULL : conn_config->CAfile);
+  const bool verifypeer = conn_config->verifypeer;
+  char * const ssl_cert = ssl_config->primary.clientcert;
+  const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
+  char *ciphers;
+  OSStatus err = noErr;
+#if CURL_BUILD_MAC
+  int darwinver_maj = 0, darwinver_min = 0;
+
+  DEBUGASSERT(backend);
+
+  CURL_TRC_CF(data, cf, "connect_step1");
+  GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
+#endif /* CURL_BUILD_MAC */
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+  if(SSLCreateContext) {  /* use the newer API if available */
+    if(backend->ssl_ctx)
+      CFRelease(backend->ssl_ctx);
+    backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
+    if(!backend->ssl_ctx) {
+      failf(data, "SSL: couldn't create a context");
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  else {
+  /* The old ST API does not exist under iOS, so don't compile it: */
+#if CURL_SUPPORT_MAC_10_8
+    if(backend->ssl_ctx)
+      (void)SSLDisposeContext(backend->ssl_ctx);
+    err = SSLNewContext(false, &(backend->ssl_ctx));
+    if(err != noErr) {
+      failf(data, "SSL: couldn't create a context: OSStatus %d", err);
+      return CURLE_OUT_OF_MEMORY;
+    }
+#endif /* CURL_SUPPORT_MAC_10_8 */
+  }
+#else
+  if(backend->ssl_ctx)
+    (void)SSLDisposeContext(backend->ssl_ctx);
+  err = SSLNewContext(false, &(backend->ssl_ctx));
+  if(err != noErr) {
+    failf(data, "SSL: couldn't create a context: OSStatus %d", err);
+    return CURLE_OUT_OF_MEMORY;
+  }
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+  backend->ssl_write_buffered_length = 0UL; /* reset buffered write length */
+
+  /* check to see if we've been told to use an explicit SSL/TLS version */
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+  if(SSLSetProtocolVersionMax) {
+    switch(conn_config->version) {
+    case CURL_SSLVERSION_TLSv1:
+      (void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1);
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+      if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
+        (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol13);
+      }
+      else {
+        (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12);
+      }
+#else
+      (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12);
+#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
+          HAVE_BUILTIN_AVAILABLE == 1 */
+      break;
+    case CURL_SSLVERSION_DEFAULT:
+    case CURL_SSLVERSION_TLSv1_0:
+    case CURL_SSLVERSION_TLSv1_1:
+    case CURL_SSLVERSION_TLSv1_2:
+    case CURL_SSLVERSION_TLSv1_3:
+      {
+        CURLcode result = set_ssl_version_min_max(cf, data);
+        if(result != CURLE_OK)
+          return result;
+        break;
+      }
+    case CURL_SSLVERSION_SSLv3:
+    case CURL_SSLVERSION_SSLv2:
+      failf(data, "SSL versions not supported");
+      return CURLE_NOT_BUILT_IN;
+    default:
+      failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+  else {
+#if CURL_SUPPORT_MAC_10_8
+    (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+                                       kSSLProtocolAll,
+                                       false);
+    switch(conn_config->version) {
+    case CURL_SSLVERSION_DEFAULT:
+    case CURL_SSLVERSION_TLSv1:
+      (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+                                         kTLSProtocol1,
+                                         true);
+      (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+                                         kTLSProtocol11,
+                                         true);
+      (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+                                         kTLSProtocol12,
+                                         true);
+      break;
+    case CURL_SSLVERSION_TLSv1_0:
+    case CURL_SSLVERSION_TLSv1_1:
+    case CURL_SSLVERSION_TLSv1_2:
+    case CURL_SSLVERSION_TLSv1_3:
+      {
+        CURLcode result = set_ssl_version_min_max(cf, data);
+        if(result != CURLE_OK)
+          return result;
+        break;
+      }
+    case CURL_SSLVERSION_SSLv3:
+    case CURL_SSLVERSION_SSLv2:
+      failf(data, "SSL versions not supported");
+      return CURLE_NOT_BUILT_IN;
+    default:
+      failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+#endif  /* CURL_SUPPORT_MAC_10_8 */
+  }
+#else
+  if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) {
+    failf(data, "Your version of the OS does not support to set maximum"
+                " SSL/TLS version");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+  (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false);
+  switch(conn_config->version) {
+  case CURL_SSLVERSION_DEFAULT:
+  case CURL_SSLVERSION_TLSv1:
+  case CURL_SSLVERSION_TLSv1_0:
+    (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+                                       kTLSProtocol1,
+                                       true);
+    break;
+  case CURL_SSLVERSION_TLSv1_1:
+    failf(data, "Your version of the OS does not support TLSv1.1");
+    return CURLE_SSL_CONNECT_ERROR;
+  case CURL_SSLVERSION_TLSv1_2:
+    failf(data, "Your version of the OS does not support TLSv1.2");
+    return CURLE_SSL_CONNECT_ERROR;
+  case CURL_SSLVERSION_TLSv1_3:
+    failf(data, "Your version of the OS does not support TLSv1.3");
+    return CURLE_SSL_CONNECT_ERROR;
+  case CURL_SSLVERSION_SSLv2:
+  case CURL_SSLVERSION_SSLv3:
+    failf(data, "SSL versions not supported");
+    return CURLE_NOT_BUILT_IN;
+  default:
+    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+  if(connssl->alpn) {
+    if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
+      struct alpn_proto_buf proto;
+      size_t i;
+      CFStringRef cstr;
+      CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0,
+                                                       &kCFTypeArrayCallBacks);
+      for(i = 0; i < connssl->alpn->count; ++i) {
+        cstr = CFStringCreateWithCString(NULL, connssl->alpn->entries[i],
+                                         kCFStringEncodingUTF8);
+        if(!cstr)
+          return CURLE_OUT_OF_MEMORY;
+        CFArrayAppendValue(alpnArr, cstr);
+        CFRelease(cstr);
+      }
+      err = SSLSetALPNProtocols(backend->ssl_ctx, alpnArr);
+      if(err != noErr)
+        infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d",
+              err);
+      CFRelease(alpnArr);
+      Curl_alpn_to_proto_str(&proto, connssl->alpn);
+      infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+    }
+  }
+#endif
+
+  if(ssl_config->key) {
+    infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
+          "Transport. The private key must be in the Keychain.");
+  }
+
+  if(ssl_cert || ssl_cert_blob) {
+    bool is_cert_data = ssl_cert_blob != NULL;
+    bool is_cert_file = (!is_cert_data) && is_file(ssl_cert);
+    SecIdentityRef cert_and_key = NULL;
+
+    /* User wants to authenticate with a client cert. Look for it. Assume that
+       the user wants to use an identity loaded from the Keychain. If not, try
+       it as a file on disk */
+
+    if(!is_cert_data)
+      err = CopyIdentityWithLabel(ssl_cert, &cert_and_key);
+    else
+      err = !noErr;
+    if((err != noErr) && (is_cert_file || is_cert_data)) {
+      if(!ssl_config->cert_type)
+        infof(data, "SSL: Certificate type not set, assuming "
+              "PKCS#12 format.");
+      else if(!strcasecompare(ssl_config->cert_type, "P12")) {
+        failf(data, "SSL: The Security framework only supports "
+              "loading identities that are in PKCS#12 format.");
+        return CURLE_SSL_CERTPROBLEM;
+      }
+
+      err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob,
+                                       ssl_config->key_passwd,
+                                       &cert_and_key);
+    }
+
+    if(err == noErr && cert_and_key) {
+      SecCertificateRef cert = NULL;
+      CFTypeRef certs_c[1];
+      CFArrayRef certs;
+
+      /* If we found one, print it out: */
+      err = SecIdentityCopyCertificate(cert_and_key, &cert);
+      if(err == noErr) {
+        char *certp;
+        CURLcode result = CopyCertSubject(data, cert, &certp);
+        if(!result) {
+          infof(data, "Client certificate: %s", certp);
+          free(certp);
+        }
+
+        CFRelease(cert);
+        if(result == CURLE_PEER_FAILED_VERIFICATION)
+          return CURLE_SSL_CERTPROBLEM;
+        if(result)
+          return result;
+      }
+      certs_c[0] = cert_and_key;
+      certs = CFArrayCreate(NULL, (const void **)certs_c, 1L,
+                            &kCFTypeArrayCallBacks);
+      err = SSLSetCertificate(backend->ssl_ctx, certs);
+      if(certs)
+        CFRelease(certs);
+      if(err != noErr) {
+        failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err);
+        return CURLE_SSL_CERTPROBLEM;
+      }
+      CFRelease(cert_and_key);
+    }
+    else {
+      const char *cert_showfilename_error =
+        is_cert_data ? "(memory blob)" : ssl_cert;
+
+      switch(err) {
+      case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */
+        failf(data, "SSL: Incorrect password for the certificate \"%s\" "
+                    "and its private key.", cert_showfilename_error);
+        break;
+      case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */
+        failf(data, "SSL: Couldn't make sense of the data in the "
+                    "certificate \"%s\" and its private key.",
+                    cert_showfilename_error);
+        break;
+      case -25260: /* errSecPassphraseRequired */
+        failf(data, "SSL The certificate \"%s\" requires a password.",
+                    cert_showfilename_error);
+        break;
+      case errSecItemNotFound:
+        failf(data, "SSL: Can't find the certificate \"%s\" and its private "
+                    "key in the Keychain.", cert_showfilename_error);
+        break;
+      default:
+        failf(data, "SSL: Can't load the certificate \"%s\" and its private "
+                    "key: OSStatus %d", cert_showfilename_error, err);
+        break;
+      }
+      return CURLE_SSL_CERTPROBLEM;
+    }
+  }
+
+  /* SSL always tries to verify the peer, this only says whether it should
+   * fail to connect if the verification fails, or if it should continue
+   * anyway. In the latter case the result of the verification is checked with
+   * SSL_get_verify_result() below. */
+#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
+  /* Snow Leopard introduced the SSLSetSessionOption() function, but due to
+     a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag
+     works, it doesn't work as expected under Snow Leopard, Lion or
+     Mountain Lion.
+     So we need to call SSLSetEnableCertVerify() on those older cats in order
+     to disable certificate validation if the user turned that off.
+     (SecureTransport will always validate the certificate chain by
+     default.)
+  Note:
+  Darwin 11.x.x is Lion (10.7)
+  Darwin 12.x.x is Mountain Lion (10.8)
+  Darwin 13.x.x is Mavericks (10.9)
+  Darwin 14.x.x is Yosemite (10.10)
+  Darwin 15.x.x is El Capitan (10.11)
+  */
+#if CURL_BUILD_MAC
+  if(SSLSetSessionOption && darwinver_maj >= 13) {
+#else
+  if(SSLSetSessionOption) {
+#endif /* CURL_BUILD_MAC */
+    bool break_on_auth = !conn_config->verifypeer ||
+      ssl_cafile || ssl_cablob;
+    err = SSLSetSessionOption(backend->ssl_ctx,
+                              kSSLSessionOptionBreakOnServerAuth,
+                              break_on_auth);
+    if(err != noErr) {
+      failf(data, "SSL: SSLSetSessionOption() failed: OSStatus %d", err);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+  else {
+#if CURL_SUPPORT_MAC_10_8
+    err = SSLSetEnableCertVerify(backend->ssl_ctx,
+                                 conn_config->verifypeer?true:false);
+    if(err != noErr) {
+      failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+#endif /* CURL_SUPPORT_MAC_10_8 */
+  }
+#else
+  err = SSLSetEnableCertVerify(backend->ssl_ctx,
+                               conn_config->verifypeer?true:false);
+  if(err != noErr) {
+    failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
+
+  if((ssl_cafile || ssl_cablob) && verifypeer) {
+    bool is_cert_data = ssl_cablob != NULL;
+    bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile);
+
+    if(!(is_cert_file || is_cert_data)) {
+      failf(data, "SSL: can't load CA certificate file %s",
+            ssl_cafile ? ssl_cafile : "(blob memory)");
+      return CURLE_SSL_CACERT_BADFILE;
+    }
+  }
+
+  /* Configure hostname check. SNI is used if available.
+   * Both hostname check and SNI require SSLSetPeerDomainName().
+   * Also: the verifyhost setting influences SNI usage */
+  if(conn_config->verifyhost) {
+    char *server = connssl->peer.sni?
+                   connssl->peer.sni : connssl->peer.hostname;
+    err = SSLSetPeerDomainName(backend->ssl_ctx, server, strlen(server));
+
+    if(err != noErr) {
+      failf(data, "SSL: SSLSetPeerDomainName() failed: OSStatus %d",
+            err);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+
+    if(connssl->peer.type != CURL_SSL_PEER_DNS) {
+      infof(data, "WARNING: using IP address, SNI is being disabled by "
+            "the OS.");
+    }
+  }
+  else {
+    infof(data, "WARNING: disabling hostname validation also disables SNI.");
+  }
+
+  ciphers = conn_config->cipher_list;
+  if(ciphers) {
+    err = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers);
+  }
+  else {
+    err = sectransp_set_default_ciphers(data, backend->ssl_ctx);
+  }
+  if(err != noErr) {
+    failf(data, "SSL: Unable to set ciphers for SSL/TLS handshake. "
+          "Error code: %d", err);
+    return CURLE_SSL_CIPHER;
+  }
+
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+  /* We want to enable 1/n-1 when using a CBC cipher unless the user
+     specifically doesn't want us doing that: */
+  if(SSLSetSessionOption) {
+    SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
+                        !ssl_config->enable_beast);
+    SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart,
+                      ssl_config->falsestart); /* false start support */
+  }
+#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+
+  /* Check if there's a cached ID we can/should use here! */
+  if(ssl_config->primary.sessionid) {
+    char *ssl_sessionid;
+    size_t ssl_sessionid_len;
+
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(cf, data, (void **)&ssl_sessionid,
+                              &ssl_sessionid_len)) {
+      /* we got a session id, use it! */
+      err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
+      Curl_ssl_sessionid_unlock(data);
+      if(err != noErr) {
+        failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      /* Informational message */
+      infof(data, "SSL reusing session ID");
+    }
+    /* If there isn't one, then let's make one up! This has to be done prior
+       to starting the handshake. */
+    else {
+      CURLcode result;
+      ssl_sessionid =
+        aprintf("%s:%d:%d:%s:%d",
+                ssl_cafile ? ssl_cafile : "(blob memory)",
+                verifypeer, conn_config->verifyhost, connssl->peer.hostname,
+                connssl->port);
+      ssl_sessionid_len = strlen(ssl_sessionid);
+
+      err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
+      if(err != noErr) {
+        Curl_ssl_sessionid_unlock(data);
+        failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+
+      result = Curl_ssl_addsessionid(cf, data, ssl_sessionid,
+                                     ssl_sessionid_len, NULL);
+      Curl_ssl_sessionid_unlock(data);
+      if(result) {
+        failf(data, "failed to store ssl session");
+        return result;
+      }
+    }
+  }
+
+  err = SSLSetIOFuncs(backend->ssl_ctx,
+                      sectransp_bio_cf_in_read,
+                      sectransp_bio_cf_out_write);
+  if(err != noErr) {
+    failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  err = SSLSetConnection(backend->ssl_ctx, cf);
+  if(err != noErr) {
+    failf(data, "SSL: SSLSetConnection() failed: %d", err);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  connssl->connecting_state = ssl_connect_2;
+  return CURLE_OK;
+}
+
+static long pem_to_der(const char *in, unsigned char **out, size_t *outlen)
+{
+  char *sep_start, *sep_end, *cert_start, *cert_end;
+  size_t i, j, err;
+  size_t len;
+  unsigned char *b64;
+
+  /* Jump through the separators at the beginning of the certificate. */
+  sep_start = strstr(in, "-----");
+  if(!sep_start)
+    return 0;
+  cert_start = strstr(sep_start + 1, "-----");
+  if(!cert_start)
+    return -1;
+
+  cert_start += 5;
+
+  /* Find separator after the end of the certificate. */
+  cert_end = strstr(cert_start, "-----");
+  if(!cert_end)
+    return -1;
+
+  sep_end = strstr(cert_end + 1, "-----");
+  if(!sep_end)
+    return -1;
+  sep_end += 5;
+
+  len = cert_end - cert_start;
+  b64 = malloc(len + 1);
+  if(!b64)
+    return -1;
+
+  /* Create base64 string without linefeeds. */
+  for(i = 0, j = 0; i < len; i++) {
+    if(cert_start[i] != '\r' && cert_start[i] != '\n')
+      b64[j++] = cert_start[i];
+  }
+  b64[j] = '\0';
+
+  err = Curl_base64_decode((const char *)b64, out, outlen);
+  free(b64);
+  if(err) {
+    free(*out);
+    return -1;
+  }
+
+  return sep_end - in;
+}
+
+#define MAX_CERTS_SIZE (50*1024*1024) /* arbitrary - to catch mistakes */
+
+static int read_cert(const char *file, unsigned char **out, size_t *outlen)
+{
+  int fd;
+  ssize_t n;
+  unsigned char buf[512];
+  struct dynbuf certs;
+
+  Curl_dyn_init(&certs, MAX_CERTS_SIZE);
+
+  fd = open(file, 0);
+  if(fd < 0)
+    return -1;
+
+  for(;;) {
+    n = read(fd, buf, sizeof(buf));
+    if(!n)
+      break;
+    if(n < 0) {
+      close(fd);
+      Curl_dyn_free(&certs);
+      return -1;
+    }
+    if(Curl_dyn_addn(&certs, buf, n)) {
+      close(fd);
+      return -1;
+    }
+  }
+  close(fd);
+
+  *out = Curl_dyn_uptr(&certs);
+  *outlen = Curl_dyn_len(&certs);
+
+  return 0;
+}
+
+static int append_cert_to_array(struct Curl_easy *data,
+                                const unsigned char *buf, size_t buflen,
+                                CFMutableArrayRef array)
+{
+    char *certp;
+    CURLcode result;
+    SecCertificateRef cacert;
+    CFDataRef certdata;
+
+    certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
+    if(!certdata) {
+      failf(data, "SSL: failed to allocate array for CA certificate");
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    cacert = SecCertificateCreateWithData(kCFAllocatorDefault, certdata);
+    CFRelease(certdata);
+    if(!cacert) {
+      failf(data, "SSL: failed to create SecCertificate from CA certificate");
+      return CURLE_SSL_CACERT_BADFILE;
+    }
+
+    /* Check if cacert is valid. */
+    result = CopyCertSubject(data, cacert, &certp);
+    switch(result) {
+      case CURLE_OK:
+        break;
+      case CURLE_PEER_FAILED_VERIFICATION:
+        return CURLE_SSL_CACERT_BADFILE;
+      case CURLE_OUT_OF_MEMORY:
+      default:
+        return result;
+    }
+    free(certp);
+
+    CFArrayAppendValue(array, cacert);
+    CFRelease(cacert);
+
+    return CURLE_OK;
+}
+
+static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                const unsigned char *certbuf, size_t buflen,
+                                SSLContextRef ctx)
+{
+  int n = 0, rc;
+  long res;
+  unsigned char *der;
+  size_t derlen, offset = 0;
+  OSStatus ret;
+  SecTrustResultType trust_eval;
+  CFMutableArrayRef array = NULL;
+  SecTrustRef trust = NULL;
+  CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
+  (void)cf;
+  /*
+   * Certbuf now contains the contents of the certificate file, which can be
+   * - a single DER certificate,
+   * - a single PEM certificate or
+   * - a bunch of PEM certificates (certificate bundle).
+   *
+   * Go through certbuf, and convert any PEM certificate in it into DER
+   * format.
+   */
+  array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+  if(!array) {
+    failf(data, "SSL: out of memory creating CA certificate array");
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+
+  while(offset < buflen) {
+    n++;
+
+    /*
+     * Check if the certificate is in PEM format, and convert it to DER. If
+     * this fails, we assume the certificate is in DER format.
+     */
+    res = pem_to_der((const char *)certbuf + offset, &der, &derlen);
+    if(res < 0) {
+      failf(data, "SSL: invalid CA certificate #%d (offset %zu) in bundle",
+            n, offset);
+      result = CURLE_SSL_CACERT_BADFILE;
+      goto out;
+    }
+    offset += res;
+
+    if(res == 0 && offset == 0) {
+      /* This is not a PEM file, probably a certificate in DER format. */
+      rc = append_cert_to_array(data, certbuf, buflen, array);
+      if(rc != CURLE_OK) {
+        CURL_TRC_CF(data, cf, "append_cert for CA failed");
+        result = rc;
+        goto out;
+      }
+      break;
+    }
+    else if(res == 0) {
+      /* No more certificates in the bundle. */
+      break;
+    }
+
+    rc = append_cert_to_array(data, der, derlen, array);
+    free(der);
+    if(rc != CURLE_OK) {
+      CURL_TRC_CF(data, cf, "append_cert for CA failed");
+      result = rc;
+      goto out;
+    }
+  }
+
+  ret = SSLCopyPeerTrust(ctx, &trust);
+  if(!trust) {
+    failf(data, "SSL: error getting certificate chain");
+    goto out;
+  }
+  else if(ret != noErr) {
+    failf(data, "SSLCopyPeerTrust() returned error %d", ret);
+    goto out;
+  }
+
+  CURL_TRC_CF(data, cf, "setting %d trust anchors", n);
+  ret = SecTrustSetAnchorCertificates(trust, array);
+  if(ret != noErr) {
+    failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret);
+    goto out;
+  }
+  ret = SecTrustSetAnchorCertificatesOnly(trust, true);
+  if(ret != noErr) {
+    failf(data, "SecTrustSetAnchorCertificatesOnly() returned error %d", ret);
+    goto out;
+  }
+
+  trust_eval = 0;
+  ret = SecTrustEvaluate(trust, &trust_eval);
+  if(ret != noErr) {
+    failf(data, "SecTrustEvaluate() returned error %d", ret);
+    goto out;
+  }
+
+  switch(trust_eval) {
+    case kSecTrustResultUnspecified:
+      /* what does this really mean? */
+      CURL_TRC_CF(data, cf, "trust result: Unspecified");
+      result = CURLE_OK;
+      goto out;
+    case kSecTrustResultProceed:
+      CURL_TRC_CF(data, cf, "trust result: Proceed");
+      result = CURLE_OK;
+      goto out;
+
+    case kSecTrustResultRecoverableTrustFailure:
+      failf(data, "SSL: peer not verified:  RecoverableTrustFailure");
+      goto out;
+    case kSecTrustResultDeny:
+      failf(data, "SSL: peer not verified:  Deny");
+      goto out;
+    default:
+      failf(data, "SSL: perr not verified: result=%d", trust_eval);
+      goto out;
+  }
+
+out:
+  if(trust)
+    CFRelease(trust);
+  if(array)
+    CFRelease(array);
+  return result;
+}
+
+static CURLcode verify_cert(struct Curl_cfilter *cf,
+                            struct Curl_easy *data, const char *cafile,
+                            const struct curl_blob *ca_info_blob,
+                            SSLContextRef ctx)
+{
+  CURLcode result;
+  unsigned char *certbuf;
+  size_t buflen;
+  bool free_certbuf = FALSE;
+
+  if(ca_info_blob) {
+    CURL_TRC_CF(data, cf, "verify_peer, CA from config blob");
+    certbuf = ca_info_blob->data;
+    buflen = ca_info_blob->len;
+  }
+  else if(cafile) {
+    CURL_TRC_CF(data, cf, "verify_peer, CA from file '%s'", cafile);
+    if(read_cert(cafile, &certbuf, &buflen) < 0) {
+      failf(data, "SSL: failed to read or invalid CA certificate");
+      return CURLE_SSL_CACERT_BADFILE;
+    }
+    free_certbuf = TRUE;
+  }
+  else
+    return CURLE_SSL_CACERT_BADFILE;
+
+  result = verify_cert_buf(cf, data, certbuf, buflen, ctx);
+  if(free_certbuf)
+    free(certbuf);
+  return result;
+}
+
+
+#ifdef SECTRANSP_PINNEDPUBKEY
+static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
+                                    SSLContextRef ctx,
+                                    const char *pinnedpubkey)
+{  /* Scratch */
+  size_t pubkeylen, realpubkeylen, spkiHeaderLength = 24;
+  unsigned char *pubkey = NULL, *realpubkey = NULL;
+  const unsigned char *spkiHeader = NULL;
+  CFDataRef publicKeyBits = NULL;
+
+  /* Result is returned to caller */
+  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+  /* if a path wasn't specified, don't pin */
+  if(!pinnedpubkey)
+    return CURLE_OK;
+
+
+  if(!ctx)
+    return result;
+
+  do {
+    SecTrustRef trust;
+    OSStatus ret;
+    SecKeyRef keyRef;
+
+    ret = SSLCopyPeerTrust(ctx, &trust);
+    if(ret != noErr || !trust)
+      break;
+
+    keyRef = SecTrustCopyPublicKey(trust);
+    CFRelease(trust);
+    if(!keyRef)
+      break;
+
+#ifdef SECTRANSP_PINNEDPUBKEY_V1
+
+    publicKeyBits = SecKeyCopyExternalRepresentation(keyRef, NULL);
+    CFRelease(keyRef);
+    if(!publicKeyBits)
+      break;
+
+#elif SECTRANSP_PINNEDPUBKEY_V2
+
+    {
+        OSStatus success;
+        success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
+                                &publicKeyBits);
+        CFRelease(keyRef);
+        if(success != errSecSuccess || !publicKeyBits)
+          break;
+    }
+
+#endif /* SECTRANSP_PINNEDPUBKEY_V2 */
+
+    pubkeylen = CFDataGetLength(publicKeyBits);
+    pubkey = (unsigned char *)CFDataGetBytePtr(publicKeyBits);
+
+    switch(pubkeylen) {
+      case 526:
+        /* 4096 bit RSA pubkeylen == 526 */
+        spkiHeader = rsa4096SpkiHeader;
+        break;
+      case 270:
+        /* 2048 bit RSA pubkeylen == 270 */
+        spkiHeader = rsa2048SpkiHeader;
+        break;
+#ifdef SECTRANSP_PINNEDPUBKEY_V1
+      case 65:
+        /* ecDSA secp256r1 pubkeylen == 65 */
+        spkiHeader = ecDsaSecp256r1SpkiHeader;
+        spkiHeaderLength = 26;
+        break;
+      case 97:
+        /* ecDSA secp384r1 pubkeylen == 97 */
+        spkiHeader = ecDsaSecp384r1SpkiHeader;
+        spkiHeaderLength = 23;
+        break;
+      default:
+        infof(data, "SSL: unhandled public key length: %zu", pubkeylen);
+#elif SECTRANSP_PINNEDPUBKEY_V2
+      default:
+        /* ecDSA secp256r1 pubkeylen == 91 header already included?
+         * ecDSA secp384r1 header already included too
+         * we assume rest of algorithms do same, so do nothing
+         */
+        result = Curl_pin_peer_pubkey(data, pinnedpubkey, pubkey,
+                                    pubkeylen);
+#endif /* SECTRANSP_PINNEDPUBKEY_V2 */
+        continue; /* break from loop */
+    }
+
+    realpubkeylen = pubkeylen + spkiHeaderLength;
+    realpubkey = malloc(realpubkeylen);
+    if(!realpubkey)
+      break;
+
+    memcpy(realpubkey, spkiHeader, spkiHeaderLength);
+    memcpy(realpubkey + spkiHeaderLength, pubkey, pubkeylen);
+
+    result = Curl_pin_peer_pubkey(data, pinnedpubkey, realpubkey,
+                                  realpubkeylen);
+
+  } while(0);
+
+  Curl_safefree(realpubkey);
+  if(publicKeyBits)
+    CFRelease(publicKeyBits);
+
+  return result;
+}
+#endif /* SECTRANSP_PINNEDPUBKEY */
+
+static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf,
+                                        struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct st_ssl_backend_data *backend =
+    (struct st_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  OSStatus err;
+  SSLCipherSuite cipher;
+  SSLProtocol protocol = 0;
+
+  DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
+              || ssl_connect_2_reading == connssl->connecting_state
+              || ssl_connect_2_writing == connssl->connecting_state);
+  DEBUGASSERT(backend);
+  CURL_TRC_CF(data, cf, "connect_step2");
+
+  /* Here goes nothing: */
+check_handshake:
+  err = SSLHandshake(backend->ssl_ctx);
+
+  if(err != noErr) {
+    switch(err) {
+      case errSSLWouldBlock:  /* they're not done with us yet */
+        connssl->connecting_state = backend->ssl_direction ?
+            ssl_connect_2_writing : ssl_connect_2_reading;
+        return CURLE_OK;
+
+      /* The below is errSSLServerAuthCompleted; it's not defined in
+        Leopard's headers */
+      case -9841:
+        if((conn_config->CAfile || conn_config->ca_info_blob) &&
+           conn_config->verifypeer) {
+          CURLcode result = verify_cert(cf, data, conn_config->CAfile,
+                                        conn_config->ca_info_blob,
+                                        backend->ssl_ctx);
+          if(result)
+            return result;
+        }
+        /* the documentation says we need to call SSLHandshake() again */
+        goto check_handshake;
+
+      /* Problem with encrypt / decrypt */
+      case errSSLPeerDecodeError:
+        failf(data, "Decode failed");
+        break;
+      case errSSLDecryptionFail:
+      case errSSLPeerDecryptionFail:
+        failf(data, "Decryption failed");
+        break;
+      case errSSLPeerDecryptError:
+        failf(data, "A decryption error occurred");
+        break;
+      case errSSLBadCipherSuite:
+        failf(data, "A bad SSL cipher suite was encountered");
+        break;
+      case errSSLCrypto:
+        failf(data, "An underlying cryptographic error was encountered");
+        break;
+#if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9
+      case errSSLWeakPeerEphemeralDHKey:
+        failf(data, "Indicates a weak ephemeral Diffie-Hellman key");
+        break;
+#endif
+
+      /* Problem with the message record validation */
+      case errSSLBadRecordMac:
+      case errSSLPeerBadRecordMac:
+        failf(data, "A record with a bad message authentication code (MAC) "
+                    "was encountered");
+        break;
+      case errSSLRecordOverflow:
+      case errSSLPeerRecordOverflow:
+        failf(data, "A record overflow occurred");
+        break;
+
+      /* Problem with zlib decompression */
+      case errSSLPeerDecompressFail:
+        failf(data, "Decompression failed");
+        break;
+
+      /* Problem with access */
+      case errSSLPeerAccessDenied:
+        failf(data, "Access was denied");
+        break;
+      case errSSLPeerInsufficientSecurity:
+        failf(data, "There is insufficient security for this operation");
+        break;
+
+      /* These are all certificate problems with the server: */
+      case errSSLXCertChainInvalid:
+        failf(data, "SSL certificate problem: Invalid certificate chain");
+        return CURLE_PEER_FAILED_VERIFICATION;
+      case errSSLUnknownRootCert:
+        failf(data, "SSL certificate problem: Untrusted root certificate");
+        return CURLE_PEER_FAILED_VERIFICATION;
+      case errSSLNoRootCert:
+        failf(data, "SSL certificate problem: No root certificate");
+        return CURLE_PEER_FAILED_VERIFICATION;
+      case errSSLCertNotYetValid:
+        failf(data, "SSL certificate problem: The certificate chain had a "
+                    "certificate that is not yet valid");
+        return CURLE_PEER_FAILED_VERIFICATION;
+      case errSSLCertExpired:
+      case errSSLPeerCertExpired:
+        failf(data, "SSL certificate problem: Certificate chain had an "
+              "expired certificate");
+        return CURLE_PEER_FAILED_VERIFICATION;
+      case errSSLBadCert:
+      case errSSLPeerBadCert:
+        failf(data, "SSL certificate problem: Couldn't understand the server "
+              "certificate format");
+        return CURLE_PEER_FAILED_VERIFICATION;
+      case errSSLPeerUnsupportedCert:
+        failf(data, "SSL certificate problem: An unsupported certificate "
+                    "format was encountered");
+        return CURLE_PEER_FAILED_VERIFICATION;
+      case errSSLPeerCertRevoked:
+        failf(data, "SSL certificate problem: The certificate was revoked");
+        return CURLE_PEER_FAILED_VERIFICATION;
+      case errSSLPeerCertUnknown:
+        failf(data, "SSL certificate problem: The certificate is unknown");
+        return CURLE_PEER_FAILED_VERIFICATION;
+
+      /* These are all certificate problems with the client: */
+      case errSecAuthFailed:
+        failf(data, "SSL authentication failed");
+        break;
+      case errSSLPeerHandshakeFail:
+        failf(data, "SSL peer handshake failed, the server most likely "
+              "requires a client certificate to connect");
+        break;
+      case errSSLPeerUnknownCA:
+        failf(data, "SSL server rejected the client certificate due to "
+              "the certificate being signed by an unknown certificate "
+              "authority");
+        break;
+
+      /* This error is raised if the server's cert didn't match the server's
+         host name: */
+      case errSSLHostNameMismatch:
+        failf(data, "SSL certificate peer verification failed, the "
+              "certificate did not match \"%s\"\n", connssl->peer.dispname);
+        return CURLE_PEER_FAILED_VERIFICATION;
+
+      /* Problem with SSL / TLS negotiation */
+      case errSSLNegotiation:
+        failf(data, "Could not negotiate an SSL cipher suite with the server");
+        break;
+      case errSSLBadConfiguration:
+        failf(data, "A configuration error occurred");
+        break;
+      case errSSLProtocol:
+        failf(data, "SSL protocol error");
+        break;
+      case errSSLPeerProtocolVersion:
+        failf(data, "A bad protocol version was encountered");
+        break;
+      case errSSLPeerNoRenegotiation:
+        failf(data, "No renegotiation is allowed");
+        break;
+
+      /* Generic handshake errors: */
+      case errSSLConnectionRefused:
+        failf(data, "Server dropped the connection during the SSL handshake");
+        break;
+      case errSSLClosedAbort:
+        failf(data, "Server aborted the SSL handshake");
+        break;
+      case errSSLClosedGraceful:
+        failf(data, "The connection closed gracefully");
+        break;
+      case errSSLClosedNoNotify:
+        failf(data, "The server closed the session with no notification");
+        break;
+      /* Sometimes paramErr happens with buggy ciphers: */
+      case paramErr:
+      case errSSLInternal:
+      case errSSLPeerInternalError:
+        failf(data, "Internal SSL engine error encountered during the "
+              "SSL handshake");
+        break;
+      case errSSLFatalAlert:
+        failf(data, "Fatal SSL engine error encountered during the SSL "
+              "handshake");
+        break;
+      /* Unclassified error */
+      case errSSLBufferOverflow:
+        failf(data, "An insufficient buffer was provided");
+        break;
+      case errSSLIllegalParam:
+        failf(data, "An illegal parameter was encountered");
+        break;
+      case errSSLModuleAttach:
+        failf(data, "Module attach failure");
+        break;
+      case errSSLSessionNotFound:
+        failf(data, "An attempt to restore an unknown session failed");
+        break;
+      case errSSLPeerExportRestriction:
+        failf(data, "An export restriction occurred");
+        break;
+      case errSSLPeerUserCancelled:
+        failf(data, "The user canceled the operation");
+        break;
+      case errSSLPeerUnexpectedMsg:
+        failf(data, "Peer rejected unexpected message");
+        break;
+#if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9
+      /* Treating non-fatal error as fatal like before */
+      case errSSLClientHelloReceived:
+        failf(data, "A non-fatal result for providing a server name "
+                    "indication");
+        break;
+#endif
+
+      /* Error codes defined in the enum but should never be returned.
+         We list them here just in case. */
+#if CURL_BUILD_MAC_10_6
+      /* Only returned when kSSLSessionOptionBreakOnCertRequested is set */
+      case errSSLClientCertRequested:
+        failf(data, "Server requested a client certificate during the "
+              "handshake");
+        return CURLE_SSL_CLIENTCERT;
+#endif
+#if CURL_BUILD_MAC_10_9
+      /* Alias for errSSLLast, end of error range */
+      case errSSLUnexpectedRecord:
+        failf(data, "Unexpected (skipped) record in DTLS");
+        break;
+#endif
+      default:
+        /* May also return codes listed in Security Framework Result Codes */
+        failf(data, "Unknown SSL protocol error in connection to %s:%d",
+              connssl->peer.hostname, err);
+        break;
+    }
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+  else {
+    /* we have been connected fine, we're not waiting for anything else. */
+    connssl->connecting_state = ssl_connect_3;
+
+#ifdef SECTRANSP_PINNEDPUBKEY
+    if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
+      CURLcode result =
+        pkp_pin_peer_pubkey(data, backend->ssl_ctx,
+                            data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
+      if(result) {
+        failf(data, "SSL: public key does not match pinned public key");
+        return result;
+      }
+    }
+#endif /* SECTRANSP_PINNEDPUBKEY */
+
+    /* Informational message */
+    (void)SSLGetNegotiatedCipher(backend->ssl_ctx, &cipher);
+    (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol);
+    switch(protocol) {
+      case kSSLProtocol2:
+        infof(data, "SSL 2.0 connection using %s",
+              TLSCipherNameForNumber(cipher));
+        break;
+      case kSSLProtocol3:
+        infof(data, "SSL 3.0 connection using %s",
+              TLSCipherNameForNumber(cipher));
+        break;
+      case kTLSProtocol1:
+        infof(data, "TLS 1.0 connection using %s",
+              TLSCipherNameForNumber(cipher));
+        break;
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+      case kTLSProtocol11:
+        infof(data, "TLS 1.1 connection using %s",
+              TLSCipherNameForNumber(cipher));
+        break;
+      case kTLSProtocol12:
+        infof(data, "TLS 1.2 connection using %s",
+              TLSCipherNameForNumber(cipher));
+        break;
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
+      case kTLSProtocol13:
+        infof(data, "TLS 1.3 connection using %s",
+              TLSCipherNameForNumber(cipher));
+        break;
+#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
+      default:
+        infof(data, "Unknown protocol connection");
+        break;
+    }
+
+#if(CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+    if(connssl->alpn) {
+      if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
+        CFArrayRef alpnArr = NULL;
+        CFStringRef chosenProtocol = NULL;
+        err = SSLCopyALPNProtocols(backend->ssl_ctx, &alpnArr);
+
+        if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1)
+          chosenProtocol = CFArrayGetValueAtIndex(alpnArr, 0);
+
+#ifdef USE_HTTP2
+        if(chosenProtocol &&
+           !CFStringCompare(chosenProtocol, CFSTR(ALPN_H2), 0)) {
+          cf->conn->alpn = CURL_HTTP_VERSION_2;
+        }
+        else
+#endif
+        if(chosenProtocol &&
+           !CFStringCompare(chosenProtocol, CFSTR(ALPN_HTTP_1_1), 0)) {
+          cf->conn->alpn = CURL_HTTP_VERSION_1_1;
+        }
+        else
+          infof(data, VTLS_INFOF_NO_ALPN);
+
+        Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
+                            BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
+
+        /* chosenProtocol is a reference to the string within alpnArr
+           and doesn't need to be freed separately */
+        if(alpnArr)
+          CFRelease(alpnArr);
+      }
+    }
+#endif
+
+    return CURLE_OK;
+  }
+}
+
+static CURLcode
+add_cert_to_certinfo(struct Curl_easy *data,
+                     SecCertificateRef server_cert,
+                     int idx)
+{
+  CURLcode result = CURLE_OK;
+  const char *beg;
+  const char *end;
+  CFDataRef cert_data = SecCertificateCopyData(server_cert);
+
+  if(!cert_data)
+    return CURLE_PEER_FAILED_VERIFICATION;
+
+  beg = (const char *)CFDataGetBytePtr(cert_data);
+  end = beg + CFDataGetLength(cert_data);
+  result = Curl_extract_certinfo(data, idx, beg, end);
+  CFRelease(cert_data);
+  return result;
+}
+
+static CURLcode
+collect_server_cert_single(struct Curl_cfilter *cf, struct Curl_easy *data,
+                           SecCertificateRef server_cert,
+                           CFIndex idx)
+{
+  CURLcode result = CURLE_OK;
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  if(data->set.verbose) {
+    char *certp;
+    result = CopyCertSubject(data, server_cert, &certp);
+    if(!result) {
+      infof(data, "Server certificate: %s", certp);
+      free(certp);
+    }
+  }
+#endif
+  if(ssl_config->certinfo)
+    result = add_cert_to_certinfo(data, server_cert, (int)idx);
+  return result;
+}
+
+/* This should be called during step3 of the connection at the earliest */
+static CURLcode collect_server_cert(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  const bool show_verbose_server_cert = data->set.verbose;
+#else
+  const bool show_verbose_server_cert = false;
+#endif
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  CURLcode result = ssl_config->certinfo ?
+    CURLE_PEER_FAILED_VERIFICATION : CURLE_OK;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct st_ssl_backend_data *backend =
+    (struct st_ssl_backend_data *)connssl->backend;
+  CFArrayRef server_certs = NULL;
+  SecCertificateRef server_cert;
+  OSStatus err;
+  CFIndex i, count;
+  SecTrustRef trust = NULL;
+
+  DEBUGASSERT(backend);
+
+  if(!show_verbose_server_cert && !ssl_config->certinfo)
+    return CURLE_OK;
+
+  if(!backend->ssl_ctx)
+    return result;
+
+#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
+#if CURL_BUILD_IOS
+#pragma unused(server_certs)
+  err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
+  /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
+     a null trust, so be on guard for that: */
+  if(err == noErr && trust) {
+    count = SecTrustGetCertificateCount(trust);
+    if(ssl_config->certinfo)
+      result = Curl_ssl_init_certinfo(data, (int)count);
+    for(i = 0L ; !result && (i < count) ; i++) {
+      server_cert = SecTrustGetCertificateAtIndex(trust, i);
+      result = collect_server_cert_single(cf, data, server_cert, i);
+    }
+    CFRelease(trust);
+  }
+#else
+  /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion.
+     The function SecTrustGetCertificateAtIndex() is officially present
+     in Lion, but it is unfortunately also present in Snow Leopard as
+     private API and doesn't work as expected. So we have to look for
+     a different symbol to make sure this code is only executed under
+     Lion or later. */
+  if(SecTrustCopyPublicKey) {
+#pragma unused(server_certs)
+    err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
+    /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
+       a null trust, so be on guard for that: */
+    if(err == noErr && trust) {
+      count = SecTrustGetCertificateCount(trust);
+      if(ssl_config->certinfo)
+        result = Curl_ssl_init_certinfo(data, (int)count);
+      for(i = 0L ; !result && (i < count) ; i++) {
+        server_cert = SecTrustGetCertificateAtIndex(trust, i);
+        result = collect_server_cert_single(cf, data, server_cert, i);
+      }
+      CFRelease(trust);
+    }
+  }
+  else {
+#if CURL_SUPPORT_MAC_10_8
+    err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs);
+    /* Just in case SSLCopyPeerCertificates() returns null too... */
+    if(err == noErr && server_certs) {
+      count = CFArrayGetCount(server_certs);
+      if(ssl_config->certinfo)
+        result = Curl_ssl_init_certinfo(data, (int)count);
+      for(i = 0L ; !result && (i < count) ; i++) {
+        server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs,
+                                                                i);
+        result = collect_server_cert_single(cf, data, server_cert, i);
+      }
+      CFRelease(server_certs);
+    }
+#endif /* CURL_SUPPORT_MAC_10_8 */
+  }
+#endif /* CURL_BUILD_IOS */
+#else
+#pragma unused(trust)
+  err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs);
+  if(err == noErr) {
+    count = CFArrayGetCount(server_certs);
+    if(ssl_config->certinfo)
+      result = Curl_ssl_init_certinfo(data, (int)count);
+    for(i = 0L ; !result && (i < count) ; i++) {
+      server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i);
+      result = collect_server_cert_single(cf, data, server_cert, i);
+    }
+    CFRelease(server_certs);
+  }
+#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
+  return result;
+}
+
+static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf,
+                                        struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  CURLcode result;
+
+  CURL_TRC_CF(data, cf, "connect_step3");
+  /* There is no step 3!
+   * Well, okay, let's collect server certificates, and if verbose mode is on,
+   * let's print the details of the server certificates. */
+  result = collect_server_cert(cf, data);
+  if(result)
+    return result;
+
+  connssl->connecting_state = ssl_connect_done;
+  return CURLE_OK;
+}
+
+static CURLcode
+sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
+                         bool nonblocking,
+                         bool *done)
+{
+  CURLcode result;
+  struct ssl_connect_data *connssl = cf->ctx;
+  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+  int what;
+
+  /* check if the connection has already been established */
+  if(ssl_connection_complete == connssl->state) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  if(ssl_connect_1 == connssl->connecting_state) {
+    /* Find out how much more time we're allowed */
+    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    result = sectransp_connect_step1(cf, data);
+    if(result)
+      return result;
+  }
+
+  while(ssl_connect_2 == connssl->connecting_state ||
+        ssl_connect_2_reading == connssl->connecting_state ||
+        ssl_connect_2_writing == connssl->connecting_state) {
+
+    /* check allowed time left */
+    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    /* if ssl is expecting something, check if it's available. */
+    if(connssl->connecting_state == ssl_connect_2_reading ||
+       connssl->connecting_state == ssl_connect_2_writing) {
+
+      curl_socket_t writefd = ssl_connect_2_writing ==
+      connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+      curl_socket_t readfd = ssl_connect_2_reading ==
+      connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+                               nonblocking ? 0 : timeout_ms);
+      if(what < 0) {
+        /* fatal error */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      else if(0 == what) {
+        if(nonblocking) {
+          *done = FALSE;
+          return CURLE_OK;
+        }
+        else {
+          /* timeout */
+          failf(data, "SSL connection timeout");
+          return CURLE_OPERATION_TIMEDOUT;
+        }
+      }
+      /* socket is readable or writable */
+    }
+
+    /* Run transaction, and return to the caller if it failed or if this
+     * connection is done nonblocking and this loop would execute again. This
+     * permits the owner of a multi handle to abort a connection attempt
+     * before step2 has completed while ensuring that a client using select()
+     * or epoll() will always have a valid fdset to wait on.
+     */
+    result = sectransp_connect_step2(cf, data);
+    if(result || (nonblocking &&
+                  (ssl_connect_2 == connssl->connecting_state ||
+                   ssl_connect_2_reading == connssl->connecting_state ||
+                   ssl_connect_2_writing == connssl->connecting_state)))
+      return result;
+
+  } /* repeat step2 until all transactions are done. */
+
+
+  if(ssl_connect_3 == connssl->connecting_state) {
+    result = sectransp_connect_step3(cf, data);
+    if(result)
+      return result;
+  }
+
+  if(ssl_connect_done == connssl->connecting_state) {
+    CURL_TRC_CF(data, cf, "connected");
+    connssl->state = ssl_connection_complete;
+    *done = TRUE;
+  }
+  else
+    *done = FALSE;
+
+  /* Reset our connect state machine */
+  connssl->connecting_state = ssl_connect_1;
+
+  return CURLE_OK;
+}
+
+static CURLcode sectransp_connect_nonblocking(struct Curl_cfilter *cf,
+                                              struct Curl_easy *data,
+                                              bool *done)
+{
+  return sectransp_connect_common(cf, data, TRUE, done);
+}
+
+static CURLcode sectransp_connect(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data)
+{
+  CURLcode result;
+  bool done = FALSE;
+
+  result = sectransp_connect_common(cf, data, FALSE, &done);
+
+  if(result)
+    return result;
+
+  DEBUGASSERT(done);
+
+  return CURLE_OK;
+}
+
+static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct st_ssl_backend_data *backend =
+    (struct st_ssl_backend_data *)connssl->backend;
+
+  (void) data;
+
+  DEBUGASSERT(backend);
+
+  if(backend->ssl_ctx) {
+    CURL_TRC_CF(data, cf, "close");
+    (void)SSLClose(backend->ssl_ctx);
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+    if(SSLCreateContext)
+      CFRelease(backend->ssl_ctx);
+#if CURL_SUPPORT_MAC_10_8
+    else
+      (void)SSLDisposeContext(backend->ssl_ctx);
+#endif  /* CURL_SUPPORT_MAC_10_8 */
+#else
+    (void)SSLDisposeContext(backend->ssl_ctx);
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+    backend->ssl_ctx = NULL;
+  }
+}
+
+static int sectransp_shutdown(struct Curl_cfilter *cf,
+                              struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct st_ssl_backend_data *backend =
+    (struct st_ssl_backend_data *)connssl->backend;
+  ssize_t nread;
+  int what;
+  int rc;
+  char buf[120];
+  int loop = 10; /* avoid getting stuck */
+  CURLcode result;
+
+  DEBUGASSERT(backend);
+
+  if(!backend->ssl_ctx)
+    return 0;
+
+#ifndef CURL_DISABLE_FTP
+  if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
+    return 0;
+#endif
+
+  sectransp_close(cf, data);
+
+  rc = 0;
+
+  what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
+                         SSL_SHUTDOWN_TIMEOUT);
+
+  CURL_TRC_CF(data, cf, "shutdown");
+  while(loop--) {
+    if(what < 0) {
+      /* anything that gets here is fatally bad */
+      failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+      rc = -1;
+      break;
+    }
+
+    if(!what) {                                /* timeout */
+      failf(data, "SSL shutdown timeout");
+      break;
+    }
+
+    /* Something to read, let's do it and hope that it is the close
+     notify alert from the server. No way to SSL_Read now, so use read(). */
+
+    nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
+
+    if(nread < 0) {
+      failf(data, "read: %s", curl_easy_strerror(result));
+      rc = -1;
+    }
+
+    if(nread <= 0)
+      break;
+
+    what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), 0);
+  }
+
+  return rc;
+}
+
+static void sectransp_session_free(void *ptr)
+{
+  /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
+     cached session ID inside the Security framework. There is a private
+     function that does this, but I don't want to have to explain to you why I
+     got your application rejected from the App Store due to the use of a
+     private API, so the best we can do is free up our own char array that we
+     created way back in sectransp_connect_step1... */
+  Curl_safefree(ptr);
+}
+
+static size_t sectransp_version(char *buffer, size_t size)
+{
+  return msnprintf(buffer, size, "SecureTransport");
+}
+
+static bool sectransp_data_pending(struct Curl_cfilter *cf,
+                                   const struct Curl_easy *data)
+{
+  const struct ssl_connect_data *connssl = cf->ctx;
+  struct st_ssl_backend_data *backend =
+    (struct st_ssl_backend_data *)connssl->backend;
+  OSStatus err;
+  size_t buffer;
+
+  (void)data;
+  DEBUGASSERT(backend);
+
+  if(backend->ssl_ctx) {  /* SSL is in use */
+    CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending");
+    err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer);
+    if(err == noErr)
+      return buffer > 0UL;
+    return false;
+  }
+  else
+    return false;
+}
+
+static CURLcode sectransp_random(struct Curl_easy *data UNUSED_PARAM,
+                                 unsigned char *entropy, size_t length)
+{
+  /* arc4random_buf() isn't available on cats older than Lion, so let's
+     do this manually for the benefit of the older cats. */
+  size_t i;
+  u_int32_t random_number = 0;
+
+  (void)data;
+
+  for(i = 0 ; i < length ; i++) {
+    if(i % sizeof(u_int32_t) == 0)
+      random_number = arc4random();
+    entropy[i] = random_number & 0xFF;
+    random_number >>= 8;
+  }
+  i = random_number = 0;
+  return CURLE_OK;
+}
+
+static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */
+                                    size_t tmplen,
+                                    unsigned char *sha256sum, /* output */
+                                    size_t sha256len)
+{
+  (void)sha256len;
+  assert(sha256len >= CURL_SHA256_DIGEST_LENGTH);
+  (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum);
+  return CURLE_OK;
+}
+
+static bool sectransp_false_start(void)
+{
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+  if(SSLSetSessionOption)
+    return TRUE;
+#endif
+  return FALSE;
+}
+
+static ssize_t sectransp_send(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              const void *mem,
+                              size_t len,
+                              CURLcode *curlcode)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct st_ssl_backend_data *backend =
+    (struct st_ssl_backend_data *)connssl->backend;
+  size_t processed = 0UL;
+  OSStatus err;
+
+  DEBUGASSERT(backend);
+
+  /* The SSLWrite() function works a little differently than expected. The
+     fourth argument (processed) is currently documented in Apple's
+     documentation as: "On return, the length, in bytes, of the data actually
+     written."
+
+     Now, one could interpret that as "written to the socket," but actually,
+     it returns the amount of data that was written to a buffer internal to
+     the SSLContextRef instead. So it's possible for SSLWrite() to return
+     errSSLWouldBlock and a number of bytes "written" because those bytes were
+     encrypted and written to a buffer, not to the socket.
+
+     So if this happens, then we need to keep calling SSLWrite() over and
+     over again with no new data until it quits returning errSSLWouldBlock. */
+
+  /* Do we have buffered data to write from the last time we were called? */
+  if(backend->ssl_write_buffered_length) {
+    /* Write the buffered data: */
+    err = SSLWrite(backend->ssl_ctx, NULL, 0UL, &processed);
+    switch(err) {
+      case noErr:
+        /* processed is always going to be 0 because we didn't write to
+           the buffer, so return how much was written to the socket */
+        processed = backend->ssl_write_buffered_length;
+        backend->ssl_write_buffered_length = 0UL;
+        break;
+      case errSSLWouldBlock: /* argh, try again */
+        *curlcode = CURLE_AGAIN;
+        return -1L;
+      default:
+        failf(data, "SSLWrite() returned error %d", err);
+        *curlcode = CURLE_SEND_ERROR;
+        return -1L;
+    }
+  }
+  else {
+    /* We've got new data to write: */
+    err = SSLWrite(backend->ssl_ctx, mem, len, &processed);
+    if(err != noErr) {
+      switch(err) {
+        case errSSLWouldBlock:
+          /* Data was buffered but not sent, we have to tell the caller
+             to try sending again, and remember how much was buffered */
+          backend->ssl_write_buffered_length = len;
+          *curlcode = CURLE_AGAIN;
+          return -1L;
+        default:
+          failf(data, "SSLWrite() returned error %d", err);
+          *curlcode = CURLE_SEND_ERROR;
+          return -1L;
+      }
+    }
+  }
+  return (ssize_t)processed;
+}
+
+static ssize_t sectransp_recv(struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              char *buf,
+                              size_t buffersize,
+                              CURLcode *curlcode)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct st_ssl_backend_data *backend =
+    (struct st_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  size_t processed = 0UL;
+  OSStatus err;
+
+  DEBUGASSERT(backend);
+
+again:
+  *curlcode = CURLE_OK;
+  err = SSLRead(backend->ssl_ctx, buf, buffersize, &processed);
+
+  if(err != noErr) {
+    switch(err) {
+      case errSSLWouldBlock:  /* return how much we read (if anything) */
+        if(processed) {
+          return (ssize_t)processed;
+        }
+        *curlcode = CURLE_AGAIN;
+        return -1L;
+
+      /* errSSLClosedGraceful - server gracefully shut down the SSL session
+         errSSLClosedNoNotify - server hung up on us instead of sending a
+           closure alert notice, read() is returning 0
+         Either way, inform the caller that the server disconnected. */
+      case errSSLClosedGraceful:
+      case errSSLClosedNoNotify:
+        *curlcode = CURLE_OK;
+        return 0;
+
+        /* The below is errSSLPeerAuthCompleted; it's not defined in
+           Leopard's headers */
+      case -9841:
+        if((conn_config->CAfile || conn_config->ca_info_blob) &&
+           conn_config->verifypeer) {
+          CURLcode result = verify_cert(cf, data, conn_config->CAfile,
+                                        conn_config->ca_info_blob,
+                                        backend->ssl_ctx);
+          if(result) {
+            *curlcode = result;
+            return -1;
+          }
+        }
+        goto again;
+      default:
+        failf(data, "SSLRead() return error %d", err);
+        *curlcode = CURLE_RECV_ERROR;
+        return -1L;
+    }
+  }
+  return (ssize_t)processed;
+}
+
+static void *sectransp_get_internals(struct ssl_connect_data *connssl,
+                                     CURLINFO info UNUSED_PARAM)
+{
+  struct st_ssl_backend_data *backend =
+    (struct st_ssl_backend_data *)connssl->backend;
+  (void)info;
+  DEBUGASSERT(backend);
+  return backend->ssl_ctx;
+}
+
+const struct Curl_ssl Curl_ssl_sectransp = {
+  { CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */
+
+  SSLSUPP_CAINFO_BLOB |
+  SSLSUPP_CERTINFO |
+#ifdef SECTRANSP_PINNEDPUBKEY
+  SSLSUPP_PINNEDPUBKEY |
+#endif /* SECTRANSP_PINNEDPUBKEY */
+  SSLSUPP_HTTPS_PROXY,
+
+  sizeof(struct st_ssl_backend_data),
+
+  Curl_none_init,                     /* init */
+  Curl_none_cleanup,                  /* cleanup */
+  sectransp_version,                  /* version */
+  Curl_none_check_cxn,                /* check_cxn */
+  sectransp_shutdown,                 /* shutdown */
+  sectransp_data_pending,             /* data_pending */
+  sectransp_random,                   /* random */
+  Curl_none_cert_status_request,      /* cert_status_request */
+  sectransp_connect,                  /* connect */
+  sectransp_connect_nonblocking,      /* connect_nonblocking */
+  Curl_ssl_adjust_pollset,            /* adjust_pollset */
+  sectransp_get_internals,            /* get_internals */
+  sectransp_close,                    /* close_one */
+  Curl_none_close_all,                /* close_all */
+  sectransp_session_free,             /* session_free */
+  Curl_none_set_engine,               /* set_engine */
+  Curl_none_set_engine_default,       /* set_engine_default */
+  Curl_none_engines_list,             /* engines_list */
+  sectransp_false_start,              /* false_start */
+  sectransp_sha256sum,                /* sha256sum */
+  NULL,                               /* associate_connection */
+  NULL,                               /* disassociate_connection */
+  NULL,                               /* free_multi_ssl_backend_data */
+  sectransp_recv,                     /* recv decrypted data */
+  sectransp_send,                     /* send data to encrypt */
+};
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif /* USE_SECTRANSP */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/sectransp.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/sectransp.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/sectransp.h	(revision 104083)
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_SECTRANSP_H
+#define HEADER_CURL_SECTRANSP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Nick Zitzmann, <nickzman@gmail.com>.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_SECTRANSP
+
+extern const struct Curl_ssl Curl_ssl_sectransp;
+
+#endif /* USE_SECTRANSP */
+#endif /* HEADER_CURL_SECTRANSP_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/vtls.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/vtls.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/vtls.c	(revision 104083)
@@ -0,0 +1,2168 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* This file is for implementing all "generic" SSL functions that all libcurl
+   internals should use. It is then responsible for calling the proper
+   "backend" function.
+
+   SSL-functions in libcurl should call functions in this source file, and not
+   to any specific SSL-layer.
+
+   Curl_ssl_ - prefix for generic ones
+
+   Note that this source code uses the functions of the configured SSL
+   backend via the global Curl_ssl instance.
+
+   "SSL/TLS Strong Encryption: An Introduction"
+   https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html
+*/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "urldata.h"
+#include "cfilters.h"
+
+#include "vtls.h" /* generic SSL protos etc */
+#include "vtls_int.h"
+#include "slist.h"
+#include "sendf.h"
+#include "strcase.h"
+#include "url.h"
+#include "progress.h"
+#include "share.h"
+#include "multiif.h"
+#include "timeval.h"
+#include "curl_md5.h"
+#include "warnless.h"
+#include "curl_base64.h"
+#include "curl_printf.h"
+#include "inet_pton.h"
+#include "strdup.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+/* convenience macro to check if this handle is using a shared SSL session */
+#define SSLSESSION_SHARED(data) (data->share &&                        \
+                                 (data->share->specifier &             \
+                                  (1<<CURL_LOCK_DATA_SSL_SESSION)))
+
+#define CLONE_STRING(var)                    \
+  do {                                       \
+    if(source->var) {                        \
+      dest->var = strdup(source->var);       \
+      if(!dest->var)                         \
+        return FALSE;                        \
+    }                                        \
+    else                                     \
+      dest->var = NULL;                      \
+  } while(0)
+
+#define CLONE_BLOB(var)                        \
+  do {                                         \
+    if(blobdup(&dest->var, source->var))       \
+      return FALSE;                            \
+  } while(0)
+
+static CURLcode blobdup(struct curl_blob **dest,
+                        struct curl_blob *src)
+{
+  DEBUGASSERT(dest);
+  DEBUGASSERT(!*dest);
+  if(src) {
+    /* only if there's data to dupe! */
+    struct curl_blob *d;
+    d = malloc(sizeof(struct curl_blob) + src->len);
+    if(!d)
+      return CURLE_OUT_OF_MEMORY;
+    d->len = src->len;
+    /* Always duplicate because the connection may survive longer than the
+       handle that passed in the blob. */
+    d->flags = CURL_BLOB_COPY;
+    d->data = (void *)((char *)d + sizeof(struct curl_blob));
+    memcpy(d->data, src->data, src->len);
+    *dest = d;
+  }
+  return CURLE_OK;
+}
+
+/* returns TRUE if the blobs are identical */
+static bool blobcmp(struct curl_blob *first, struct curl_blob *second)
+{
+  if(!first && !second) /* both are NULL */
+    return TRUE;
+  if(!first || !second) /* one is NULL */
+    return FALSE;
+  if(first->len != second->len) /* different sizes */
+    return FALSE;
+  return !memcmp(first->data, second->data, first->len); /* same data */
+}
+
+#ifdef USE_SSL
+static const struct alpn_spec ALPN_SPEC_H11 = {
+  { ALPN_HTTP_1_1 }, 1
+};
+#ifdef USE_HTTP2
+static const struct alpn_spec ALPN_SPEC_H2_H11 = {
+  { ALPN_H2, ALPN_HTTP_1_1 }, 2
+};
+#endif
+
+static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn)
+{
+  if(!use_alpn)
+    return NULL;
+#ifdef USE_HTTP2
+  if(httpwant >= CURL_HTTP_VERSION_2)
+    return &ALPN_SPEC_H2_H11;
+#else
+  (void)httpwant;
+#endif
+  /* Use the ALPN protocol "http/1.1" for HTTP/1.x.
+     Avoid "http/1.0" because some servers don't support it. */
+  return &ALPN_SPEC_H11;
+}
+#endif /* USE_SSL */
+
+
+void Curl_ssl_easy_config_init(struct Curl_easy *data)
+{
+  /*
+   * libcurl 7.10 introduced SSL verification *by default*! This needs to be
+   * switched off unless wanted.
+   */
+  data->set.ssl.primary.verifypeer = TRUE;
+  data->set.ssl.primary.verifyhost = TRUE;
+  data->set.ssl.primary.sessionid = TRUE; /* session ID caching by default */
+#ifndef CURL_DISABLE_PROXY
+  data->set.proxy_ssl = data->set.ssl;
+#endif
+}
+
+static bool
+match_ssl_primary_config(struct Curl_easy *data,
+                         struct ssl_primary_config *c1,
+                         struct ssl_primary_config *c2)
+{
+  (void)data;
+  if((c1->version == c2->version) &&
+     (c1->version_max == c2->version_max) &&
+     (c1->ssl_options == c2->ssl_options) &&
+     (c1->verifypeer == c2->verifypeer) &&
+     (c1->verifyhost == c2->verifyhost) &&
+     (c1->verifystatus == c2->verifystatus) &&
+     blobcmp(c1->cert_blob, c2->cert_blob) &&
+     blobcmp(c1->ca_info_blob, c2->ca_info_blob) &&
+     blobcmp(c1->issuercert_blob, c2->issuercert_blob) &&
+     Curl_safecmp(c1->CApath, c2->CApath) &&
+     Curl_safecmp(c1->CAfile, c2->CAfile) &&
+     Curl_safecmp(c1->issuercert, c2->issuercert) &&
+     Curl_safecmp(c1->clientcert, c2->clientcert) &&
+#ifdef USE_TLS_SRP
+     !Curl_timestrcmp(c1->username, c2->username) &&
+     !Curl_timestrcmp(c1->password, c2->password) &&
+#endif
+     strcasecompare(c1->cipher_list, c2->cipher_list) &&
+     strcasecompare(c1->cipher_list13, c2->cipher_list13) &&
+     strcasecompare(c1->curves, c2->curves) &&
+     strcasecompare(c1->CRLfile, c2->CRLfile) &&
+     strcasecompare(c1->pinned_key, c2->pinned_key))
+    return TRUE;
+
+  return FALSE;
+}
+
+bool Curl_ssl_conn_config_match(struct Curl_easy *data,
+                                struct connectdata *candidate,
+                                bool proxy)
+{
+#ifndef CURL_DISABLE_PROXY
+  if(proxy)
+    return match_ssl_primary_config(data, &data->set.proxy_ssl.primary,
+                                    &candidate->proxy_ssl_config);
+#else
+  (void)proxy;
+#endif
+  return match_ssl_primary_config(data, &data->set.ssl.primary,
+                                  &candidate->ssl_config);
+}
+
+static bool clone_ssl_primary_config(struct ssl_primary_config *source,
+                                     struct ssl_primary_config *dest)
+{
+  dest->version = source->version;
+  dest->version_max = source->version_max;
+  dest->verifypeer = source->verifypeer;
+  dest->verifyhost = source->verifyhost;
+  dest->verifystatus = source->verifystatus;
+  dest->sessionid = source->sessionid;
+  dest->ssl_options = source->ssl_options;
+
+  CLONE_BLOB(cert_blob);
+  CLONE_BLOB(ca_info_blob);
+  CLONE_BLOB(issuercert_blob);
+  CLONE_STRING(CApath);
+  CLONE_STRING(CAfile);
+  CLONE_STRING(issuercert);
+  CLONE_STRING(clientcert);
+  CLONE_STRING(cipher_list);
+  CLONE_STRING(cipher_list13);
+  CLONE_STRING(pinned_key);
+  CLONE_STRING(curves);
+  CLONE_STRING(CRLfile);
+#ifdef USE_TLS_SRP
+  CLONE_STRING(username);
+  CLONE_STRING(password);
+#endif
+
+  return TRUE;
+}
+
+static void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
+{
+  Curl_safefree(sslc->CApath);
+  Curl_safefree(sslc->CAfile);
+  Curl_safefree(sslc->issuercert);
+  Curl_safefree(sslc->clientcert);
+  Curl_safefree(sslc->cipher_list);
+  Curl_safefree(sslc->cipher_list13);
+  Curl_safefree(sslc->pinned_key);
+  Curl_safefree(sslc->cert_blob);
+  Curl_safefree(sslc->ca_info_blob);
+  Curl_safefree(sslc->issuercert_blob);
+  Curl_safefree(sslc->curves);
+  Curl_safefree(sslc->CRLfile);
+#ifdef USE_TLS_SRP
+  Curl_safefree(sslc->username);
+  Curl_safefree(sslc->password);
+#endif
+}
+
+CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data)
+{
+  data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH];
+  data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE];
+  data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE];
+  data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
+  data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
+  data->set.ssl.primary.cipher_list =
+    data->set.str[STRING_SSL_CIPHER_LIST];
+  data->set.ssl.primary.cipher_list13 =
+    data->set.str[STRING_SSL_CIPHER13_LIST];
+  data->set.ssl.primary.pinned_key =
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+  data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT];
+  data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
+  data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES];
+#ifdef USE_TLS_SRP
+  data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME];
+  data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD];
+#endif
+  data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE];
+  data->set.ssl.key = data->set.str[STRING_KEY];
+  data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE];
+  data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD];
+  data->set.ssl.primary.clientcert = data->set.str[STRING_CERT];
+  data->set.ssl.key_blob = data->set.blobs[BLOB_KEY];
+
+#ifndef CURL_DISABLE_PROXY
+  data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
+  data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
+  data->set.proxy_ssl.primary.cipher_list =
+    data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
+  data->set.proxy_ssl.primary.cipher_list13 =
+    data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
+  data->set.proxy_ssl.primary.pinned_key =
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
+  data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
+  data->set.proxy_ssl.primary.ca_info_blob =
+    data->set.blobs[BLOB_CAINFO_PROXY];
+  data->set.proxy_ssl.primary.issuercert =
+    data->set.str[STRING_SSL_ISSUERCERT_PROXY];
+  data->set.proxy_ssl.primary.issuercert_blob =
+    data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
+  data->set.proxy_ssl.primary.CRLfile =
+    data->set.str[STRING_SSL_CRLFILE_PROXY];
+  data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
+  data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
+  data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
+  data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
+  data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
+  data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
+#ifdef USE_TLS_SRP
+  data->set.proxy_ssl.primary.username =
+    data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
+  data->set.proxy_ssl.primary.password =
+    data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
+#endif
+#endif /* CURL_DISABLE_PROXY */
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
+                                   struct connectdata *conn)
+{
+  /* Clone "primary" SSL configurations from the esay handle to
+   * the connection. They are used for connection cache matching and
+   * probably outlive the easy handle */
+  if(!clone_ssl_primary_config(&data->set.ssl.primary, &conn->ssl_config))
+    return CURLE_OUT_OF_MEMORY;
+#ifndef CURL_DISABLE_PROXY
+  if(!clone_ssl_primary_config(&data->set.proxy_ssl.primary,
+                               &conn->proxy_ssl_config))
+    return CURLE_OUT_OF_MEMORY;
+#endif
+  return CURLE_OK;
+}
+
+void Curl_ssl_conn_config_cleanup(struct connectdata *conn)
+{
+  Curl_free_primary_ssl_config(&conn->ssl_config);
+#ifndef CURL_DISABLE_PROXY
+  Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
+#endif
+}
+
+void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy)
+{
+  /* May be called on an easy that has no connection yet */
+  if(data->conn) {
+    struct ssl_primary_config *src, *dest;
+#ifndef CURL_DISABLE_PROXY
+    src = for_proxy? &data->set.proxy_ssl.primary : &data->set.ssl.primary;
+    dest = for_proxy? &data->conn->proxy_ssl_config : &data->conn->ssl_config;
+#else
+    (void)for_proxy;
+    src = &data->set.ssl.primary;
+    dest = &data->conn->ssl_config;
+#endif
+    dest->verifyhost = src->verifyhost;
+    dest->verifypeer = src->verifypeer;
+    dest->verifystatus = src->verifystatus;
+  }
+}
+
+#ifdef USE_SSL
+static int multissl_setup(const struct Curl_ssl *backend);
+#endif
+
+curl_sslbackend Curl_ssl_backend(void)
+{
+#ifdef USE_SSL
+  multissl_setup(NULL);
+  return Curl_ssl->info.id;
+#else
+  return CURLSSLBACKEND_NONE;
+#endif
+}
+
+#ifdef USE_SSL
+
+/* "global" init done? */
+static bool init_ssl = FALSE;
+
+/**
+ * Global SSL init
+ *
+ * @retval 0 error initializing SSL
+ * @retval 1 SSL initialized successfully
+ */
+int Curl_ssl_init(void)
+{
+  /* make sure this is only done once */
+  if(init_ssl)
+    return 1;
+  init_ssl = TRUE; /* never again */
+
+  return Curl_ssl->init();
+}
+
+#if defined(CURL_WITH_MULTI_SSL)
+static const struct Curl_ssl Curl_ssl_multi;
+#endif
+
+/* Global cleanup */
+void Curl_ssl_cleanup(void)
+{
+  if(init_ssl) {
+    /* only cleanup if we did a previous init */
+    Curl_ssl->cleanup();
+#if defined(CURL_WITH_MULTI_SSL)
+    Curl_ssl = &Curl_ssl_multi;
+#endif
+    init_ssl = FALSE;
+  }
+}
+
+static bool ssl_prefs_check(struct Curl_easy *data)
+{
+  /* check for CURLOPT_SSLVERSION invalid parameter value */
+  const unsigned char sslver = data->set.ssl.primary.version;
+  if(sslver >= CURL_SSLVERSION_LAST) {
+    failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
+    return FALSE;
+  }
+
+  switch(data->set.ssl.primary.version_max) {
+  case CURL_SSLVERSION_MAX_NONE:
+  case CURL_SSLVERSION_MAX_DEFAULT:
+    break;
+
+  default:
+    if((data->set.ssl.primary.version_max >> 16) < sslver) {
+      failf(data, "CURL_SSLVERSION_MAX incompatible with CURL_SSLVERSION");
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data,
+                                     const struct alpn_spec *alpn)
+{
+  struct ssl_connect_data *ctx;
+
+  (void)data;
+  ctx = calloc(1, sizeof(*ctx));
+  if(!ctx)
+    return NULL;
+
+  ctx->alpn = alpn;
+  ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data);
+  if(!ctx->backend) {
+    free(ctx);
+    return NULL;
+  }
+  return ctx;
+}
+
+static void cf_ctx_free(struct ssl_connect_data *ctx)
+{
+  if(ctx) {
+    free(ctx->backend);
+    free(ctx);
+  }
+}
+
+static CURLcode ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  CURLcode result;
+
+  if(!ssl_prefs_check(data))
+    return CURLE_SSL_CONNECT_ERROR;
+
+  /* mark this is being ssl-enabled from here on. */
+  connssl->state = ssl_connection_negotiating;
+
+  result = Curl_ssl->connect_blocking(cf, data);
+
+  if(!result) {
+    DEBUGASSERT(connssl->state == ssl_connection_complete);
+  }
+
+  return result;
+}
+
+static CURLcode
+ssl_connect_nonblocking(struct Curl_cfilter *cf, struct Curl_easy *data,
+                        bool *done)
+{
+  if(!ssl_prefs_check(data))
+    return CURLE_SSL_CONNECT_ERROR;
+
+  /* mark this is being ssl requested from here on. */
+  return Curl_ssl->connect_nonblocking(cf, data, done);
+}
+
+/*
+ * Lock shared SSL session data
+ */
+void Curl_ssl_sessionid_lock(struct Curl_easy *data)
+{
+  if(SSLSESSION_SHARED(data))
+    Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+}
+
+/*
+ * Unlock shared SSL session data
+ */
+void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
+{
+  if(SSLSESSION_SHARED(data))
+    Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
+}
+
+/*
+ * Check if there's a session ID for the given connection in the cache, and if
+ * there's one suitable, it is provided. Returns TRUE when no entry matched.
+ */
+bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           void **ssl_sessionid,
+                           size_t *idsize) /* set 0 if unknown */
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  struct Curl_ssl_session *check;
+  size_t i;
+  long *general_age;
+  bool no_match = TRUE;
+
+  *ssl_sessionid = NULL;
+  if(!ssl_config)
+    return TRUE;
+
+  DEBUGASSERT(ssl_config->primary.sessionid);
+
+  if(!ssl_config->primary.sessionid || !data->state.session)
+    /* session ID reuse is disabled or the session cache has not been
+       setup */
+    return TRUE;
+
+  /* Lock if shared */
+  if(SSLSESSION_SHARED(data))
+    general_age = &data->share->sessionage;
+  else
+    general_age = &data->state.sessionage;
+
+  for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
+    check = &data->state.session[i];
+    if(!check->sessionid)
+      /* not session ID means blank entry */
+      continue;
+    if(strcasecompare(connssl->peer.hostname, check->name) &&
+       ((!cf->conn->bits.conn_to_host && !check->conn_to_host) ||
+        (cf->conn->bits.conn_to_host && check->conn_to_host &&
+         strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) &&
+       ((!cf->conn->bits.conn_to_port && check->conn_to_port == -1) ||
+        (cf->conn->bits.conn_to_port && check->conn_to_port != -1 &&
+         cf->conn->conn_to_port == check->conn_to_port)) &&
+       (connssl->port == check->remote_port) &&
+       strcasecompare(cf->conn->handler->scheme, check->scheme) &&
+       match_ssl_primary_config(data, conn_config, &check->ssl_config)) {
+      /* yes, we have a session ID! */
+      (*general_age)++;          /* increase general age */
+      check->age = *general_age; /* set this as used in this age */
+      *ssl_sessionid = check->sessionid;
+      if(idsize)
+        *idsize = check->idsize;
+      no_match = FALSE;
+      break;
+    }
+  }
+
+  DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
+               no_match? "Didn't find": "Found",
+               Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
+               cf->conn->handler->scheme, connssl->peer.hostname,
+               connssl->port));
+  return no_match;
+}
+
+/*
+ * Kill a single session ID entry in the cache.
+ */
+void Curl_ssl_kill_session(struct Curl_ssl_session *session)
+{
+  if(session->sessionid) {
+    /* defensive check */
+
+    /* free the ID the SSL-layer specific way */
+    Curl_ssl->session_free(session->sessionid);
+
+    session->sessionid = NULL;
+    session->age = 0; /* fresh */
+
+    Curl_free_primary_ssl_config(&session->ssl_config);
+
+    Curl_safefree(session->name);
+    Curl_safefree(session->conn_to_host);
+  }
+}
+
+/*
+ * Delete the given session ID from the cache.
+ */
+void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
+{
+  size_t i;
+
+  for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
+    struct Curl_ssl_session *check = &data->state.session[i];
+
+    if(check->sessionid == ssl_sessionid) {
+      Curl_ssl_kill_session(check);
+      break;
+    }
+  }
+}
+
+/*
+ * Store session id in the session cache. The ID passed on to this function
+ * must already have been extracted and allocated the proper way for the SSL
+ * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
+ * later on.
+ */
+CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               void *ssl_sessionid,
+                               size_t idsize,
+                               bool *added)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  size_t i;
+  struct Curl_ssl_session *store;
+  long oldest_age;
+  char *clone_host;
+  char *clone_conn_to_host;
+  int conn_to_port;
+  long *general_age;
+
+  if(added)
+    *added = FALSE;
+
+  if(!data->state.session)
+    return CURLE_OK;
+
+  store = &data->state.session[0];
+  oldest_age = data->state.session[0].age; /* zero if unused */
+  (void)ssl_config;
+  DEBUGASSERT(ssl_config->primary.sessionid);
+
+  clone_host = strdup(connssl->peer.hostname);
+  if(!clone_host)
+    return CURLE_OUT_OF_MEMORY; /* bail out */
+
+  if(cf->conn->bits.conn_to_host) {
+    clone_conn_to_host = strdup(cf->conn->conn_to_host.name);
+    if(!clone_conn_to_host) {
+      free(clone_host);
+      return CURLE_OUT_OF_MEMORY; /* bail out */
+    }
+  }
+  else
+    clone_conn_to_host = NULL;
+
+  if(cf->conn->bits.conn_to_port)
+    conn_to_port = cf->conn->conn_to_port;
+  else
+    conn_to_port = -1;
+
+  /* Now we should add the session ID and the host name to the cache, (remove
+     the oldest if necessary) */
+
+  /* If using shared SSL session, lock! */
+  if(SSLSESSION_SHARED(data)) {
+    general_age = &data->share->sessionage;
+  }
+  else {
+    general_age = &data->state.sessionage;
+  }
+
+  /* find an empty slot for us, or find the oldest */
+  for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) &&
+        data->state.session[i].sessionid; i++) {
+    if(data->state.session[i].age < oldest_age) {
+      oldest_age = data->state.session[i].age;
+      store = &data->state.session[i];
+    }
+  }
+  if(i == data->set.general_ssl.max_ssl_sessions)
+    /* cache is full, we must "kill" the oldest entry! */
+    Curl_ssl_kill_session(store);
+  else
+    store = &data->state.session[i]; /* use this slot */
+
+  /* now init the session struct wisely */
+  store->sessionid = ssl_sessionid;
+  store->idsize = idsize;
+  store->age = *general_age;    /* set current age */
+  /* free it if there's one already present */
+  free(store->name);
+  free(store->conn_to_host);
+  store->name = clone_host;               /* clone host name */
+  store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
+  store->conn_to_port = conn_to_port; /* connect to port number */
+  /* port number */
+  store->remote_port = connssl->port;
+  store->scheme = cf->conn->handler->scheme;
+
+  if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) {
+    Curl_free_primary_ssl_config(&store->ssl_config);
+    store->sessionid = NULL; /* let caller free sessionid */
+    free(clone_host);
+    free(clone_conn_to_host);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(added)
+    *added = TRUE;
+
+  DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
+               store->scheme, store->name, store->remote_port,
+               Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server"));
+  return CURLE_OK;
+}
+
+void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend)
+{
+  if(Curl_ssl->free_multi_ssl_backend_data && mbackend)
+    Curl_ssl->free_multi_ssl_backend_data(mbackend);
+}
+
+void Curl_ssl_close_all(struct Curl_easy *data)
+{
+  /* kill the session ID cache if not shared */
+  if(data->state.session && !SSLSESSION_SHARED(data)) {
+    size_t i;
+    for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++)
+      /* the single-killer function handles empty table slots */
+      Curl_ssl_kill_session(&data->state.session[i]);
+
+    /* free the cache data */
+    Curl_safefree(data->state.session);
+  }
+
+  Curl_ssl->close_all(data);
+}
+
+void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              struct easy_pollset *ps)
+{
+  if(!cf->connected) {
+    struct ssl_connect_data *connssl = cf->ctx;
+    curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
+    if(sock != CURL_SOCKET_BAD) {
+      if(connssl->connecting_state == ssl_connect_2_writing) {
+        Curl_pollset_set_out_only(data, ps, sock);
+        CURL_TRC_CF(data, cf, "adjust_pollset, POLLOUT fd=%"
+                    CURL_FORMAT_SOCKET_T, sock);
+      }
+      else {
+        Curl_pollset_set_in_only(data, ps, sock);
+        CURL_TRC_CF(data, cf, "adjust_pollset, POLLIN fd=%"
+                    CURL_FORMAT_SOCKET_T, sock);
+      }
+    }
+  }
+}
+
+/* Selects an SSL crypto engine
+ */
+CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
+{
+  return Curl_ssl->set_engine(data, engine);
+}
+
+/* Selects the default SSL crypto engine
+ */
+CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data)
+{
+  return Curl_ssl->set_engine_default(data);
+}
+
+/* Return list of OpenSSL crypto engine names. */
+struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data)
+{
+  return Curl_ssl->engines_list(data);
+}
+
+/*
+ * This sets up a session ID cache to the specified size. Make sure this code
+ * is agnostic to what underlying SSL technology we use.
+ */
+CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
+{
+  struct Curl_ssl_session *session;
+
+  if(data->state.session)
+    /* this is just a precaution to prevent multiple inits */
+    return CURLE_OK;
+
+  session = calloc(amount, sizeof(struct Curl_ssl_session));
+  if(!session)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* store the info in the SSL section */
+  data->set.general_ssl.max_ssl_sessions = amount;
+  data->state.session = session;
+  data->state.sessionage = 1; /* this is brand new */
+  return CURLE_OK;
+}
+
+static size_t multissl_version(char *buffer, size_t size);
+
+void Curl_ssl_version(char *buffer, size_t size)
+{
+#ifdef CURL_WITH_MULTI_SSL
+  (void)multissl_version(buffer, size);
+#else
+  (void)Curl_ssl->version(buffer, size);
+#endif
+}
+
+void Curl_ssl_free_certinfo(struct Curl_easy *data)
+{
+  struct curl_certinfo *ci = &data->info.certs;
+
+  if(ci->num_of_certs) {
+    /* free all individual lists used */
+    int i;
+    for(i = 0; i<ci->num_of_certs; i++) {
+      curl_slist_free_all(ci->certinfo[i]);
+      ci->certinfo[i] = NULL;
+    }
+
+    free(ci->certinfo); /* free the actual array too */
+    ci->certinfo = NULL;
+    ci->num_of_certs = 0;
+  }
+}
+
+CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num)
+{
+  struct curl_certinfo *ci = &data->info.certs;
+  struct curl_slist **table;
+
+  /* Free any previous certificate information structures */
+  Curl_ssl_free_certinfo(data);
+
+  /* Allocate the required certificate information structures */
+  table = calloc((size_t) num, sizeof(struct curl_slist *));
+  if(!table)
+    return CURLE_OUT_OF_MEMORY;
+
+  ci->num_of_certs = num;
+  ci->certinfo = table;
+
+  return CURLE_OK;
+}
+
+/*
+ * 'value' is NOT a null-terminated string
+ */
+CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
+                                    int certnum,
+                                    const char *label,
+                                    const char *value,
+                                    size_t valuelen)
+{
+  struct curl_certinfo *ci = &data->info.certs;
+  struct curl_slist *nl;
+  CURLcode result = CURLE_OK;
+  struct dynbuf build;
+
+  Curl_dyn_init(&build, 10000);
+
+  if(Curl_dyn_add(&build, label) ||
+     Curl_dyn_addn(&build, ":", 1) ||
+     Curl_dyn_addn(&build, value, valuelen))
+    return CURLE_OUT_OF_MEMORY;
+
+  nl = Curl_slist_append_nodup(ci->certinfo[certnum],
+                               Curl_dyn_ptr(&build));
+  if(!nl) {
+    Curl_dyn_free(&build);
+    curl_slist_free_all(ci->certinfo[certnum]);
+    result = CURLE_OUT_OF_MEMORY;
+  }
+
+  ci->certinfo[certnum] = nl;
+  return result;
+}
+
+CURLcode Curl_ssl_random(struct Curl_easy *data,
+                         unsigned char *entropy,
+                         size_t length)
+{
+  return Curl_ssl->random(data, entropy, length);
+}
+
+/*
+ * Public key pem to der conversion
+ */
+
+static CURLcode pubkey_pem_to_der(const char *pem,
+                                  unsigned char **der, size_t *der_len)
+{
+  char *stripped_pem, *begin_pos, *end_pos;
+  size_t pem_count, stripped_pem_count = 0, pem_len;
+  CURLcode result;
+
+  /* if no pem, exit. */
+  if(!pem)
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
+  if(!begin_pos)
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  pem_count = begin_pos - pem;
+  /* Invalid if not at beginning AND not directly following \n */
+  if(0 != pem_count && '\n' != pem[pem_count - 1])
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* 26 is length of "-----BEGIN PUBLIC KEY-----" */
+  pem_count += 26;
+
+  /* Invalid if not directly following \n */
+  end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----");
+  if(!end_pos)
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  pem_len = end_pos - pem;
+
+  stripped_pem = malloc(pem_len - pem_count + 1);
+  if(!stripped_pem)
+    return CURLE_OUT_OF_MEMORY;
+
+  /*
+   * Here we loop through the pem array one character at a time between the
+   * correct indices, and place each character that is not '\n' or '\r'
+   * into the stripped_pem array, which should represent the raw base64 string
+   */
+  while(pem_count < pem_len) {
+    if('\n' != pem[pem_count] && '\r' != pem[pem_count])
+      stripped_pem[stripped_pem_count++] = pem[pem_count];
+    ++pem_count;
+  }
+  /* Place the null terminator in the correct place */
+  stripped_pem[stripped_pem_count] = '\0';
+
+  result = Curl_base64_decode(stripped_pem, der, der_len);
+
+  Curl_safefree(stripped_pem);
+
+  return result;
+}
+
+/*
+ * Generic pinned public key check.
+ */
+
+CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
+                              const char *pinnedpubkey,
+                              const unsigned char *pubkey, size_t pubkeylen)
+{
+  FILE *fp;
+  unsigned char *buf = NULL, *pem_ptr = NULL;
+  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)data;
+#endif
+
+  /* if a path wasn't specified, don't pin */
+  if(!pinnedpubkey)
+    return CURLE_OK;
+  if(!pubkey || !pubkeylen)
+    return result;
+
+  /* only do this if pinnedpubkey starts with "sha256//", length 8 */
+  if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
+    CURLcode encode;
+    size_t encodedlen = 0;
+    char *encoded = NULL, *pinkeycopy, *begin_pos, *end_pos;
+    unsigned char *sha256sumdigest;
+
+    if(!Curl_ssl->sha256sum) {
+      /* without sha256 support, this cannot match */
+      return result;
+    }
+
+    /* compute sha256sum of public key */
+    sha256sumdigest = malloc(CURL_SHA256_DIGEST_LENGTH);
+    if(!sha256sumdigest)
+      return CURLE_OUT_OF_MEMORY;
+    encode = Curl_ssl->sha256sum(pubkey, pubkeylen,
+                                 sha256sumdigest, CURL_SHA256_DIGEST_LENGTH);
+
+    if(!encode)
+      encode = Curl_base64_encode((char *)sha256sumdigest,
+                                  CURL_SHA256_DIGEST_LENGTH, &encoded,
+                                  &encodedlen);
+    Curl_safefree(sha256sumdigest);
+
+    if(encode)
+      return encode;
+
+    infof(data, " public key hash: sha256//%s", encoded);
+
+    /* it starts with sha256//, copy so we can modify it */
+    pinkeycopy = strdup(pinnedpubkey);
+    if(!pinkeycopy) {
+      Curl_safefree(encoded);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    /* point begin_pos to the copy, and start extracting keys */
+    begin_pos = pinkeycopy;
+    do {
+      end_pos = strstr(begin_pos, ";sha256//");
+      /*
+       * if there is an end_pos, null terminate,
+       * otherwise it'll go to the end of the original string
+       */
+      if(end_pos)
+        end_pos[0] = '\0';
+
+      /* compare base64 sha256 digests, 8 is the length of "sha256//" */
+      if(encodedlen == strlen(begin_pos + 8) &&
+         !memcmp(encoded, begin_pos + 8, encodedlen)) {
+        result = CURLE_OK;
+        break;
+      }
+
+      /*
+       * change back the null-terminator we changed earlier,
+       * and look for next begin
+       */
+      if(end_pos) {
+        end_pos[0] = ';';
+        begin_pos = strstr(end_pos, "sha256//");
+      }
+    } while(end_pos && begin_pos);
+    Curl_safefree(encoded);
+    Curl_safefree(pinkeycopy);
+    return result;
+  }
+
+  fp = fopen(pinnedpubkey, "rb");
+  if(!fp)
+    return result;
+
+  do {
+    long filesize;
+    size_t size, pem_len;
+    CURLcode pem_read;
+
+    /* Determine the file's size */
+    if(fseek(fp, 0, SEEK_END))
+      break;
+    filesize = ftell(fp);
+    if(fseek(fp, 0, SEEK_SET))
+      break;
+    if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
+      break;
+
+    /*
+     * if the size of our certificate is bigger than the file
+     * size then it can't match
+     */
+    size = curlx_sotouz((curl_off_t) filesize);
+    if(pubkeylen > size)
+      break;
+
+    /*
+     * Allocate buffer for the pinned key
+     * With 1 additional byte for null terminator in case of PEM key
+     */
+    buf = malloc(size + 1);
+    if(!buf)
+      break;
+
+    /* Returns number of elements read, which should be 1 */
+    if((int) fread(buf, size, 1, fp) != 1)
+      break;
+
+    /* If the sizes are the same, it can't be base64 encoded, must be der */
+    if(pubkeylen == size) {
+      if(!memcmp(pubkey, buf, pubkeylen))
+        result = CURLE_OK;
+      break;
+    }
+
+    /*
+     * Otherwise we will assume it's PEM and try to decode it
+     * after placing null terminator
+     */
+    buf[size] = '\0';
+    pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
+    /* if it wasn't read successfully, exit */
+    if(pem_read)
+      break;
+
+    /*
+     * if the size of our certificate doesn't match the size of
+     * the decoded file, they can't be the same, otherwise compare
+     */
+    if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
+      result = CURLE_OK;
+  } while(0);
+
+  Curl_safefree(buf);
+  Curl_safefree(pem_ptr);
+  fclose(fp);
+
+  return result;
+}
+
+/*
+ * Check whether the SSL backend supports the status_request extension.
+ */
+bool Curl_ssl_cert_status_request(void)
+{
+  return Curl_ssl->cert_status_request();
+}
+
+/*
+ * Check whether the SSL backend supports false start.
+ */
+bool Curl_ssl_false_start(struct Curl_easy *data)
+{
+  (void)data;
+  return Curl_ssl->false_start();
+}
+
+/*
+ * Default implementations for unsupported functions.
+ */
+
+int Curl_none_init(void)
+{
+  return 1;
+}
+
+void Curl_none_cleanup(void)
+{ }
+
+int Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
+                       struct Curl_easy *data UNUSED_PARAM)
+{
+  (void)data;
+  (void)cf;
+  return 0;
+}
+
+int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  (void)cf;
+  (void)data;
+  return -1;
+}
+
+CURLcode Curl_none_random(struct Curl_easy *data UNUSED_PARAM,
+                          unsigned char *entropy UNUSED_PARAM,
+                          size_t length UNUSED_PARAM)
+{
+  (void)data;
+  (void)entropy;
+  (void)length;
+  return CURLE_NOT_BUILT_IN;
+}
+
+void Curl_none_close_all(struct Curl_easy *data UNUSED_PARAM)
+{
+  (void)data;
+}
+
+void Curl_none_session_free(void *ptr UNUSED_PARAM)
+{
+  (void)ptr;
+}
+
+bool Curl_none_data_pending(struct Curl_cfilter *cf UNUSED_PARAM,
+                            const struct Curl_easy *data UNUSED_PARAM)
+{
+  (void)cf;
+  (void)data;
+  return 0;
+}
+
+bool Curl_none_cert_status_request(void)
+{
+  return FALSE;
+}
+
+CURLcode Curl_none_set_engine(struct Curl_easy *data UNUSED_PARAM,
+                              const char *engine UNUSED_PARAM)
+{
+  (void)data;
+  (void)engine;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode Curl_none_set_engine_default(struct Curl_easy *data UNUSED_PARAM)
+{
+  (void)data;
+  return CURLE_NOT_BUILT_IN;
+}
+
+struct curl_slist *Curl_none_engines_list(struct Curl_easy *data UNUSED_PARAM)
+{
+  (void)data;
+  return (struct curl_slist *)NULL;
+}
+
+bool Curl_none_false_start(void)
+{
+  return FALSE;
+}
+
+static int multissl_init(void)
+{
+  if(multissl_setup(NULL))
+    return 1;
+  return Curl_ssl->init();
+}
+
+static CURLcode multissl_connect(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data)
+{
+  if(multissl_setup(NULL))
+    return CURLE_FAILED_INIT;
+  return Curl_ssl->connect_blocking(cf, data);
+}
+
+static CURLcode multissl_connect_nonblocking(struct Curl_cfilter *cf,
+                                             struct Curl_easy *data,
+                                             bool *done)
+{
+  if(multissl_setup(NULL))
+    return CURLE_FAILED_INIT;
+  return Curl_ssl->connect_nonblocking(cf, data, done);
+}
+
+static void multissl_adjust_pollset(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data,
+                                     struct easy_pollset *ps)
+{
+  if(multissl_setup(NULL))
+    return;
+  Curl_ssl->adjust_pollset(cf, data, ps);
+}
+
+static void *multissl_get_internals(struct ssl_connect_data *connssl,
+                                    CURLINFO info)
+{
+  if(multissl_setup(NULL))
+    return NULL;
+  return Curl_ssl->get_internals(connssl, info);
+}
+
+static void multissl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  if(multissl_setup(NULL))
+    return;
+  Curl_ssl->close(cf, data);
+}
+
+static ssize_t multissl_recv_plain(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   char *buf, size_t len, CURLcode *code)
+{
+  if(multissl_setup(NULL))
+    return CURLE_FAILED_INIT;
+  return Curl_ssl->recv_plain(cf, data, buf, len, code);
+}
+
+static ssize_t multissl_send_plain(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   const void *mem, size_t len,
+                                   CURLcode *code)
+{
+  if(multissl_setup(NULL))
+    return CURLE_FAILED_INIT;
+  return Curl_ssl->send_plain(cf, data, mem, len, code);
+}
+
+static const struct Curl_ssl Curl_ssl_multi = {
+  { CURLSSLBACKEND_NONE, "multi" },  /* info */
+  0, /* supports nothing */
+  (size_t)-1, /* something insanely large to be on the safe side */
+
+  multissl_init,                     /* init */
+  Curl_none_cleanup,                 /* cleanup */
+  multissl_version,                  /* version */
+  Curl_none_check_cxn,               /* check_cxn */
+  Curl_none_shutdown,                /* shutdown */
+  Curl_none_data_pending,            /* data_pending */
+  Curl_none_random,                  /* random */
+  Curl_none_cert_status_request,     /* cert_status_request */
+  multissl_connect,                  /* connect */
+  multissl_connect_nonblocking,      /* connect_nonblocking */
+  multissl_adjust_pollset,          /* adjust_pollset */
+  multissl_get_internals,            /* get_internals */
+  multissl_close,                    /* close_one */
+  Curl_none_close_all,               /* close_all */
+  Curl_none_session_free,            /* session_free */
+  Curl_none_set_engine,              /* set_engine */
+  Curl_none_set_engine_default,      /* set_engine_default */
+  Curl_none_engines_list,            /* engines_list */
+  Curl_none_false_start,             /* false_start */
+  NULL,                              /* sha256sum */
+  NULL,                              /* associate_connection */
+  NULL,                              /* disassociate_connection */
+  NULL,                              /* free_multi_ssl_backend_data */
+  multissl_recv_plain,               /* recv decrypted data */
+  multissl_send_plain,               /* send data to encrypt */
+};
+
+const struct Curl_ssl *Curl_ssl =
+#if defined(CURL_WITH_MULTI_SSL)
+  &Curl_ssl_multi;
+#elif defined(USE_WOLFSSL)
+  &Curl_ssl_wolfssl;
+#elif defined(USE_SECTRANSP)
+  &Curl_ssl_sectransp;
+#elif defined(USE_GNUTLS)
+  &Curl_ssl_gnutls;
+#elif defined(USE_MBEDTLS)
+  &Curl_ssl_mbedtls;
+#elif defined(USE_RUSTLS)
+  &Curl_ssl_rustls;
+#elif defined(USE_OPENSSL)
+  &Curl_ssl_openssl;
+#elif defined(USE_SCHANNEL)
+  &Curl_ssl_schannel;
+#elif defined(USE_BEARSSL)
+  &Curl_ssl_bearssl;
+#else
+#error "Missing struct Curl_ssl for selected SSL backend"
+#endif
+
+static const struct Curl_ssl *available_backends[] = {
+#if defined(USE_WOLFSSL)
+  &Curl_ssl_wolfssl,
+#endif
+#if defined(USE_SECTRANSP)
+  &Curl_ssl_sectransp,
+#endif
+#if defined(USE_GNUTLS)
+  &Curl_ssl_gnutls,
+#endif
+#if defined(USE_MBEDTLS)
+  &Curl_ssl_mbedtls,
+#endif
+#if defined(USE_OPENSSL)
+  &Curl_ssl_openssl,
+#endif
+#if defined(USE_SCHANNEL)
+  &Curl_ssl_schannel,
+#endif
+#if defined(USE_BEARSSL)
+  &Curl_ssl_bearssl,
+#endif
+#if defined(USE_RUSTLS)
+  &Curl_ssl_rustls,
+#endif
+  NULL
+};
+
+static size_t multissl_version(char *buffer, size_t size)
+{
+  static const struct Curl_ssl *selected;
+  static char backends[200];
+  static size_t backends_len;
+  const struct Curl_ssl *current;
+
+  current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl;
+
+  if(current != selected) {
+    char *p = backends;
+    char *end = backends + sizeof(backends);
+    int i;
+
+    selected = current;
+
+    backends[0] = '\0';
+
+    for(i = 0; available_backends[i]; ++i) {
+      char vb[200];
+      bool paren = (selected != available_backends[i]);
+
+      if(available_backends[i]->version(vb, sizeof(vb))) {
+        p += msnprintf(p, end - p, "%s%s%s%s", (p != backends ? " " : ""),
+                       (paren ? "(" : ""), vb, (paren ? ")" : ""));
+      }
+    }
+
+    backends_len = p - backends;
+  }
+
+  if(size) {
+    if(backends_len < size)
+      strcpy(buffer, backends);
+    else
+      *buffer = 0; /* did not fit */
+  }
+  return 0;
+}
+
+static int multissl_setup(const struct Curl_ssl *backend)
+{
+  const char *env;
+  char *env_tmp;
+
+  if(Curl_ssl != &Curl_ssl_multi)
+    return 1;
+
+  if(backend) {
+    Curl_ssl = backend;
+    return 0;
+  }
+
+  if(!available_backends[0])
+    return 1;
+
+  env = env_tmp = curl_getenv("CURL_SSL_BACKEND");
+#ifdef CURL_DEFAULT_SSL_BACKEND
+  if(!env)
+    env = CURL_DEFAULT_SSL_BACKEND;
+#endif
+  if(env) {
+    int i;
+    for(i = 0; available_backends[i]; i++) {
+      if(strcasecompare(env, available_backends[i]->info.name)) {
+        Curl_ssl = available_backends[i];
+        free(env_tmp);
+        return 0;
+      }
+    }
+  }
+
+  /* Fall back to first available backend */
+  Curl_ssl = available_backends[0];
+  free(env_tmp);
+  return 0;
+}
+
+/* This function is used to select the SSL backend to use. It is called by
+   curl_global_sslset (easy.c) which uses the global init lock. */
+CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
+                                   const curl_ssl_backend ***avail)
+{
+  int i;
+
+  if(avail)
+    *avail = (const curl_ssl_backend **)&available_backends;
+
+  if(Curl_ssl != &Curl_ssl_multi)
+    return id == Curl_ssl->info.id ||
+           (name && strcasecompare(name, Curl_ssl->info.name)) ?
+           CURLSSLSET_OK :
+#if defined(CURL_WITH_MULTI_SSL)
+           CURLSSLSET_TOO_LATE;
+#else
+           CURLSSLSET_UNKNOWN_BACKEND;
+#endif
+
+  for(i = 0; available_backends[i]; i++) {
+    if(available_backends[i]->info.id == id ||
+       (name && strcasecompare(available_backends[i]->info.name, name))) {
+      multissl_setup(available_backends[i]);
+      return CURLSSLSET_OK;
+    }
+  }
+
+  return CURLSSLSET_UNKNOWN_BACKEND;
+}
+
+#else /* USE_SSL */
+CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
+                                   const curl_ssl_backend ***avail)
+{
+  (void)id;
+  (void)name;
+  (void)avail;
+  return CURLSSLSET_NO_BACKENDS;
+}
+
+#endif /* !USE_SSL */
+
+#ifdef USE_SSL
+
+void Curl_ssl_peer_cleanup(struct ssl_peer *peer)
+{
+  if(peer->dispname != peer->hostname)
+    free(peer->dispname);
+  free(peer->sni);
+  free(peer->hostname);
+  peer->hostname = peer->sni = peer->dispname = NULL;
+  peer->type = CURL_SSL_PEER_DNS;
+}
+
+static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  if(connssl) {
+    Curl_ssl->close(cf, data);
+    connssl->state = ssl_connection_none;
+    Curl_ssl_peer_cleanup(&connssl->peer);
+  }
+  cf->connected = FALSE;
+}
+
+static ssl_peer_type get_peer_type(const char *hostname)
+{
+  if(hostname && hostname[0]) {
+#ifdef ENABLE_IPV6
+    struct in6_addr addr;
+#else
+    struct in_addr addr;
+#endif
+    if(Curl_inet_pton(AF_INET, hostname, &addr))
+      return CURL_SSL_PEER_IPV4;
+#ifdef ENABLE_IPV6
+    else if(Curl_inet_pton(AF_INET6, hostname, &addr)) {
+      return CURL_SSL_PEER_IPV6;
+    }
+#endif
+  }
+  return CURL_SSL_PEER_DNS;
+}
+
+CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  const char *ehostname, *edispname;
+  int eport;
+
+  /* We need the hostname for SNI negotiation. Once handshaked, this
+   * remains the SNI hostname for the TLS connection. But when the
+   * connection is reused, the settings in cf->conn might change.
+   * So we keep a copy of the hostname we use for SNI.
+   */
+#ifndef CURL_DISABLE_PROXY
+  if(Curl_ssl_cf_is_proxy(cf)) {
+    ehostname = cf->conn->http_proxy.host.name;
+    edispname = cf->conn->http_proxy.host.dispname;
+    eport = cf->conn->http_proxy.port;
+  }
+  else
+#endif
+  {
+    ehostname = cf->conn->host.name;
+    edispname = cf->conn->host.dispname;
+    eport = cf->conn->remote_port;
+  }
+
+  /* change if ehostname changed */
+  DEBUGASSERT(!ehostname || ehostname[0]);
+  if(ehostname && (!peer->hostname
+                   || strcmp(ehostname, peer->hostname))) {
+    Curl_ssl_peer_cleanup(peer);
+    peer->hostname = strdup(ehostname);
+    if(!peer->hostname) {
+      Curl_ssl_peer_cleanup(peer);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    if(!edispname || !strcmp(ehostname, edispname))
+      peer->dispname = peer->hostname;
+    else {
+      peer->dispname = strdup(edispname);
+      if(!peer->dispname) {
+        Curl_ssl_peer_cleanup(peer);
+        return CURLE_OUT_OF_MEMORY;
+      }
+    }
+
+    peer->sni = NULL;
+    peer->type = get_peer_type(peer->hostname);
+    if(peer->type == CURL_SSL_PEER_DNS && peer->hostname[0]) {
+      /* not an IP address, normalize according to RCC 6066 ch. 3,
+       * max len of SNI is 2^16-1, no trailing dot */
+      size_t len = strlen(peer->hostname);
+      if(len && (peer->hostname[len-1] == '.'))
+        len--;
+      if(len < USHRT_MAX) {
+        peer->sni = calloc(1, len + 1);
+        if(!peer->sni) {
+          Curl_ssl_peer_cleanup(peer);
+          return CURLE_OUT_OF_MEMORY;
+        }
+        Curl_strntolower(peer->sni, peer->hostname, len);
+        peer->sni[len] = 0;
+      }
+    }
+
+  }
+  connssl->port = eport;
+  return CURLE_OK;
+}
+
+static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct cf_call_data save;
+
+  CF_DATA_SAVE(save, cf, data);
+  cf_close(cf, data);
+  CF_DATA_RESTORE(cf, save);
+  cf_ctx_free(cf->ctx);
+  cf->ctx = NULL;
+}
+
+static void ssl_cf_close(struct Curl_cfilter *cf,
+                         struct Curl_easy *data)
+{
+  struct cf_call_data save;
+
+  CF_DATA_SAVE(save, cf, data);
+  cf_close(cf, data);
+  if(cf->next)
+    cf->next->cft->do_close(cf->next, data);
+  CF_DATA_RESTORE(cf, save);
+}
+
+static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               bool blocking, bool *done)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct cf_call_data save;
+  CURLcode result;
+
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  CF_DATA_SAVE(save, cf, data);
+  CURL_TRC_CF(data, cf, "cf_connect()");
+  (void)connssl;
+  DEBUGASSERT(data->conn);
+  DEBUGASSERT(data->conn == cf->conn);
+  DEBUGASSERT(connssl);
+  DEBUGASSERT(cf->conn->host.name);
+
+  result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+  if(result || !*done)
+    goto out;
+
+  *done = FALSE;
+  result = Curl_ssl_peer_init(&connssl->peer, cf);
+  if(result)
+    goto out;
+
+  if(blocking) {
+    result = ssl_connect(cf, data);
+    *done = (result == CURLE_OK);
+  }
+  else {
+    result = ssl_connect_nonblocking(cf, data, done);
+  }
+
+  if(!result && *done) {
+    cf->connected = TRUE;
+    connssl->handshake_done = Curl_now();
+    DEBUGASSERT(connssl->state == ssl_connection_complete);
+  }
+out:
+  CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done);
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
+static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
+                                const struct Curl_easy *data)
+{
+  struct cf_call_data save;
+  bool result;
+
+  CF_DATA_SAVE(save, cf, data);
+  if(Curl_ssl->data_pending(cf, data))
+    result = TRUE;
+  else
+    result = cf->next->cft->has_data_pending(cf->next, data);
+  CF_DATA_RESTORE(cf, save);
+  return result;
+}
+
+static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
+                           struct Curl_easy *data, const void *buf, size_t len,
+                           CURLcode *err)
+{
+  struct cf_call_data save;
+  ssize_t nwritten;
+
+  CF_DATA_SAVE(save, cf, data);
+  *err = CURLE_OK;
+  nwritten = Curl_ssl->send_plain(cf, data, buf, len, err);
+  CF_DATA_RESTORE(cf, save);
+  return nwritten;
+}
+
+static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
+                           struct Curl_easy *data, char *buf, size_t len,
+                           CURLcode *err)
+{
+  struct cf_call_data save;
+  ssize_t nread;
+
+  CF_DATA_SAVE(save, cf, data);
+  *err = CURLE_OK;
+  nread = Curl_ssl->recv_plain(cf, data, buf, len, err);
+  if(nread > 0) {
+    DEBUGASSERT((size_t)nread <= len);
+  }
+  else if(nread == 0) {
+    /* eof */
+    *err = CURLE_OK;
+  }
+  CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len,
+              nread, *err);
+  CF_DATA_RESTORE(cf, save);
+  return nread;
+}
+
+static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   struct easy_pollset *ps)
+{
+  struct cf_call_data save;
+
+  if(!cf->connected) {
+    CF_DATA_SAVE(save, cf, data);
+    Curl_ssl->adjust_pollset(cf, data, ps);
+    CF_DATA_RESTORE(cf, save);
+  }
+}
+
+static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
+                             struct Curl_easy *data,
+                             int event, int arg1, void *arg2)
+{
+  struct cf_call_data save;
+
+  (void)arg1;
+  (void)arg2;
+  switch(event) {
+  case CF_CTRL_DATA_ATTACH:
+    if(Curl_ssl->attach_data) {
+      CF_DATA_SAVE(save, cf, data);
+      Curl_ssl->attach_data(cf, data);
+      CF_DATA_RESTORE(cf, save);
+    }
+    break;
+  case CF_CTRL_DATA_DETACH:
+    if(Curl_ssl->detach_data) {
+      CF_DATA_SAVE(save, cf, data);
+      Curl_ssl->detach_data(cf, data);
+      CF_DATA_RESTORE(cf, save);
+    }
+    break;
+  default:
+    break;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode ssl_cf_query(struct Curl_cfilter *cf,
+                             struct Curl_easy *data,
+                             int query, int *pres1, void *pres2)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+
+  switch(query) {
+  case CF_QUERY_TIMER_APPCONNECT: {
+    struct curltime *when = pres2;
+    if(cf->connected && !Curl_ssl_cf_is_proxy(cf))
+      *when = connssl->handshake_done;
+    return CURLE_OK;
+  }
+  default:
+    break;
+  }
+  return cf->next?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
+}
+
+static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data,
+                            bool *input_pending)
+{
+  struct cf_call_data save;
+  int result;
+  /*
+   * This function tries to determine connection status.
+   *
+   * Return codes:
+   *     1 means the connection is still in place
+   *     0 means the connection has been closed
+   *    -1 means the connection status is unknown
+   */
+  CF_DATA_SAVE(save, cf, data);
+  result = Curl_ssl->check_cxn(cf, data);
+  CF_DATA_RESTORE(cf, save);
+  if(result > 0) {
+    *input_pending = TRUE;
+    return TRUE;
+  }
+  if(result == 0) {
+    *input_pending = FALSE;
+    return FALSE;
+  }
+  /* ssl backend does not know */
+  return cf->next?
+    cf->next->cft->is_alive(cf->next, data, input_pending) :
+    FALSE; /* pessimistic in absence of data */
+}
+
+struct Curl_cftype Curl_cft_ssl = {
+  "SSL",
+  CF_TYPE_SSL,
+  CURL_LOG_LVL_NONE,
+  ssl_cf_destroy,
+  ssl_cf_connect,
+  ssl_cf_close,
+  Curl_cf_def_get_host,
+  ssl_cf_adjust_pollset,
+  ssl_cf_data_pending,
+  ssl_cf_send,
+  ssl_cf_recv,
+  ssl_cf_cntrl,
+  cf_ssl_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  ssl_cf_query,
+};
+
+#ifndef CURL_DISABLE_PROXY
+
+struct Curl_cftype Curl_cft_ssl_proxy = {
+  "SSL-PROXY",
+  CF_TYPE_SSL,
+  CURL_LOG_LVL_NONE,
+  ssl_cf_destroy,
+  ssl_cf_connect,
+  ssl_cf_close,
+  Curl_cf_def_get_host,
+  ssl_cf_adjust_pollset,
+  ssl_cf_data_pending,
+  ssl_cf_send,
+  ssl_cf_recv,
+  ssl_cf_cntrl,
+  cf_ssl_is_alive,
+  Curl_cf_def_conn_keep_alive,
+  Curl_cf_def_query,
+};
+
+#endif /* !CURL_DISABLE_PROXY */
+
+static CURLcode cf_ssl_create(struct Curl_cfilter **pcf,
+                              struct Curl_easy *data,
+                              struct connectdata *conn)
+{
+  struct Curl_cfilter *cf = NULL;
+  struct ssl_connect_data *ctx;
+  CURLcode result;
+
+  DEBUGASSERT(data->conn);
+
+  ctx = cf_ctx_new(data, alpn_get_spec(data->state.httpwant,
+                                       conn->bits.tls_enable_alpn));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+
+  result = Curl_cf_create(&cf, &Curl_cft_ssl, ctx);
+
+out:
+  if(result)
+    cf_ctx_free(ctx);
+  *pcf = result? NULL : cf;
+  return result;
+}
+
+CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
+                              struct connectdata *conn,
+                              int sockindex)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result;
+
+  result = cf_ssl_create(&cf, data, conn);
+  if(!result)
+    Curl_conn_cf_add(data, conn, sockindex, cf);
+  return result;
+}
+
+CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at,
+                                  struct Curl_easy *data)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result;
+
+  result = cf_ssl_create(&cf, data, cf_at->conn);
+  if(!result)
+    Curl_conn_cf_insert_after(cf_at, cf);
+  return result;
+}
+
+#ifndef CURL_DISABLE_PROXY
+
+static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf,
+                                    struct Curl_easy *data,
+                                    struct connectdata *conn)
+{
+  struct Curl_cfilter *cf = NULL;
+  struct ssl_connect_data *ctx;
+  CURLcode result;
+  bool use_alpn = conn->bits.tls_enable_alpn;
+  int httpwant = CURL_HTTP_VERSION_1_1;
+
+#ifdef USE_HTTP2
+  if(conn->http_proxy.proxytype == CURLPROXY_HTTPS2) {
+    use_alpn = TRUE;
+    httpwant = CURL_HTTP_VERSION_2;
+  }
+#endif
+
+  ctx = cf_ctx_new(data, alpn_get_spec(httpwant, use_alpn));
+  if(!ctx) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  result = Curl_cf_create(&cf, &Curl_cft_ssl_proxy, ctx);
+
+out:
+  if(result)
+    cf_ctx_free(ctx);
+  *pcf = result? NULL : cf;
+  return result;
+}
+
+CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
+                                        struct Curl_easy *data)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result;
+
+  result = cf_ssl_proxy_create(&cf, data, cf_at->conn);
+  if(!result)
+    Curl_conn_cf_insert_after(cf_at, cf);
+  return result;
+}
+
+#endif /* !CURL_DISABLE_PROXY */
+
+bool Curl_ssl_supports(struct Curl_easy *data, int option)
+{
+  (void)data;
+  return (Curl_ssl->supports & option)? TRUE : FALSE;
+}
+
+static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
+{
+  for(; cf; cf = cf->next) {
+    if(cf->cft == &Curl_cft_ssl)
+      return cf;
+#ifndef CURL_DISABLE_PROXY
+    if(cf->cft == &Curl_cft_ssl_proxy)
+      return cf;
+#endif
+  }
+  return NULL;
+}
+
+
+void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
+                             CURLINFO info, int n)
+{
+  void *result = NULL;
+  (void)n;
+  if(data->conn) {
+    struct Curl_cfilter *cf;
+    /* get first SSL filter in chain, if any is present */
+    cf = get_ssl_filter(data->conn->cfilter[sockindex]);
+    if(cf) {
+      struct cf_call_data save;
+      CF_DATA_SAVE(save, cf, data);
+      result = Curl_ssl->get_internals(cf->ctx, info);
+      CF_DATA_RESTORE(cf, save);
+    }
+  }
+  return result;
+}
+
+CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
+                                 int sockindex)
+{
+  struct Curl_cfilter *cf, *head;
+  CURLcode result = CURLE_OK;
+
+  (void)data;
+  head = data->conn? data->conn->cfilter[sockindex] : NULL;
+  for(cf = head; cf; cf = cf->next) {
+    if(cf->cft == &Curl_cft_ssl) {
+      if(Curl_ssl->shut_down(cf, data))
+        result = CURLE_SSL_SHUTDOWN_FAILED;
+      Curl_conn_cf_discard_sub(head, cf, data, FALSE);
+      break;
+    }
+  }
+  return result;
+}
+
+bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)
+{
+#ifndef CURL_DISABLE_PROXY
+  return (cf->cft == &Curl_cft_ssl_proxy);
+#else
+  (void)cf;
+  return FALSE;
+#endif
+}
+
+struct ssl_config_data *
+Curl_ssl_cf_get_config(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+#ifdef CURL_DISABLE_PROXY
+  (void)cf;
+  return &data->set.ssl;
+#else
+  return Curl_ssl_cf_is_proxy(cf)? &data->set.proxy_ssl : &data->set.ssl;
+#endif
+}
+
+struct ssl_primary_config *
+Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf)
+{
+#ifdef CURL_DISABLE_PROXY
+  return &cf->conn->ssl_config;
+#else
+  return Curl_ssl_cf_is_proxy(cf)?
+    &cf->conn->proxy_ssl_config : &cf->conn->ssl_config;
+#endif
+}
+
+CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf,
+                                const struct alpn_spec *spec)
+{
+  size_t i, len;
+  int off = 0;
+  unsigned char blen;
+
+  memset(buf, 0, sizeof(*buf));
+  for(i = 0; spec && i < spec->count; ++i) {
+    len = strlen(spec->entries[i]);
+    if(len >= ALPN_NAME_MAX)
+      return CURLE_FAILED_INIT;
+    blen = (unsigned  char)len;
+    if(off + blen + 1 >= (int)sizeof(buf->data))
+      return CURLE_FAILED_INIT;
+    buf->data[off++] = blen;
+    memcpy(buf->data + off, spec->entries[i], blen);
+    off += blen;
+  }
+  buf->len = off;
+  return CURLE_OK;
+}
+
+CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf,
+                                const struct alpn_spec *spec)
+{
+  size_t i, len;
+  size_t off = 0;
+
+  memset(buf, 0, sizeof(*buf));
+  for(i = 0; spec && i < spec->count; ++i) {
+    len = strlen(spec->entries[i]);
+    if(len >= ALPN_NAME_MAX)
+      return CURLE_FAILED_INIT;
+    if(off + len + 2 >= sizeof(buf->data))
+      return CURLE_FAILED_INIT;
+    if(off)
+      buf->data[off++] = ',';
+    memcpy(buf->data + off, spec->entries[i], len);
+    off += len;
+  }
+  buf->data[off] = '\0';
+  buf->len = (int)off;
+  return CURLE_OK;
+}
+
+CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  const unsigned char *proto,
+                                  size_t proto_len)
+{
+  int can_multi = 0;
+  unsigned char *palpn =
+#ifndef CURL_DISABLE_PROXY
+    (cf->conn->bits.tunnel_proxy && Curl_ssl_cf_is_proxy(cf))?
+    &cf->conn->proxy_alpn : &cf->conn->alpn
+#else
+    &cf->conn->alpn
+#endif
+    ;
+
+  if(proto && proto_len) {
+    if(proto_len == ALPN_HTTP_1_1_LENGTH &&
+       !memcmp(ALPN_HTTP_1_1, proto, ALPN_HTTP_1_1_LENGTH)) {
+      *palpn = CURL_HTTP_VERSION_1_1;
+    }
+#ifdef USE_HTTP2
+    else if(proto_len == ALPN_H2_LENGTH &&
+            !memcmp(ALPN_H2, proto, ALPN_H2_LENGTH)) {
+      *palpn = CURL_HTTP_VERSION_2;
+      can_multi = 1;
+    }
+#endif
+#ifdef USE_HTTP3
+    else if(proto_len == ALPN_H3_LENGTH &&
+            !memcmp(ALPN_H3, proto, ALPN_H3_LENGTH)) {
+      *palpn = CURL_HTTP_VERSION_3;
+      can_multi = 1;
+    }
+#endif
+    else {
+      *palpn = CURL_HTTP_VERSION_NONE;
+      failf(data, "unsupported ALPN protocol: '%.*s'", (int)proto_len, proto);
+      /* TODO: do we want to fail this? Previous code just ignored it and
+       * some vtls backends even ignore the return code of this function. */
+      /* return CURLE_NOT_BUILT_IN; */
+      goto out;
+    }
+    infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, (int)proto_len, proto);
+  }
+  else {
+    *palpn = CURL_HTTP_VERSION_NONE;
+    infof(data, VTLS_INFOF_NO_ALPN);
+  }
+
+out:
+  if(!Curl_ssl_cf_is_proxy(cf))
+    Curl_multiuse_state(data, can_multi?
+                        BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
+  return CURLE_OK;
+}
+
+#endif /* USE_SSL */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/vtls.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/vtls.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/vtls.h	(revision 104083)
@@ -0,0 +1,258 @@
+#ifndef HEADER_CURL_VTLS_H
+#define HEADER_CURL_VTLS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+struct connectdata;
+struct ssl_config_data;
+struct ssl_primary_config;
+struct Curl_ssl_session;
+
+#define SSLSUPP_CA_PATH      (1<<0) /* supports CAPATH */
+#define SSLSUPP_CERTINFO     (1<<1) /* supports CURLOPT_CERTINFO */
+#define SSLSUPP_PINNEDPUBKEY (1<<2) /* supports CURLOPT_PINNEDPUBLICKEY */
+#define SSLSUPP_SSL_CTX      (1<<3) /* supports CURLOPT_SSL_CTX */
+#define SSLSUPP_HTTPS_PROXY  (1<<4) /* supports access via HTTPS proxies */
+#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */
+#define SSLSUPP_CAINFO_BLOB  (1<<6)
+
+#define ALPN_ACCEPTED "ALPN: server accepted "
+
+#define VTLS_INFOF_NO_ALPN                                      \
+  "ALPN: server did not agree on a protocol. Uses default."
+#define VTLS_INFOF_ALPN_OFFER_1STR              \
+  "ALPN: curl offers %s"
+#define VTLS_INFOF_ALPN_ACCEPTED_1STR           \
+  ALPN_ACCEPTED "%s"
+#define VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR       \
+  ALPN_ACCEPTED "%.*s"
+
+/* Curl_multi SSL backend-specific data; declared differently by each SSL
+   backend */
+struct multi_ssl_backend_data;
+struct Curl_cfilter;
+
+CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
+                                   const curl_ssl_backend ***avail);
+
+#ifndef MAX_PINNED_PUBKEY_SIZE
+#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */
+#endif
+
+#ifndef CURL_SHA256_DIGEST_LENGTH
+#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */
+#endif
+
+curl_sslbackend Curl_ssl_backend(void);
+
+/**
+ * Init ssl config for a new easy handle.
+ */
+void Curl_ssl_easy_config_init(struct Curl_easy *data);
+
+/**
+ * Init the `data->set.ssl` and `data->set.proxy_ssl` for
+ * connection matching use.
+ */
+CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data);
+
+/**
+ * Init SSL configs (main + proxy) for a new connection from the easy handle.
+ */
+CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
+                                   struct connectdata *conn);
+
+/**
+ * Free allocated resources in SSL configs (main + proxy) for
+ * the given connection.
+ */
+void Curl_ssl_conn_config_cleanup(struct connectdata *conn);
+
+/**
+ * Return TRUE iff SSL configuration from `conn` is functionally the
+ * same as the one on `candidate`.
+ * @param proxy   match the proxy SSL config or the main one
+ */
+bool Curl_ssl_conn_config_match(struct Curl_easy *data,
+                                struct connectdata *candidate,
+                                bool proxy);
+
+/* Update certain connection SSL config flags after they have
+ * been changed on the easy handle. Will work for `verifypeer`,
+ * `verifyhost` and `verifystatus`. */
+void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy);
+
+/**
+ * Init SSL peer information for filter. Can be called repeatedly.
+ */
+CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf);
+/**
+ * Free all allocated data and reset peer information.
+ */
+void Curl_ssl_peer_cleanup(struct ssl_peer *peer);
+
+#ifdef USE_SSL
+int Curl_ssl_init(void);
+void Curl_ssl_cleanup(void);
+/* tell the SSL stuff to close down all open information regarding
+   connections (and thus session ID caching etc) */
+void Curl_ssl_close_all(struct Curl_easy *data);
+CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine);
+/* Sets engine as default for all SSL operations */
+CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data);
+struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data);
+
+/* init the SSL session ID cache */
+CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t);
+void Curl_ssl_version(char *buffer, size_t size);
+
+/* Certificate information list handling. */
+
+void Curl_ssl_free_certinfo(struct Curl_easy *data);
+CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num);
+CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, int certnum,
+                                    const char *label, const char *value,
+                                    size_t valuelen);
+CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum,
+                                const char *label, const char *value);
+
+/* Functions to be used by SSL library adaptation functions */
+
+/* Lock session cache mutex.
+ * Call this before calling other Curl_ssl_*session* functions
+ * Caller should unlock this mutex as soon as possible, as it may block
+ * other SSL connection from making progress.
+ * The purpose of explicitly locking SSL session cache data is to allow
+ * individual SSL engines to manage session lifetime in their specific way.
+ */
+void Curl_ssl_sessionid_lock(struct Curl_easy *data);
+
+/* Unlock session cache mutex */
+void Curl_ssl_sessionid_unlock(struct Curl_easy *data);
+
+/* Kill a single session ID entry in the cache
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * This will call engine-specific curlssl_session_free function, which must
+ * take sessionid object ownership from sessionid cache
+ * (e.g. decrement refcount).
+ */
+void Curl_ssl_kill_session(struct Curl_ssl_session *session);
+/* delete a session from the cache
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * This will call engine-specific curlssl_session_free function, which must
+ * take sessionid object ownership from sessionid cache
+ * (e.g. decrement refcount).
+ */
+void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid);
+
+/* get N random bytes into the buffer */
+CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer,
+                         size_t length);
+/* Check pinned public key. */
+CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
+                              const char *pinnedpubkey,
+                              const unsigned char *pubkey, size_t pubkeylen);
+
+bool Curl_ssl_cert_status_request(void);
+
+bool Curl_ssl_false_start(struct Curl_easy *data);
+
+void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend);
+
+#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
+
+CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
+                              struct connectdata *conn,
+                              int sockindex);
+
+CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at,
+                                  struct Curl_easy *data);
+
+CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
+                                 int sockindex);
+
+#ifndef CURL_DISABLE_PROXY
+CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
+                                        struct Curl_easy *data);
+#endif /* !CURL_DISABLE_PROXY */
+
+/**
+ * True iff the underlying SSL implementation supports the option.
+ * Option is one of the defined SSLSUPP_* values.
+ * `data` maybe NULL for the features of the default implementation.
+ */
+bool Curl_ssl_supports(struct Curl_easy *data, int ssl_option);
+
+/**
+ * Get the internal ssl instance (like OpenSSL's SSL*) from the filter
+ * chain at `sockindex` of type specified by `info`.
+ * For `n` == 0, the first active (top down) instance is returned.
+ * 1 gives the second active, etc.
+ * NULL is returned when no active SSL filter is present.
+ */
+void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
+                             CURLINFO info, int n);
+
+/**
+ * Get the ssl_config_data in `data` that is relevant for cfilter `cf`.
+ */
+struct ssl_config_data *Curl_ssl_cf_get_config(struct Curl_cfilter *cf,
+                                               struct Curl_easy *data);
+
+/**
+ * Get the primary config relevant for the filter from its connection.
+ */
+struct ssl_primary_config *
+  Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf);
+
+extern struct Curl_cftype Curl_cft_ssl;
+#ifndef CURL_DISABLE_PROXY
+extern struct Curl_cftype Curl_cft_ssl_proxy;
+#endif
+
+#else /* if not USE_SSL */
+
+/* When SSL support is not present, just define away these function calls */
+#define Curl_ssl_init() 1
+#define Curl_ssl_cleanup() Curl_nop_stmt
+#define Curl_ssl_close_all(x) Curl_nop_stmt
+#define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN
+#define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN
+#define Curl_ssl_engines_list(x) NULL
+#define Curl_ssl_initsessions(x,y) CURLE_OK
+#define Curl_ssl_free_certinfo(x) Curl_nop_stmt
+#define Curl_ssl_kill_session(x) Curl_nop_stmt
+#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
+#define Curl_ssl_cert_status_request() FALSE
+#define Curl_ssl_false_start(a) FALSE
+#define Curl_ssl_get_internals(a,b,c,d) NULL
+#define Curl_ssl_supports(a,b) FALSE
+#define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN
+#define Curl_ssl_cfilter_remove(a,b) CURLE_OK
+#define Curl_ssl_cf_get_config(a,b) NULL
+#define Curl_ssl_cf_get_primary_config(a) NULL
+#endif
+
+#endif /* HEADER_CURL_VTLS_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/vtls_int.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/vtls_int.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/vtls_int.h	(revision 104083)
@@ -0,0 +1,208 @@
+#ifndef HEADER_CURL_VTLS_INT_H
+#define HEADER_CURL_VTLS_INT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+#include "cfilters.h"
+#include "urldata.h"
+
+#ifdef USE_SSL
+
+/* see https://www.iana.org/assignments/tls-extensiontype-values/ */
+#define ALPN_HTTP_1_1_LENGTH 8
+#define ALPN_HTTP_1_1 "http/1.1"
+#define ALPN_H2_LENGTH 2
+#define ALPN_H2 "h2"
+#define ALPN_H3_LENGTH 2
+#define ALPN_H3 "h3"
+
+/* conservative sizes on the ALPN entries and count we are handling,
+ * we can increase these if we ever feel the need or have to accommodate
+ * ALPN strings from the "outside". */
+#define ALPN_NAME_MAX     10
+#define ALPN_ENTRIES_MAX  3
+#define ALPN_PROTO_BUF_MAX   (ALPN_ENTRIES_MAX * (ALPN_NAME_MAX + 1))
+
+struct alpn_spec {
+  const char entries[ALPN_ENTRIES_MAX][ALPN_NAME_MAX];
+  size_t count; /* number of entries */
+};
+
+struct alpn_proto_buf {
+  unsigned char data[ALPN_PROTO_BUF_MAX];
+  int len;
+};
+
+CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf,
+                                const struct alpn_spec *spec);
+CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf,
+                                const struct alpn_spec *spec);
+
+CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  const unsigned char *proto,
+                                  size_t proto_len);
+
+/* Information in each SSL cfilter context: cf->ctx */
+struct ssl_connect_data {
+  ssl_connection_state state;
+  ssl_connect_state connecting_state;
+  struct ssl_peer peer;
+  const struct alpn_spec *alpn;     /* ALPN to use or NULL for none */
+  void *backend;                    /* vtls backend specific props */
+  struct cf_call_data call_data;    /* data handle used in current call */
+  struct curltime handshake_done;   /* time when handshake finished */
+  int port;                         /* remote port at origin */
+  BIT(use_alpn);                    /* if ALPN shall be used in handshake */
+  BIT(reused_session);              /* session-ID was reused for this */
+  BIT(peer_closed);                 /* peer has closed connection */
+};
+
+
+#undef CF_CTX_CALL_DATA
+#define CF_CTX_CALL_DATA(cf)  \
+  ((struct ssl_connect_data *)(cf)->ctx)->call_data
+
+
+/* Definitions for SSL Implementations */
+
+struct Curl_ssl {
+  /*
+   * This *must* be the first entry to allow returning the list of available
+   * backends in curl_global_sslset().
+   */
+  curl_ssl_backend info;
+  unsigned int supports; /* bitfield, see above */
+  size_t sizeof_ssl_backend_data;
+
+  int (*init)(void);
+  void (*cleanup)(void);
+
+  size_t (*version)(char *buffer, size_t size);
+  int (*check_cxn)(struct Curl_cfilter *cf, struct Curl_easy *data);
+  int (*shut_down)(struct Curl_cfilter *cf,
+                   struct Curl_easy *data);
+  bool (*data_pending)(struct Curl_cfilter *cf,
+                       const struct Curl_easy *data);
+
+  /* return 0 if a find random is filled in */
+  CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy,
+                     size_t length);
+  bool (*cert_status_request)(void);
+
+  CURLcode (*connect_blocking)(struct Curl_cfilter *cf,
+                               struct Curl_easy *data);
+  CURLcode (*connect_nonblocking)(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  bool *done);
+
+  /* During handshake, adjust the pollset to include the socket
+   * for POLLOUT or POLLIN as needed.
+   * Mandatory. */
+  void (*adjust_pollset)(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          struct easy_pollset *ps);
+  void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
+  void (*close)(struct Curl_cfilter *cf, struct Curl_easy *data);
+  void (*close_all)(struct Curl_easy *data);
+  void (*session_free)(void *ptr);
+
+  CURLcode (*set_engine)(struct Curl_easy *data, const char *engine);
+  CURLcode (*set_engine_default)(struct Curl_easy *data);
+  struct curl_slist *(*engines_list)(struct Curl_easy *data);
+
+  bool (*false_start)(void);
+  CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
+                    unsigned char *sha256sum, size_t sha256sumlen);
+
+  bool (*attach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);
+  void (*detach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);
+
+  void (*free_multi_ssl_backend_data)(struct multi_ssl_backend_data *mbackend);
+
+  ssize_t (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
+                        char *buf, size_t len, CURLcode *code);
+  ssize_t (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
+                        const void *mem, size_t len, CURLcode *code);
+
+};
+
+extern const struct Curl_ssl *Curl_ssl;
+
+
+int Curl_none_init(void);
+void Curl_none_cleanup(void);
+int Curl_none_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data);
+int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data);
+CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy,
+                          size_t length);
+void Curl_none_close_all(struct Curl_easy *data);
+void Curl_none_session_free(void *ptr);
+bool Curl_none_data_pending(struct Curl_cfilter *cf,
+                            const struct Curl_easy *data);
+bool Curl_none_cert_status_request(void);
+CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine);
+CURLcode Curl_none_set_engine_default(struct Curl_easy *data);
+struct curl_slist *Curl_none_engines_list(struct Curl_easy *data);
+bool Curl_none_false_start(void);
+void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              struct easy_pollset *ps);
+
+/**
+ * Get the SSL filter below the given one or NULL if there is none.
+ */
+bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf);
+
+/* extract a session ID
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Caller must make sure that the ownership of returned sessionid object
+ * is properly taken (e.g. its refcount is incremented
+ * under sessionid mutex).
+ */
+bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           void **ssl_sessionid,
+                           size_t *idsize); /* set 0 if unknown */
+/* add a new session ID
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Caller must ensure that it has properly shared ownership of this sessionid
+ * object with cache (e.g. incrementing refcount on success)
+ */
+CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               void *ssl_sessionid,
+                               size_t idsize,
+                               bool *added);
+
+#include "openssl.h"        /* OpenSSL versions */
+#include "gtls.h"           /* GnuTLS versions */
+#include "wolfssl.h"        /* wolfSSL versions */
+#include "schannel.h"       /* Schannel SSPI version */
+#include "sectransp.h"      /* SecureTransport (Darwin) version */
+#include "mbedtls.h"        /* mbedTLS versions */
+#include "bearssl.h"        /* BearSSL versions */
+#include "rustls.h"         /* rustls versions */
+
+#endif /* USE_SSL */
+
+#endif /* HEADER_CURL_VTLS_INT_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/wolfssl.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/wolfssl.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/wolfssl.c	(revision 104083)
@@ -0,0 +1,1420 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all wolfSSL specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ *
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_WOLFSSL
+
+#define WOLFSSL_OPTIONS_IGNORE_SYS
+#include <wolfssl/version.h>
+#include <wolfssl/options.h>
+
+/* To determine what functions are available we rely on one or both of:
+   - the user's options.h generated by wolfSSL
+   - the symbols detected by curl's configure
+   Since they are markedly different from one another, and one or the other may
+   not be available, we do some checking below to bring things in sync. */
+
+/* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */
+#ifndef HAVE_ALPN
+#ifdef HAVE_WOLFSSL_USEALPN
+#define HAVE_ALPN
+#endif
+#endif
+
+#include <limits.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "vtls.h"
+#include "vtls_int.h"
+#include "keylog.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "strcase.h"
+#include "x509asn1.h"
+#include "curl_printf.h"
+#include "multiif.h"
+
+#include <wolfssl/openssl/ssl.h>
+#include <wolfssl/ssl.h>
+#include <wolfssl/error-ssl.h>
+#include "wolfssl.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* KEEP_PEER_CERT is a product of the presence of build time symbol
+   OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
+   in wolfSSL's settings.h, and the latter two are build time symbols in
+   options.h. */
+#ifndef KEEP_PEER_CERT
+#if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
+    (defined(OPENSSL_EXTRA) && !defined(NO_CERTS))
+#define KEEP_PEER_CERT
+#endif
+#endif
+
+#if defined(HAVE_WOLFSSL_FULL_BIO) && HAVE_WOLFSSL_FULL_BIO
+#define USE_BIO_CHAIN
+#else
+#undef USE_BIO_CHAIN
+#endif
+
+struct wolfssl_ssl_backend_data {
+  WOLFSSL_CTX *ctx;
+  WOLFSSL     *handle;
+  CURLcode    io_result;   /* result of last BIO cfilter operation */
+};
+
+#ifdef OPENSSL_EXTRA
+/*
+ * Availability note:
+ * The TLS 1.3 secret callback (wolfSSL_set_tls13_secret_cb) was added in
+ * WolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that
+ * option is not set, then TLS 1.3 will not be logged.
+ * For TLS 1.2 and before, we use wolfSSL_get_keys().
+ * SSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA
+ * (--enable-opensslextra or --enable-all).
+ */
+#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
+static int
+wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
+                              int secretSz, void *ctx)
+{
+  const char *label;
+  unsigned char client_random[SSL3_RANDOM_SIZE];
+  (void)ctx;
+
+  if(!ssl || !Curl_tls_keylog_enabled()) {
+    return 0;
+  }
+
+  switch(id) {
+  case CLIENT_EARLY_TRAFFIC_SECRET:
+    label = "CLIENT_EARLY_TRAFFIC_SECRET";
+    break;
+  case CLIENT_HANDSHAKE_TRAFFIC_SECRET:
+    label = "CLIENT_HANDSHAKE_TRAFFIC_SECRET";
+    break;
+  case SERVER_HANDSHAKE_TRAFFIC_SECRET:
+    label = "SERVER_HANDSHAKE_TRAFFIC_SECRET";
+    break;
+  case CLIENT_TRAFFIC_SECRET:
+    label = "CLIENT_TRAFFIC_SECRET_0";
+    break;
+  case SERVER_TRAFFIC_SECRET:
+    label = "SERVER_TRAFFIC_SECRET_0";
+    break;
+  case EARLY_EXPORTER_SECRET:
+    label = "EARLY_EXPORTER_SECRET";
+    break;
+  case EXPORTER_SECRET:
+    label = "EXPORTER_SECRET";
+    break;
+  default:
+    return 0;
+  }
+
+  if(SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE) == 0) {
+    /* Should never happen as wolfSSL_KeepArrays() was called before. */
+    return 0;
+  }
+
+  Curl_tls_keylog_write(label, client_random, secret, secretSz);
+  return 0;
+}
+#endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */
+
+static void
+wolfssl_log_tls12_secret(SSL *ssl)
+{
+  unsigned char *ms, *sr, *cr;
+  unsigned int msLen, srLen, crLen, i, x = 0;
+
+#if LIBWOLFSSL_VERSION_HEX >= 0x0300d000 /* >= 3.13.0 */
+  /* wolfSSL_GetVersion is available since 3.13, we use it instead of
+   * SSL_version since the latter relies on OPENSSL_ALL (--enable-opensslall or
+   * --enable-all). Failing to perform this check could result in an unusable
+   * key log line when TLS 1.3 is actually negotiated. */
+  switch(wolfSSL_GetVersion(ssl)) {
+  case WOLFSSL_SSLV3:
+  case WOLFSSL_TLSV1:
+  case WOLFSSL_TLSV1_1:
+  case WOLFSSL_TLSV1_2:
+    break;
+  default:
+    /* TLS 1.3 does not use this mechanism, the "master secret" returned below
+     * is not directly usable. */
+    return;
+  }
+#endif
+
+  if(wolfSSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) !=
+     SSL_SUCCESS) {
+    return;
+  }
+
+  /* Check for a missing master secret and skip logging. That can happen if
+   * curl rejects the server certificate and aborts the handshake.
+   */
+  for(i = 0; i < msLen; i++) {
+    x |= ms[i];
+  }
+  if(x == 0) {
+    return;
+  }
+
+  Curl_tls_keylog_write("CLIENT_RANDOM", cr, ms, msLen);
+}
+#endif /* OPENSSL_EXTRA */
+
+static int do_file_type(const char *type)
+{
+  if(!type || !type[0])
+    return SSL_FILETYPE_PEM;
+  if(strcasecompare(type, "PEM"))
+    return SSL_FILETYPE_PEM;
+  if(strcasecompare(type, "DER"))
+    return SSL_FILETYPE_ASN1;
+  return -1;
+}
+
+#ifdef HAVE_LIBOQS
+struct group_name_map {
+  const word16 group;
+  const char   *name;
+};
+
+static const struct group_name_map gnm[] = {
+  { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" },
+  { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" },
+  { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" },
+  { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" },
+  { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" },
+  { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" },
+  { 0, NULL }
+};
+#endif
+
+#ifdef USE_BIO_CHAIN
+
+static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio)
+{
+  wolfSSL_BIO_set_shutdown(bio, 1);
+  wolfSSL_BIO_set_data(bio, NULL);
+  return 1;
+}
+
+static int wolfssl_bio_cf_destroy(WOLFSSL_BIO *bio)
+{
+  if(!bio)
+    return 0;
+  return 1;
+}
+
+static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
+{
+  struct Curl_cfilter *cf = BIO_get_data(bio);
+  long ret = 1;
+
+  (void)cf;
+  (void)ptr;
+  switch(cmd) {
+  case BIO_CTRL_GET_CLOSE:
+    ret = (long)wolfSSL_BIO_get_shutdown(bio);
+    break;
+  case BIO_CTRL_SET_CLOSE:
+    wolfSSL_BIO_set_shutdown(bio, (int)num);
+    break;
+  case BIO_CTRL_FLUSH:
+    /* we do no delayed writes, but if we ever would, this
+     * needs to trigger it. */
+    ret = 1;
+    break;
+  case BIO_CTRL_DUP:
+    ret = 1;
+    break;
+#ifdef BIO_CTRL_EOF
+  case BIO_CTRL_EOF:
+    /* EOF has been reached on input? */
+    return (!cf->next || !cf->next->connected);
+#endif
+  default:
+    ret = 0;
+    break;
+  }
+  return ret;
+}
+
+static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio,
+                                    const char *buf, int blen)
+{
+  struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct wolfssl_ssl_backend_data *backend =
+    (struct wolfssl_ssl_backend_data *)connssl->backend;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  ssize_t nwritten;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(data);
+  nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+  backend->io_result = result;
+  CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
+              blen, nwritten, result);
+  wolfSSL_BIO_clear_retry_flags(bio);
+  if(nwritten < 0 && CURLE_AGAIN == result)
+    BIO_set_retry_write(bio);
+  return (int)nwritten;
+}
+
+static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
+{
+  struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct wolfssl_ssl_backend_data *backend =
+    (struct wolfssl_ssl_backend_data *)connssl->backend;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+  ssize_t nread;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(data);
+  /* OpenSSL catches this case, so should we. */
+  if(!buf)
+    return 0;
+
+  nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+  backend->io_result = result;
+  CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %zd, %d", blen, nread, result);
+  wolfSSL_BIO_clear_retry_flags(bio);
+  if(nread < 0 && CURLE_AGAIN == result)
+    BIO_set_retry_read(bio);
+  else if(nread == 0)
+    connssl->peer_closed = TRUE;
+  return (int)nread;
+}
+
+static WOLFSSL_BIO_METHOD *wolfssl_bio_cf_method = NULL;
+
+static void wolfssl_bio_cf_init_methods(void)
+{
+  wolfssl_bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO");
+  wolfSSL_BIO_meth_set_write(wolfssl_bio_cf_method, &wolfssl_bio_cf_out_write);
+  wolfSSL_BIO_meth_set_read(wolfssl_bio_cf_method, &wolfssl_bio_cf_in_read);
+  wolfSSL_BIO_meth_set_ctrl(wolfssl_bio_cf_method, &wolfssl_bio_cf_ctrl);
+  wolfSSL_BIO_meth_set_create(wolfssl_bio_cf_method, &wolfssl_bio_cf_create);
+  wolfSSL_BIO_meth_set_destroy(wolfssl_bio_cf_method, &wolfssl_bio_cf_destroy);
+}
+
+static void wolfssl_bio_cf_free_methods(void)
+{
+  wolfSSL_BIO_meth_free(wolfssl_bio_cf_method);
+}
+
+#else /* USE_BIO_CHAIN */
+
+#define wolfssl_bio_cf_init_methods() Curl_nop_stmt
+#define wolfssl_bio_cf_free_methods() Curl_nop_stmt
+
+#endif /* !USE_BIO_CHAIN */
+
+/*
+ * This function loads all the client/CA certificates and CRLs. Setup the TLS
+ * layer and do all necessary magic.
+ */
+static CURLcode
+wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  char *ciphers, *curves;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct wolfssl_ssl_backend_data *backend =
+    (struct wolfssl_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+  const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  const char * const ssl_cafile =
+    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+    (ca_info_blob ? NULL : conn_config->CAfile);
+  const char * const ssl_capath = conn_config->CApath;
+  WOLFSSL_METHOD* req_method = NULL;
+#ifdef HAVE_LIBOQS
+  word16 oqsAlg = 0;
+  size_t idx = 0;
+#endif
+#ifdef HAVE_SNI
+  bool sni = FALSE;
+#define use_sni(x)  sni = (x)
+#else
+#define use_sni(x)  Curl_nop_stmt
+#endif
+  bool imported_native_ca = false;
+  bool imported_ca_info_blob = false;
+
+  DEBUGASSERT(backend);
+
+  if(connssl->state == ssl_connection_complete)
+    return CURLE_OK;
+
+  if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) {
+    failf(data, "wolfSSL does not support to set maximum SSL/TLS version");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  /* check to see if we've been told to use an explicit SSL/TLS version */
+  switch(conn_config->version) {
+  case CURL_SSLVERSION_DEFAULT:
+  case CURL_SSLVERSION_TLSv1:
+#if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
+    /* minimum protocol version is set later after the CTX object is created */
+    req_method = SSLv23_client_method();
+#else
+    infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
+          "TLS 1.0 is used exclusively");
+    req_method = TLSv1_client_method();
+#endif
+    use_sni(TRUE);
+    break;
+  case CURL_SSLVERSION_TLSv1_0:
+#if defined(WOLFSSL_ALLOW_TLSV10) && !defined(NO_OLD_TLS)
+    req_method = TLSv1_client_method();
+    use_sni(TRUE);
+#else
+    failf(data, "wolfSSL does not support TLS 1.0");
+    return CURLE_NOT_BUILT_IN;
+#endif
+    break;
+  case CURL_SSLVERSION_TLSv1_1:
+#ifndef NO_OLD_TLS
+    req_method = TLSv1_1_client_method();
+    use_sni(TRUE);
+#else
+    failf(data, "wolfSSL does not support TLS 1.1");
+    return CURLE_NOT_BUILT_IN;
+#endif
+    break;
+  case CURL_SSLVERSION_TLSv1_2:
+#ifndef WOLFSSL_NO_TLS12
+    req_method = TLSv1_2_client_method();
+    use_sni(TRUE);
+#else
+    failf(data, "wolfSSL does not support TLS 1.2");
+    return CURLE_NOT_BUILT_IN;
+#endif
+    break;
+  case CURL_SSLVERSION_TLSv1_3:
+#ifdef WOLFSSL_TLS13
+    req_method = wolfTLSv1_3_client_method();
+    use_sni(TRUE);
+    break;
+#else
+    failf(data, "wolfSSL: TLS 1.3 is not yet supported");
+    return CURLE_SSL_CONNECT_ERROR;
+#endif
+  default:
+    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  if(!req_method) {
+    failf(data, "SSL: couldn't create a method");
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(backend->ctx)
+    wolfSSL_CTX_free(backend->ctx);
+  backend->ctx = wolfSSL_CTX_new(req_method);
+
+  if(!backend->ctx) {
+    failf(data, "SSL: couldn't create a context");
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  switch(conn_config->version) {
+  case CURL_SSLVERSION_DEFAULT:
+  case CURL_SSLVERSION_TLSv1:
+#if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
+    /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is
+     * whatever minimum version of TLS was built in and at least TLS 1.0. For
+     * later library versions that could change (eg TLS 1.0 built in but
+     * defaults to TLS 1.1) so we have this short circuit evaluation to find
+     * the minimum supported TLS version.
+    */
+    if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) &&
+       (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) &&
+       (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1)
+#ifdef WOLFSSL_TLS13
+       && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1)
+#endif
+      ) {
+      failf(data, "SSL: couldn't set the minimum protocol version");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+#endif
+  default:
+    break;
+  }
+
+  ciphers = conn_config->cipher_list;
+  if(ciphers) {
+    if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
+      failf(data, "failed setting cipher list: %s", ciphers);
+      return CURLE_SSL_CIPHER;
+    }
+    infof(data, "Cipher selection: %s", ciphers);
+  }
+
+  curves = conn_config->curves;
+  if(curves) {
+
+#ifdef HAVE_LIBOQS
+    for(idx = 0; gnm[idx].name != NULL; idx++) {
+      if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) {
+        oqsAlg = gnm[idx].group;
+        break;
+      }
+    }
+
+    if(oqsAlg == 0)
+#endif
+    {
+      if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
+        failf(data, "failed setting curves list: '%s'", curves);
+        return CURLE_SSL_CIPHER;
+      }
+    }
+  }
+
+#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
+  /* load native CA certificates */
+  if(ssl_config->native_ca_store) {
+    if(wolfSSL_CTX_load_system_CA_certs(backend->ctx) != WOLFSSL_SUCCESS) {
+      infof(data, "error importing native CA store, continuing anyway");
+    }
+    else {
+      imported_native_ca = true;
+      infof(data, "successfully imported native CA store");
+    }
+  }
+#endif /* !NO_FILESYSTEM */
+
+  /* load certificate blob */
+  if(ca_info_blob) {
+    if(wolfSSL_CTX_load_verify_buffer(backend->ctx, ca_info_blob->data,
+                                      ca_info_blob->len,
+                                      SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+      if(imported_native_ca) {
+        infof(data, "error importing CA certificate blob, continuing anyway");
+      }
+      else {
+        failf(data, "error importing CA certificate blob");
+        return CURLE_SSL_CACERT_BADFILE;
+      }
+    }
+    else {
+      imported_ca_info_blob = true;
+      infof(data, "successfully imported CA certificate blob");
+    }
+  }
+
+#ifndef NO_FILESYSTEM
+  /* load trusted cacert from file if not blob */
+  if(ssl_cafile || ssl_capath) {
+    int rc =
+      wolfSSL_CTX_load_verify_locations_ex(backend->ctx,
+                                           ssl_cafile,
+                                           ssl_capath,
+                                           WOLFSSL_LOAD_FLAG_IGNORE_ERR);
+    if(SSL_SUCCESS != rc) {
+      if(conn_config->verifypeer && !imported_ca_info_blob &&
+         !imported_native_ca) {
+        /* Fail if we insist on successfully verifying the server. */
+        failf(data, "error setting certificate verify locations:"
+              " CAfile: %s CApath: %s",
+              ssl_cafile ? ssl_cafile : "none",
+              ssl_capath ? ssl_capath : "none");
+        return CURLE_SSL_CACERT_BADFILE;
+      }
+      else {
+        /* Just continue with a warning if no strict certificate
+           verification is required. */
+        infof(data, "error setting certificate verify locations,"
+              " continuing anyway:");
+      }
+    }
+    else {
+      /* Everything is fine. */
+      infof(data, "successfully set certificate verify locations:");
+    }
+    infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
+    infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
+  }
+
+  /* Load the client certificate, and private key */
+  if(ssl_config->primary.clientcert && ssl_config->key) {
+    int file_type = do_file_type(ssl_config->cert_type);
+
+    if(file_type == WOLFSSL_FILETYPE_PEM) {
+      if(wolfSSL_CTX_use_certificate_chain_file(backend->ctx,
+                                                ssl_config->primary.clientcert)
+         != 1) {
+        failf(data, "unable to use client certificate");
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+    }
+    else if(file_type == WOLFSSL_FILETYPE_ASN1) {
+      if(wolfSSL_CTX_use_certificate_file(backend->ctx,
+                                          ssl_config->primary.clientcert,
+                                          file_type) != 1) {
+        failf(data, "unable to use client certificate");
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+    }
+    else {
+      failf(data, "unknown cert type");
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+
+    file_type = do_file_type(ssl_config->key_type);
+    if(wolfSSL_CTX_use_PrivateKey_file(backend->ctx, ssl_config->key,
+                                       file_type) != 1) {
+      failf(data, "unable to set private key");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+#endif /* !NO_FILESYSTEM */
+
+  /* SSL always tries to verify the peer, this only says whether it should
+   * fail to connect if the verification fails, or if it should continue
+   * anyway. In the latter case the result of the verification is checked with
+   * SSL_get_verify_result() below. */
+  wolfSSL_CTX_set_verify(backend->ctx,
+                         conn_config->verifypeer?SSL_VERIFY_PEER:
+                         SSL_VERIFY_NONE, NULL);
+
+#ifdef HAVE_SNI
+  if(sni && connssl->peer.sni) {
+    size_t sni_len = strlen(connssl->peer.sni);
+    if((sni_len < USHRT_MAX)) {
+      if(wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME,
+                            connssl->peer.sni,
+                            (unsigned short)sni_len) != 1) {
+        failf(data, "Failed to set SNI");
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+    }
+  }
+#endif
+
+  /* give application a chance to interfere with SSL set up. */
+  if(data->set.ssl.fsslctx) {
+    CURLcode result = (*data->set.ssl.fsslctx)(data, backend->ctx,
+                                               data->set.ssl.fsslctxp);
+    if(result) {
+      failf(data, "error signaled by ssl ctx callback");
+      return result;
+    }
+  }
+#ifdef NO_FILESYSTEM
+  else if(conn_config->verifypeer) {
+    failf(data, "SSL: Certificates can't be loaded because wolfSSL was built"
+          " with \"no filesystem\". Either disable peer verification"
+          " (insecure) or if you are building an application with libcurl you"
+          " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+#endif
+
+  /* Let's make an SSL structure */
+  if(backend->handle)
+    wolfSSL_free(backend->handle);
+  backend->handle = wolfSSL_new(backend->ctx);
+  if(!backend->handle) {
+    failf(data, "SSL: couldn't create a handle");
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+#ifdef HAVE_LIBOQS
+  if(oqsAlg) {
+    if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) {
+      failf(data, "unable to use oqs KEM");
+    }
+  }
+#endif
+
+#ifdef HAVE_ALPN
+  if(connssl->alpn) {
+    struct alpn_proto_buf proto;
+    CURLcode result;
+
+    result = Curl_alpn_to_proto_str(&proto, connssl->alpn);
+    if(result ||
+       wolfSSL_UseALPN(backend->handle, (char *)proto.data, proto.len,
+                       WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
+      failf(data, "SSL: failed setting ALPN protocols");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+  }
+#endif /* HAVE_ALPN */
+
+#ifdef OPENSSL_EXTRA
+  if(Curl_tls_keylog_enabled()) {
+    /* Ensure the Client Random is preserved. */
+    wolfSSL_KeepArrays(backend->handle);
+#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
+    wolfSSL_set_tls13_secret_cb(backend->handle,
+                                wolfssl_tls13_secret_callback, NULL);
+#endif
+  }
+#endif /* OPENSSL_EXTRA */
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+  if(wolfSSL_UseSecureRenegotiation(backend->handle) != SSL_SUCCESS) {
+    failf(data, "SSL: failed setting secure renegotiation");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+#endif /* HAVE_SECURE_RENEGOTIATION */
+
+  /* Check if there's a cached ID we can/should use here! */
+  if(ssl_config->primary.sessionid) {
+    void *ssl_sessionid = NULL;
+
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
+      /* we got a session id, use it! */
+      if(!SSL_set_session(backend->handle, ssl_sessionid)) {
+        Curl_ssl_delsessionid(data, ssl_sessionid);
+        infof(data, "Can't use session ID, going on without");
+      }
+      else
+        infof(data, "SSL reusing session ID");
+    }
+    Curl_ssl_sessionid_unlock(data);
+  }
+
+#ifdef USE_BIO_CHAIN
+  {
+    WOLFSSL_BIO *bio;
+
+    bio = BIO_new(wolfssl_bio_cf_method);
+    if(!bio)
+      return CURLE_OUT_OF_MEMORY;
+
+    wolfSSL_BIO_set_data(bio, cf);
+    wolfSSL_set_bio(backend->handle, bio, bio);
+  }
+#else /* USE_BIO_CHAIN */
+  /* pass the raw socket into the SSL layer */
+  if(!wolfSSL_set_fd(backend->handle,
+                     (int)Curl_conn_cf_get_socket(cf, data))) {
+    failf(data, "SSL: SSL_set_fd failed");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+#endif /* !USE_BIO_CHAIN */
+
+  connssl->connecting_state = ssl_connect_2;
+  return CURLE_OK;
+}
+
+
+static CURLcode
+wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  int ret = -1;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct wolfssl_ssl_backend_data *backend =
+    (struct wolfssl_ssl_backend_data *)connssl->backend;
+  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+
+  DEBUGASSERT(backend);
+
+  wolfSSL_ERR_clear_error();
+
+  /* Enable RFC2818 checks */
+  if(conn_config->verifyhost) {
+    char *snihost = connssl->peer.sni?
+                    connssl->peer.sni : connssl->peer.hostname;
+    if(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE)
+      return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  ret = wolfSSL_connect(backend->handle);
+
+#ifdef OPENSSL_EXTRA
+  if(Curl_tls_keylog_enabled()) {
+    /* If key logging is enabled, wait for the handshake to complete and then
+     * proceed with logging secrets (for TLS 1.2 or older).
+     *
+     * During the handshake (ret==-1), wolfSSL_want_read() is true as it waits
+     * for the server response. At that point the master secret is not yet
+     * available, so we must not try to read it.
+     * To log the secret on completion with a handshake failure, detect
+     * completion via the observation that there is nothing to read or write.
+     * Note that OpenSSL SSL_want_read() is always true here. If wolfSSL ever
+     * changes, the worst case is that no key is logged on error.
+     */
+    if(ret == SSL_SUCCESS ||
+       (!wolfSSL_want_read(backend->handle) &&
+        !wolfSSL_want_write(backend->handle))) {
+      wolfssl_log_tls12_secret(backend->handle);
+      /* Client Random and master secrets are no longer needed, erase these.
+       * Ignored while the handshake is still in progress. */
+      wolfSSL_FreeArrays(backend->handle);
+    }
+  }
+#endif  /* OPENSSL_EXTRA */
+
+  if(ret != 1) {
+    char error_buffer[WOLFSSL_MAX_ERROR_SZ];
+    int  detail = wolfSSL_get_error(backend->handle, ret);
+
+    if(SSL_ERROR_WANT_READ == detail) {
+      connssl->connecting_state = ssl_connect_2_reading;
+      return CURLE_OK;
+    }
+    else if(SSL_ERROR_WANT_WRITE == detail) {
+      connssl->connecting_state = ssl_connect_2_writing;
+      return CURLE_OK;
+    }
+    /* There is no easy way to override only the CN matching.
+     * This will enable the override of both mismatching SubjectAltNames
+     * as also mismatching CN fields */
+    else if(DOMAIN_NAME_MISMATCH == detail) {
+#if 1
+      failf(data, " subject alt name(s) or common name do not match \"%s\"",
+            connssl->peer.dispname);
+      return CURLE_PEER_FAILED_VERIFICATION;
+#else
+      /* When the wolfssl_check_domain_name() is used and you desire to
+       * continue on a DOMAIN_NAME_MISMATCH, i.e. 'ssl_config.verifyhost
+       * == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA
+       * error. The only way to do this is currently to switch the
+       * Wolfssl_check_domain_name() in and out based on the
+       * 'ssl_config.verifyhost' value. */
+      if(conn_config->verifyhost) {
+        failf(data,
+              " subject alt name(s) or common name do not match \"%s\"\n",
+              connssl->dispname);
+        return CURLE_PEER_FAILED_VERIFICATION;
+      }
+      else {
+        infof(data,
+              " subject alt name(s) and/or common name do not match \"%s\"",
+              connssl->dispname);
+        return CURLE_OK;
+      }
+#endif
+    }
+#if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
+    else if(ASN_NO_SIGNER_E == detail) {
+      if(conn_config->verifypeer) {
+        failf(data, " CA signer not available for verification");
+        return CURLE_SSL_CACERT_BADFILE;
+      }
+      else {
+        /* Just continue with a warning if no strict certificate
+           verification is required. */
+        infof(data, "CA signer not available for verification, "
+                    "continuing anyway");
+      }
+    }
+#endif
+    else if(backend->io_result == CURLE_AGAIN) {
+      return CURLE_OK;
+    }
+    else {
+      failf(data, "SSL_connect failed with error %d: %s", detail,
+            wolfSSL_ERR_error_string(detail, error_buffer));
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+
+  if(pinnedpubkey) {
+#ifdef KEEP_PEER_CERT
+    X509 *x509;
+    const char *x509_der;
+    int x509_der_len;
+    struct Curl_X509certificate x509_parsed;
+    struct Curl_asn1Element *pubkey;
+    CURLcode result;
+
+    x509 = wolfSSL_get_peer_certificate(backend->handle);
+    if(!x509) {
+      failf(data, "SSL: failed retrieving server certificate");
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len);
+    if(!x509_der) {
+      failf(data, "SSL: failed retrieving ASN.1 server certificate");
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    memset(&x509_parsed, 0, sizeof(x509_parsed));
+    if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+    pubkey = &x509_parsed.subjectPublicKeyInfo;
+    if(!pubkey->header || pubkey->end <= pubkey->header) {
+      failf(data, "SSL: failed retrieving public key from server certificate");
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    result = Curl_pin_peer_pubkey(data,
+                                  pinnedpubkey,
+                                  (const unsigned char *)pubkey->header,
+                                  (size_t)(pubkey->end - pubkey->header));
+    if(result) {
+      failf(data, "SSL: public key does not match pinned public key");
+      return result;
+    }
+#else
+    failf(data, "Library lacks pinning support built-in");
+    return CURLE_NOT_BUILT_IN;
+#endif
+  }
+
+#ifdef HAVE_ALPN
+  if(connssl->alpn) {
+    int rc;
+    char *protocol = NULL;
+    unsigned short protocol_len = 0;
+
+    rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len);
+
+    if(rc == SSL_SUCCESS) {
+      Curl_alpn_set_negotiated(cf, data, (const unsigned char *)protocol,
+                               protocol_len);
+    }
+    else if(rc == SSL_ALPN_NOT_FOUND)
+      Curl_alpn_set_negotiated(cf, data, NULL, 0);
+    else {
+      failf(data, "ALPN, failure getting protocol, error %d", rc);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+#endif /* HAVE_ALPN */
+
+  connssl->connecting_state = ssl_connect_3;
+#if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
+  infof(data, "SSL connection using %s / %s",
+        wolfSSL_get_version(backend->handle),
+        wolfSSL_get_cipher_name(backend->handle));
+#else
+  infof(data, "SSL connected");
+#endif
+
+  return CURLE_OK;
+}
+
+
+static CURLcode
+wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct wolfssl_ssl_backend_data *backend =
+    (struct wolfssl_ssl_backend_data *)connssl->backend;
+  const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+
+  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+  DEBUGASSERT(backend);
+
+  if(ssl_config->primary.sessionid) {
+    bool incache;
+    bool added = FALSE;
+    void *old_ssl_sessionid = NULL;
+    /* wolfSSL_get1_session allocates memory that has to be freed. */
+    WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle);
+
+    if(our_ssl_sessionid) {
+      Curl_ssl_sessionid_lock(data);
+      incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
+      if(incache) {
+        if(old_ssl_sessionid != our_ssl_sessionid) {
+          infof(data, "old SSL session ID is stale, removing");
+          Curl_ssl_delsessionid(data, old_ssl_sessionid);
+          incache = FALSE;
+        }
+      }
+
+      if(!incache) {
+        result = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, 0, NULL);
+        if(result) {
+          Curl_ssl_sessionid_unlock(data);
+          wolfSSL_SESSION_free(our_ssl_sessionid);
+          failf(data, "failed to store ssl session");
+          return result;
+        }
+        else {
+          added = TRUE;
+        }
+      }
+      Curl_ssl_sessionid_unlock(data);
+
+      if(!added) {
+        /* If the session info wasn't added to the cache, free our copy. */
+        wolfSSL_SESSION_free(our_ssl_sessionid);
+      }
+    }
+  }
+
+  connssl->connecting_state = ssl_connect_done;
+
+  return result;
+}
+
+
+static ssize_t wolfssl_send(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            const void *mem,
+                            size_t len,
+                            CURLcode *curlcode)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct wolfssl_ssl_backend_data *backend =
+    (struct wolfssl_ssl_backend_data *)connssl->backend;
+  char error_buffer[WOLFSSL_MAX_ERROR_SZ];
+  int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
+  int rc;
+
+  DEBUGASSERT(backend);
+
+  wolfSSL_ERR_clear_error();
+
+  rc = wolfSSL_write(backend->handle, mem, memlen);
+  if(rc <= 0) {
+    int err = wolfSSL_get_error(backend->handle, rc);
+
+    switch(err) {
+    case SSL_ERROR_WANT_READ:
+    case SSL_ERROR_WANT_WRITE:
+      /* there's data pending, re-invoke SSL_write() */
+      CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
+      *curlcode = CURLE_AGAIN;
+      return -1;
+    default:
+      if(backend->io_result == CURLE_AGAIN) {
+        CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
+        *curlcode = CURLE_AGAIN;
+        return -1;
+      }
+      CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d", len, rc, err);
+      failf(data, "SSL write: %s, errno %d",
+            wolfSSL_ERR_error_string(err, error_buffer),
+            SOCKERRNO);
+      *curlcode = CURLE_SEND_ERROR;
+      return -1;
+    }
+  }
+  CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc);
+  return rc;
+}
+
+static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct wolfssl_ssl_backend_data *backend =
+    (struct wolfssl_ssl_backend_data *)connssl->backend;
+
+  (void) data;
+
+  DEBUGASSERT(backend);
+
+  if(backend->handle) {
+    char buf[32];
+    /* Maybe the server has already sent a close notify alert.
+       Read it to avoid an RST on the TCP connection. */
+    (void)wolfSSL_read(backend->handle, buf, (int)sizeof(buf));
+    if(!connssl->peer_closed)
+      (void)wolfSSL_shutdown(backend->handle);
+    wolfSSL_free(backend->handle);
+    backend->handle = NULL;
+  }
+  if(backend->ctx) {
+    wolfSSL_CTX_free(backend->ctx);
+    backend->ctx = NULL;
+  }
+}
+
+static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            char *buf, size_t blen,
+                            CURLcode *curlcode)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct wolfssl_ssl_backend_data *backend =
+    (struct wolfssl_ssl_backend_data *)connssl->backend;
+  char error_buffer[WOLFSSL_MAX_ERROR_SZ];
+  int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
+  int nread;
+
+  DEBUGASSERT(backend);
+
+  wolfSSL_ERR_clear_error();
+  *curlcode = CURLE_OK;
+
+  nread = wolfSSL_read(backend->handle, buf, buffsize);
+
+  if(nread <= 0) {
+    int err = wolfSSL_get_error(backend->handle, nread);
+
+    switch(err) {
+    case SSL_ERROR_ZERO_RETURN: /* no more data */
+      CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
+      *curlcode = CURLE_OK;
+      return 0;
+    case SSL_ERROR_NONE:
+    case SSL_ERROR_WANT_READ:
+    case SSL_ERROR_WANT_WRITE:
+      /* there's data pending, re-invoke wolfSSL_read() */
+      CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
+      *curlcode = CURLE_AGAIN;
+      return -1;
+    default:
+      if(backend->io_result == CURLE_AGAIN) {
+        CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
+        *curlcode = CURLE_AGAIN;
+        return -1;
+      }
+      failf(data, "SSL read: %s, errno %d",
+            wolfSSL_ERR_error_string(err, error_buffer), SOCKERRNO);
+      *curlcode = CURLE_RECV_ERROR;
+      return -1;
+    }
+  }
+  CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> %d", blen, nread);
+  return nread;
+}
+
+
+static void wolfssl_session_free(void *ptr)
+{
+  wolfSSL_SESSION_free(ptr);
+}
+
+
+static size_t wolfssl_version(char *buffer, size_t size)
+{
+#if LIBWOLFSSL_VERSION_HEX >= 0x03006000
+  return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
+#elif defined(WOLFSSL_VERSION)
+  return msnprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
+#endif
+}
+
+
+static int wolfssl_init(void)
+{
+  int ret;
+
+#ifdef OPENSSL_EXTRA
+  Curl_tls_keylog_open();
+#endif
+  ret = (wolfSSL_Init() == SSL_SUCCESS);
+  wolfssl_bio_cf_init_methods();
+  return ret;
+}
+
+
+static void wolfssl_cleanup(void)
+{
+  wolfssl_bio_cf_free_methods();
+  wolfSSL_Cleanup();
+#ifdef OPENSSL_EXTRA
+  Curl_tls_keylog_close();
+#endif
+}
+
+
+static bool wolfssl_data_pending(struct Curl_cfilter *cf,
+                                 const struct Curl_easy *data)
+{
+  struct ssl_connect_data *ctx = cf->ctx;
+  struct wolfssl_ssl_backend_data *backend;
+
+  (void)data;
+  DEBUGASSERT(ctx && ctx->backend);
+
+  backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
+  if(backend->handle)   /* SSL is in use */
+    return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE;
+  else
+    return FALSE;
+}
+
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+static int wolfssl_shutdown(struct Curl_cfilter *cf,
+                            struct Curl_easy *data)
+{
+  struct ssl_connect_data *ctx = cf->ctx;
+  struct wolfssl_ssl_backend_data *backend;
+  int retval = 0;
+
+  (void)data;
+  DEBUGASSERT(ctx && ctx->backend);
+
+  backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
+  if(backend->handle) {
+    wolfSSL_ERR_clear_error();
+    wolfSSL_free(backend->handle);
+    backend->handle = NULL;
+  }
+  return retval;
+}
+
+
+static CURLcode
+wolfssl_connect_common(struct Curl_cfilter *cf,
+                       struct Curl_easy *data,
+                       bool nonblocking,
+                       bool *done)
+{
+  CURLcode result;
+  struct ssl_connect_data *connssl = cf->ctx;
+  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+  int what;
+
+  /* check if the connection has already been established */
+  if(ssl_connection_complete == connssl->state) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  if(ssl_connect_1 == connssl->connecting_state) {
+    /* Find out how much more time we're allowed */
+    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    result = wolfssl_connect_step1(cf, data);
+    if(result)
+      return result;
+  }
+
+  while(ssl_connect_2 == connssl->connecting_state ||
+        ssl_connect_2_reading == connssl->connecting_state ||
+        ssl_connect_2_writing == connssl->connecting_state) {
+
+    /* check allowed time left */
+    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    /* if ssl is expecting something, check if it's available. */
+    if(connssl->connecting_state == ssl_connect_2_reading
+       || connssl->connecting_state == ssl_connect_2_writing) {
+
+      curl_socket_t writefd = ssl_connect_2_writing ==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+      curl_socket_t readfd = ssl_connect_2_reading ==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+                               nonblocking?0:timeout_ms);
+      if(what < 0) {
+        /* fatal error */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      else if(0 == what) {
+        if(nonblocking) {
+          *done = FALSE;
+          return CURLE_OK;
+        }
+        else {
+          /* timeout */
+          failf(data, "SSL connection timeout");
+          return CURLE_OPERATION_TIMEDOUT;
+        }
+      }
+      /* socket is readable or writable */
+    }
+
+    /* Run transaction, and return to the caller if it failed or if
+     * this connection is part of a multi handle and this loop would
+     * execute again. This permits the owner of a multi handle to
+     * abort a connection attempt before step2 has completed while
+     * ensuring that a client using select() or epoll() will always
+     * have a valid fdset to wait on.
+     */
+    result = wolfssl_connect_step2(cf, data);
+    if(result || (nonblocking &&
+                  (ssl_connect_2 == connssl->connecting_state ||
+                   ssl_connect_2_reading == connssl->connecting_state ||
+                   ssl_connect_2_writing == connssl->connecting_state)))
+      return result;
+  } /* repeat step2 until all transactions are done. */
+
+  if(ssl_connect_3 == connssl->connecting_state) {
+    result = wolfssl_connect_step3(cf, data);
+    if(result)
+      return result;
+  }
+
+  if(ssl_connect_done == connssl->connecting_state) {
+    connssl->state = ssl_connection_complete;
+    *done = TRUE;
+  }
+  else
+    *done = FALSE;
+
+  /* Reset our connect state machine */
+  connssl->connecting_state = ssl_connect_1;
+
+  return CURLE_OK;
+}
+
+
+static CURLcode wolfssl_connect_nonblocking(struct Curl_cfilter *cf,
+                                            struct Curl_easy *data,
+                                            bool *done)
+{
+  return wolfssl_connect_common(cf, data, TRUE, done);
+}
+
+
+static CURLcode wolfssl_connect(struct Curl_cfilter *cf,
+                                struct Curl_easy *data)
+{
+  CURLcode result;
+  bool done = FALSE;
+
+  result = wolfssl_connect_common(cf, data, FALSE, &done);
+  if(result)
+    return result;
+
+  DEBUGASSERT(done);
+
+  return CURLE_OK;
+}
+
+static CURLcode wolfssl_random(struct Curl_easy *data,
+                               unsigned char *entropy, size_t length)
+{
+  WC_RNG rng;
+  (void)data;
+  if(wc_InitRng(&rng))
+    return CURLE_FAILED_INIT;
+  if(length > UINT_MAX)
+    return CURLE_FAILED_INIT;
+  if(wc_RNG_GenerateBlock(&rng, entropy, (unsigned)length))
+    return CURLE_FAILED_INIT;
+  if(wc_FreeRng(&rng))
+    return CURLE_FAILED_INIT;
+  return CURLE_OK;
+}
+
+static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
+                                  size_t tmplen,
+                                  unsigned char *sha256sum /* output */,
+                                  size_t unused)
+{
+  wc_Sha256 SHA256pw;
+  (void)unused;
+  if(wc_InitSha256(&SHA256pw))
+    return CURLE_FAILED_INIT;
+  wc_Sha256Update(&SHA256pw, tmp, (word32)tmplen);
+  wc_Sha256Final(&SHA256pw, sha256sum);
+  return CURLE_OK;
+}
+
+static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
+                                   CURLINFO info UNUSED_PARAM)
+{
+  struct wolfssl_ssl_backend_data *backend =
+    (struct wolfssl_ssl_backend_data *)connssl->backend;
+  (void)info;
+  DEBUGASSERT(backend);
+  return backend->handle;
+}
+
+const struct Curl_ssl Curl_ssl_wolfssl = {
+  { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */
+
+#ifdef KEEP_PEER_CERT
+  SSLSUPP_PINNEDPUBKEY |
+#endif
+#ifdef USE_BIO_CHAIN
+  SSLSUPP_HTTPS_PROXY |
+#endif
+  SSLSUPP_CA_PATH |
+  SSLSUPP_CAINFO_BLOB |
+  SSLSUPP_SSL_CTX,
+
+  sizeof(struct wolfssl_ssl_backend_data),
+
+  wolfssl_init,                    /* init */
+  wolfssl_cleanup,                 /* cleanup */
+  wolfssl_version,                 /* version */
+  Curl_none_check_cxn,             /* check_cxn */
+  wolfssl_shutdown,                /* shutdown */
+  wolfssl_data_pending,            /* data_pending */
+  wolfssl_random,                  /* random */
+  Curl_none_cert_status_request,   /* cert_status_request */
+  wolfssl_connect,                 /* connect */
+  wolfssl_connect_nonblocking,     /* connect_nonblocking */
+  Curl_ssl_adjust_pollset,         /* adjust_pollset */
+  wolfssl_get_internals,           /* get_internals */
+  wolfssl_close,                   /* close_one */
+  Curl_none_close_all,             /* close_all */
+  wolfssl_session_free,            /* session_free */
+  Curl_none_set_engine,            /* set_engine */
+  Curl_none_set_engine_default,    /* set_engine_default */
+  Curl_none_engines_list,          /* engines_list */
+  Curl_none_false_start,           /* false_start */
+  wolfssl_sha256sum,               /* sha256sum */
+  NULL,                            /* associate_connection */
+  NULL,                            /* disassociate_connection */
+  NULL,                            /* free_multi_ssl_backend_data */
+  wolfssl_recv,                    /* recv decrypted data */
+  wolfssl_send,                    /* send data to encrypt */
+};
+
+#endif
Index: trunk/src/libs/curl-8.7.1/lib/vtls/wolfssl.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/wolfssl.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/wolfssl.h	(revision 104083)
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_WOLFSSL_H
+#define HEADER_CURL_WOLFSSL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_WOLFSSL
+
+extern const struct Curl_ssl Curl_ssl_wolfssl;
+
+#endif /* USE_WOLFSSL */
+#endif /* HEADER_CURL_WOLFSSL_H */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/x509asn1.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/x509asn1.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/x509asn1.c	(revision 104083)
@@ -0,0 +1,1229 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) ||      \
+  defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
+
+#if defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
+#define WANT_PARSEX509 /* uses Curl_parseX509() */
+#endif
+
+#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
+#define WANT_EXTRACT_CERTINFO /* uses Curl_extract_certinfo() */
+#define WANT_PARSEX509 /* ... uses Curl_parseX509() */
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "strcase.h"
+#include "curl_ctype.h"
+#include "hostcheck.h"
+#include "vtls/vtls.h"
+#include "vtls/vtls_int.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "curl_base64.h"
+#include "x509asn1.h"
+#include "dynbuf.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Constants.
+ */
+
+/* Largest supported ASN.1 structure. */
+#define CURL_ASN1_MAX                   ((size_t) 0x40000)      /* 256K */
+
+/* ASN.1 classes. */
+#define CURL_ASN1_UNIVERSAL             0
+#define CURL_ASN1_APPLICATION           1
+#define CURL_ASN1_CONTEXT_SPECIFIC      2
+#define CURL_ASN1_PRIVATE               3
+
+/* ASN.1 types. */
+#define CURL_ASN1_BOOLEAN               1
+#define CURL_ASN1_INTEGER               2
+#define CURL_ASN1_BIT_STRING            3
+#define CURL_ASN1_OCTET_STRING          4
+#define CURL_ASN1_NULL                  5
+#define CURL_ASN1_OBJECT_IDENTIFIER     6
+#define CURL_ASN1_OBJECT_DESCRIPTOR     7
+#define CURL_ASN1_INSTANCE_OF           8
+#define CURL_ASN1_REAL                  9
+#define CURL_ASN1_ENUMERATED            10
+#define CURL_ASN1_EMBEDDED              11
+#define CURL_ASN1_UTF8_STRING           12
+#define CURL_ASN1_RELATIVE_OID          13
+#define CURL_ASN1_SEQUENCE              16
+#define CURL_ASN1_SET                   17
+#define CURL_ASN1_NUMERIC_STRING        18
+#define CURL_ASN1_PRINTABLE_STRING      19
+#define CURL_ASN1_TELETEX_STRING        20
+#define CURL_ASN1_VIDEOTEX_STRING       21
+#define CURL_ASN1_IA5_STRING            22
+#define CURL_ASN1_UTC_TIME              23
+#define CURL_ASN1_GENERALIZED_TIME      24
+#define CURL_ASN1_GRAPHIC_STRING        25
+#define CURL_ASN1_VISIBLE_STRING        26
+#define CURL_ASN1_GENERAL_STRING        27
+#define CURL_ASN1_UNIVERSAL_STRING      28
+#define CURL_ASN1_CHARACTER_STRING      29
+#define CURL_ASN1_BMP_STRING            30
+
+/* Max sixes */
+
+#define MAX_X509_STR  10000
+#define MAX_X509_CERT 100000
+
+#ifdef WANT_EXTRACT_CERTINFO
+/* ASN.1 OID table entry. */
+struct Curl_OID {
+  const char *numoid;  /* Dotted-numeric OID. */
+  const char *textoid; /* OID name. */
+};
+
+/* ASN.1 OIDs. */
+static const char       cnOID[] = "2.5.4.3";    /* Common name. */
+static const char       sanOID[] = "2.5.29.17"; /* Subject alternative name. */
+
+static const struct Curl_OID OIDtable[] = {
+  { "1.2.840.10040.4.1",        "dsa" },
+  { "1.2.840.10040.4.3",        "dsa-with-sha1" },
+  { "1.2.840.10045.2.1",        "ecPublicKey" },
+  { "1.2.840.10045.3.0.1",      "c2pnb163v1" },
+  { "1.2.840.10045.4.1",        "ecdsa-with-SHA1" },
+  { "1.2.840.10046.2.1",        "dhpublicnumber" },
+  { "1.2.840.113549.1.1.1",     "rsaEncryption" },
+  { "1.2.840.113549.1.1.2",     "md2WithRSAEncryption" },
+  { "1.2.840.113549.1.1.4",     "md5WithRSAEncryption" },
+  { "1.2.840.113549.1.1.5",     "sha1WithRSAEncryption" },
+  { "1.2.840.113549.1.1.10",    "RSASSA-PSS" },
+  { "1.2.840.113549.1.1.14",    "sha224WithRSAEncryption" },
+  { "1.2.840.113549.1.1.11",    "sha256WithRSAEncryption" },
+  { "1.2.840.113549.1.1.12",    "sha384WithRSAEncryption" },
+  { "1.2.840.113549.1.1.13",    "sha512WithRSAEncryption" },
+  { "1.2.840.113549.2.2",       "md2" },
+  { "1.2.840.113549.2.5",       "md5" },
+  { "1.3.14.3.2.26",            "sha1" },
+  { cnOID,                      "CN" },
+  { "2.5.4.4",                  "SN" },
+  { "2.5.4.5",                  "serialNumber" },
+  { "2.5.4.6",                  "C" },
+  { "2.5.4.7",                  "L" },
+  { "2.5.4.8",                  "ST" },
+  { "2.5.4.9",                  "streetAddress" },
+  { "2.5.4.10",                 "O" },
+  { "2.5.4.11",                 "OU" },
+  { "2.5.4.12",                 "title" },
+  { "2.5.4.13",                 "description" },
+  { "2.5.4.17",                 "postalCode" },
+  { "2.5.4.41",                 "name" },
+  { "2.5.4.42",                 "givenName" },
+  { "2.5.4.43",                 "initials" },
+  { "2.5.4.44",                 "generationQualifier" },
+  { "2.5.4.45",                 "X500UniqueIdentifier" },
+  { "2.5.4.46",                 "dnQualifier" },
+  { "2.5.4.65",                 "pseudonym" },
+  { "1.2.840.113549.1.9.1",     "emailAddress" },
+  { "2.5.4.72",                 "role" },
+  { sanOID,                     "subjectAltName" },
+  { "2.5.29.18",                "issuerAltName" },
+  { "2.5.29.19",                "basicConstraints" },
+  { "2.16.840.1.101.3.4.2.4",   "sha224" },
+  { "2.16.840.1.101.3.4.2.1",   "sha256" },
+  { "2.16.840.1.101.3.4.2.2",   "sha384" },
+  { "2.16.840.1.101.3.4.2.3",   "sha512" },
+  { (const char *) NULL,        (const char *) NULL }
+};
+
+#endif /* WANT_EXTRACT_CERTINFO */
+
+/*
+ * Lightweight ASN.1 parser.
+ * In particular, it does not check for syntactic/lexical errors.
+ * It is intended to support certificate information gathering for SSL backends
+ * that offer a mean to get certificates as a whole, but do not supply
+ * entry points to get particular certificate sub-fields.
+ * Please note there is no pretension here to rewrite a full SSL library.
+ */
+
+static const char *getASN1Element(struct Curl_asn1Element *elem,
+                                  const char *beg, const char *end)
+  WARN_UNUSED_RESULT;
+
+static const char *getASN1Element(struct Curl_asn1Element *elem,
+                                  const char *beg, const char *end)
+{
+  unsigned char b;
+  size_t len;
+  struct Curl_asn1Element lelem;
+
+  /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg'
+     ending at `end'.
+     Returns a pointer in source string after the parsed element, or NULL
+     if an error occurs. */
+  if(!beg || !end || beg >= end || !*beg ||
+     (size_t)(end - beg) > CURL_ASN1_MAX)
+    return NULL;
+
+  /* Process header byte. */
+  elem->header = beg;
+  b = (unsigned char) *beg++;
+  elem->constructed = (b & 0x20) != 0;
+  elem->class = (b >> 6) & 3;
+  b &= 0x1F;
+  if(b == 0x1F)
+    return NULL; /* Long tag values not supported here. */
+  elem->tag = b;
+
+  /* Process length. */
+  if(beg >= end)
+    return NULL;
+  b = (unsigned char) *beg++;
+  if(!(b & 0x80))
+    len = b;
+  else if(!(b &= 0x7F)) {
+    /* Unspecified length. Since we have all the data, we can determine the
+       effective length by skipping element until an end element is found. */
+    if(!elem->constructed)
+      return NULL;
+    elem->beg = beg;
+    while(beg < end && *beg) {
+      beg = getASN1Element(&lelem, beg, end);
+      if(!beg)
+        return NULL;
+    }
+    if(beg >= end)
+      return NULL;
+    elem->end = beg;
+    return beg + 1;
+  }
+  else if((unsigned)b > (size_t)(end - beg))
+    return NULL; /* Does not fit in source. */
+  else {
+    /* Get long length. */
+    len = 0;
+    do {
+      if(len & 0xFF000000L)
+        return NULL;  /* Lengths > 32 bits are not supported. */
+      len = (len << 8) | (unsigned char) *beg++;
+    } while(--b);
+  }
+  if(len > (size_t)(end - beg))
+    return NULL;  /* Element data does not fit in source. */
+  elem->beg = beg;
+  elem->end = beg + len;
+  return elem->end;
+}
+
+#ifdef WANT_EXTRACT_CERTINFO
+
+/*
+ * Search the null terminated OID or OID identifier in local table.
+ * Return the table entry pointer or NULL if not found.
+ */
+static const struct Curl_OID *searchOID(const char *oid)
+{
+  const struct Curl_OID *op;
+  for(op = OIDtable; op->numoid; op++)
+    if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid))
+      return op;
+
+  return NULL;
+}
+
+/*
+ * Convert an ASN.1 Boolean value into its string representation.
+ *
+ * Return error code.
+ */
+
+static CURLcode bool2str(struct dynbuf *store,
+                         const char *beg, const char *end)
+{
+  if(end - beg != 1)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  return Curl_dyn_add(store, *beg? "TRUE": "FALSE");
+}
+
+/*
+ * Convert an ASN.1 octet string to a printable string.
+ *
+ * Return error code.
+ */
+static CURLcode octet2str(struct dynbuf *store,
+                          const char *beg, const char *end)
+{
+  CURLcode result = CURLE_OK;
+
+  while(!result && beg < end)
+    result = Curl_dyn_addf(store, "%02x:", (unsigned char) *beg++);
+
+  return result;
+}
+
+static CURLcode bit2str(struct dynbuf *store,
+                        const char *beg, const char *end)
+{
+  /* Convert an ASN.1 bit string to a printable string. */
+
+  if(++beg > end)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  return octet2str(store, beg, end);
+}
+
+/*
+ * Convert an ASN.1 integer value into its string representation.
+ *
+ * Returns error.
+ */
+static CURLcode int2str(struct dynbuf *store,
+                        const char *beg, const char *end)
+{
+  unsigned int val = 0;
+  size_t n = end - beg;
+
+  if(!n)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  if(n > 4)
+    return octet2str(store, beg, end);
+
+  /* Represent integers <= 32-bit as a single value. */
+  if(*beg & 0x80)
+    val = ~val;
+
+  do
+    val = (val << 8) | *(const unsigned char *) beg++;
+  while(beg < end);
+  return Curl_dyn_addf(store, "%s%x", val >= 10? "0x": "", val);
+}
+
+/*
+ * Convert from an ASN.1 typed string to UTF8.
+ *
+ * The result is stored in a dynbuf that is inited by the user of this
+ * function.
+ *
+ * Returns error.
+ */
+static CURLcode
+utf8asn1str(struct dynbuf *to, int type, const char *from, const char *end)
+{
+  size_t inlength = end - from;
+  int size = 1;
+  CURLcode result = CURLE_OK;
+
+  switch(type) {
+  case CURL_ASN1_BMP_STRING:
+    size = 2;
+    break;
+  case CURL_ASN1_UNIVERSAL_STRING:
+    size = 4;
+    break;
+  case CURL_ASN1_NUMERIC_STRING:
+  case CURL_ASN1_PRINTABLE_STRING:
+  case CURL_ASN1_TELETEX_STRING:
+  case CURL_ASN1_IA5_STRING:
+  case CURL_ASN1_VISIBLE_STRING:
+  case CURL_ASN1_UTF8_STRING:
+    break;
+  default:
+    return CURLE_BAD_FUNCTION_ARGUMENT;  /* Conversion not supported. */
+  }
+
+  if(inlength % size)
+    /* Length inconsistent with character size. */
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  if(type == CURL_ASN1_UTF8_STRING) {
+    /* Just copy. */
+    if(inlength)
+      result = Curl_dyn_addn(to, from, inlength);
+  }
+  else {
+    while(!result && (from < end)) {
+      char buf[4]; /* decode buffer */
+      int charsize = 1;
+      unsigned int wc = 0;
+
+      switch(size) {
+      case 4:
+        wc = (wc << 8) | *(const unsigned char *) from++;
+        wc = (wc << 8) | *(const unsigned char *) from++;
+        FALLTHROUGH();
+      case 2:
+        wc = (wc << 8) | *(const unsigned char *) from++;
+        FALLTHROUGH();
+      default: /* case 1: */
+        wc = (wc << 8) | *(const unsigned char *) from++;
+      }
+      if(wc >= 0x00000080) {
+        if(wc >= 0x00000800) {
+          if(wc >= 0x00010000) {
+            if(wc >= 0x00200000) {
+              free(buf);
+              /* Invalid char. size for target encoding. */
+              return CURLE_WEIRD_SERVER_REPLY;
+            }
+            buf[3] = (char) (0x80 | (wc & 0x3F));
+            wc = (wc >> 6) | 0x00010000;
+            charsize++;
+          }
+          buf[2] = (char) (0x80 | (wc & 0x3F));
+          wc = (wc >> 6) | 0x00000800;
+          charsize++;
+        }
+        buf[1] = (char) (0x80 | (wc & 0x3F));
+        wc = (wc >> 6) | 0x000000C0;
+        charsize++;
+      }
+      buf[0] = (char) wc;
+      result = Curl_dyn_addn(to, buf, charsize);
+    }
+  }
+  return result;
+}
+
+/*
+ * Convert an ASN.1 OID into its dotted string representation.
+ *
+ * Return error code.
+ */
+static CURLcode encodeOID(struct dynbuf *store,
+                          const char *beg, const char *end)
+{
+  unsigned int x;
+  unsigned int y;
+  CURLcode result = CURLE_OK;
+
+  /* Process the first two numbers. */
+  y = *(const unsigned char *) beg++;
+  x = y / 40;
+  y -= x * 40;
+
+  result = Curl_dyn_addf(store, "%u.%u", x, y);
+  if(result)
+    return result;
+
+  /* Process the trailing numbers. */
+  while(beg < end) {
+    x = 0;
+    do {
+      if(x & 0xFF000000)
+        return 0;
+      y = *(const unsigned char *) beg++;
+      x = (x << 7) | (y & 0x7F);
+    } while(y & 0x80);
+    result = Curl_dyn_addf(store, ".%u", x);
+  }
+  return result;
+}
+
+/*
+ * Convert an ASN.1 OID into its dotted or symbolic string representation.
+ *
+ * Return error code.
+ */
+
+static CURLcode OID2str(struct dynbuf *store,
+                        const char *beg, const char *end, bool symbolic)
+{
+  CURLcode result = CURLE_OK;
+  if(beg < end) {
+    if(symbolic) {
+      struct dynbuf buf;
+      Curl_dyn_init(&buf, MAX_X509_STR);
+      result = encodeOID(&buf, beg, end);
+
+      if(!result) {
+        const struct Curl_OID *op = searchOID(Curl_dyn_ptr(&buf));
+        if(op)
+          result = Curl_dyn_add(store, op->textoid);
+        Curl_dyn_free(&buf);
+      }
+    }
+    else
+      result = encodeOID(store, beg, end);
+  }
+  return result;
+}
+
+static CURLcode GTime2str(struct dynbuf *store,
+                          const char *beg, const char *end)
+{
+  const char *tzp;
+  const char *fracp;
+  char sec1, sec2;
+  size_t fracl;
+  size_t tzl;
+  const char *sep = "";
+
+  /* Convert an ASN.1 Generalized time to a printable string.
+     Return the dynamically allocated string, or NULL if an error occurs. */
+
+  for(fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++)
+    ;
+
+  /* Get seconds digits. */
+  sec1 = '0';
+  switch(fracp - beg - 12) {
+  case 0:
+    sec2 = '0';
+    break;
+  case 2:
+    sec1 = fracp[-2];
+    FALLTHROUGH();
+  case 1:
+    sec2 = fracp[-1];
+    break;
+  default:
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
+  /* Scan for timezone, measure fractional seconds. */
+  tzp = fracp;
+  fracl = 0;
+  if(fracp < end && (*fracp == '.' || *fracp == ',')) {
+    fracp++;
+    do
+      tzp++;
+    while(tzp < end && *tzp >= '0' && *tzp <= '9');
+    /* Strip leading zeroes in fractional seconds. */
+    for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--)
+      ;
+  }
+
+  /* Process timezone. */
+  if(tzp >= end)
+    ;           /* Nothing to do. */
+  else if(*tzp == 'Z') {
+    tzp = " GMT";
+    end = tzp + 4;
+  }
+  else {
+    sep = " ";
+    tzp++;
+  }
+
+  tzl = end - tzp;
+  return Curl_dyn_addf(store,
+                       "%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
+                       beg, beg + 4, beg + 6,
+                       beg + 8, beg + 10, sec1, sec2,
+                       fracl? ".": "", (int)fracl, fracp,
+                       sep, (int)tzl, tzp);
+}
+
+/*
+ * Convert an ASN.1 UTC time to a printable string.
+ *
+ * Return error code.
+ */
+static CURLcode UTime2str(struct dynbuf *store,
+                             const char *beg, const char *end)
+{
+  const char *tzp;
+  size_t tzl;
+  const char *sec;
+
+  for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++)
+    ;
+  /* Get the seconds. */
+  sec = beg + 10;
+  switch(tzp - sec) {
+  case 0:
+    sec = "00";
+    FALLTHROUGH();
+  case 2:
+    break;
+  default:
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
+  /* Process timezone. */
+  if(tzp >= end)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  if(*tzp == 'Z') {
+    tzp = "GMT";
+    end = tzp + 3;
+  }
+  else
+    tzp++;
+
+  tzl = end - tzp;
+  return Curl_dyn_addf(store, "%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
+                       20 - (*beg >= '5'), beg, beg + 2, beg + 4,
+                       beg + 6, beg + 8, sec,
+                       (int)tzl, tzp);
+}
+
+/*
+ * Convert an ASN.1 element to a printable string.
+ *
+ * Return error
+ */
+static CURLcode ASN1tostr(struct dynbuf *store,
+                          struct Curl_asn1Element *elem, int type)
+{
+  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
+  if(elem->constructed)
+    return CURLE_OK; /* No conversion of structured elements. */
+
+  if(!type)
+    type = elem->tag;   /* Type not forced: use element tag as type. */
+
+  switch(type) {
+  case CURL_ASN1_BOOLEAN:
+    result = bool2str(store, elem->beg, elem->end);
+    break;
+  case CURL_ASN1_INTEGER:
+  case CURL_ASN1_ENUMERATED:
+    result = int2str(store, elem->beg, elem->end);
+    break;
+  case CURL_ASN1_BIT_STRING:
+    result = bit2str(store, elem->beg, elem->end);
+    break;
+  case CURL_ASN1_OCTET_STRING:
+    result = octet2str(store, elem->beg, elem->end);
+    break;
+  case CURL_ASN1_NULL:
+    result = Curl_dyn_addn(store, "", 1);
+    break;
+  case CURL_ASN1_OBJECT_IDENTIFIER:
+    result = OID2str(store, elem->beg, elem->end, TRUE);
+    break;
+  case CURL_ASN1_UTC_TIME:
+    result = UTime2str(store, elem->beg, elem->end);
+    break;
+  case CURL_ASN1_GENERALIZED_TIME:
+    result = GTime2str(store, elem->beg, elem->end);
+    break;
+  case CURL_ASN1_UTF8_STRING:
+  case CURL_ASN1_NUMERIC_STRING:
+  case CURL_ASN1_PRINTABLE_STRING:
+  case CURL_ASN1_TELETEX_STRING:
+  case CURL_ASN1_IA5_STRING:
+  case CURL_ASN1_VISIBLE_STRING:
+  case CURL_ASN1_UNIVERSAL_STRING:
+  case CURL_ASN1_BMP_STRING:
+    result = utf8asn1str(store, type, elem->beg, elem->end);
+    break;
+  }
+
+  return result;
+}
+
+/*
+ * ASCII encode distinguished name at `dn' into the store dynbuf.
+ *
+ * Returns error.
+ */
+static CURLcode encodeDN(struct dynbuf *store, struct Curl_asn1Element *dn)
+{
+  struct Curl_asn1Element rdn;
+  struct Curl_asn1Element atv;
+  struct Curl_asn1Element oid;
+  struct Curl_asn1Element value;
+  const char *p1;
+  const char *p2;
+  const char *p3;
+  const char *str;
+  CURLcode result = CURLE_OK;
+  bool added = FALSE;
+  struct dynbuf temp;
+  Curl_dyn_init(&temp, MAX_X509_STR);
+
+  for(p1 = dn->beg; p1 < dn->end;) {
+    p1 = getASN1Element(&rdn, p1, dn->end);
+    if(!p1) {
+      result = CURLE_BAD_FUNCTION_ARGUMENT;
+      goto error;
+    }
+    for(p2 = rdn.beg; p2 < rdn.end;) {
+      p2 = getASN1Element(&atv, p2, rdn.end);
+      if(!p2) {
+        result = CURLE_BAD_FUNCTION_ARGUMENT;
+        goto error;
+      }
+      p3 = getASN1Element(&oid, atv.beg, atv.end);
+      if(!p3) {
+        result = CURLE_BAD_FUNCTION_ARGUMENT;
+        goto error;
+      }
+      if(!getASN1Element(&value, p3, atv.end)) {
+        result = CURLE_BAD_FUNCTION_ARGUMENT;
+        goto error;
+      }
+      Curl_dyn_reset(&temp);
+      result = ASN1tostr(&temp, &oid, 0);
+      if(result)
+        goto error;
+
+      str = Curl_dyn_ptr(&temp);
+
+      /* Encode delimiter.
+         If attribute has a short uppercase name, delimiter is ", ". */
+      for(p3 = str; ISUPPER(*p3); p3++)
+        ;
+      if(added) {
+        if(p3 - str > 2)
+          result = Curl_dyn_addn(store, "/", 1);
+        else
+          result = Curl_dyn_addn(store, ", ", 2);
+        if(result)
+          goto error;
+      }
+
+      /* Encode attribute name. */
+      result = Curl_dyn_add(store, str);
+      if(result)
+        goto error;
+
+      /* Generate equal sign. */
+      result = Curl_dyn_addn(store, "=", 1);
+      if(result)
+        goto error;
+
+      /* Generate value. */
+      result = ASN1tostr(store, &value, 0);
+      if(result)
+        goto error;
+      Curl_dyn_reset(&temp);
+      added = TRUE; /* use separator for next */
+    }
+  }
+error:
+  Curl_dyn_free(&temp);
+
+  return result;
+}
+
+#endif /* WANT_EXTRACT_CERTINFO */
+
+#ifdef WANT_PARSEX509
+/*
+ * ASN.1 parse an X509 certificate into structure subfields.
+ * Syntax is assumed to have already been checked by the SSL backend.
+ * See RFC 5280.
+ */
+int Curl_parseX509(struct Curl_X509certificate *cert,
+                   const char *beg, const char *end)
+{
+  struct Curl_asn1Element elem;
+  struct Curl_asn1Element tbsCertificate;
+  const char *ccp;
+  static const char defaultVersion = 0;  /* v1. */
+
+  cert->certificate.header = NULL;
+  cert->certificate.beg = beg;
+  cert->certificate.end = end;
+
+  /* Get the sequence content. */
+  if(!getASN1Element(&elem, beg, end))
+    return -1;  /* Invalid bounds/size. */
+  beg = elem.beg;
+  end = elem.end;
+
+  /* Get tbsCertificate. */
+  beg = getASN1Element(&tbsCertificate, beg, end);
+  if(!beg)
+    return -1;
+  /* Skip the signatureAlgorithm. */
+  beg = getASN1Element(&cert->signatureAlgorithm, beg, end);
+  if(!beg)
+    return -1;
+  /* Get the signatureValue. */
+  if(!getASN1Element(&cert->signature, beg, end))
+    return -1;
+
+  /* Parse TBSCertificate. */
+  beg = tbsCertificate.beg;
+  end = tbsCertificate.end;
+  /* Get optional version, get serialNumber. */
+  cert->version.header = NULL;
+  cert->version.beg = &defaultVersion;
+  cert->version.end = &defaultVersion + sizeof(defaultVersion);
+  beg = getASN1Element(&elem, beg, end);
+  if(!beg)
+    return -1;
+  if(elem.tag == 0) {
+    if(!getASN1Element(&cert->version, elem.beg, elem.end))
+      return -1;
+    beg = getASN1Element(&elem, beg, end);
+    if(!beg)
+      return -1;
+  }
+  cert->serialNumber = elem;
+  /* Get signature algorithm. */
+  beg = getASN1Element(&cert->signatureAlgorithm, beg, end);
+  /* Get issuer. */
+  beg = getASN1Element(&cert->issuer, beg, end);
+  if(!beg)
+    return -1;
+  /* Get notBefore and notAfter. */
+  beg = getASN1Element(&elem, beg, end);
+  if(!beg)
+    return -1;
+  ccp = getASN1Element(&cert->notBefore, elem.beg, elem.end);
+  if(!ccp)
+    return -1;
+  if(!getASN1Element(&cert->notAfter, ccp, elem.end))
+    return -1;
+  /* Get subject. */
+  beg = getASN1Element(&cert->subject, beg, end);
+  if(!beg)
+    return -1;
+  /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */
+  beg = getASN1Element(&cert->subjectPublicKeyInfo, beg, end);
+  if(!beg)
+    return -1;
+  ccp = getASN1Element(&cert->subjectPublicKeyAlgorithm,
+                       cert->subjectPublicKeyInfo.beg,
+                       cert->subjectPublicKeyInfo.end);
+  if(!ccp)
+    return -1;
+  if(!getASN1Element(&cert->subjectPublicKey, ccp,
+                     cert->subjectPublicKeyInfo.end))
+    return -1;
+  /* Get optional issuerUiqueID, subjectUniqueID and extensions. */
+  cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0;
+  cert->extensions.tag = elem.tag = 0;
+  cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL;
+  cert->issuerUniqueID.beg = cert->issuerUniqueID.end = "";
+  cert->subjectUniqueID.beg = cert->subjectUniqueID.end = "";
+  cert->extensions.header = NULL;
+  cert->extensions.beg = cert->extensions.end = "";
+  if(beg < end) {
+    beg = getASN1Element(&elem, beg, end);
+    if(!beg)
+      return -1;
+  }
+  if(elem.tag == 1) {
+    cert->issuerUniqueID = elem;
+    if(beg < end) {
+      beg = getASN1Element(&elem, beg, end);
+      if(!beg)
+        return -1;
+    }
+  }
+  if(elem.tag == 2) {
+    cert->subjectUniqueID = elem;
+    if(beg < end) {
+      beg = getASN1Element(&elem, beg, end);
+      if(!beg)
+        return -1;
+    }
+  }
+  if(elem.tag == 3)
+    if(!getASN1Element(&cert->extensions, elem.beg, elem.end))
+      return -1;
+  return 0;
+}
+
+#endif /* WANT_PARSEX509 */
+
+#ifdef WANT_EXTRACT_CERTINFO
+
+static CURLcode dumpAlgo(struct dynbuf *store,
+                         struct Curl_asn1Element *param,
+                         const char *beg, const char *end)
+{
+  struct Curl_asn1Element oid;
+
+  /* Get algorithm parameters and return algorithm name. */
+
+  beg = getASN1Element(&oid, beg, end);
+  if(!beg)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  param->header = NULL;
+  param->tag = 0;
+  param->beg = param->end = end;
+  if(beg < end) {
+    const char *p = getASN1Element(param, beg, end);
+    if(!p)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+  return OID2str(store, oid.beg, oid.end, TRUE);
+}
+
+/*
+ * This is a convenience function for push_certinfo_len that takes a zero
+ * terminated value.
+ */
+static CURLcode ssl_push_certinfo(struct Curl_easy *data,
+                                  int certnum,
+                                  const char *label,
+                                  const char *value)
+{
+  size_t valuelen = strlen(value);
+
+  return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
+}
+
+/*
+ * This is a convenience function for push_certinfo_len that takes a
+ * dynbuf value.
+ *
+ * It also does the verbose output if !certnum.
+ */
+static CURLcode ssl_push_certinfo_dyn(struct Curl_easy *data,
+                                      int certnum,
+                                      const char *label,
+                                      struct dynbuf *ptr)
+{
+  size_t valuelen = Curl_dyn_len(ptr);
+  char *value = Curl_dyn_ptr(ptr);
+
+  CURLcode result = Curl_ssl_push_certinfo_len(data, certnum, label,
+                                               value, valuelen);
+
+  if(!certnum && !result)
+    infof(data, "   %s: %s", label, value);
+
+  return result;
+}
+
+static CURLcode do_pubkey_field(struct Curl_easy *data, int certnum,
+                                const char *label,
+                                struct Curl_asn1Element *elem)
+{
+  CURLcode result;
+  struct dynbuf out;
+
+  Curl_dyn_init(&out, MAX_X509_STR);
+
+  /* Generate a certificate information record for the public key. */
+
+  result = ASN1tostr(&out, elem, 0);
+  if(!result) {
+    if(data->set.ssl.certinfo)
+      result = ssl_push_certinfo_dyn(data, certnum, label, &out);
+    Curl_dyn_free(&out);
+  }
+  return result;
+}
+
+/* return 0 on success, 1 on error */
+static int do_pubkey(struct Curl_easy *data, int certnum,
+                     const char *algo, struct Curl_asn1Element *param,
+                     struct Curl_asn1Element *pubkey)
+{
+  struct Curl_asn1Element elem;
+  struct Curl_asn1Element pk;
+  const char *p;
+
+  /* Generate all information records for the public key. */
+
+  if(strcasecompare(algo, "ecPublicKey")) {
+    /*
+     * ECC public key is all the data, a value of type BIT STRING mapped to
+     * OCTET STRING and should not be parsed as an ASN.1 value.
+     */
+    const size_t len = ((pubkey->end - pubkey->beg - 2) * 4);
+    if(!certnum)
+      infof(data, "   ECC Public Key (%zu bits)", len);
+    if(data->set.ssl.certinfo) {
+      char q[sizeof(len) * 8 / 3 + 1];
+      (void)msnprintf(q, sizeof(q), "%zu", len);
+      if(ssl_push_certinfo(data, certnum, "ECC Public Key", q))
+        return 1;
+    }
+    return do_pubkey_field(data, certnum, "ecPublicKey", pubkey);
+  }
+
+  /* Get the public key (single element). */
+  if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end))
+    return 1;
+
+  if(strcasecompare(algo, "rsaEncryption")) {
+    const char *q;
+    size_t len;
+
+    p = getASN1Element(&elem, pk.beg, pk.end);
+    if(!p)
+      return 1;
+
+    /* Compute key length. */
+    for(q = elem.beg; !*q && q < elem.end; q++)
+      ;
+    len = ((elem.end - q) * 8);
+    if(len) {
+      unsigned int i;
+      for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
+        len--;
+    }
+    if(len > 32)
+      elem.beg = q;     /* Strip leading zero bytes. */
+    if(!certnum)
+      infof(data, "   RSA Public Key (%zu bits)", len);
+    if(data->set.ssl.certinfo) {
+      char r[sizeof(len) * 8 / 3 + 1];
+      msnprintf(r, sizeof(r), "%zu", len);
+      if(ssl_push_certinfo(data, certnum, "RSA Public Key", r))
+        return 1;
+    }
+    /* Generate coefficients. */
+    if(do_pubkey_field(data, certnum, "rsa(n)", &elem))
+      return 1;
+    if(!getASN1Element(&elem, p, pk.end))
+      return 1;
+    if(do_pubkey_field(data, certnum, "rsa(e)", &elem))
+      return 1;
+  }
+  else if(strcasecompare(algo, "dsa")) {
+    p = getASN1Element(&elem, param->beg, param->end);
+    if(p) {
+      if(do_pubkey_field(data, certnum, "dsa(p)", &elem))
+        return 1;
+      p = getASN1Element(&elem, p, param->end);
+      if(p) {
+        if(do_pubkey_field(data, certnum, "dsa(q)", &elem))
+          return 1;
+        if(getASN1Element(&elem, p, param->end)) {
+          if(do_pubkey_field(data, certnum, "dsa(g)", &elem))
+            return 1;
+          if(do_pubkey_field(data, certnum, "dsa(pub_key)", &pk))
+            return 1;
+        }
+      }
+    }
+  }
+  else if(strcasecompare(algo, "dhpublicnumber")) {
+    p = getASN1Element(&elem, param->beg, param->end);
+    if(p) {
+      if(do_pubkey_field(data, certnum, "dh(p)", &elem))
+        return 1;
+      if(getASN1Element(&elem, param->beg, param->end)) {
+        if(do_pubkey_field(data, certnum, "dh(g)", &elem))
+          return 1;
+        if(do_pubkey_field(data, certnum, "dh(pub_key)", &pk))
+          return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+/*
+ * Convert an ASN.1 distinguished name into a printable string.
+ * Return error.
+ */
+static CURLcode DNtostr(struct dynbuf *store,
+                        struct Curl_asn1Element *dn)
+{
+  return encodeDN(store, dn);
+}
+
+CURLcode Curl_extract_certinfo(struct Curl_easy *data,
+                               int certnum,
+                               const char *beg,
+                               const char *end)
+{
+  struct Curl_X509certificate cert;
+  struct Curl_asn1Element param;
+  char *certptr;
+  size_t clen;
+  struct dynbuf out;
+  CURLcode result = CURLE_OK;
+  unsigned int version;
+  const char *ptr;
+  int rc;
+
+  if(!data->set.ssl.certinfo)
+    if(certnum)
+      return CURLE_OK;
+
+  Curl_dyn_init(&out, MAX_X509_STR);
+  /* Prepare the certificate information for curl_easy_getinfo(). */
+
+  /* Extract the certificate ASN.1 elements. */
+  if(Curl_parseX509(&cert, beg, end))
+    return CURLE_PEER_FAILED_VERIFICATION;
+
+  /* Subject. */
+  result = DNtostr(&out, &cert.subject);
+  if(result)
+    goto done;
+  if(data->set.ssl.certinfo) {
+    result = ssl_push_certinfo_dyn(data, certnum, "Subject", &out);
+    if(result)
+      goto done;
+  }
+  Curl_dyn_reset(&out);
+
+  /* Issuer. */
+  result = DNtostr(&out, &cert.issuer);
+  if(result)
+    goto done;
+  if(data->set.ssl.certinfo) {
+    result = ssl_push_certinfo_dyn(data, certnum, "Issuer", &out);
+    if(result)
+      goto done;
+  }
+  Curl_dyn_reset(&out);
+
+  /* Version (always fits in less than 32 bits). */
+  version = 0;
+  for(ptr = cert.version.beg; ptr < cert.version.end; ptr++)
+    version = (version << 8) | *(const unsigned char *) ptr;
+  if(data->set.ssl.certinfo) {
+    result = Curl_dyn_addf(&out, "%x", version);
+    if(result)
+      goto done;
+    result = ssl_push_certinfo_dyn(data, certnum, "Version", &out);
+    if(result)
+      goto done;
+    Curl_dyn_reset(&out);
+  }
+
+  /* Serial number. */
+  result = ASN1tostr(&out, &cert.serialNumber, 0);
+  if(result)
+    goto done;
+  if(data->set.ssl.certinfo) {
+    result = ssl_push_certinfo_dyn(data, certnum, "Serial Number", &out);
+    if(result)
+      goto done;
+  }
+  Curl_dyn_reset(&out);
+
+  /* Signature algorithm .*/
+  result = dumpAlgo(&out, &param, cert.signatureAlgorithm.beg,
+                    cert.signatureAlgorithm.end);
+  if(result)
+    goto done;
+  if(data->set.ssl.certinfo) {
+    result = ssl_push_certinfo_dyn(data, certnum, "Signature Algorithm",
+                                   &out);
+    if(result)
+      goto done;
+  }
+  Curl_dyn_reset(&out);
+
+  /* Start Date. */
+  result = ASN1tostr(&out, &cert.notBefore, 0);
+  if(result)
+    goto done;
+  if(data->set.ssl.certinfo) {
+    result = ssl_push_certinfo_dyn(data, certnum, "Start Date", &out);
+    if(result)
+      goto done;
+  }
+  Curl_dyn_reset(&out);
+
+  /* Expire Date. */
+  result = ASN1tostr(&out, &cert.notAfter, 0);
+  if(result)
+    goto done;
+  if(data->set.ssl.certinfo) {
+    result = ssl_push_certinfo_dyn(data, certnum, "Expire Date", &out);
+    if(result)
+      goto done;
+  }
+  Curl_dyn_reset(&out);
+
+  /* Public Key Algorithm. */
+  result = dumpAlgo(&out, &param, cert.subjectPublicKeyAlgorithm.beg,
+                    cert.subjectPublicKeyAlgorithm.end);
+  if(result)
+    goto done;
+  if(data->set.ssl.certinfo) {
+    result = ssl_push_certinfo_dyn(data, certnum, "Public Key Algorithm",
+                                   &out);
+    if(result)
+      goto done;
+  }
+
+  rc = do_pubkey(data, certnum, Curl_dyn_ptr(&out),
+                 &param, &cert.subjectPublicKey);
+  if(rc) {
+    result = CURLE_OUT_OF_MEMORY; /* the most likely error */
+    goto done;
+  }
+  Curl_dyn_reset(&out);
+
+  /* Signature. */
+  result = ASN1tostr(&out, &cert.signature, 0);
+  if(result)
+    goto done;
+  if(data->set.ssl.certinfo) {
+    result = ssl_push_certinfo_dyn(data, certnum, "Signature", &out);
+    if(result)
+      goto done;
+  }
+  Curl_dyn_reset(&out);
+
+  /* Generate PEM certificate. */
+  result = Curl_base64_encode(cert.certificate.beg,
+                              cert.certificate.end - cert.certificate.beg,
+                              &certptr, &clen);
+  if(result)
+    goto done;
+
+  /* Generate the final output certificate string. Format is:
+     -----BEGIN CERTIFICATE-----\n
+     <max 64 base64 characters>\n
+     .
+     .
+     .
+     -----END CERTIFICATE-----\n
+   */
+
+  Curl_dyn_reset(&out);
+
+  /* Build the certificate string. */
+  result = Curl_dyn_add(&out, "-----BEGIN CERTIFICATE-----\n");
+  if(!result) {
+    size_t j = 0;
+
+    while(!result && (j < clen)) {
+      size_t chunksize = (clen - j) > 64 ? 64 : (clen - j);
+      result = Curl_dyn_addn(&out, &certptr[j], chunksize);
+      if(!result)
+        result = Curl_dyn_addn(&out, "\n", 1);
+      j += chunksize;
+    }
+    if(!result)
+      result = Curl_dyn_add(&out, "-----END CERTIFICATE-----\n");
+  }
+  free(certptr);
+  if(!result)
+    if(data->set.ssl.certinfo)
+      result = ssl_push_certinfo_dyn(data, certnum, "Cert", &out);
+
+done:
+  Curl_dyn_free(&out);
+  return result;
+}
+
+#endif /* WANT_EXTRACT_CERTINFO */
+
+#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
Index: trunk/src/libs/curl-8.7.1/lib/vtls/x509asn1.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/vtls/x509asn1.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/vtls/x509asn1.h	(revision 104083)
@@ -0,0 +1,80 @@
+#ifndef HEADER_CURL_X509ASN1_H
+#define HEADER_CURL_X509ASN1_H
+
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
+  defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
+
+#include "cfilters.h"
+#include "urldata.h"
+
+/*
+ * Types.
+ */
+
+/* ASN.1 parsed element. */
+struct Curl_asn1Element {
+  const char *header;         /* Pointer to header byte. */
+  const char *beg;            /* Pointer to element data. */
+  const char *end;            /* Pointer to 1st byte after element. */
+  unsigned char class;        /* ASN.1 element class. */
+  unsigned char tag;          /* ASN.1 element tag. */
+  bool          constructed;  /* Element is constructed. */
+};
+
+/* X509 certificate: RFC 5280. */
+struct Curl_X509certificate {
+  struct Curl_asn1Element certificate;
+  struct Curl_asn1Element version;
+  struct Curl_asn1Element serialNumber;
+  struct Curl_asn1Element signatureAlgorithm;
+  struct Curl_asn1Element signature;
+  struct Curl_asn1Element issuer;
+  struct Curl_asn1Element notBefore;
+  struct Curl_asn1Element notAfter;
+  struct Curl_asn1Element subject;
+  struct Curl_asn1Element subjectPublicKeyInfo;
+  struct Curl_asn1Element subjectPublicKeyAlgorithm;
+  struct Curl_asn1Element subjectPublicKey;
+  struct Curl_asn1Element issuerUniqueID;
+  struct Curl_asn1Element subjectUniqueID;
+  struct Curl_asn1Element extensions;
+};
+
+/*
+ * Prototypes.
+ */
+
+int Curl_parseX509(struct Curl_X509certificate *cert,
+                   const char *beg, const char *end);
+CURLcode Curl_extract_certinfo(struct Curl_easy *data, int certnum,
+                               const char *beg, const char *end);
+CURLcode Curl_verifyhost(struct Curl_cfilter *cf, struct Curl_easy *data,
+                         const char *beg, const char *end);
+#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
+#endif /* HEADER_CURL_X509ASN1_H */
Index: trunk/src/libs/curl-8.7.1/lib/warnless.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/warnless.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/warnless.c	(revision 104083)
@@ -0,0 +1,386 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(__INTEL_COMPILER) && defined(__unix__)
+
+#ifdef HAVE_NETINET_IN_H
+#  include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#  include <arpa/inet.h>
+#endif
+
+#endif /* __INTEL_COMPILER && __unix__ */
+
+#include "warnless.h"
+
+#ifdef _WIN32
+#undef read
+#undef write
+#endif
+
+#include <limits.h>
+
+#define CURL_MASK_UCHAR   ((unsigned char)~0)
+#define CURL_MASK_SCHAR   (CURL_MASK_UCHAR >> 1)
+
+#define CURL_MASK_USHORT  ((unsigned short)~0)
+#define CURL_MASK_SSHORT  (CURL_MASK_USHORT >> 1)
+
+#define CURL_MASK_UINT    ((unsigned int)~0)
+#define CURL_MASK_SINT    (CURL_MASK_UINT >> 1)
+
+#define CURL_MASK_ULONG   ((unsigned long)~0)
+#define CURL_MASK_SLONG   (CURL_MASK_ULONG >> 1)
+
+#define CURL_MASK_UCOFFT  ((unsigned CURL_TYPEOF_CURL_OFF_T)~0)
+#define CURL_MASK_SCOFFT  (CURL_MASK_UCOFFT >> 1)
+
+#define CURL_MASK_USIZE_T ((size_t)~0)
+#define CURL_MASK_SSIZE_T (CURL_MASK_USIZE_T >> 1)
+
+/*
+** unsigned long to unsigned short
+*/
+
+unsigned short curlx_ultous(unsigned long ulnum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_USHORT);
+  return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned long to unsigned char
+*/
+
+unsigned char curlx_ultouc(unsigned long ulnum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_UCHAR);
+  return (unsigned char)(ulnum & (unsigned long) CURL_MASK_UCHAR);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to signed curl_off_t
+*/
+
+curl_off_t curlx_uztoso(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#elif defined(_MSC_VER)
+#  pragma warning(push)
+#  pragma warning(disable:4310) /* cast truncates constant value */
+#endif
+
+  DEBUGASSERT(uznum <= (size_t) CURL_MASK_SCOFFT);
+  return (curl_off_t)(uznum & (size_t) CURL_MASK_SCOFFT);
+
+#if defined(__INTEL_COMPILER) || defined(_MSC_VER)
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to signed int
+*/
+
+int curlx_uztosi(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(uznum <= (size_t) CURL_MASK_SINT);
+  return (int)(uznum & (size_t) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to unsigned long
+*/
+
+unsigned long curlx_uztoul(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+#if ULONG_MAX < SIZE_T_MAX
+  DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG);
+#endif
+  return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to unsigned int
+*/
+
+unsigned int curlx_uztoui(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+#if UINT_MAX < SIZE_T_MAX
+  DEBUGASSERT(uznum <= (size_t) CURL_MASK_UINT);
+#endif
+  return (unsigned int)(uznum & (size_t) CURL_MASK_UINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed long to signed int
+*/
+
+int curlx_sltosi(long slnum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(slnum >= 0);
+#if INT_MAX < LONG_MAX
+  DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_SINT);
+#endif
+  return (int)(slnum & (long) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** signed long to unsigned int
+*/
+
+unsigned int curlx_sltoui(long slnum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(slnum >= 0);
+#if UINT_MAX < LONG_MAX
+  DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_UINT);
+#endif
+  return (unsigned int)(slnum & (long) CURL_MASK_UINT);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** signed long to unsigned short
+*/
+
+unsigned short curlx_sltous(long slnum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(slnum >= 0);
+  DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_USHORT);
+  return (unsigned short)(slnum & (long) CURL_MASK_USHORT);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to signed ssize_t
+*/
+
+ssize_t curlx_uztosz(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(uznum <= (size_t) CURL_MASK_SSIZE_T);
+  return (ssize_t)(uznum & (size_t) CURL_MASK_SSIZE_T);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** signed curl_off_t to unsigned size_t
+*/
+
+size_t curlx_sotouz(curl_off_t sonum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(sonum >= 0);
+  return (size_t)(sonum & (curl_off_t) CURL_MASK_USIZE_T);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** signed ssize_t to signed int
+*/
+
+int curlx_sztosi(ssize_t sznum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(sznum >= 0);
+#if INT_MAX < SSIZE_T_MAX
+  DEBUGASSERT((size_t) sznum <= (size_t) CURL_MASK_SINT);
+#endif
+  return (int)(sznum & (ssize_t) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned int to unsigned short
+*/
+
+unsigned short curlx_uitous(unsigned int uinum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_USHORT);
+  return (unsigned short) (uinum & (unsigned int) CURL_MASK_USHORT);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** signed int to unsigned size_t
+*/
+
+size_t curlx_sitouz(int sinum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(sinum >= 0);
+  return (size_t) sinum;
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+#ifdef USE_WINSOCK
+
+/*
+** curl_socket_t to signed int
+*/
+
+int curlx_sktosi(curl_socket_t s)
+{
+  return (int)((ssize_t) s);
+}
+
+/*
+** signed int to curl_socket_t
+*/
+
+curl_socket_t curlx_sitosk(int i)
+{
+  return (curl_socket_t)((ssize_t) i);
+}
+
+#endif /* USE_WINSOCK */
+
+#if defined(_WIN32)
+
+ssize_t curlx_read(int fd, void *buf, size_t count)
+{
+  return (ssize_t)read(fd, buf, curlx_uztoui(count));
+}
+
+ssize_t curlx_write(int fd, const void *buf, size_t count)
+{
+  return (ssize_t)write(fd, buf, curlx_uztoui(count));
+}
+
+#endif /* _WIN32 */
+
+/* Ensure that warnless.h redefinitions continue to have an effect
+   in "unity" builds. */
+#undef HEADER_CURL_WARNLESS_H_REDEFS
Index: trunk/src/libs/curl-8.7.1/lib/warnless.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/warnless.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/warnless.h	(revision 104083)
@@ -0,0 +1,106 @@
+#ifndef HEADER_CURL_WARNLESS_H
+#define HEADER_CURL_WARNLESS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_WINSOCK
+#include <curl/curl.h> /* for curl_socket_t */
+#endif
+
+#define CURLX_FUNCTION_CAST(target_type, func) \
+  (target_type)(void (*) (void))(func)
+
+unsigned short curlx_ultous(unsigned long ulnum);
+
+unsigned char curlx_ultouc(unsigned long ulnum);
+
+int curlx_uztosi(size_t uznum);
+
+curl_off_t curlx_uztoso(size_t uznum);
+
+unsigned long curlx_uztoul(size_t uznum);
+
+unsigned int curlx_uztoui(size_t uznum);
+
+int curlx_sltosi(long slnum);
+
+unsigned int curlx_sltoui(long slnum);
+
+unsigned short curlx_sltous(long slnum);
+
+ssize_t curlx_uztosz(size_t uznum);
+
+size_t curlx_sotouz(curl_off_t sonum);
+
+int curlx_sztosi(ssize_t sznum);
+
+unsigned short curlx_uitous(unsigned int uinum);
+
+size_t curlx_sitouz(int sinum);
+
+#ifdef USE_WINSOCK
+
+int curlx_sktosi(curl_socket_t s);
+
+curl_socket_t curlx_sitosk(int i);
+
+#endif /* USE_WINSOCK */
+
+#if defined(_WIN32)
+
+ssize_t curlx_read(int fd, void *buf, size_t count);
+
+ssize_t curlx_write(int fd, const void *buf, size_t count);
+
+#endif /* _WIN32 */
+
+#if defined(__INTEL_COMPILER) && defined(__unix__)
+
+int curlx_FD_ISSET(int fd, fd_set *fdset);
+
+void curlx_FD_SET(int fd, fd_set *fdset);
+
+void curlx_FD_ZERO(fd_set *fdset);
+
+unsigned short curlx_htons(unsigned short usnum);
+
+unsigned short curlx_ntohs(unsigned short usnum);
+
+#endif /* __INTEL_COMPILER && __unix__ */
+
+#endif /* HEADER_CURL_WARNLESS_H */
+
+#ifndef HEADER_CURL_WARNLESS_H_REDEFS
+#define HEADER_CURL_WARNLESS_H_REDEFS
+
+#if defined(_WIN32)
+#undef  read
+#define read(fd, buf, count)  curlx_read(fd, buf, count)
+#undef  write
+#define write(fd, buf, count) curlx_write(fd, buf, count)
+#endif
+
+#endif /* HEADER_CURL_WARNLESS_H_REDEFS */
Index: trunk/src/libs/curl-8.7.1/lib/ws.c
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/ws.c	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/ws.c	(revision 104083)
@@ -0,0 +1,1270 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+#include <curl/curl.h>
+
+#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+
+#include "urldata.h"
+#include "bufq.h"
+#include "dynbuf.h"
+#include "rand.h"
+#include "curl_base64.h"
+#include "connect.h"
+#include "sendf.h"
+#include "multiif.h"
+#include "ws.h"
+#include "easyif.h"
+#include "transfer.h"
+#include "nonblock.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+#define WSBIT_FIN 0x80
+#define WSBIT_OPCODE_CONT  0
+#define WSBIT_OPCODE_TEXT  (1)
+#define WSBIT_OPCODE_BIN   (2)
+#define WSBIT_OPCODE_CLOSE (8)
+#define WSBIT_OPCODE_PING  (9)
+#define WSBIT_OPCODE_PONG  (0xa)
+#define WSBIT_OPCODE_MASK  (0xf)
+
+#define WSBIT_MASK 0x80
+
+/* buffer dimensioning */
+#define WS_CHUNK_SIZE 65535
+#define WS_CHUNK_COUNT 2
+
+struct ws_frame_meta {
+  char proto_opcode;
+  int flags;
+  const char *name;
+};
+
+static struct ws_frame_meta WS_FRAMES[] = {
+  { WSBIT_OPCODE_CONT,  CURLWS_CONT,   "CONT" },
+  { WSBIT_OPCODE_TEXT,  CURLWS_TEXT,   "TEXT" },
+  { WSBIT_OPCODE_BIN,   CURLWS_BINARY, "BIN" },
+  { WSBIT_OPCODE_CLOSE, CURLWS_CLOSE,  "CLOSE" },
+  { WSBIT_OPCODE_PING,  CURLWS_PING,   "PING" },
+  { WSBIT_OPCODE_PONG,  CURLWS_PONG,   "PONG" },
+};
+
+static const char *ws_frame_name_of_op(unsigned char proto_opcode)
+{
+  unsigned char opcode = proto_opcode & WSBIT_OPCODE_MASK;
+  size_t i;
+  for(i = 0; i < sizeof(WS_FRAMES)/sizeof(WS_FRAMES[0]); ++i) {
+    if(WS_FRAMES[i].proto_opcode == opcode)
+      return WS_FRAMES[i].name;
+  }
+  return "???";
+}
+
+static int ws_frame_op2flags(unsigned char proto_opcode)
+{
+  unsigned char opcode = proto_opcode & WSBIT_OPCODE_MASK;
+  size_t i;
+  for(i = 0; i < sizeof(WS_FRAMES)/sizeof(WS_FRAMES[0]); ++i) {
+    if(WS_FRAMES[i].proto_opcode == opcode)
+      return WS_FRAMES[i].flags;
+  }
+  return 0;
+}
+
+static unsigned char ws_frame_flags2op(int flags)
+{
+  size_t i;
+  for(i = 0; i < sizeof(WS_FRAMES)/sizeof(WS_FRAMES[0]); ++i) {
+    if(WS_FRAMES[i].flags & flags)
+      return WS_FRAMES[i].proto_opcode;
+  }
+  return 0;
+}
+
+static void ws_dec_info(struct ws_decoder *dec, struct Curl_easy *data,
+                        const char *msg)
+{
+  switch(dec->head_len) {
+  case 0:
+    break;
+  case 1:
+    infof(data, "WS-DEC: %s [%s%s]", msg,
+          ws_frame_name_of_op(dec->head[0]),
+          (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL");
+    break;
+  default:
+    if(dec->head_len < dec->head_total) {
+      infof(data, "WS-DEC: %s [%s%s](%d/%d)", msg,
+            ws_frame_name_of_op(dec->head[0]),
+            (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
+            dec->head_len, dec->head_total);
+    }
+    else {
+      infof(data, "WS-DEC: %s [%s%s payload=%" CURL_FORMAT_CURL_OFF_T
+                  "/%" CURL_FORMAT_CURL_OFF_T "]",
+            msg, ws_frame_name_of_op(dec->head[0]),
+            (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
+            dec->payload_offset, dec->payload_len);
+    }
+    break;
+  }
+}
+
+typedef ssize_t ws_write_payload(const unsigned char *buf, size_t buflen,
+                                 int frame_age, int frame_flags,
+                                 curl_off_t payload_offset,
+                                 curl_off_t payload_len,
+                                 void *userp,
+                                 CURLcode *err);
+
+
+static void ws_dec_reset(struct ws_decoder *dec)
+{
+  dec->frame_age = 0;
+  dec->frame_flags = 0;
+  dec->payload_offset = 0;
+  dec->payload_len = 0;
+  dec->head_len = dec->head_total = 0;
+  dec->state = WS_DEC_INIT;
+}
+
+static void ws_dec_init(struct ws_decoder *dec)
+{
+  ws_dec_reset(dec);
+}
+
+static CURLcode ws_dec_read_head(struct ws_decoder *dec,
+                                 struct Curl_easy *data,
+                                 struct bufq *inraw)
+{
+  const unsigned char *inbuf;
+  size_t inlen;
+
+  while(Curl_bufq_peek(inraw, &inbuf, &inlen)) {
+    if(dec->head_len == 0) {
+      dec->head[0] = *inbuf;
+      Curl_bufq_skip(inraw, 1);
+
+      dec->frame_flags  = ws_frame_op2flags(dec->head[0]);
+      if(!dec->frame_flags) {
+        failf(data, "WS: unknown opcode: %x", dec->head[0]);
+        ws_dec_reset(dec);
+        return CURLE_RECV_ERROR;
+      }
+      dec->head_len = 1;
+      /* ws_dec_info(dec, data, "seeing opcode"); */
+      continue;
+    }
+    else if(dec->head_len == 1) {
+      dec->head[1] = *inbuf;
+      Curl_bufq_skip(inraw, 1);
+      dec->head_len = 2;
+
+      if(dec->head[1] & WSBIT_MASK) {
+        /* A client MUST close a connection if it detects a masked frame. */
+        failf(data, "WS: masked input frame");
+        ws_dec_reset(dec);
+        return CURLE_RECV_ERROR;
+      }
+      /* How long is the frame head? */
+      if(dec->head[1] == 126) {
+        dec->head_total = 4;
+        continue;
+      }
+      else if(dec->head[1] == 127) {
+        dec->head_total = 10;
+        continue;
+      }
+      else {
+        dec->head_total = 2;
+      }
+    }
+
+    if(dec->head_len < dec->head_total) {
+      dec->head[dec->head_len] = *inbuf;
+      Curl_bufq_skip(inraw, 1);
+      ++dec->head_len;
+      if(dec->head_len < dec->head_total) {
+        /* ws_dec_info(dec, data, "decoding head"); */
+        continue;
+      }
+    }
+    /* got the complete frame head */
+    DEBUGASSERT(dec->head_len == dec->head_total);
+    switch(dec->head_total) {
+    case 2:
+      dec->payload_len = dec->head[1];
+      break;
+    case 4:
+      dec->payload_len = (dec->head[2] << 8) | dec->head[3];
+      break;
+    case 10:
+      if(dec->head[2] > 127) {
+        failf(data, "WS: frame length longer than 64 signed not supported");
+        return CURLE_RECV_ERROR;
+      }
+      dec->payload_len = ((curl_off_t)dec->head[2] << 56) |
+        (curl_off_t)dec->head[3] << 48 |
+        (curl_off_t)dec->head[4] << 40 |
+        (curl_off_t)dec->head[5] << 32 |
+        (curl_off_t)dec->head[6] << 24 |
+        (curl_off_t)dec->head[7] << 16 |
+        (curl_off_t)dec->head[8] << 8 |
+        dec->head[9];
+      break;
+    default:
+      /* this should never happen */
+      DEBUGASSERT(0);
+      failf(data, "WS: unexpected frame header length");
+      return CURLE_RECV_ERROR;
+    }
+
+    dec->frame_age = 0;
+    dec->payload_offset = 0;
+    ws_dec_info(dec, data, "decoded");
+    return CURLE_OK;
+  }
+  return CURLE_AGAIN;
+}
+
+static CURLcode ws_dec_pass_payload(struct ws_decoder *dec,
+                                    struct Curl_easy *data,
+                                    struct bufq *inraw,
+                                    ws_write_payload *write_payload,
+                                    void *write_ctx)
+{
+  const unsigned char *inbuf;
+  size_t inlen;
+  ssize_t nwritten;
+  CURLcode result;
+  curl_off_t remain = dec->payload_len - dec->payload_offset;
+
+  (void)data;
+  while(remain && Curl_bufq_peek(inraw, &inbuf, &inlen)) {
+    if((curl_off_t)inlen > remain)
+      inlen = (size_t)remain;
+    nwritten = write_payload(inbuf, inlen, dec->frame_age, dec->frame_flags,
+                             dec->payload_offset, dec->payload_len,
+                             write_ctx, &result);
+    if(nwritten < 0)
+      return result;
+    Curl_bufq_skip(inraw, (size_t)nwritten);
+    dec->payload_offset += (curl_off_t)nwritten;
+    remain = dec->payload_len - dec->payload_offset;
+    /* infof(data, "WS-DEC: passed  %zd bytes payload, %"
+             CURL_FORMAT_CURL_OFF_T " remain",
+             nwritten, remain); */
+  }
+
+  return remain? CURLE_AGAIN : CURLE_OK;
+}
+
+static CURLcode ws_dec_pass(struct ws_decoder *dec,
+                            struct Curl_easy *data,
+                            struct bufq *inraw,
+                            ws_write_payload *write_payload,
+                            void *write_ctx)
+{
+  CURLcode result;
+
+  if(Curl_bufq_is_empty(inraw))
+    return CURLE_AGAIN;
+
+  switch(dec->state) {
+  case WS_DEC_INIT:
+    ws_dec_reset(dec);
+    dec->state = WS_DEC_HEAD;
+    FALLTHROUGH();
+  case WS_DEC_HEAD:
+    result = ws_dec_read_head(dec, data, inraw);
+    if(result) {
+      if(result != CURLE_AGAIN) {
+        infof(data, "WS: decode error %d", (int)result);
+        break;  /* real error */
+      }
+      /* incomplete ws frame head */
+      DEBUGASSERT(Curl_bufq_is_empty(inraw));
+      break;
+    }
+    /* head parsing done */
+    dec->state = WS_DEC_PAYLOAD;
+    if(dec->payload_len == 0) {
+      ssize_t nwritten;
+      const unsigned char tmp = '\0';
+      /* special case of a 0 length frame, need to write once */
+      nwritten = write_payload(&tmp, 0, dec->frame_age, dec->frame_flags,
+                               0, 0, write_ctx, &result);
+      if(nwritten < 0)
+        return result;
+      dec->state = WS_DEC_INIT;
+      break;
+    }
+    FALLTHROUGH();
+  case WS_DEC_PAYLOAD:
+    result = ws_dec_pass_payload(dec, data, inraw, write_payload, write_ctx);
+    ws_dec_info(dec, data, "passing");
+    if(result)
+      return result;
+    /* paylod parsing done */
+    dec->state = WS_DEC_INIT;
+    break;
+  default:
+    /* we covered all enums above, but some code analyzers are whimps */
+    result = CURLE_FAILED_INIT;
+  }
+  return result;
+}
+
+static void update_meta(struct websocket *ws,
+                        int frame_age, int frame_flags,
+                        curl_off_t payload_offset,
+                        curl_off_t payload_len,
+                        size_t cur_len)
+{
+  ws->frame.age = frame_age;
+  ws->frame.flags = frame_flags;
+  ws->frame.offset = payload_offset;
+  ws->frame.len = cur_len;
+  ws->frame.bytesleft = (payload_len - payload_offset - cur_len);
+}
+
+/* WebSockets decoding client writer */
+struct ws_cw_ctx {
+  struct Curl_cwriter super;
+  struct bufq buf;
+};
+
+static CURLcode ws_cw_init(struct Curl_easy *data,
+                           struct Curl_cwriter *writer)
+{
+  struct ws_cw_ctx *ctx = writer->ctx;
+  (void)data;
+  Curl_bufq_init2(&ctx->buf, WS_CHUNK_SIZE, 1, BUFQ_OPT_SOFT_LIMIT);
+  return CURLE_OK;
+}
+
+static void ws_cw_close(struct Curl_easy *data, struct Curl_cwriter *writer)
+{
+  struct ws_cw_ctx *ctx = writer->ctx;
+  (void) data;
+  Curl_bufq_free(&ctx->buf);
+}
+
+struct ws_cw_dec_ctx {
+  struct Curl_easy *data;
+  struct websocket *ws;
+  struct Curl_cwriter *next_writer;
+  int cw_type;
+};
+
+static ssize_t ws_cw_dec_next(const unsigned char *buf, size_t buflen,
+                              int frame_age, int frame_flags,
+                              curl_off_t payload_offset,
+                              curl_off_t payload_len,
+                              void *user_data,
+                              CURLcode *err)
+{
+  struct ws_cw_dec_ctx *ctx = user_data;
+  struct Curl_easy *data = ctx->data;
+  struct websocket *ws = ctx->ws;
+  curl_off_t remain = (payload_len - (payload_offset + buflen));
+
+  (void)frame_age;
+  if((frame_flags & CURLWS_PING) && !remain) {
+    /* auto-respond to PINGs, only works for single-frame payloads atm */
+    size_t bytes;
+    infof(data, "WS: auto-respond to PING with a PONG");
+    /* send back the exact same content as a PONG */
+    *err = curl_ws_send(data, buf, buflen, &bytes, 0, CURLWS_PONG);
+    if(*err)
+      return -1;
+  }
+  else if(buflen || !remain) {
+    /* forward the decoded frame to the next client writer. */
+    update_meta(ws, frame_age, frame_flags, payload_offset,
+                payload_len, buflen);
+
+    *err = Curl_cwriter_write(data, ctx->next_writer, ctx->cw_type,
+                              (const char *)buf, buflen);
+    if(*err)
+      return -1;
+  }
+  *err = CURLE_OK;
+  return (ssize_t)buflen;
+}
+
+static CURLcode ws_cw_write(struct Curl_easy *data,
+                            struct Curl_cwriter *writer, int type,
+                            const char *buf, size_t nbytes)
+{
+  struct ws_cw_ctx *ctx = writer->ctx;
+  struct websocket *ws;
+  CURLcode result;
+
+  if(!(type & CLIENTWRITE_BODY) || data->set.ws_raw_mode)
+    return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+
+  ws = data->conn->proto.ws;
+  if(!ws) {
+    failf(data, "WS: not a websocket transfer");
+    return CURLE_FAILED_INIT;
+  }
+
+  if(nbytes) {
+    ssize_t nwritten;
+    nwritten = Curl_bufq_write(&ctx->buf, (const unsigned char *)buf,
+                               nbytes, &result);
+    if(nwritten < 0) {
+      infof(data, "WS: error adding data to buffer %d", result);
+      return result;
+    }
+  }
+
+  while(!Curl_bufq_is_empty(&ctx->buf)) {
+    struct ws_cw_dec_ctx pass_ctx;
+    pass_ctx.data = data;
+    pass_ctx.ws = ws;
+    pass_ctx.next_writer = writer->next;
+    pass_ctx.cw_type = type;
+    result = ws_dec_pass(&ws->dec, data, &ctx->buf,
+                         ws_cw_dec_next, &pass_ctx);
+    if(result == CURLE_AGAIN)
+      /* insufficient amount of data, keep it for later.
+       * we pretend to have written all since we have a copy */
+      return CURLE_OK;
+    else if(result) {
+      infof(data, "WS: decode error %d", (int)result);
+      return result;
+    }
+  }
+
+  if((type & CLIENTWRITE_EOS) && !Curl_bufq_is_empty(&ctx->buf)) {
+    infof(data, "WS: decode ending with %zd frame bytes remaining",
+          Curl_bufq_len(&ctx->buf));
+    return CURLE_RECV_ERROR;
+  }
+
+  return CURLE_OK;
+}
+
+/* WebSocket payload decoding client writer. */
+static const struct Curl_cwtype ws_cw_decode = {
+  "ws-decode",
+  NULL,
+  ws_cw_init,
+  ws_cw_write,
+  ws_cw_close,
+  sizeof(struct ws_cw_ctx)
+};
+
+
+static void ws_enc_info(struct ws_encoder *enc, struct Curl_easy *data,
+                        const char *msg)
+{
+  infof(data, "WS-ENC: %s [%s%s%s payload=%" CURL_FORMAT_CURL_OFF_T
+              "/%" CURL_FORMAT_CURL_OFF_T "]",
+        msg, ws_frame_name_of_op(enc->firstbyte),
+        (enc->firstbyte & WSBIT_OPCODE_MASK) == WSBIT_OPCODE_CONT ?
+        " CONT" : "",
+        (enc->firstbyte & WSBIT_FIN)? "" : " NON-FIN",
+        enc->payload_len - enc->payload_remain, enc->payload_len);
+}
+
+static void ws_enc_reset(struct ws_encoder *enc)
+{
+  enc->payload_remain = 0;
+  enc->xori = 0;
+  enc->contfragment = FALSE;
+}
+
+static void ws_enc_init(struct ws_encoder *enc)
+{
+  ws_enc_reset(enc);
+}
+
+/***
+    RFC 6455 Section 5.2
+
+      0                   1                   2                   3
+      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+     +-+-+-+-+-------+-+-------------+-------------------------------+
+     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
+     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
+     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
+     | |1|2|3|       |K|             |                               |
+     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
+     |     Extended payload length continued, if payload len == 127  |
+     + - - - - - - - - - - - - - - - +-------------------------------+
+     |                               |Masking-key, if MASK set to 1  |
+     +-------------------------------+-------------------------------+
+     | Masking-key (continued)       |          Payload Data         |
+     +-------------------------------- - - - - - - - - - - - - - - - +
+     :                     Payload Data continued ...                :
+     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+     |                     Payload Data continued ...                |
+     +---------------------------------------------------------------+
+*/
+
+static ssize_t ws_enc_write_head(struct Curl_easy *data,
+                                 struct ws_encoder *enc,
+                                 unsigned int flags,
+                                 curl_off_t payload_len,
+                                 struct bufq *out,
+                                 CURLcode *err)
+{
+  unsigned char firstbyte = 0;
+  unsigned char opcode;
+  unsigned char head[14];
+  size_t hlen;
+  ssize_t n;
+
+  if(payload_len < 0) {
+    failf(data, "WS: starting new frame with negative payload length %"
+                CURL_FORMAT_CURL_OFF_T, payload_len);
+    *err = CURLE_SEND_ERROR;
+    return -1;
+  }
+
+  if(enc->payload_remain > 0) {
+    /* trying to write a new frame before the previous one is finished */
+    failf(data, "WS: starting new frame with %zd bytes from last one"
+                "remaining to be sent", (ssize_t)enc->payload_remain);
+    *err = CURLE_SEND_ERROR;
+    return -1;
+  }
+
+  opcode = ws_frame_flags2op(flags);
+  if(!opcode) {
+    failf(data, "WS: provided flags not recognized '%x'", flags);
+    *err = CURLE_SEND_ERROR;
+    return -1;
+  }
+
+  if(!(flags & CURLWS_CONT)) {
+    if(!enc->contfragment)
+      /* not marked as continuing, this is the final fragment */
+      firstbyte |= WSBIT_FIN | opcode;
+    else
+      /* marked as continuing, this is the final fragment; set CONT
+         opcode and FIN bit */
+      firstbyte |= WSBIT_FIN | WSBIT_OPCODE_CONT;
+
+    enc->contfragment = FALSE;
+  }
+  else if(enc->contfragment) {
+    /* the previous fragment was not a final one and this isn't either, keep a
+       CONT opcode and no FIN bit */
+    firstbyte |= WSBIT_OPCODE_CONT;
+  }
+  else {
+    firstbyte = opcode;
+    enc->contfragment = TRUE;
+  }
+
+  head[0] = enc->firstbyte = firstbyte;
+  if(payload_len > 65535) {
+    head[1] = 127 | WSBIT_MASK;
+    head[2] = (unsigned char)((payload_len >> 56) & 0xff);
+    head[3] = (unsigned char)((payload_len >> 48) & 0xff);
+    head[4] = (unsigned char)((payload_len >> 40) & 0xff);
+    head[5] = (unsigned char)((payload_len >> 32) & 0xff);
+    head[6] = (unsigned char)((payload_len >> 24) & 0xff);
+    head[7] = (unsigned char)((payload_len >> 16) & 0xff);
+    head[8] = (unsigned char)((payload_len >> 8) & 0xff);
+    head[9] = (unsigned char)(payload_len & 0xff);
+    hlen = 10;
+  }
+  else if(payload_len >= 126) {
+    head[1] = 126 | WSBIT_MASK;
+    head[2] = (unsigned char)((payload_len >> 8) & 0xff);
+    head[3] = (unsigned char)(payload_len & 0xff);
+    hlen = 4;
+  }
+  else {
+    head[1] = (unsigned char)payload_len | WSBIT_MASK;
+    hlen = 2;
+  }
+
+  enc->payload_remain = enc->payload_len = payload_len;
+  ws_enc_info(enc, data, "sending");
+
+  /* add 4 bytes mask */
+  memcpy(&head[hlen], &enc->mask, 4);
+  hlen += 4;
+  /* reset for payload to come */
+  enc->xori = 0;
+
+  n = Curl_bufq_write(out, head, hlen, err);
+  if(n < 0)
+    return -1;
+  if((size_t)n != hlen) {
+    /* We use a bufq with SOFT_LIMIT, writing should always succeed */
+    DEBUGASSERT(0);
+    *err = CURLE_SEND_ERROR;
+    return -1;
+  }
+  return n;
+}
+
+static ssize_t ws_enc_write_payload(struct ws_encoder *enc,
+                                    struct Curl_easy *data,
+                                    const unsigned char *buf, size_t buflen,
+                                    struct bufq *out, CURLcode *err)
+{
+  ssize_t n;
+  size_t i, len;
+
+  if(Curl_bufq_is_full(out)) {
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+
+  /* not the most performant way to do this */
+  len = buflen;
+  if((curl_off_t)len > enc->payload_remain)
+    len = (size_t)enc->payload_remain;
+
+  for(i = 0; i < len; ++i) {
+    unsigned char c = buf[i] ^ enc->mask[enc->xori];
+    n = Curl_bufq_write(out, &c, 1, err);
+    if(n < 0) {
+      if((*err != CURLE_AGAIN) || !i)
+        return -1;
+      break;
+    }
+    enc->xori++;
+    enc->xori &= 3;
+  }
+  enc->payload_remain -= (curl_off_t)i;
+  ws_enc_info(enc, data, "buffered");
+  return (ssize_t)i;
+}
+
+
+struct wsfield {
+  const char *name;
+  const char *val;
+};
+
+CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req)
+{
+  unsigned int i;
+  CURLcode result = CURLE_OK;
+  unsigned char rand[16];
+  char *randstr;
+  size_t randlen;
+  char keyval[40];
+  struct SingleRequest *k = &data->req;
+  struct wsfield heads[]= {
+    {
+      /* The request MUST contain an |Upgrade| header field whose value
+         MUST include the "websocket" keyword. */
+      "Upgrade:", "websocket"
+    },
+    {
+      /* The request MUST contain a |Connection| header field whose value
+         MUST include the "Upgrade" token. */
+      "Connection:", "Upgrade",
+    },
+    {
+      /* The request MUST include a header field with the name
+         |Sec-WebSocket-Version|. The value of this header field MUST be
+         13. */
+      "Sec-WebSocket-Version:", "13",
+    },
+    {
+      /* The request MUST include a header field with the name
+         |Sec-WebSocket-Key|. The value of this header field MUST be a nonce
+         consisting of a randomly selected 16-byte value that has been
+         base64-encoded (see Section 4 of [RFC4648]). The nonce MUST be
+         selected randomly for each connection. */
+      "Sec-WebSocket-Key:", NULL,
+    }
+  };
+  heads[3].val = &keyval[0];
+
+  /* 16 bytes random */
+  result = Curl_rand(data, (unsigned char *)rand, sizeof(rand));
+  if(result)
+    return result;
+  result = Curl_base64_encode((char *)rand, sizeof(rand), &randstr, &randlen);
+  if(result)
+    return result;
+  DEBUGASSERT(randlen < sizeof(keyval));
+  if(randlen >= sizeof(keyval))
+    return CURLE_FAILED_INIT;
+  strcpy(keyval, randstr);
+  free(randstr);
+  for(i = 0; !result && (i < sizeof(heads)/sizeof(heads[0])); i++) {
+    if(!Curl_checkheaders(data, STRCONST(heads[i].name))) {
+#ifdef USE_HYPER
+      char field[128];
+      msnprintf(field, sizeof(field), "%s %s", heads[i].name,
+                heads[i].val);
+      result = Curl_hyper_header(data, req, field);
+#else
+      (void)data;
+      result = Curl_dyn_addf(req, "%s %s\r\n", heads[i].name,
+                             heads[i].val);
+#endif
+    }
+  }
+  k->upgr101 = UPGR101_WS;
+  return result;
+}
+
+/*
+ * 'nread' is number of bytes of websocket data already in the buffer at
+ * 'mem'.
+ */
+CURLcode Curl_ws_accept(struct Curl_easy *data,
+                        const char *mem, size_t nread)
+{
+  struct SingleRequest *k = &data->req;
+  struct websocket *ws;
+  struct Curl_cwriter *ws_dec_writer;
+  CURLcode result;
+
+  DEBUGASSERT(data->conn);
+  ws = data->conn->proto.ws;
+  if(!ws) {
+    size_t chunk_size = WS_CHUNK_SIZE;
+    ws = calloc(1, sizeof(*ws));
+    if(!ws)
+      return CURLE_OUT_OF_MEMORY;
+    data->conn->proto.ws = ws;
+#ifdef DEBUGBUILD
+    {
+      char *p = getenv("CURL_WS_CHUNK_SIZE");
+      if(p) {
+        long l = strtol(p, NULL, 10);
+        if(l > 0 && l <= (1*1024*1024)) {
+          chunk_size = (size_t)l;
+        }
+      }
+    }
+#endif
+    DEBUGF(infof(data, "WS, using chunk size %zu", chunk_size));
+    Curl_bufq_init2(&ws->recvbuf, chunk_size, WS_CHUNK_COUNT,
+                    BUFQ_OPT_SOFT_LIMIT);
+    Curl_bufq_init2(&ws->sendbuf, chunk_size, WS_CHUNK_COUNT,
+                    BUFQ_OPT_SOFT_LIMIT);
+    ws_dec_init(&ws->dec);
+    ws_enc_init(&ws->enc);
+  }
+  else {
+    Curl_bufq_reset(&ws->recvbuf);
+    ws_dec_reset(&ws->dec);
+    ws_enc_reset(&ws->enc);
+  }
+  /* Verify the Sec-WebSocket-Accept response.
+
+     The sent value is the base64 encoded version of a SHA-1 hash done on the
+     |Sec-WebSocket-Key| header field concatenated with
+     the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".
+  */
+
+  /* If the response includes a |Sec-WebSocket-Extensions| header field and
+     this header field indicates the use of an extension that was not present
+     in the client's handshake (the server has indicated an extension not
+     requested by the client), the client MUST Fail the WebSocket Connection.
+  */
+
+  /* If the response includes a |Sec-WebSocket-Protocol| header field
+     and this header field indicates the use of a subprotocol that was
+     not present in the client's handshake (the server has indicated a
+     subprotocol not requested by the client), the client MUST Fail
+     the WebSocket Connection. */
+
+  /* 4 bytes random */
+
+  result = Curl_rand(data, (unsigned char *)&ws->enc.mask,
+                     sizeof(ws->enc.mask));
+  if(result)
+    return result;
+  infof(data, "Received 101, switch to WebSocket; mask %02x%02x%02x%02x",
+        ws->enc.mask[0], ws->enc.mask[1], ws->enc.mask[2], ws->enc.mask[3]);
+
+  /* Install our client writer that decodes WS frames payload */
+  result = Curl_cwriter_create(&ws_dec_writer, data, &ws_cw_decode,
+                               CURL_CW_CONTENT_DECODE);
+  if(result)
+    return result;
+
+  result = Curl_cwriter_add(data, ws_dec_writer);
+  if(result) {
+    Curl_cwriter_free(data, ws_dec_writer);
+    return result;
+  }
+
+  if(data->set.connect_only) {
+    ssize_t nwritten;
+    /* In CONNECT_ONLY setup, the payloads from `mem` need to be received
+     * when using `curl_ws_recv` later on after this transfer is already
+     * marked as DONE. */
+    nwritten = Curl_bufq_write(&ws->recvbuf, (const unsigned char *)mem,
+                               nread, &result);
+    if(nwritten < 0)
+      return result;
+    infof(data, "%zu bytes websocket payload", nread);
+  }
+  else { /* !connect_only */
+    /* And pass any additional data to the writers */
+    if(nread) {
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)mem, nread);
+    }
+  }
+  k->upgr101 = UPGR101_RECEIVED;
+
+  return result;
+}
+
+struct ws_collect {
+  struct Curl_easy *data;
+  unsigned char *buffer;
+  size_t buflen;
+  size_t bufidx;
+  int frame_age;
+  int frame_flags;
+  curl_off_t payload_offset;
+  curl_off_t payload_len;
+  bool written;
+};
+
+static ssize_t ws_client_collect(const unsigned char *buf, size_t buflen,
+                                 int frame_age, int frame_flags,
+                                 curl_off_t payload_offset,
+                                 curl_off_t payload_len,
+                                 void *userp,
+                                 CURLcode *err)
+{
+  struct ws_collect *ctx = userp;
+  size_t nwritten;
+  curl_off_t remain = (payload_len - (payload_offset + buflen));
+
+  if(!ctx->bufidx) {
+    /* first write */
+    ctx->frame_age = frame_age;
+    ctx->frame_flags = frame_flags;
+    ctx->payload_offset = payload_offset;
+    ctx->payload_len = payload_len;
+  }
+
+  if((frame_flags & CURLWS_PING) && !remain) {
+    /* auto-respond to PINGs, only works for single-frame payloads atm */
+    size_t bytes;
+    infof(ctx->data, "WS: auto-respond to PING with a PONG");
+    /* send back the exact same content as a PONG */
+    *err = curl_ws_send(ctx->data, buf, buflen, &bytes, 0, CURLWS_PONG);
+    if(*err)
+      return -1;
+    nwritten = bytes;
+  }
+  else {
+    ctx->written = TRUE;
+    DEBUGASSERT(ctx->buflen >= ctx->bufidx);
+    nwritten = CURLMIN(buflen, ctx->buflen - ctx->bufidx);
+    if(!nwritten) {
+      if(!buflen) {  /* 0 length write, we accept that */
+        *err = CURLE_OK;
+        return 0;
+      }
+      *err = CURLE_AGAIN;  /* no more space */
+      return -1;
+    }
+    *err = CURLE_OK;
+    memcpy(ctx->buffer + ctx->bufidx, buf, nwritten);
+    ctx->bufidx += nwritten;
+  }
+  return nwritten;
+}
+
+static ssize_t nw_in_recv(void *reader_ctx,
+                          unsigned char *buf, size_t buflen,
+                          CURLcode *err)
+{
+  struct Curl_easy *data = reader_ctx;
+  size_t nread;
+
+  *err = curl_easy_recv(data, buf, buflen, &nread);
+  if(*err)
+    return -1;
+  return (ssize_t)nread;
+}
+
+CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
+                                  size_t buflen, size_t *nread,
+                                  const struct curl_ws_frame **metap)
+{
+  struct connectdata *conn = data->conn;
+  struct websocket *ws;
+  bool done = FALSE; /* not filled passed buffer yet */
+  struct ws_collect ctx;
+  CURLcode result;
+
+  if(!conn) {
+    /* Unhappy hack with lifetimes of transfers and connection */
+    if(!data->set.connect_only) {
+      failf(data, "CONNECT_ONLY is required");
+      return CURLE_UNSUPPORTED_PROTOCOL;
+    }
+
+    Curl_getconnectinfo(data, &conn);
+    if(!conn) {
+      failf(data, "connection not found");
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+  }
+  ws = conn->proto.ws;
+  if(!ws) {
+    failf(data, "connection is not setup for websocket");
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
+  *nread = 0;
+  *metap = NULL;
+  /* get a download buffer */
+  result = Curl_preconnect(data);
+  if(result)
+    return result;
+
+  memset(&ctx, 0, sizeof(ctx));
+  ctx.data = data;
+  ctx.buffer = buffer;
+  ctx.buflen = buflen;
+
+  while(!done) {
+    /* receive more when our buffer is empty */
+    if(Curl_bufq_is_empty(&ws->recvbuf)) {
+      ssize_t n = Curl_bufq_slurp(&ws->recvbuf, nw_in_recv, data, &result);
+      if(n < 0) {
+        return result;
+      }
+      else if(n == 0) {
+        /* connection closed */
+        infof(data, "connection expectedly closed?");
+        return CURLE_GOT_NOTHING;
+      }
+      DEBUGF(infof(data, "curl_ws_recv, added %zu bytes from network",
+                   Curl_bufq_len(&ws->recvbuf)));
+    }
+
+    result = ws_dec_pass(&ws->dec, data, &ws->recvbuf,
+                         ws_client_collect, &ctx);
+    if(result == CURLE_AGAIN) {
+      if(!ctx.written) {
+        ws_dec_info(&ws->dec, data, "need more input");
+        continue;  /* nothing written, try more input */
+      }
+      done = TRUE;
+      break;
+    }
+    else if(result) {
+      return result;
+    }
+    else if(ctx.written) {
+      /* The decoded frame is passed back to our caller.
+       * There are frames like PING were we auto-respond to and
+       * that we do not return. For these `ctx.written` is not set. */
+      done = TRUE;
+      break;
+    }
+  }
+
+  /* update frame information to be passed back */
+  update_meta(ws, ctx.frame_age, ctx.frame_flags, ctx.payload_offset,
+              ctx.payload_len, ctx.bufidx);
+  *metap = &ws->frame;
+  *nread = ws->frame.len;
+  /* infof(data, "curl_ws_recv(len=%zu) -> %zu bytes (frame at %"
+           CURL_FORMAT_CURL_OFF_T ", %" CURL_FORMAT_CURL_OFF_T " left)",
+           buflen, *nread, ws->frame.offset, ws->frame.bytesleft); */
+  return CURLE_OK;
+}
+
+static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws,
+                         bool complete)
+{
+  if(!Curl_bufq_is_empty(&ws->sendbuf)) {
+    CURLcode result;
+    const unsigned char *out;
+    size_t outlen, n;
+
+    while(Curl_bufq_peek(&ws->sendbuf, &out, &outlen)) {
+      if(data->set.connect_only)
+        result = Curl_senddata(data, out, outlen, &n);
+      else {
+        result = Curl_xfer_send(data, out, outlen, &n);
+        if(!result && !n && outlen)
+          result = CURLE_AGAIN;
+      }
+
+      if(result) {
+        if(result == CURLE_AGAIN) {
+          if(!complete) {
+            infof(data, "WS: flush EAGAIN, %zu bytes remain in buffer",
+                  Curl_bufq_len(&ws->sendbuf));
+            return result;
+          }
+          /* TODO: the current design does not allow for buffered writes.
+           * We need to flush the buffer now. There is no ws_flush() later */
+          n = 0;
+          continue;
+        }
+        else if(result) {
+          failf(data, "WS: flush, write error %d", result);
+          return result;
+        }
+      }
+      else {
+        infof(data, "WS: flushed %zu bytes", n);
+        Curl_bufq_skip(&ws->sendbuf, n);
+      }
+    }
+  }
+  return CURLE_OK;
+}
+
+CURL_EXTERN CURLcode curl_ws_send(CURL *data, const void *buffer,
+                                  size_t buflen, size_t *sent,
+                                  curl_off_t fragsize,
+                                  unsigned int flags)
+{
+  struct websocket *ws;
+  ssize_t n;
+  size_t nwritten, space;
+  CURLcode result;
+
+  *sent = 0;
+  if(!data->conn && data->set.connect_only) {
+    result = Curl_connect_only_attach(data);
+    if(result)
+      return result;
+  }
+  if(!data->conn) {
+    failf(data, "No associated connection");
+    return CURLE_SEND_ERROR;
+  }
+  if(!data->conn->proto.ws) {
+    failf(data, "Not a websocket transfer");
+    return CURLE_SEND_ERROR;
+  }
+  ws = data->conn->proto.ws;
+
+  if(data->set.ws_raw_mode) {
+    if(fragsize || flags) {
+      DEBUGF(infof(data, "ws_send: "
+                   "fragsize and flags cannot be non-zero in raw mode"));
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+    if(!buflen)
+      /* nothing to do */
+      return CURLE_OK;
+    /* raw mode sends exactly what was requested, and this is from within
+       the write callback */
+    if(Curl_is_in_callback(data)) {
+      result = Curl_xfer_send(data, buffer, buflen, &nwritten);
+    }
+    else
+      result = Curl_senddata(data, buffer, buflen, &nwritten);
+
+    infof(data, "WS: wanted to send %zu bytes, sent %zu bytes",
+          buflen, nwritten);
+    *sent = nwritten;
+    return result;
+  }
+
+  /* Not RAW mode, buf we do the frame encoding */
+  result = ws_flush(data, ws, FALSE);
+  if(result)
+    return result;
+
+  /* TODO: the current design does not allow partial writes, afaict.
+   * It is not clear how the application is supposed to react. */
+  space = Curl_bufq_space(&ws->sendbuf);
+  DEBUGF(infof(data, "curl_ws_send(len=%zu), sendbuf len=%zu space %zu",
+               buflen, Curl_bufq_len(&ws->sendbuf), space));
+  if(space < 14)
+    return CURLE_AGAIN;
+
+  if(flags & CURLWS_OFFSET) {
+    if(fragsize) {
+      /* a frame series 'fragsize' bytes big, this is the first */
+      n = ws_enc_write_head(data, &ws->enc, flags, fragsize,
+                            &ws->sendbuf, &result);
+      if(n < 0)
+        return result;
+    }
+    else {
+      if((curl_off_t)buflen > ws->enc.payload_remain) {
+        infof(data, "WS: unaligned frame size (sending %zu instead of %"
+                    CURL_FORMAT_CURL_OFF_T ")",
+              buflen, ws->enc.payload_remain);
+      }
+    }
+  }
+  else if(!ws->enc.payload_remain) {
+    n = ws_enc_write_head(data, &ws->enc, flags, (curl_off_t)buflen,
+                          &ws->sendbuf, &result);
+    if(n < 0)
+      return result;
+  }
+
+  n = ws_enc_write_payload(&ws->enc, data,
+                           buffer, buflen, &ws->sendbuf, &result);
+  if(n < 0)
+    return result;
+
+  *sent = (size_t)n;
+  return ws_flush(data, ws, TRUE);
+}
+
+static void ws_free(struct connectdata *conn)
+{
+  if(conn && conn->proto.ws) {
+    Curl_bufq_free(&conn->proto.ws->recvbuf);
+    Curl_bufq_free(&conn->proto.ws->sendbuf);
+    Curl_safefree(conn->proto.ws);
+  }
+}
+
+static CURLcode ws_setup_conn(struct Curl_easy *data,
+                              struct connectdata *conn)
+{
+  /* websockets is 1.1 only (for now) */
+  data->state.httpwant = CURL_HTTP_VERSION_1_1;
+  return Curl_http_setup_conn(data, conn);
+}
+
+
+static CURLcode ws_disconnect(struct Curl_easy *data,
+                              struct connectdata *conn,
+                              bool dead_connection)
+{
+  (void)data;
+  (void)dead_connection;
+  ws_free(conn);
+  return CURLE_OK;
+}
+
+CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
+{
+  /* we only return something for websocket, called from within the callback
+     when not using raw mode */
+  if(GOOD_EASY_HANDLE(data) && Curl_is_in_callback(data) && data->conn &&
+     data->conn->proto.ws && !data->set.ws_raw_mode)
+    return &data->conn->proto.ws->frame;
+  return NULL;
+}
+
+const struct Curl_handler Curl_handler_ws = {
+  "WS",                                 /* scheme */
+  ws_setup_conn,                        /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  Curl_http_connect,                    /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  Curl_http_getsock_do,                 /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ws_disconnect,                        /* disconnect */
+  Curl_http_write_resp,                 /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_HTTP,                            /* defport */
+  CURLPROTO_WS,                         /* protocol */
+  CURLPROTO_HTTP,                       /* family */
+  PROTOPT_CREDSPERREQUEST |             /* flags */
+  PROTOPT_USERPWDCTRL
+};
+
+#ifdef USE_SSL
+const struct Curl_handler Curl_handler_wss = {
+  "WSS",                                /* scheme */
+  ws_setup_conn,                        /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  Curl_http_connect,                    /* connect_it */
+  NULL,                                 /* connecting */
+  ZERO_NULL,                            /* doing */
+  NULL,                                 /* proto_getsock */
+  Curl_http_getsock_do,                 /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ws_disconnect,                        /* disconnect */
+  Curl_http_write_resp,                 /* write_resp */
+  ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
+  PORT_HTTPS,                           /* defport */
+  CURLPROTO_WSS,                        /* protocol */
+  CURLPROTO_HTTP,                       /* family */
+  PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | /* flags */
+  PROTOPT_USERPWDCTRL
+};
+#endif
+
+
+#else
+
+CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
+                                  size_t *nread,
+                                  const struct curl_ws_frame **metap)
+{
+  (void)curl;
+  (void)buffer;
+  (void)buflen;
+  (void)nread;
+  (void)metap;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer,
+                                  size_t buflen, size_t *sent,
+                                  curl_off_t fragsize,
+                                  unsigned int flags)
+{
+  (void)curl;
+  (void)buffer;
+  (void)buflen;
+  (void)sent;
+  (void)fragsize;
+  (void)flags;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
+{
+  (void)data;
+  return NULL;
+}
+#endif /* USE_WEBSOCKETS */
Index: trunk/src/libs/curl-8.7.1/lib/ws.h
===================================================================
--- trunk/src/libs/curl-8.7.1/lib/ws.h	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/lib/ws.h	(revision 104083)
@@ -0,0 +1,90 @@
+#ifndef HEADER_CURL_WS_H
+#define HEADER_CURL_WS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+
+#ifdef USE_HYPER
+#define REQTYPE void
+#else
+#define REQTYPE struct dynbuf
+#endif
+
+/* a client-side WS frame decoder, parsing frame headers and
+ * payload, keeping track of current position and stats */
+enum ws_dec_state {
+  WS_DEC_INIT,
+  WS_DEC_HEAD,
+  WS_DEC_PAYLOAD
+};
+
+struct ws_decoder {
+  int frame_age;        /* zero */
+  int frame_flags;      /* See the CURLWS_* defines */
+  curl_off_t payload_offset;   /* the offset parsing is at */
+  curl_off_t payload_len;
+  unsigned char head[10];
+  int head_len, head_total;
+  enum ws_dec_state state;
+};
+
+/* a client-side WS frame encoder, generating frame headers and
+ * converting payloads, tracking remaining data in current frame */
+struct ws_encoder {
+  curl_off_t payload_len;  /* payload length of current frame */
+  curl_off_t payload_remain;  /* remaining payload of current */
+  unsigned int xori; /* xor index */
+  unsigned char mask[4]; /* 32 bit mask for this connection */
+  unsigned char firstbyte; /* first byte of frame we encode */
+  bool contfragment; /* set TRUE if the previous fragment sent was not final */
+};
+
+/* A websocket connection with en- and decoder that treat frames
+ * and keep track of boundaries. */
+struct websocket {
+  struct Curl_easy *data; /* used for write callback handling */
+  struct ws_decoder dec;  /* decode of we frames */
+  struct ws_encoder enc;  /* decode of we frames */
+  struct bufq recvbuf;    /* raw data from the server */
+  struct bufq sendbuf;    /* raw data to be sent to the server */
+  struct curl_ws_frame frame;  /* the current WS FRAME received */
+};
+
+CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req);
+CURLcode Curl_ws_accept(struct Curl_easy *data, const char *mem, size_t len);
+
+extern const struct Curl_handler Curl_handler_ws;
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_wss;
+#endif
+
+
+#else
+#define Curl_ws_request(x,y) CURLE_OK
+#define Curl_ws_free(x) Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_WS_H */
Index: trunk/src/libs/curl-8.7.1/libcurl.def
===================================================================
--- trunk/src/libs/curl-8.7.1/libcurl.def	(revision 104083)
+++ trunk/src/libs/curl-8.7.1/libcurl.def	(revision 104083)
@@ -0,0 +1,94 @@
+EXPORTS
+curl_easy_cleanup
+curl_easy_duphandle
+curl_easy_escape
+curl_easy_getinfo
+curl_easy_header
+curl_easy_init
+curl_easy_nextheader
+curl_easy_option_by_id
+curl_easy_option_by_name
+curl_easy_option_next
+curl_easy_pause
+curl_easy_perform
+curl_easy_recv
+curl_easy_reset
+curl_easy_send
+curl_easy_setopt
+curl_easy_strerror
+curl_easy_unescape
+curl_easy_upkeep
+curl_escape
+curl_formadd
+curl_formfree
+curl_formget
+curl_free
+curl_getdate
+curl_getenv
+curl_global_cleanup
+curl_global_init
+curl_global_init_mem
+curl_global_sslset
+curl_global_trace
+curl_maprintf
+curl_mfprintf
+curl_mime_addpart
+curl_mime_data
+curl_mime_data_cb
+curl_mime_encoder
+curl_mime_filedata
+curl_mime_filename
+curl_mime_free
+curl_mime_headers
+curl_mime_init
+curl_mime_name
+curl_mime_subparts
+curl_mime_type
+curl_mprintf
+curl_msnprintf
+curl_msprintf
+curl_multi_add_handle
+curl_multi_assign
+curl_multi_cleanup
+curl_multi_fdset
+curl_multi_get_handles
+curl_multi_info_read
+curl_multi_init
+curl_multi_perform
+curl_multi_poll
+curl_multi_remove_handle
+curl_multi_setopt
+curl_multi_socket
+curl_multi_socket_action
+curl_multi_socket_all
+curl_multi_strerror
+curl_multi_timeout
+curl_multi_wait
+curl_multi_wakeup
+curl_mvaprintf
+curl_mvfprintf
+curl_mvprintf
+curl_mvsnprintf
+curl_mvsprintf
+curl_pushheader_byname
+curl_pushheader_bynum
+curl_share_cleanup
+curl_share_init
+curl_share_setopt
+curl_share_strerror
+curl_slist_append
+curl_slist_free_all
+curl_strequal
+curl_strnequal
+curl_unescape
+curl_url
+curl_url_cleanup
+curl_url_dup
+curl_url_get
+curl_url_set
+curl_url_strerror
+curl_version
+curl_version_info
+curl_ws_meta
+curl_ws_recv
+curl_ws_send
