HttpGet
HTTPS
https
+HTTPSRR
hyper's
Högskolan
IANA
SRP
SRWLOCK
SSL
-SSLS
ssl
SSLeay
SSLKEYLOGFILE
+SSLS
sslv
SSLv
SSLVERSION
endif()
option(CURL_LTO "Enable compiler Link Time Optimizations" OFF)
-cmake_dependent_option(ENABLE_THREADED_RESOLVER "Enable threaded DNS lookup"
- ON "NOT ENABLE_ARES;NOT DOS;NOT AMIGA"
- OFF)
+if(NOT DOS AND NOT AMIGA)
+ # if c-ares is used, default the threaded resolver to OFF
+ if(ENABLE_ARES)
+ set(_enable_threaded_resolver_default OFF)
+ else()
+ set(_enable_threaded_resolver_default ON)
+ endif()
+ option(ENABLE_THREADED_RESOLVER "Enable threaded DNS lookup" ${_enable_threaded_resolver_default})
+endif()
include(PickyWarnings)
if(NOT HAVE_ECH)
message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/AWS-LC/wolfSSL")
else()
- message(STATUS "ECH enabled.")
+ message(STATUS "ECH enabled")
+ # ECH wants HTTPSRR
+ set(USE_HTTPSRR ON)
+ message(STATUS "HTTPSRR enabled")
endif()
else()
message(FATAL_ERROR "ECH requires ECH-enablded OpenSSL, BoringSSL, AWS-LC or wolfSSL")
curl_add_if("gsasl" USE_GSASL)
curl_add_if("zstd" HAVE_ZSTD)
curl_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32)
+curl_add_if("c-ares-rr" USE_ARES AND ENABLE_THREADED_RESOLVER)
curl_add_if("IDN" (HAVE_LIBIDN2 AND HAVE_IDN2_H) OR
USE_WIN32_IDN OR
USE_APPLE_IDN)
curl_add_if("Debug" ENABLE_DEBUG)
curl_add_if("TrackMemory" ENABLE_CURLDEBUG)
curl_add_if("ECH" _ssl_enabled AND HAVE_ECH)
+curl_add_if("HTTPSRR" _ssl_enabled AND USE_HTTPSRR)
curl_add_if("PSL" USE_LIBPSL)
curl_add_if("CAcert" CURL_CA_EMBED_SET)
curl_add_if("SSLS-EXPORT" _ssl_enabled AND USE_SSLS_EXPORT)
AM_CONDITIONAL(USE_MANUAL, test x"$USE_MANUAL" = x1)
CURL_CHECK_LIB_ARES
+CURL_CHECK_OPTION_THREADED_RESOLVER
-if test "x$want_ares" != xyes; then
- CURL_CHECK_OPTION_THREADED_RESOLVER
-
- if test "$ipv6" = yes; then
- CURL_DARWIN_SYSTEMCONFIGURATION
- fi
+if test "$ipv6" = yes; then
+ CURL_DARWIN_SYSTEMCONFIGURATION
fi
-dnl ************************************************************
-dnl disable POSIX threads
-dnl
-AC_MSG_CHECKING([whether to use POSIX threads for threaded resolver])
-AC_ARG_ENABLE(pthreads,
-AS_HELP_STRING([--enable-pthreads],
- [Enable POSIX threads (default for threaded resolver)])
-AS_HELP_STRING([--disable-pthreads],[Disable POSIX threads]),
-[ case "$enableval" in
- no)
- AC_MSG_RESULT(no)
- want_pthreads=no
- ;;
- *)
- AC_MSG_RESULT(yes)
- want_pthreads=yes
- ;;
- esac ], [
- default_pthreads=1
- if test "$curl_cv_native_windows" = "yes"; then
- default_pthreads=0
- else
- case $host_os in
- msdos*)
- default_pthreads=0
- ;;
- esac
- fi
- if test "$default_pthreads" = '0'; then
- AC_MSG_RESULT(no)
- want_pthreads=no
- else
- AC_MSG_RESULT(auto)
- want_pthreads=auto
- fi
- ]
-)
-
dnl turn off pthreads if rt is disabled
-if test "$want_pthreads" != "no"; then
- if test "$want_pthreads" = "yes" && test "$dontwant_rt" = "yes"; then
- AC_MSG_ERROR([options --enable-pthreads and --disable-rt are mutually exclusive])
- fi
- if test "$dontwant_rt" != "no"; then
- dnl if --enable-pthreads was explicit then warn it's being ignored
- if test "$want_pthreads" = "yes"; then
- AC_MSG_WARN([--enable-pthreads Ignored since librt is disabled.])
- fi
- want_pthreads=no
- fi
+if test "$want_threaded_resolver" = "yes" && test "$dontwant_rt" = "yes"; then
+ AC_MSG_ERROR([options --enable-pthreads and --disable-rt are mutually exclusive])
fi
-dnl turn off pthreads if no threaded resolver
-if test "$want_pthreads" != "no" && test "$want_thres" != "yes"; then
- want_pthreads=no
+dnl Windows threaded resolver check
+if test "$want_threaded_resolver" = "yes" && test "$curl_cv_native_windows" = "yes"; then
+ USE_THREADS_WIN32=1
+ AC_DEFINE(USE_THREADS_WIN32, 1, [if you want Win32 threaded DNS lookup])
+ curl_res_msg="Win32 threaded"
fi
dnl detect pthreads
-if test "$want_pthreads" != "no"; then
+if test "$want_threaded_resolver" = "yes" && test "$USE_THREADS_WIN32" != "1"; then
AC_CHECK_HEADER(pthread.h,
[ AC_DEFINE(HAVE_PTHREAD_H, 1, [if you have <pthread.h>])
save_CFLAGS="$CFLAGS"
])
fi
-dnl threaded resolver check
-if test "$want_thres" = "yes" && test "x$USE_THREADS_POSIX" != "x1"; then
- if test "$want_pthreads" = "yes"; then
- AC_MSG_ERROR([--enable-pthreads but pthreads was not found])
- fi
- dnl If native Windows fallback on Win32 threads since no POSIX threads
- if test "$curl_cv_native_windows" = "yes"; then
- USE_THREADS_WIN32=1
- AC_DEFINE(USE_THREADS_WIN32, 1, [if you want Win32 threaded DNS lookup])
- curl_res_msg="Win32 threaded"
- else
- AC_MSG_ERROR([Threaded resolver enabled but no thread library found])
- fi
+dnl Did we find a threading option?
+if test "$want_threaded_resolver" != "no" -a "x$USE_THREADS_POSIX" != "x1" -a "x$USE_THREADS_WIN32" != "x1"; then
+ AC_MSG_ERROR([Threaded resolver enabled but no thread library found])
fi
AC_CHECK_HEADER(dirent.h,
fi
-dnl *************************************************************
-dnl check whether HTTPSRR support if desired
-dnl
-if test "x$want_httpsrr" != "xno"; then
- AC_MSG_RESULT([HTTPSRR support is available])
- AC_DEFINE(USE_HTTPSRR, 1, [enable HTTPS RR support])
- experimental="$experimental HTTPSRR"
-fi
-
dnl *************************************************************
dnl check whether ECH support, if desired, is actually available
dnl
AC_DEFINE(USE_ECH, 1, [if ECH support is available])
AC_MSG_RESULT($ECH_SUPPORT)
experimental="$experimental ECH"
+ dnl ECH wants HTTPSRR
+ want_httpsrr="yes"
else
AC_MSG_ERROR([--enable-ech ignored: No ECH support found])
fi
fi
+dnl *************************************************************
+dnl check whether HTTPSRR support if desired
+dnl
+if test "x$want_httpsrr" != "xno"; then
+ AC_MSG_RESULT([HTTPSRR support is enabled])
+ AC_DEFINE(USE_HTTPSRR, 1, [enable HTTPS RR support])
+ experimental="$experimental HTTPSRR"
+ curl_httpsrr_msg="enabled (--disable-httpsrr)"
+fi
+
+
dnl *************************************************************
dnl check whether OpenSSL (lookalikes) have SSL_set0_wbio
dnl
-o "x$USE_THREADS_WIN32" = "x1"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES AsynchDNS"
fi
+if test "x$USE_ARES" = "x1" -a "$want_threaded_resolver" = "yes"; then
+ SUPPORT_FEATURES="$SUPPORT_FEATURES c-ares-rr"
+fi
if test "x$IDN_ENABLED" = "x1"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES IDN"
fi
fi
fi
+if test "x$want_httpsrr" != "xno"; then
+ SUPPORT_FEATURES="$SUPPORT_FEATURES HTTPSRR"
+fi
+
if test "x$SSLS_EXPORT_ENABLED" = "x1"; then
SUPPORT_FEATURES="$SUPPORT_FEATURES SSLS-EXPORT"
fi
HTTP2: ${curl_h2_msg}
HTTP3: ${curl_h3_msg}
ECH: ${curl_ech_msg}
+ HTTPS RR: ${curl_httpsrr_msg}
SSLS-EXPORT: ${curl_ssls_export_msg}
Protocols: ${SUPPORT_PROTOCOLS_LOWER}
Features: ${SUPPORT_FEATURES}
# FEATURES
-## alt-svc
+## `alt-svc`
*features* mask bit: CURL_VERSION_ALTSVC
HTTP Alt-Svc parsing and the associated options (Added in 7.64.1)
-## AsynchDNS
+## `AsynchDNS`
*features* mask bit: CURL_VERSION_ASYNCHDNS
more exact timeouts (even on Windows) and less blocking when using the multi
interface. (added in 7.10.7)
-## brotli
+## `brotli`
*features* mask bit: CURL_VERSION_BROTLI
supports HTTP Brotli content encoding using libbrotlidec (Added in 7.57.0)
-## Debug
+## `c-ares-rr`
+
+*features* mask bit: non-existent
+
+libcurl was built to use c-ares for EXPERIMENTAL HTTPS resource record
+resolves, but uses the threaded resolver for "normal" resolves (Added in
+8.12.0)
+
+## `Debug`
*features* mask bit: CURL_VERSION_DEBUG
libcurl was built with debug capabilities (added in 7.10.6)
-## ECH
+## `ECH`
*features* mask bit: non-existent
libcurl was built with ECH support (experimental, added in 8.8.0)
-## gsasl
+## `gsasl`
*features* mask bit: CURL_VERSION_GSASL
libcurl was built with libgsasl and thus with some extra SCRAM-SHA
authentication methods. (added in 7.76.0)
-## GSS-API
+## `GSS-API`
*features* mask bit: CURL_VERSION_GSSAPI
to use the current user credentials without the app having to pass them on.
(Added in 7.38.0)
-## HSTS
+## `HSTS`
*features* mask bit: CURL_VERSION_HSTS
libcurl was built with support for HSTS (HTTP Strict Transport Security)
(Added in 7.74.0)
-## HTTP2
+## `HTTP2`
*features* mask bit: CURL_VERSION_HTTP2
libcurl was built with support for HTTP2.
(Added in 7.33.0)
-## HTTP3
+## `HTTP3`
*features* mask bit: CURL_VERSION_HTTP3
HTTP/3 and QUIC support are built-in (Added in 7.66.0)
-## HTTPS-proxy
+## `HTTPS-proxy`
*features* mask bit: CURL_VERSION_HTTPS_PROXY
libcurl was built with support for HTTPS-proxy.
(Added in 7.52.0)
-## IDN
+## `HTTPSRR`
+
+*features* mask bit: non-existent
+
+libcurl was built with EXPERIMENTAL support for HTTPS resource records (Added
+in 8.12.0)
+
+## `IDN`
*features* mask bit: CURL_VERSION_IDN
libcurl was built with support for IDNA, domain names with international
letters. (Added in 7.12.0)
-## IPv6
+## `IPv6`
*features* mask bit: CURL_VERSION_IPV6
supports IPv6
-## Kerberos
+## `Kerberos`
*features* mask bit: CURL_VERSION_KERBEROS5
supports Kerberos V5 authentication for FTP, IMAP, LDAP, POP3, SMTP and
SOCKSv5 proxy. (Added in 7.40.0)
-## Largefile
+## `Largefile`
*features* mask bit: CURL_VERSION_LARGEFILE
libcurl was built with support for large files. (Added in 7.11.1)
-## libz
+## `libz`
*features* mask bit: CURL_VERSION_LIBZ
supports HTTP deflate using libz (Added in 7.10)
-## MultiSSL
+## `MultiSSL`
*features* mask bit: CURL_VERSION_MULTI_SSL
curl_global_sslset(3).
(Added in 7.56.0)
-## NTLM
+## `NTLM`
*features* mask bit: CURL_VERSION_NTLM
supports HTTP NTLM (added in 7.10.6)
-## NTLM_WB
+## `NTLM_WB`
*features* mask bit: CURL_VERSION_NTLM_WB
libcurl was built with support for NTLM delegation to a winbind helper.
(Added in 7.22.0) This feature was removed from curl in 8.8.0.
-## PSL
+## `PSL`
*features* mask bit: CURL_VERSION_PSL
libcurl ignore cookies with a domain that is on the list.
(Added in 7.47.0)
-## SPNEGO
+## `SPNEGO`
*features* mask bit: CURL_VERSION_SPNEGO
libcurl was built with support for SPNEGO authentication (Simple and Protected
GSS-API Negotiation Mechanism, defined in RFC 2478.) (added in 7.10.8)
-## SSL
+## `SSL`
*features* mask bit: CURL_VERSION_SSL
supports SSL (HTTPS/FTPS) (Added in 7.10)
-## SSLS-EXPORT
+## `SSLS-EXPORT`
*features* mask bit: non-existent
libcurl was built with SSL session import/export support
(experimental, added in 8.12.0)
-## SSPI
+## `SSPI`
*features* mask bit: CURL_VERSION_SSPI
Digest authentication. It also allows libcurl to use the current user
credentials without the app having to pass them on. (Added in 7.13.2)
-## threadsafe
+## `threadsafe`
*features* mask bit: CURL_VERSION_THREADSAFE
libcurl was built with thread-safety support (Atomic or SRWLOCK) to protect
curl initialization. (Added in 7.84.0) See libcurl-thread(3)
-## TLS-SRP
+## `TLS-SRP`
*features* mask bit: CURL_VERSION_TLSAUTH_SRP
libcurl was built with support for TLS-SRP (in one or more of the built-in TLS
backends). (Added in 7.21.4)
-## TrackMemory
+## `TrackMemory`
*features* mask bit: CURL_VERSION_CURLDEBUG
libcurl was built with memory tracking debug capabilities. This is mainly of
interest for libcurl hackers. (added in 7.19.6)
-## Unicode
+## `Unicode`
*features* mask bit: CURL_VERSION_UNICODE
libcurl was built with Unicode support on Windows. This makes non-ASCII
characters work in filenames and options passed to libcurl. (Added in 7.72.0)
-## UnixSockets
+## `UnixSockets`
*features* mask bit: CURL_VERSION_UNIX_SOCKETS
libcurl was built with support for Unix domain sockets.
(Added in 7.40.0)
-## zstd
+## `zstd`
*features* mask bit: CURL_VERSION_ZSTD
#include "curl_setup.h"
+#ifdef USE_ARES
+
/***********************************************************************
* 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>
#include <ares_version.h> /* really old c-ares did not include this by
itself */
+/*
+ * Curl_ares_getsock() is called when the outside world (using
+ * curl_multi_fdset()) wants to get our fd_set setup and we are 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_ares_getsock(struct Curl_easy *data,
+ ares_channel channel,
+ curl_socket_t *socks)
+{
+ struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 };
+ struct timeval timebuf;
+ int max = ares_getsock(channel,
+ (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
+ struct timeval *timeout = ares_timeout(channel, &maxtime, &timebuf);
+ timediff_t milli = curlx_tvtoms(timeout);
+ Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
+ return max;
+}
+
+/*
+ * Curl_ares_perform()
+ *
+ * 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
+ */
+
+int Curl_ares_perform(ares_channel channel,
+ 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(channel, 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, (unsigned int)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 will not timeout! */
+ ares_process_fd(channel, 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(channel,
+ (pfd[i].revents & (POLLRDNORM|POLLIN)) ?
+ pfd[i].fd : ARES_SOCKET_BAD,
+ (pfd[i].revents & (POLLWRNORM|POLLOUT)) ?
+ pfd[i].fd : ARES_SOCKET_BAD);
+ }
+ return nfds;
+}
+
+#ifdef CURLRES_ARES
+
#if ARES_VERSION >= 0x010500
/* c-ares 1.5.0 or later, the callback proto is modified */
#define HAVE_CARES_CALLBACK_TIMEOUTS 1
#if ARES_VERSION >= 0x011c00
/* 1.28.0 and later have ares_query_dnsrec */
#define HAVE_ARES_QUERY_DNSREC 1
-#else
-#undef USE_HTTPSRR
+#ifdef USE_HTTPSRR
+#define USE_HTTPSRR_ARES 1
+#endif
#endif
/* The last 3 #include files should be in this order */
#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
-#ifdef USE_HTTPSRR
- struct Curl_https_rrinfo hinfo;
-#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.
/*
* Curl_resolver_getsock() is called when someone from the outside world
- * (using curl_multi_fdset()) wants to get our fd_set setup and we are 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 = { CURL_TIMEOUT_RESOLVE, 0 };
- struct timeval timebuf;
- int max = ares_getsock((ares_channel)data->state.async.resolver,
- (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
- struct timeval *timeout =
- ares_timeout((ares_channel)data->state.async.resolver, &maxtime, &timebuf);
- timediff_t milli = curlx_tvtoms(timeout);
- 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
+ * (using curl_multi_fdset()) wants to get our fd_set setup.
*/
-static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
+int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
- 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, (unsigned int)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 will not 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;
+ return Curl_ares_getsock(data, (ares_channel)data->state.async.resolver,
+ socks);
}
/*
DEBUGASSERT(dns);
*dns = NULL;
- if(waitperform(data, 0) < 0)
+ if(Curl_ares_perform((ares_channel)data->state.async.resolver, 0) < 0)
return CURLE_UNRECOVERABLE_POLL;
#ifndef HAVE_CARES_GETADDRINFO
result = Curl_resolver_error(data);
else {
*dns = data->state.async.dns;
-#ifdef USE_HTTPSRR
+#ifdef USE_HTTPSRR_ARES
{
struct Curl_https_rrinfo *lhrr =
Curl_memdup(&res->hinfo, sizeof(struct Curl_https_rrinfo));
else
timeout_ms = 1000;
- if(waitperform(data, timeout_ms) < 0)
+ if(Curl_ares_perform((ares_channel)data->state.async.resolver,
+ timeout_ms) < 0)
return CURLE_UNRECOVERABLE_POLL;
result = Curl_resolver_is_resolved(data, entry);
#endif
-#ifdef USE_HTTPSRR
-static void httpsrr_opt(struct Curl_easy *data,
- const ares_dns_rr_t *rr,
- ares_dns_rr_key_t key, size_t idx)
-{
- size_t len = 0;
- const unsigned char *val = NULL;
- unsigned short code;
- struct thread_data *res = data->state.async.tdata;
-
- code = ares_dns_rr_get_opt(rr, key, idx, &val, &len);
-
- switch(code) {
- case HTTPS_RR_CODE_ALPN: /* str_list */
- Curl_httpsrr_decode_alpn(val, len, res->hinfo.alpns);
- infof(data, "HTTPS RR ALPN: %u %u %u %u",
- res->hinfo.alpns[0], res->hinfo.alpns[1], res->hinfo.alpns[2],
- res->hinfo.alpns[3]);
- break;
- case HTTPS_RR_CODE_NO_DEF_ALPN:
- infof(data, "HTTPS RR no-def-alpn");
- break;
- case HTTPS_RR_CODE_IPV4: /* addr4 list */
- infof(data, "HTTPS RR IPv4");
- break;
- case HTTPS_RR_CODE_ECH:
- infof(data, "HTTPS RR ECH");
- break;
- case HTTPS_RR_CODE_IPV6: /* addr6 list */
- infof(data, "HTTPS RR IPv6");
- break;
- case HTTPS_RR_CODE_PORT:
- infof(data, "HTTPS RR port");
- break;
- default:
- infof(data, "HTTPS RR unknown code");
- break;
- }
-}
-
-static void dnsrec_done_cb(void *arg, ares_status_t status,
- size_t timeouts,
- const ares_dns_record_t *dnsrec)
-{
- struct Curl_easy *data = arg;
- size_t i;
- struct thread_data *res = data->state.async.tdata;
- (void)timeouts;
-
- res->num_pending--;
- if((ARES_SUCCESS != status) || !dnsrec)
- return;
-
- for(i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i++) {
- size_t opt;
- const ares_dns_rr_t *rr =
- ares_dns_record_rr_get_const(dnsrec, ARES_SECTION_ANSWER, i);
- if(ares_dns_rr_get_type(rr) != ARES_REC_TYPE_HTTPS)
- continue;
- for(opt = 0; opt < ares_dns_rr_get_opt_cnt(rr, ARES_RR_HTTPS_PARAMS);
- opt++)
- httpsrr_opt(data, rr, ARES_RR_HTTPS_PARAMS, opt);
- }
-}
-#endif
-
/*
* Curl_resolver_getaddrinfo() - when using ares
*
query_completed_cb, data);
}
#endif
-#ifdef USE_HTTPSRR
+#ifdef USE_HTTPSRR_ARES
{
res->num_pending++; /* one more */
memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo));
ares_query_dnsrec((ares_channel)data->state.async.resolver,
hostname, ARES_CLASS_IN,
ARES_REC_TYPE_HTTPS,
- dnsrec_done_cb, data, NULL);
+ Curl_dnsrec_done_cb, data, NULL);
}
#endif
*waitp = 1; /* expect asynchronous response */
#endif
}
#endif /* CURLRES_ARES */
+
+#endif /* USE_ARES */
#include "inet_ntop.h"
#include "curl_threads.h"
#include "connect.h"
+
+#ifdef USE_ARES
+#include <ares.h>
+#ifdef USE_HTTPSRR
+#define USE_HTTPSRR_ARES 1 /* the combo */
+#endif
+#endif
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
const struct addrinfo *hints);
-/* Data for synchronization between resolver thread and its parent */
-struct thread_sync_data {
- 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]; /* eventfd/pipes/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 {
- 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);
/* Treat the request as done until the thread actually starts so any early
* cleanup gets done properly.
*/
- tsd->done = 1;
+ tsd->done = TRUE;
#ifdef HAVE_GETADDRINFO
DEBUGASSERT(hints);
tsd->hints = *hints;
}
}
#endif
- tsd->done = 1;
+ tsd->done = TRUE;
Curl_mutex_release(tsd->mtx);
}
free(td);
}
else {
- tsd->done = 1;
+ tsd->done = TRUE;
Curl_mutex_release(tsd->mtx);
}
{
if(async->tdata) {
struct thread_data *td = async->tdata;
- int done;
+ bool done;
#ifndef CURL_DISABLE_SOCKETPAIR
curl_socket_t sock_rd = td->tsd.sock_pair[0];
struct Curl_easy *data = td->tsd.data;
#endif
+#ifdef USE_HTTPSRR_ARES
+ ares_destroy(data->state.async.tdata->channel);
+#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;
+ td->tsd.done = TRUE;
Curl_mutex_release(td->tsd.mtx);
if(!done) {
async->hostname = NULL;
}
+#ifdef USE_HTTPSRR_ARES
+static CURLcode resolve_httpsrr(struct Curl_easy *data,
+ struct Curl_async *asp)
+{
+ int status = ares_init(&asp->tdata->channel);
+ if(status != ARES_SUCCESS)
+ return CURLE_FAILED_INIT;
+
+ memset(&asp->tdata->hinfo, 0, sizeof(struct Curl_https_rrinfo));
+ ares_query_dnsrec(asp->tdata->channel,
+ asp->hostname, ARES_CLASS_IN,
+ ARES_REC_TYPE_HTTPS,
+ Curl_dnsrec_done_cb, data, NULL);
+
+ return CURLE_OK;
+}
+#endif
+
/*
* init_resolve_thread() starts a new thread that performs the actual
* resolve. This function returns before the resolve is done.
if(!asp->hostname)
goto err_exit;
- /* The thread will set this to 1 when complete. */
- td->tsd.done = 0;
+ /* The thread will set this TRUE when complete. */
+ td->tsd.done = FALSE;
#ifdef HAVE_GETADDRINFO
td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
if(td->thread_hnd == curl_thread_t_null) {
/* The thread never started, so mark it as done here for proper cleanup. */
- td->tsd.done = 1;
+ td->tsd.done = TRUE;
err = errno;
goto err_exit;
}
-
+#ifdef USE_HTTPSRR_ARES
+ if(resolve_httpsrr(data, asp))
+ goto err_exit;
+#endif
return TRUE;
err_exit:
struct Curl_dns_entry **entry)
{
struct thread_data *td = data->state.async.tdata;
- int done = 0;
+ bool done = FALSE;
DEBUGASSERT(entry);
*entry = NULL;
DEBUGASSERT(td);
return CURLE_COULDNT_RESOLVE_HOST;
}
+#ifdef USE_HTTPSRR_ARES
+ if(Curl_ares_perform(data->state.async.tdata->channel, 0) < 0)
+ return CURLE_UNRECOVERABLE_POLL;
+#endif
Curl_mutex_acquire(td->tsd.mtx);
done = td->tsd.done;
timediff_t milli;
timediff_t ms;
struct resdata *reslv = (struct resdata *)data->state.async.resolver;
+ int socketi = 0;
#ifndef CURL_DISABLE_SOCKETPAIR
struct thread_data *td = data->state.async.tdata;
#else
(void)socks;
#endif
+#ifdef USE_HTTPSRR_ARES
+ if(data->state.async.tdata) {
+ ret_val = Curl_ares_getsock(data, data->state.async.tdata->channel, socks);
+ for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
+ if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
+ !ARES_GETSOCK_WRITABLE(ret_val, socketi))
+ break;
+ }
+#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];
+ socks[socketi] = td->tsd.sock_pair[0];
td->tsd.data = data;
- ret_val = GETSOCK_READSOCK(0);
+ ret_val = GETSOCK_READSOCK(socketi);
}
else {
#endif
#include "curl_setup.h"
#include "curl_addrinfo.h"
+#include "httpsrr.h"
struct addrinfo;
struct hostent;
struct connectdata;
struct Curl_dns_entry;
+#ifdef CURLRES_THREADED
+#include "curl_threads.h"
+
+/* Data for synchronization between resolver thread and its parent */
+struct thread_sync_data {
+ curl_mutex_t *mtx;
+ bool 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]; /* eventfd/pipes/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 {
+ curl_thread_t thread_hnd;
+ unsigned int poll_interval;
+ timediff_t interval_end;
+ struct thread_sync_data tsd;
+#if defined(USE_HTTPSRR) && defined(USE_ARES)
+ struct Curl_https_rrinfo hinfo;
+ ares_channel channel;
+#endif
+};
+
+#elif defined(CURLRES_ARES) /* CURLRES_THREADED */
+
+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
+#ifdef USE_HTTPSRR
+ struct Curl_https_rrinfo hinfo;
+#endif
+ char hostname[1];
+};
+
+#endif /* CURLRES_ARES */
+
+#ifdef USE_ARES
+#include <ares.h>
+
+/* for HTTPS RR purposes as well */
+int Curl_ares_getsock(struct Curl_easy *data,
+ ares_channel channel,
+ curl_socket_t *socks);
+int Curl_ares_perform(ares_channel channel,
+ timediff_t timeout_ms);
+#endif
+
+
/*
* This header defines all functions in the internal asynch resolver interface.
* All asynch resolvers need to provide these functions.
# define CURL_DISABLE_HTTP_AUTH 1
#endif
-/*
- * ECH requires HTTPSRR.
- */
-
-#if defined(USE_ECH) && !defined(USE_HTTPSRR)
-# define USE_HTTPSRR
-#endif
-
/* ================================================================ */
/* No system header file shall be included in this file before this */
/* point. */
# define CURLRES_IPV4
#endif
-#ifdef USE_ARES
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+# define CURLRES_ASYNCH
+# define CURLRES_THREADED
+#elif defined(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
#include "curl_addrinfo.h"
#include "timeval.h" /* for timediff_t */
#include "asyn.h"
+#include "httpsrr.h"
#include <setjmp.h>
*/
struct Curl_hash *Curl_global_host_cache_init(void);
-#ifdef USE_HTTPSRR
-
-#define CURL_MAXLEN_host_name 253
-#define MAX_HTTPSRR_ALPNS 4
-
-struct Curl_https_rrinfo {
- /*
- * Fields from HTTPS RR. The only mandatory fields are priority and target.
- * See https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
- */
- char *target;
- unsigned char *ipv4hints; /* keytag = 4 */
- size_t ipv4hints_len;
- unsigned char *echconfiglist; /* keytag = 5 */
- size_t echconfiglist_len;
- unsigned char *ipv6hints; /* keytag = 6 */
- size_t ipv6hints_len;
- unsigned char alpns[MAX_HTTPSRR_ALPNS]; /* keytag = 1 */
- /* store parsed alpnid entries in the array, end with ALPN_none */
- int port; /* -1 means not set */
- uint16_t priority;
- bool no_def_alpn; /* keytag = 2 */
-};
-#endif
-
struct Curl_dns_entry {
struct Curl_addrinfo *addr;
#ifdef USE_HTTPSRR
#include "curl_addrinfo.h"
#include "httpsrr.h"
#include "connect.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"
CURLcode Curl_httpsrr_decode_alpn(const unsigned char *cp, size_t len,
unsigned char *alpns)
return CURLE_BAD_CONTENT_ENCODING;
}
+#ifdef USE_ARES
+
+static void httpsrr_opt(struct Curl_easy *data,
+ const ares_dns_rr_t *rr,
+ ares_dns_rr_key_t key, size_t idx)
+{
+ size_t len = 0;
+ const unsigned char *val = NULL;
+ unsigned short code;
+ struct thread_data *res = data->state.async.tdata;
+ struct Curl_https_rrinfo *hi = &res->hinfo;
+ code = ares_dns_rr_get_opt(rr, key, idx, &val, &len);
+
+ switch(code) {
+ case HTTPS_RR_CODE_ALPN: /* str_list */
+ Curl_httpsrr_decode_alpn(val, len, hi->alpns);
+ infof(data, "HTTPS RR ALPN: %u %u %u %u",
+ hi->alpns[0], hi->alpns[1], hi->alpns[2], hi->alpns[3]);
+ break;
+ case HTTPS_RR_CODE_NO_DEF_ALPN:
+ infof(data, "HTTPS RR no-def-alpn");
+ break;
+ case HTTPS_RR_CODE_IPV4: /* addr4 list */
+ infof(data, "HTTPS RR IPv4");
+ break;
+ case HTTPS_RR_CODE_ECH:
+ infof(data, "HTTPS RR ECH");
+ break;
+ case HTTPS_RR_CODE_IPV6: /* addr6 list */
+ infof(data, "HTTPS RR IPv6");
+ break;
+ case HTTPS_RR_CODE_PORT:
+ infof(data, "HTTPS RR port");
+ break;
+ default:
+ infof(data, "HTTPS RR unknown code");
+ break;
+ }
+}
+
+void Curl_dnsrec_done_cb(void *arg, ares_status_t status,
+ size_t timeouts,
+ const ares_dns_record_t *dnsrec)
+{
+ struct Curl_easy *data = arg;
+ size_t i;
+#ifdef CURLRES_ARES
+ struct thread_data *res = data->state.async.tdata;
+
+ res->num_pending--;
#endif
+ (void)timeouts;
+ if((ARES_SUCCESS != status) || !dnsrec)
+ return;
+
+ for(i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i++) {
+ size_t opt;
+ const ares_dns_rr_t *rr =
+ ares_dns_record_rr_get_const(dnsrec, ARES_SECTION_ANSWER, i);
+ if(ares_dns_rr_get_type(rr) != ARES_REC_TYPE_HTTPS)
+ continue;
+ /* When SvcPriority is 0, the SVCB record is in AliasMode. Otherwise, it
+ is in ServiceMode */
+ infof(data, "HTTPS RR priority: %u",
+ ares_dns_rr_get_u16(rr, ARES_RR_HTTPS_PRIORITY));
+ for(opt = 0; opt < ares_dns_rr_get_opt_cnt(rr, ARES_RR_HTTPS_PARAMS);
+ opt++)
+ httpsrr_opt(data, rr, ARES_RR_HTTPS_PARAMS, opt);
+ }
+}
+
+#endif /* USE_ARES */
+
+#endif /* USE_HTTPSRR */
*
***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_ARES
+#include <ares.h>
+#endif
+
+#ifdef USE_HTTPSRR
+
+#define CURL_MAXLEN_host_name 253
+#define MAX_HTTPSRR_ALPNS 4
+
+struct Curl_https_rrinfo {
+ /*
+ * Fields from HTTPS RR. The only mandatory fields are priority and target.
+ * See https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
+ */
+ char *target;
+ unsigned char *ipv4hints; /* keytag = 4 */
+ size_t ipv4hints_len;
+ unsigned char *echconfiglist; /* keytag = 5 */
+ size_t echconfiglist_len;
+ unsigned char *ipv6hints; /* keytag = 6 */
+ size_t ipv6hints_len;
+ unsigned char alpns[MAX_HTTPSRR_ALPNS]; /* keytag = 1 */
+ /* store parsed alpnid entries in the array, end with ALPN_none */
+ int port; /* -1 means not set */
+ uint16_t priority;
+ bool no_def_alpn; /* keytag = 2 */
+};
+#endif
/*
* Code points for DNS wire format SvcParams as per RFC 9460
CURLcode Curl_httpsrr_decode_alpn(const unsigned char *cp, size_t len,
unsigned char *alpns);
+#if defined(USE_ARES) && defined(USE_HTTPSRR)
+void Curl_dnsrec_done_cb(void *arg, ares_status_t status,
+ size_t timeouts,
+ const ares_dns_record_t *dnsrec);
+#endif
#endif /* HEADER_CURL_HTTPSRR_H */
#ifdef HAVE_BROTLI
FEATURE("brotli", NULL, CURL_VERSION_BROTLI),
#endif
+#if defined(CURLRES_ARES) && defined(CURLRES_THREADED)
+ FEATURE("c-ares-rr", NULL, 0),
+#endif
#ifdef DEBUGBUILD
FEATURE("Debug", NULL, CURL_VERSION_DEBUG),
#endif
#if defined(USE_SSL) && defined(USE_ECH)
FEATURE("ECH", ech_present, 0),
+
+#ifndef USE_HTTPSRR
+#error "ECH enabled but not HTTPSRR, must be a config error"
+#endif
#endif
#ifdef USE_GSASL
FEATURE("gsasl", NULL, CURL_VERSION_GSASL),
!defined(CURL_DISABLE_HTTP)
FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY),
#endif
+#if defined(USE_HTTPSRR)
+ FEATURE("HTTPSRR", NULL, 0),
+#endif
#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
FEATURE("IDN", idn_present, CURL_VERSION_IDN),
#endif
dnl -------------------------------------------------
dnl Verify if configure has been invoked with option
dnl --enable-threaded-resolver or --disable-threaded-resolver, and
-dnl set shell variable want_thres as appropriate.
+dnl set shell variable want_threaded_resolver as appropriate.
AC_DEFUN([CURL_CHECK_OPTION_THREADED_RESOLVER], [
AC_MSG_CHECKING([whether to enable the threaded resolver])
case "$OPT_THRES" in
no)
dnl --disable-threaded-resolver option used
- want_thres="no"
+ want_threaded_resolver="no"
;;
yes)
dnl --enable-threaded-resolver option used
- want_thres="yes"
+ want_threaded_resolver="yes"
;;
*)
dnl configure option not specified
case $host_os in
msdos* | amiga*)
- want_thres="no"
+ want_threaded_resolver="no"
;;
*)
- want_thres="yes"
+ if test "$want_ares" = "yes"; then
+ want_threaded_resolver="no"
+ else
+ want_threaded_resolver="yes"
+ fi
;;
esac
;;
esac
- AC_MSG_RESULT([$want_thres])
+ AC_MSG_RESULT([$want_threaded_resolver])
])
dnl CURL_CHECK_OPTION_ARES
])
-dnl CURL_CHECK_OPTION_THREADS
-dnl -------------------------------------------------
-dnl Verify if configure has been invoked with option
-dnl --enable-threads or --disable-threads, and
-dnl set shell variable want_threads as appropriate.
-
-dnl AC_DEFUN([CURL_CHECK_OPTION_THREADS], [
-dnl AC_BEFORE([$0],[CURL_CHECK_LIB_THREADS])dnl
-dnl AC_MSG_CHECKING([whether to enable threads for DNS lookups])
-dnl OPT_THREADS="default"
-dnl AC_ARG_ENABLE(threads,
-dnl AS_HELP_STRING([--enable-threads@<:@=PATH@:>@],[Enable threads for DNS lookups])
-dnl AS_HELP_STRING([--disable-threads],[Disable threads for DNS lookups]),
-dnl OPT_THREADS=$enableval)
-dnl case "$OPT_THREADS" in
-dnl no)
-dnl dnl --disable-threads option used
-dnl want_threads="no"
-dnl AC_MSG_RESULT([no])
-dnl ;;
-dnl default)
-dnl dnl configure option not specified
-dnl want_threads="no"
-dnl AC_MSG_RESULT([(assumed) no])
-dnl ;;
-dnl *)
-dnl dnl --enable-threads option used
-dnl want_threads="yes"
-dnl want_threads_path="$enableval"
-dnl AC_MSG_RESULT([yes])
-dnl ;;
-dnl esac
-dnl #
-dnl if test "$want_ares" = "assume_yes"; then
-dnl if test "$want_threads" = "yes"; then
-dnl AC_MSG_CHECKING([whether to ignore c-ares enabling assumed setting])
-dnl AC_MSG_RESULT([yes])
-dnl want_ares="no"
-dnl else
-dnl want_ares="yes"
-dnl fi
-dnl fi
-dnl if test "$want_threads" = "yes" && test "$want_ares" = "yes"; then
-dnl AC_MSG_ERROR([options --enable-ares and --enable-threads are mutually exclusive, at most one may be enabled.])
-dnl fi
-dnl ])
-
dnl CURL_CHECK_OPTION_RT
dnl -------------------------------------------------
dnl Verify if configure has been invoked with option
*)
dnl --enable-httpsrr option used
want_httpsrr="yes"
- curl_httpsrr_msg="enabled (--disable-httpsrr)"
+ curl_httpsrr_msg="enabled"
AC_MSG_RESULT([yes])
;;
esac
- `AppleIDN`
- `bearssl`
- `brotli`
-- `c-ares`
+- `c-ares` - c-ares is used for (all) name resolves
+- `c-ares-rr` - c-ares is used for additional records only
- `CharConv`
- `codeset-utf8`. If the running codeset is UTF-8 capable.
- `cookies`
# Verify data after the test has been "shot"
<verify>
<postcheck>
-%SRCDIR/libtest/test1013.pl ../curl-config %LOGDIR/stdout%TESTNUMBER features
+%SRCDIR/libtest/test1013.pl ../curl-config %LOGDIR/stdout%TESTNUMBER features > %LOGDIR/result%TESTNUMBER
</postcheck>
<errorcode>
0
CURLcode test(char *URL)
{
(void)URL;
- return 0;
+ return CURLE_OK;
}
#endif
$feature{"Unicode"} = $feat =~ /Unicode/i;
# Thread-safe init
$feature{"threadsafe"} = $feat =~ /threadsafe/i;
+ $feature{"HTTPSRR"} = $feat =~ /HTTPSRR/;
+ $feature{"c-ares-rr"} = $feat =~ /c-ares-rr/;
}
#
# Test harness currently uses a non-stunnel server in order to
$feature{"large-time"} = 1;
$feature{"large-size"} = 1;
$feature{"sha512-256"} = 1;
- $feature{"HTTPSRR"} = 1;
$feature{"local-http"} = servers::localhttp();
$feature{"codeset-utf8"} = lc(langinfo(CODESET())) eq "utf-8";
#ifndef CURL_CA_SEARCH_SAFE
"win32-ca-search-safe",
#endif
-#endif
-#ifndef USE_HTTPSRR
- "HTTPSRR",
#endif
NULL
};