mirror of
https://github.com/moparisthebest/curl
synced 2024-12-23 08:38:49 -05:00
alt-svc: the libcurl bits
This commit is contained in:
parent
4331a3b8fa
commit
e1be825453
76
configure.ac
76
configure.ac
@ -2696,7 +2696,7 @@ AC_ARG_WITH(libpsl,
|
|||||||
with_libpsl=yes)
|
with_libpsl=yes)
|
||||||
if test $with_libpsl != "no"; then
|
if test $with_libpsl != "no"; then
|
||||||
AC_SEARCH_LIBS(psl_builtin, psl,
|
AC_SEARCH_LIBS(psl_builtin, psl,
|
||||||
[curl_psl_msg="yes";
|
[curl_psl_msg="enabled";
|
||||||
AC_DEFINE([USE_LIBPSL], [1], [PSL support enabled])
|
AC_DEFINE([USE_LIBPSL], [1], [PSL support enabled])
|
||||||
],
|
],
|
||||||
[curl_psl_msg="no (libpsl not found)";
|
[curl_psl_msg="no (libpsl not found)";
|
||||||
@ -2704,7 +2704,7 @@ if test $with_libpsl != "no"; then
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL([USE_LIBPSL], [test "$curl_psl_msg" = "yes"])
|
AM_CONDITIONAL([USE_LIBPSL], [test "$curl_psl_msg" = "enabled"])
|
||||||
|
|
||||||
dnl **********************************************************************
|
dnl **********************************************************************
|
||||||
dnl Check for libmetalink
|
dnl Check for libmetalink
|
||||||
@ -4062,6 +4062,32 @@ AC_HELP_STRING([--disable-cookies],[Disable cookies support]),
|
|||||||
AC_MSG_RESULT(yes)
|
AC_MSG_RESULT(yes)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
dnl ************************************************************
|
||||||
|
dnl switch on/off alt-svc
|
||||||
|
dnl
|
||||||
|
curl_altsvc_msg="no (--enable-alt-svc)";
|
||||||
|
AC_MSG_CHECKING([whether to support alt-svc])
|
||||||
|
AC_ARG_ENABLE(alt-svc,
|
||||||
|
AC_HELP_STRING([--enable-alt-svc],[Enable alt-svc support])
|
||||||
|
AC_HELP_STRING([--disable-alt-svc],[Disable alt-svc support]),
|
||||||
|
[ case "$enableval" in
|
||||||
|
no)
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
;;
|
||||||
|
*) AC_MSG_RESULT(yes)
|
||||||
|
curl_altsvc_msg="enabled";
|
||||||
|
enable_altsvc="yes"
|
||||||
|
experimental="alt-svc"
|
||||||
|
;;
|
||||||
|
esac ],
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
)
|
||||||
|
|
||||||
|
if test "$enable_altsvc" = "yes"; then
|
||||||
|
AC_DEFINE(USE_ALTSVC, 1, [to enable alt-svc])
|
||||||
|
experimental="alt-svc"
|
||||||
|
fi
|
||||||
|
|
||||||
dnl ************************************************************
|
dnl ************************************************************
|
||||||
dnl hiding of library internal symbols
|
dnl hiding of library internal symbols
|
||||||
dnl
|
dnl
|
||||||
@ -4131,10 +4157,14 @@ if test "x$HAVE_GSSAPI" = "x1"; then
|
|||||||
SUPPORT_FEATURES="$SUPPORT_FEATURES GSS-API"
|
SUPPORT_FEATURES="$SUPPORT_FEATURES GSS-API"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "x$curl_psl_msg" = "xyes"; then
|
if test "x$curl_psl_msg" = "xenabled"; then
|
||||||
SUPPORT_FEATURES="$SUPPORT_FEATURES PSL"
|
SUPPORT_FEATURES="$SUPPORT_FEATURES PSL"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "x$enable_altsvc" = "xyes"; then
|
||||||
|
SUPPORT_FEATURES="$SUPPORT_FEATURES alt-svc"
|
||||||
|
fi
|
||||||
|
|
||||||
if test "x$CURL_DISABLE_CRYPTO_AUTH" != "x1" -a \
|
if test "x$CURL_DISABLE_CRYPTO_AUTH" != "x1" -a \
|
||||||
\( "x$HAVE_GSSAPI" = "x1" -o "x$USE_WINDOWS_SSPI" = "x1" \); then
|
\( "x$HAVE_GSSAPI" = "x1" -o "x$USE_WINDOWS_SSPI" = "x1" \); then
|
||||||
SUPPORT_FEATURES="$SUPPORT_FEATURES SPNEGO"
|
SUPPORT_FEATURES="$SUPPORT_FEATURES SPNEGO"
|
||||||
@ -4330,32 +4360,38 @@ AC_MSG_NOTICE([Configured to build curl/libcurl:
|
|||||||
LIBS: ${LIBS}
|
LIBS: ${LIBS}
|
||||||
|
|
||||||
curl version: ${CURLVERSION}
|
curl version: ${CURLVERSION}
|
||||||
SSL support: ${curl_ssl_msg}
|
SSL: ${curl_ssl_msg}
|
||||||
SSH support: ${curl_ssh_msg}
|
SSH: ${curl_ssh_msg}
|
||||||
zlib support: ${curl_zlib_msg}
|
zlib: ${curl_zlib_msg}
|
||||||
brotli support: ${curl_brotli_msg}
|
brotli: ${curl_brotli_msg}
|
||||||
GSS-API support: ${curl_gss_msg}
|
GSS-API: ${curl_gss_msg}
|
||||||
TLS-SRP support: ${curl_tls_srp_msg}
|
TLS-SRP: ${curl_tls_srp_msg}
|
||||||
resolver: ${curl_res_msg}
|
resolver: ${curl_res_msg}
|
||||||
IPv6 support: ${curl_ipv6_msg}
|
IPv6: ${curl_ipv6_msg}
|
||||||
Unix sockets support: ${curl_unix_sockets_msg}
|
Unix sockets: ${curl_unix_sockets_msg}
|
||||||
IDN support: ${curl_idn_msg}
|
IDN: ${curl_idn_msg}
|
||||||
Build libcurl: Shared=${enable_shared}, Static=${enable_static}
|
Build libcurl: Shared=${enable_shared}, Static=${enable_static}
|
||||||
Built-in manual: ${curl_manual_msg}
|
Built-in manual: ${curl_manual_msg}
|
||||||
--libcurl option: ${curl_libcurl_msg}
|
--libcurl option: ${curl_libcurl_msg}
|
||||||
Verbose errors: ${curl_verbose_msg}
|
Verbose errors: ${curl_verbose_msg}
|
||||||
Code coverage: ${curl_coverage_msg}
|
Code coverage: ${curl_coverage_msg}
|
||||||
SSPI support: ${curl_sspi_msg}
|
SSPI: ${curl_sspi_msg}
|
||||||
ca cert bundle: ${ca}${ca_warning}
|
ca cert bundle: ${ca}${ca_warning}
|
||||||
ca cert path: ${capath}${capath_warning}
|
ca cert path: ${capath}${capath_warning}
|
||||||
ca fallback: ${with_ca_fallback}
|
ca fallback: ${with_ca_fallback}
|
||||||
LDAP support: ${curl_ldap_msg}
|
LDAP: ${curl_ldap_msg}
|
||||||
LDAPS support: ${curl_ldaps_msg}
|
LDAPS: ${curl_ldaps_msg}
|
||||||
RTSP support: ${curl_rtsp_msg}
|
RTSP: ${curl_rtsp_msg}
|
||||||
RTMP support: ${curl_rtmp_msg}
|
RTMP: ${curl_rtmp_msg}
|
||||||
metalink support: ${curl_mtlnk_msg}
|
Metalink: ${curl_mtlnk_msg}
|
||||||
PSL support: ${curl_psl_msg}
|
PSL: ${curl_psl_msg}
|
||||||
HTTP2 support: ${curl_h2_msg}
|
Alt-svc: ${curl_altsvc_msg}
|
||||||
|
HTTP2: ${curl_h2_msg}
|
||||||
Protocols: ${SUPPORT_PROTOCOLS}
|
Protocols: ${SUPPORT_PROTOCOLS}
|
||||||
Features: ${SUPPORT_FEATURES}
|
Features: ${SUPPORT_FEATURES}
|
||||||
])
|
])
|
||||||
|
if test -n "$experimental"; then
|
||||||
|
cat >&2 << _EOF
|
||||||
|
WARNING: $experimental is enabled but marked EXPERIMENTAL. Use with caution!
|
||||||
|
_EOF
|
||||||
|
fi
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
.\" * | (__| |_| | _ <| |___
|
.\" * | (__| |_| | _ <| |___
|
||||||
.\" * \___|\___/|_| \_\_____|
|
.\" * \___|\___/|_| \_\_____|
|
||||||
.\" *
|
.\" *
|
||||||
.\" * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
|
.\" * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
.\" *
|
.\" *
|
||||||
.\" * This software is licensed as described in the file COPYING, which
|
.\" * This software is licensed as described in the file COPYING, which
|
||||||
.\" * you should have received as part of this distribution. The terms
|
.\" * you should have received as part of this distribution. The terms
|
||||||
@ -313,6 +313,10 @@ File to write cookies to. See \fICURLOPT_COOKIEJAR(3)\fP
|
|||||||
Start a new cookie session. See \fICURLOPT_COOKIESESSION(3)\fP
|
Start a new cookie session. See \fICURLOPT_COOKIESESSION(3)\fP
|
||||||
.IP CURLOPT_COOKIELIST
|
.IP CURLOPT_COOKIELIST
|
||||||
Add or control cookies. See \fICURLOPT_COOKIELIST(3)\fP
|
Add or control cookies. See \fICURLOPT_COOKIELIST(3)\fP
|
||||||
|
.IP CURLOPT_ALTSVC
|
||||||
|
Specify the Alt-Svc: cache file name. See \fICURLOPT_ALTSVC(3)\fP
|
||||||
|
.IP CURLOPT_ALTSVC_CTRL
|
||||||
|
Enable and configure Alt-Svc: treatment. See \fICURLOPT_ALTSVC_CTRL(3)\fP
|
||||||
.IP CURLOPT_HTTPGET
|
.IP CURLOPT_HTTPGET
|
||||||
Do an HTTP GET request. See \fICURLOPT_HTTPGET(3)\fP
|
Do an HTTP GET request. See \fICURLOPT_HTTPGET(3)\fP
|
||||||
.IP CURLOPT_REQUEST_TARGET
|
.IP CURLOPT_REQUEST_TARGET
|
||||||
|
61
docs/libcurl/opts/CURLOPT_ALTSVC.3
Normal file
61
docs/libcurl/opts/CURLOPT_ALTSVC.3
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
.\" **************************************************************************
|
||||||
|
.\" * _ _ ____ _
|
||||||
|
.\" * Project ___| | | | _ \| |
|
||||||
|
.\" * / __| | | | |_) | |
|
||||||
|
.\" * | (__| |_| | _ <| |___
|
||||||
|
.\" * \___|\___/|_| \_\_____|
|
||||||
|
.\" *
|
||||||
|
.\" * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
|
.\" *
|
||||||
|
.\" * This software is licensed 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.
|
||||||
|
.\" *
|
||||||
|
.\" **************************************************************************
|
||||||
|
.\"
|
||||||
|
.TH CURLOPT_ALTSVC 3 "5 Feb 2019" "libcurl 7.64.1" "curl_easy_setopt options"
|
||||||
|
.SH NAME
|
||||||
|
CURLOPT_ALTSVC \- set alt-svc cache file name
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.nf
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ALTSVC, char *filename);
|
||||||
|
.fi
|
||||||
|
.SH EXPERIMENTAL
|
||||||
|
Warning: this feature is early code and is marked as experimental. It can only
|
||||||
|
be enabled by explictly telling configure with \fB--enable-alt-svc\fP. You are
|
||||||
|
advised to not ship this in production before the experimental label is
|
||||||
|
removed.
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Pass in a pointer to a \fIfilename\fP to instruct libcurl to use that file as
|
||||||
|
the Alt-Svc cache to read existing cache contents from and possibly also write
|
||||||
|
it back to a after a transfer, unless \fBCURLALTSVC_READONLYFILE\fP is set in
|
||||||
|
\fICURLOPT_ALTSVC_CTRL(3)\fP.
|
||||||
|
.SH DEFAULT
|
||||||
|
NULL. The alt-svc cache is not read nor written to file.
|
||||||
|
.SH PROTOCOLS
|
||||||
|
HTTPS
|
||||||
|
.SH EXAMPLE
|
||||||
|
.nf
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
if(curl) {
|
||||||
|
curl_easy_setopt(curl, CURLOPT_ALTSVC_CTRL, CURLALTSVC_H1);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_ALTSVC, "altsvc-cache.txt");
|
||||||
|
curl_easy_perform(curl);
|
||||||
|
}
|
||||||
|
.fi
|
||||||
|
.SH AVAILABILITY
|
||||||
|
Added in 7.64.1
|
||||||
|
.SH RETURN VALUE
|
||||||
|
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR CURLOPT_ALTSVC_CTRL "(3), " CURLOPT_CONNECT_TO "(3), " CURLOPT_RESOLVE "(3), "
|
||||||
|
.BR CURLOPT_COOKIEFILE "(3), "
|
92
docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.3
Normal file
92
docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.3
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
.\" **************************************************************************
|
||||||
|
.\" * _ _ ____ _
|
||||||
|
.\" * Project ___| | | | _ \| |
|
||||||
|
.\" * / __| | | | |_) | |
|
||||||
|
.\" * | (__| |_| | _ <| |___
|
||||||
|
.\" * \___|\___/|_| \_\_____|
|
||||||
|
.\" *
|
||||||
|
.\" * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
|
.\" *
|
||||||
|
.\" * This software is licensed 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.
|
||||||
|
.\" *
|
||||||
|
.\" **************************************************************************
|
||||||
|
.\"
|
||||||
|
.TH CURLOPT_ALTSVC_CTRL 3 "5 Feb 2019" "libcurl 7.64.1" "curl_easy_setopt options"
|
||||||
|
.SH NAME
|
||||||
|
CURLOPT_ALTSVC_CTRL \- control alt-svc behavior
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.nf
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
#define CURLALTSVC_IMMEDIATELY (1<<0)
|
||||||
|
#define CURLALTSVC_ALTUSED (1<<1)
|
||||||
|
#define CURLALTSVC_READONLYFILE (1<<2)
|
||||||
|
#define CURLALTSVC_H1 (1<<3)
|
||||||
|
#define CURLALTSVC_H2 (1<<4)
|
||||||
|
#define CURLALTSVC_H3 (1<<5)
|
||||||
|
|
||||||
|
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ALTSVC_CTRL, long bitmask);
|
||||||
|
.fi
|
||||||
|
.SH EXPERIMENTAL
|
||||||
|
Warning: this feature is early code and is marked as experimental. It can only
|
||||||
|
be enabled by explictly telling configure with \fB--enable-alt-svc\fP. You are
|
||||||
|
advised to not ship this in production before the experimental label is
|
||||||
|
removed.
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Populate the long \fIbitmask\fP with the correct set of features to instruct
|
||||||
|
libcurl how to handle Alt-Svc for the transfers using this handle.
|
||||||
|
|
||||||
|
libcurl will only accept Alt-Svc headers over a secure transport, meaning
|
||||||
|
HTTPS. It will also only complete a request to an alternative origin if that
|
||||||
|
origin is properly hosted over HTTPS. These requirements are there to make
|
||||||
|
sure both the source and the destination are legitimate.
|
||||||
|
|
||||||
|
Setting any bit will enable the alt-svc engine.
|
||||||
|
.IP "CURLALTSVC_IMMEDIATELY"
|
||||||
|
If an Alt-Svc: header is received, this instructs libcurl to switch to one of
|
||||||
|
those alternatives asap rather than to save it and use for the next request.
|
||||||
|
.IP "CURLALTSVC_ALTUSED"
|
||||||
|
Issue the Alt-Used: header in all requests that have been redirected by
|
||||||
|
alt-svc.
|
||||||
|
.IP "CURLALTSVC_READONLYFILE"
|
||||||
|
Do not write the alt-svc cache back to the file specified with
|
||||||
|
\fICURLOPT_ALTSVC(3)\fP even if it gets updated. By default a file specified
|
||||||
|
with that option will be read and written to as deemed necessary.
|
||||||
|
.IP "CURLALTSVC_H1"
|
||||||
|
Accept alternative services offered over HTTP/1.1.
|
||||||
|
.IP "CURLALTSVC_H2"
|
||||||
|
Accept alternative services offered over HTTP/2. This will only be used if
|
||||||
|
libcurl was also built to actually support HTTP/2, otherwise this bit will be
|
||||||
|
ignored.
|
||||||
|
.IP "CURLALTSVC_H3"
|
||||||
|
Accept alternative services offered over HTTP/3. This will only be used if
|
||||||
|
libcurl was also built to actually support HTTP/3, otherwise this bit will be
|
||||||
|
ignored.
|
||||||
|
.SH DEFAULT
|
||||||
|
0. No Alt-Svc treatment.
|
||||||
|
.SH PROTOCOLS
|
||||||
|
HTTPS
|
||||||
|
.SH EXAMPLE
|
||||||
|
.nf
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
if(curl) {
|
||||||
|
curl_easy_setopt(curl, CURLOPT_ALTSVC_CTRL, CURLALTSVC_H1);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_ALTSVC, "altsvc-cache.txt");
|
||||||
|
curl_easy_perform(curl);
|
||||||
|
}
|
||||||
|
.fi
|
||||||
|
.SH AVAILABILITY
|
||||||
|
Added in 7.64.1
|
||||||
|
.SH RETURN VALUE
|
||||||
|
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR CURLOPT_ALTSVC "(3), " CURLOPT_CONNECT_TO "(3), " CURLOPT_RESOLVE "(3), "
|
@ -83,6 +83,8 @@ man_MANS = \
|
|||||||
CURLOPT_ACCEPTTIMEOUT_MS.3 \
|
CURLOPT_ACCEPTTIMEOUT_MS.3 \
|
||||||
CURLOPT_ACCEPT_ENCODING.3 \
|
CURLOPT_ACCEPT_ENCODING.3 \
|
||||||
CURLOPT_ADDRESS_SCOPE.3 \
|
CURLOPT_ADDRESS_SCOPE.3 \
|
||||||
|
CURLOPT_ALTSVC.3 \
|
||||||
|
CURLOPT_ALTSVC_CTRL.3 \
|
||||||
CURLOPT_APPEND.3 \
|
CURLOPT_APPEND.3 \
|
||||||
CURLOPT_AUTOREFERER.3 \
|
CURLOPT_AUTOREFERER.3 \
|
||||||
CURLOPT_BUFFERSIZE.3 \
|
CURLOPT_BUFFERSIZE.3 \
|
||||||
|
@ -12,6 +12,12 @@
|
|||||||
|
|
||||||
Name Introduced Deprecated Removed
|
Name Introduced Deprecated Removed
|
||||||
|
|
||||||
|
CURLALTSVC_ALTUSED 7.64.1
|
||||||
|
CURLALTSVC_H1 7.64.1
|
||||||
|
CURLALTSVC_H2 7.64.1
|
||||||
|
CURLALTSVC_H3 7.64.1
|
||||||
|
CURLALTSVC_IMMEDIATELY 7.64.1
|
||||||
|
CURLALTSVC_READONLYFILE 7.64.1
|
||||||
CURLAUTH_ANY 7.10.6
|
CURLAUTH_ANY 7.10.6
|
||||||
CURLAUTH_ANYSAFE 7.10.6
|
CURLAUTH_ANYSAFE 7.10.6
|
||||||
CURLAUTH_BASIC 7.10.6
|
CURLAUTH_BASIC 7.10.6
|
||||||
@ -343,6 +349,8 @@ CURLOPT_ABSTRACT_UNIX_SOCKET 7.53.0
|
|||||||
CURLOPT_ACCEPTTIMEOUT_MS 7.24.0
|
CURLOPT_ACCEPTTIMEOUT_MS 7.24.0
|
||||||
CURLOPT_ACCEPT_ENCODING 7.21.6
|
CURLOPT_ACCEPT_ENCODING 7.21.6
|
||||||
CURLOPT_ADDRESS_SCOPE 7.19.0
|
CURLOPT_ADDRESS_SCOPE 7.19.0
|
||||||
|
CURLOPT_ALTSVC 7.64.1
|
||||||
|
CURLOPT_ALTSVC_CTRL 7.64.1
|
||||||
CURLOPT_APPEND 7.17.0
|
CURLOPT_APPEND 7.17.0
|
||||||
CURLOPT_AUTOREFERER 7.1
|
CURLOPT_AUTOREFERER 7.1
|
||||||
CURLOPT_BUFFERSIZE 7.10
|
CURLOPT_BUFFERSIZE 7.10
|
||||||
@ -432,8 +440,6 @@ CURLOPT_HTTPREQUEST 7.1 - 7.15.5
|
|||||||
CURLOPT_HTTP_CONTENT_DECODING 7.16.2
|
CURLOPT_HTTP_CONTENT_DECODING 7.16.2
|
||||||
CURLOPT_HTTP_TRANSFER_DECODING 7.16.2
|
CURLOPT_HTTP_TRANSFER_DECODING 7.16.2
|
||||||
CURLOPT_HTTP_VERSION 7.9.1
|
CURLOPT_HTTP_VERSION 7.9.1
|
||||||
CURLOPT_TRAILERFUNCTION 7.64.0
|
|
||||||
CURLOPT_TRAILERDATA 7.64.0
|
|
||||||
CURLOPT_IGNORE_CONTENT_LENGTH 7.14.1
|
CURLOPT_IGNORE_CONTENT_LENGTH 7.14.1
|
||||||
CURLOPT_INFILE 7.1 7.9.7
|
CURLOPT_INFILE 7.1 7.9.7
|
||||||
CURLOPT_INFILESIZE 7.1
|
CURLOPT_INFILESIZE 7.1
|
||||||
@ -615,6 +621,8 @@ CURLOPT_TLS13_CIPHERS 7.61.0
|
|||||||
CURLOPT_TLSAUTH_PASSWORD 7.21.4
|
CURLOPT_TLSAUTH_PASSWORD 7.21.4
|
||||||
CURLOPT_TLSAUTH_TYPE 7.21.4
|
CURLOPT_TLSAUTH_TYPE 7.21.4
|
||||||
CURLOPT_TLSAUTH_USERNAME 7.21.4
|
CURLOPT_TLSAUTH_USERNAME 7.21.4
|
||||||
|
CURLOPT_TRAILERDATA 7.64.0
|
||||||
|
CURLOPT_TRAILERFUNCTION 7.64.0
|
||||||
CURLOPT_TRANSFERTEXT 7.1.1
|
CURLOPT_TRANSFERTEXT 7.1.1
|
||||||
CURLOPT_TRANSFER_ENCODING 7.21.6
|
CURLOPT_TRANSFER_ENCODING 7.21.6
|
||||||
CURLOPT_UNIX_SOCKET_PATH 7.40.0
|
CURLOPT_UNIX_SOCKET_PATH 7.40.0
|
||||||
@ -855,8 +863,6 @@ CURL_PUSH_DENY 7.44.0
|
|||||||
CURL_PUSH_OK 7.44.0
|
CURL_PUSH_OK 7.44.0
|
||||||
CURL_READFUNC_ABORT 7.12.1
|
CURL_READFUNC_ABORT 7.12.1
|
||||||
CURL_READFUNC_PAUSE 7.18.0
|
CURL_READFUNC_PAUSE 7.18.0
|
||||||
CURL_TRAILERFUNC_OK 7.64.0
|
|
||||||
CURL_TRAILERFUNC_ABORT 7.64.0
|
|
||||||
CURL_REDIR_GET_ALL 7.19.1
|
CURL_REDIR_GET_ALL 7.19.1
|
||||||
CURL_REDIR_POST_301 7.19.1
|
CURL_REDIR_POST_301 7.19.1
|
||||||
CURL_REDIR_POST_302 7.19.1
|
CURL_REDIR_POST_302 7.19.1
|
||||||
@ -903,7 +909,10 @@ CURL_TIMECOND_LASTMOD 7.9.7
|
|||||||
CURL_TIMECOND_NONE 7.9.7
|
CURL_TIMECOND_NONE 7.9.7
|
||||||
CURL_TLSAUTH_NONE 7.21.4
|
CURL_TLSAUTH_NONE 7.21.4
|
||||||
CURL_TLSAUTH_SRP 7.21.4
|
CURL_TLSAUTH_SRP 7.21.4
|
||||||
|
CURL_TRAILERFUNC_ABORT 7.64.0
|
||||||
|
CURL_TRAILERFUNC_OK 7.64.0
|
||||||
CURL_UPKEEP_INTERVAL_DEFAULT 7.62.0
|
CURL_UPKEEP_INTERVAL_DEFAULT 7.62.0
|
||||||
|
CURL_VERSION_ALTSVC 7.64.1
|
||||||
CURL_VERSION_ASYNCHDNS 7.10.7
|
CURL_VERSION_ASYNCHDNS 7.10.7
|
||||||
CURL_VERSION_BROTLI 7.57.0
|
CURL_VERSION_BROTLI 7.57.0
|
||||||
CURL_VERSION_CONV 7.15.4
|
CURL_VERSION_CONV 7.15.4
|
||||||
|
@ -881,6 +881,14 @@ typedef enum {
|
|||||||
#define CURLHEADER_UNIFIED 0
|
#define CURLHEADER_UNIFIED 0
|
||||||
#define CURLHEADER_SEPARATE (1<<0)
|
#define CURLHEADER_SEPARATE (1<<0)
|
||||||
|
|
||||||
|
/* CURLALTSVC_* are bits for the CURLOPT_ALTSVC_CTRL option */
|
||||||
|
#define CURLALTSVC_IMMEDIATELY (1<<0)
|
||||||
|
#define CURLALTSVC_ALTUSED (1<<1)
|
||||||
|
#define CURLALTSVC_READONLYFILE (1<<2)
|
||||||
|
#define CURLALTSVC_H1 (1<<3)
|
||||||
|
#define CURLALTSVC_H2 (1<<4)
|
||||||
|
#define CURLALTSVC_H3 (1<<5)
|
||||||
|
|
||||||
/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
|
/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
|
||||||
#define CURLPROTO_HTTP (1<<0)
|
#define CURLPROTO_HTTP (1<<0)
|
||||||
#define CURLPROTO_HTTPS (1<<1)
|
#define CURLPROTO_HTTPS (1<<1)
|
||||||
@ -1904,6 +1912,12 @@ typedef enum {
|
|||||||
/* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */
|
/* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */
|
||||||
CINIT(HTTP09_ALLOWED, LONG, 285),
|
CINIT(HTTP09_ALLOWED, LONG, 285),
|
||||||
|
|
||||||
|
/* alt-svc control bitmask */
|
||||||
|
CINIT(ALTSVC_CTRL, LONG, 286),
|
||||||
|
|
||||||
|
/* alt-svc cache file name to possibly read from/write to */
|
||||||
|
CINIT(ALTSVC, STRINGPOINT, 287),
|
||||||
|
|
||||||
CURLOPT_LASTENTRY /* the last unused */
|
CURLOPT_LASTENTRY /* the last unused */
|
||||||
} CURLoption;
|
} CURLoption;
|
||||||
|
|
||||||
@ -2766,6 +2780,7 @@ typedef struct {
|
|||||||
#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */
|
#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_MULTI_SSL (1<<22) /* Multiple SSL backends available */
|
||||||
#define CURL_VERSION_BROTLI (1<<23) /* Brotli features are present. */
|
#define CURL_VERSION_BROTLI (1<<23) /* Brotli features are present. */
|
||||||
|
#define CURL_VERSION_ALTSVC (1<<24) /* Alt-Svc handling built-in */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NAME curl_version_info()
|
* NAME curl_version_info()
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@ -256,6 +256,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
|
|||||||
#define _curl_is_string_option(option) \
|
#define _curl_is_string_option(option) \
|
||||||
((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \
|
((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \
|
||||||
(option) == CURLOPT_ACCEPT_ENCODING || \
|
(option) == CURLOPT_ACCEPT_ENCODING || \
|
||||||
|
(option) == CURLOPT_ALTSVC || \
|
||||||
(option) == CURLOPT_CAINFO || \
|
(option) == CURLOPT_CAINFO || \
|
||||||
(option) == CURLOPT_CAPATH || \
|
(option) == CURLOPT_CAPATH || \
|
||||||
(option) == CURLOPT_COOKIE || \
|
(option) == CURLOPT_COOKIE || \
|
||||||
|
@ -55,7 +55,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
|
|||||||
curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \
|
curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \
|
||||||
x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \
|
x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \
|
||||||
mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \
|
mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \
|
||||||
doh.c urlapi.c
|
doh.c urlapi.c altsvc.c
|
||||||
|
|
||||||
LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
|
LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
|
||||||
formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \
|
formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \
|
||||||
@ -75,7 +75,8 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
|
|||||||
curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \
|
curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \
|
||||||
x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \
|
x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \
|
||||||
curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h \
|
curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h \
|
||||||
curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h
|
curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h \
|
||||||
|
altsvc.h
|
||||||
|
|
||||||
LIB_RCFILES = libcurl.rc
|
LIB_RCFILES = libcurl.rc
|
||||||
|
|
||||||
|
569
lib/altsvc.c
Normal file
569
lib/altsvc.c
Normal file
@ -0,0 +1,569 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
|
*
|
||||||
|
* This software is licensed 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.
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
/*
|
||||||
|
* The Alt-Svc: header is defined in RFC 7838:
|
||||||
|
* https://tools.ietf.org/html/rfc7838
|
||||||
|
*/
|
||||||
|
#include "curl_setup.h"
|
||||||
|
|
||||||
|
#if !defined(CURL_DISABLE_HTTP) && defined(USE_ALTSVC)
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include "urldata.h"
|
||||||
|
#include "altsvc.h"
|
||||||
|
#include "cookie.h" /* for Curl_get_line() */
|
||||||
|
#include "strcase.h"
|
||||||
|
#include "parsedate.h"
|
||||||
|
#include "sendf.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 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
|
||||||
|
|
||||||
|
static enum alpnid alpn2alpnid(char *name)
|
||||||
|
{
|
||||||
|
if(strcasecompare(name, "h1"))
|
||||||
|
return ALPN_h1;
|
||||||
|
if(strcasecompare(name, "h2"))
|
||||||
|
return ALPN_h2;
|
||||||
|
if(strcasecompare(name, "h2c"))
|
||||||
|
return ALPN_h2c;
|
||||||
|
if(strcasecompare(name, "h3"))
|
||||||
|
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_h2c:
|
||||||
|
return "h2c";
|
||||||
|
case ALPN_h3:
|
||||||
|
return "h3";
|
||||||
|
default:
|
||||||
|
return ""; /* bad */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void altsvc_free(struct altsvc *as)
|
||||||
|
{
|
||||||
|
free(as->srchost);
|
||||||
|
free(as->dsthost);
|
||||||
|
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(sizeof(struct altsvc), 1);
|
||||||
|
if(!as)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
as->srchost = strdup(srchost);
|
||||||
|
if(!as->srchost)
|
||||||
|
goto error;
|
||||||
|
as->dsthost = strdup(dsthost);
|
||||||
|
if(!as->dsthost)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
as->srcalpnid = srcalpnid;
|
||||||
|
as->dstalpnid = dstalpnid;
|
||||||
|
as->srcport = curlx_ultous(srcport);
|
||||||
|
as->dstport = 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(date, NULL);
|
||||||
|
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);
|
||||||
|
asi->num++; /* one more entry */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load alt-svc entries from the given file. The text based line-oriented file
|
||||||
|
* format is documented here:
|
||||||
|
* https://github.com/curl/curl/wiki/QUIC-implementation
|
||||||
|
*
|
||||||
|
* This function only returns error on major problems that prevents 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;
|
||||||
|
char *line = NULL;
|
||||||
|
FILE *fp = fopen(file, FOPEN_READTEXT);
|
||||||
|
if(fp) {
|
||||||
|
line = malloc(MAX_ALTSVC_LINE);
|
||||||
|
if(!line)
|
||||||
|
goto fail;
|
||||||
|
while(Curl_get_line(line, MAX_ALTSVC_LINE, fp)) {
|
||||||
|
char *lineptr = line;
|
||||||
|
while(*lineptr && ISBLANK(*lineptr))
|
||||||
|
lineptr++;
|
||||||
|
if(*lineptr == '#')
|
||||||
|
/* skip commented lines */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
altsvc_add(asi, lineptr);
|
||||||
|
}
|
||||||
|
free(line); /* free the line buffer */
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
free(line);
|
||||||
|
fclose(fp);
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write this single altsvc entry to a single output line
|
||||||
|
*/
|
||||||
|
|
||||||
|
static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
|
||||||
|
{
|
||||||
|
struct tm stamp;
|
||||||
|
Curl_gmtime(as->expires, &stamp);
|
||||||
|
|
||||||
|
fprintf(fp,
|
||||||
|
"%s %s %u "
|
||||||
|
"%s %s %u "
|
||||||
|
"\"%d%02d%02d "
|
||||||
|
"%02d:%02d:%02d\" "
|
||||||
|
"%u %d\n",
|
||||||
|
Curl_alpnid2str(as->srcalpnid), as->srchost, as->srcport,
|
||||||
|
Curl_alpnid2str(as->dstalpnid), as->dsthost, as->dstport,
|
||||||
|
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(sizeof(struct altsvcinfo), 1);
|
||||||
|
if(!asi)
|
||||||
|
return NULL;
|
||||||
|
Curl_llist_init(&asi->list, NULL);
|
||||||
|
|
||||||
|
/* set default behavior */
|
||||||
|
asi->flags = CURLALTSVC_H1
|
||||||
|
#ifdef USE_NGHTTP2
|
||||||
|
| CURLALTSVC_H2
|
||||||
|
#endif
|
||||||
|
#ifdef USE_HTTP3
|
||||||
|
/* TODO: adjust when known */
|
||||||
|
| 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);
|
||||||
|
if(!ctrl)
|
||||||
|
/* unexpected */
|
||||||
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
|
asi->flags = ctrl;
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curl_altsvc_cleanup() frees an altsvc cache instance and all associated
|
||||||
|
* resources.
|
||||||
|
*/
|
||||||
|
void Curl_altsvc_cleanup(struct altsvcinfo *altsvc)
|
||||||
|
{
|
||||||
|
struct curl_llist_element *e;
|
||||||
|
struct curl_llist_element *n;
|
||||||
|
if(altsvc) {
|
||||||
|
for(e = altsvc->list.head; e; e = n) {
|
||||||
|
struct altsvc *as = e->ptr;
|
||||||
|
n = e->next;
|
||||||
|
altsvc_free(as);
|
||||||
|
}
|
||||||
|
free(altsvc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curl_altsvc_save() writes the altsvc cache to a file.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_altsvc_save(struct altsvcinfo *altsvc, const char *file)
|
||||||
|
{
|
||||||
|
struct curl_llist_element *e;
|
||||||
|
struct curl_llist_element *n;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
FILE *out;
|
||||||
|
|
||||||
|
if(!altsvc)
|
||||||
|
/* no cache activated */
|
||||||
|
return CURLE_OK;
|
||||||
|
|
||||||
|
if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file[0])
|
||||||
|
/* marked as read-only or zero length file name */
|
||||||
|
return CURLE_OK;
|
||||||
|
out = fopen(file, FOPEN_WRITETEXT);
|
||||||
|
if(!out)
|
||||||
|
return CURLE_WRITE_ERROR;
|
||||||
|
fputs("# Your alt-svc cache. https://curl.haxx.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);
|
||||||
|
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 && ISALNUM(*p))
|
||||||
|
p++;
|
||||||
|
len = p - protop;
|
||||||
|
|
||||||
|
if(!len || (len >= buflen))
|
||||||
|
return CURLE_BAD_FUNCTION_ARGUMENT; /* TODO: improve error code */
|
||||||
|
memcpy(alpnbuf, protop, len);
|
||||||
|
alpnbuf[len] = 0;
|
||||||
|
*ptr = p;
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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->srcalpnid) &&
|
||||||
|
(srcport == as->srcport) &&
|
||||||
|
strcasecompare(srchost, as->srchost)) {
|
||||||
|
Curl_llist_remove(&asi->list, e, NULL);
|
||||||
|
altsvc_free(as);
|
||||||
|
asi->num--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUGBUILD
|
||||||
|
/* to play well with debug builds, we can *set* a fixed time this will
|
||||||
|
return */
|
||||||
|
static time_t 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);
|
||||||
|
}
|
||||||
|
#define time(x) debugtime(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
enum alpnid dstalpnid = srcalpnid; /* the same by default */
|
||||||
|
char namebuf[MAX_ALTSVC_HOSTLEN] = "";
|
||||||
|
char alpnbuf[MAX_ALTSVC_ALPNLEN] = "";
|
||||||
|
struct altsvc *as;
|
||||||
|
unsigned short dstport = srcport; /* the same by default */
|
||||||
|
const char *semip;
|
||||||
|
time_t maxage = 24 * 3600; /* default is 24 hours */
|
||||||
|
bool persist = FALSE;
|
||||||
|
CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
DEBUGASSERT(asi);
|
||||||
|
|
||||||
|
/* Flush all cached alternatives for this source origin, if any */
|
||||||
|
altsvc_flush(asi, srcalpnid, srchost, srcport);
|
||||||
|
|
||||||
|
/* "clear" is a magic keyword */
|
||||||
|
if(strcasecompare(alpnbuf, "clear")) {
|
||||||
|
/* TODO: clear whatever it is it should clear */
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The 'ma' and 'persist' flags are annoyingly meant for all alternatives
|
||||||
|
but are set after the list on the line. Scan for the semicolons and get
|
||||||
|
those fields first! */
|
||||||
|
semip = p;
|
||||||
|
do {
|
||||||
|
semip = strchr(semip, ';');
|
||||||
|
if(semip) {
|
||||||
|
char option[32];
|
||||||
|
unsigned long num;
|
||||||
|
char *end_ptr;
|
||||||
|
semip++; /* pass the semicolon */
|
||||||
|
result = getalnum(&semip, option, sizeof(option));
|
||||||
|
if(result)
|
||||||
|
break;
|
||||||
|
while(*semip && ISBLANK(*semip))
|
||||||
|
semip++;
|
||||||
|
if(*semip != '=')
|
||||||
|
continue;
|
||||||
|
semip++;
|
||||||
|
num = strtoul(semip, &end_ptr, 10);
|
||||||
|
if(num < ULONG_MAX) {
|
||||||
|
if(strcasecompare("ma", option))
|
||||||
|
maxage = num;
|
||||||
|
else if(strcasecompare("persist", option) && (num == 1))
|
||||||
|
persist = TRUE;
|
||||||
|
}
|
||||||
|
semip = end_ptr;
|
||||||
|
}
|
||||||
|
} while(semip);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(*p == '=') {
|
||||||
|
/* [protocol]="[host][:port]" */
|
||||||
|
dstalpnid = alpn2alpnid(alpnbuf);
|
||||||
|
if(!dstalpnid) {
|
||||||
|
infof(data, "Unknown alt-svc protocol \"%s\", ignoring...\n", alpnbuf);
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
if(*p == '\"') {
|
||||||
|
const char *dsthost;
|
||||||
|
p++;
|
||||||
|
if(*p != ':') {
|
||||||
|
/* host name starts here */
|
||||||
|
const char *hostp = p;
|
||||||
|
while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
|
||||||
|
p++;
|
||||||
|
len = p - hostp;
|
||||||
|
if(!len || (len >= MAX_ALTSVC_HOSTLEN))
|
||||||
|
return CURLE_BAD_FUNCTION_ARGUMENT; /* TODO: improve error code */
|
||||||
|
memcpy(namebuf, hostp, len);
|
||||||
|
namebuf[len] = 0;
|
||||||
|
dsthost = namebuf;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* no destination name, use source host */
|
||||||
|
dsthost = srchost;
|
||||||
|
}
|
||||||
|
if(*p == ':') {
|
||||||
|
/* a port number */
|
||||||
|
char *end_ptr;
|
||||||
|
unsigned long port = strtoul(++p, &end_ptr, 10);
|
||||||
|
if(port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
|
||||||
|
infof(data, "Unknown alt-svc port number, ignoring...\n");
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
p = end_ptr;
|
||||||
|
dstport = curlx_ultous(port);
|
||||||
|
}
|
||||||
|
if(*p++ != '\"')
|
||||||
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
|
as = altsvc_createid(srchost, dsthost,
|
||||||
|
srcalpnid, dstalpnid,
|
||||||
|
srcport, dstport);
|
||||||
|
if(as) {
|
||||||
|
/* TODO: 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);
|
||||||
|
asi->num++; /* one more entry */
|
||||||
|
infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport,
|
||||||
|
Curl_alpnid2str(dstalpnid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 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)
|
||||||
|
/* failed to parse, but since we alredy did at least one host we
|
||||||
|
return OK */
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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,
|
||||||
|
enum alpnid *dstalpnid, const char **dsthost,
|
||||||
|
int *dstport)
|
||||||
|
{
|
||||||
|
struct curl_llist_element *e;
|
||||||
|
struct curl_llist_element *n;
|
||||||
|
time_t now = time(NULL);
|
||||||
|
DEBUGASSERT(asi);
|
||||||
|
DEBUGASSERT(srchost);
|
||||||
|
DEBUGASSERT(dsthost);
|
||||||
|
|
||||||
|
for(e = asi->list.head; e; e = n) {
|
||||||
|
struct altsvc *as = e->ptr;
|
||||||
|
n = e->next;
|
||||||
|
if(as->expires < now) {
|
||||||
|
/* an expired entry, remove */
|
||||||
|
altsvc_free(as);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if((as->srcalpnid == srcalpnid) &&
|
||||||
|
strcasecompare(as->srchost, srchost) &&
|
||||||
|
as->srcport == srcport) {
|
||||||
|
/* match */
|
||||||
|
*dstalpnid = as->dstalpnid;
|
||||||
|
*dsthost = as->dsthost;
|
||||||
|
*dstport = as->dstport;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CURL_DISABLE_HTTP || USE_ALTSVC */
|
77
lib/altsvc.h
Normal file
77
lib/altsvc.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#ifndef HEADER_CURL_ALTSVC_H
|
||||||
|
#define HEADER_CURL_ALTSVC_H
|
||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
|
*
|
||||||
|
* This software is licensed 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.
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
#include "curl_setup.h"
|
||||||
|
|
||||||
|
#if !defined(CURL_DISABLE_HTTP) && defined(USE_ALTSVC)
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include "llist.h"
|
||||||
|
|
||||||
|
enum alpnid {
|
||||||
|
ALPN_none,
|
||||||
|
ALPN_h1,
|
||||||
|
ALPN_h2,
|
||||||
|
ALPN_h2c,
|
||||||
|
ALPN_h3
|
||||||
|
};
|
||||||
|
|
||||||
|
struct altsvc {
|
||||||
|
char *srchost;
|
||||||
|
char *dsthost;
|
||||||
|
unsigned short srcport;
|
||||||
|
unsigned short dstport;
|
||||||
|
enum alpnid srcalpnid;
|
||||||
|
enum alpnid dstalpnid;
|
||||||
|
time_t expires;
|
||||||
|
bool persist;
|
||||||
|
int prio;
|
||||||
|
struct curl_llist_element node;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct altsvcinfo {
|
||||||
|
char *filename;
|
||||||
|
struct curl_llist list; /* list of entries */
|
||||||
|
size_t num; /* number of alt-svc 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 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,
|
||||||
|
enum alpnid *dstalpnid, const char **dsthost,
|
||||||
|
int *dstport);
|
||||||
|
#else
|
||||||
|
/* disabled */
|
||||||
|
#define Curl_altsvc_save(a,b)
|
||||||
|
#endif /* CURL_DISABLE_HTTP || USE_ALTSVC */
|
||||||
|
#endif /* HEADER_CURL_ALTSVC_H */
|
@ -1092,7 +1092,7 @@ Curl_cookie_add(struct Curl_easy *data,
|
|||||||
* get_line() makes sure to only return complete whole lines that fit in 'len'
|
* get_line() makes sure to only return complete whole lines that fit in 'len'
|
||||||
* bytes and end with a newline.
|
* bytes and end with a newline.
|
||||||
*/
|
*/
|
||||||
static char *get_line(char *buf, int len, FILE *input)
|
char *Curl_get_line(char *buf, int len, FILE *input)
|
||||||
{
|
{
|
||||||
bool partial = FALSE;
|
bool partial = FALSE;
|
||||||
while(1) {
|
while(1) {
|
||||||
@ -1172,7 +1172,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
|
|||||||
line = malloc(MAX_COOKIE_LINE);
|
line = malloc(MAX_COOKIE_LINE);
|
||||||
if(!line)
|
if(!line)
|
||||||
goto fail;
|
goto fail;
|
||||||
while(get_line(line, MAX_COOKIE_LINE, fp)) {
|
while(Curl_get_line(line, MAX_COOKIE_LINE, fp)) {
|
||||||
if(checkprefix("Set-Cookie:", line)) {
|
if(checkprefix("Set-Cookie:", line)) {
|
||||||
/* This is a cookie line, get it! */
|
/* This is a cookie line, get it! */
|
||||||
lineptr = &line[11];
|
lineptr = &line[11];
|
||||||
|
@ -101,6 +101,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *,
|
|||||||
void Curl_cookie_freelist(struct Cookie *cookies);
|
void Curl_cookie_freelist(struct Cookie *cookies);
|
||||||
void Curl_cookie_clearall(struct CookieInfo *cookies);
|
void Curl_cookie_clearall(struct CookieInfo *cookies);
|
||||||
void Curl_cookie_clearsess(struct CookieInfo *cookies);
|
void Curl_cookie_clearsess(struct CookieInfo *cookies);
|
||||||
|
char *Curl_get_line(char *buf, int len, FILE *input);
|
||||||
|
|
||||||
#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES)
|
#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES)
|
||||||
#define Curl_cookie_list(x) NULL
|
#define Curl_cookie_list(x) NULL
|
||||||
|
15
lib/http.c
15
lib/http.c
@ -77,6 +77,7 @@
|
|||||||
#include "http2.h"
|
#include "http2.h"
|
||||||
#include "connect.h"
|
#include "connect.h"
|
||||||
#include "strdup.h"
|
#include "strdup.h"
|
||||||
|
#include "altsvc.h"
|
||||||
|
|
||||||
/* The last 3 #include files should be in this order */
|
/* The last 3 #include files should be in this order */
|
||||||
#include "curl_printf.h"
|
#include "curl_printf.h"
|
||||||
@ -3978,6 +3979,20 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef USE_ALTSVC
|
||||||
|
/* If enabled, the header is incoming and this is over HTTPS */
|
||||||
|
else if(data->asi && checkprefix("Alt-Svc:", k->p) &&
|
||||||
|
(conn->handler->flags & PROTOPT_SSL)) {
|
||||||
|
/* the ALPN of the current request */
|
||||||
|
enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
|
||||||
|
result = Curl_altsvc_parse(data, data->asi,
|
||||||
|
&k->p[ strlen("Alt-Svc:") ],
|
||||||
|
id, conn->host.name,
|
||||||
|
curlx_uitous(conn->remote_port));
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
else if(conn->handler->protocol & CURLPROTO_RTSP) {
|
else if(conn->handler->protocol & CURLPROTO_RTSP) {
|
||||||
result = Curl_rtsp_parseheader(conn, k->p);
|
result = Curl_rtsp_parseheader(conn, k->p);
|
||||||
if(result)
|
if(result)
|
||||||
|
26
lib/setopt.c
26
lib/setopt.c
@ -44,6 +44,7 @@
|
|||||||
#include "http2.h"
|
#include "http2.h"
|
||||||
#include "setopt.h"
|
#include "setopt.h"
|
||||||
#include "multiif.h"
|
#include "multiif.h"
|
||||||
|
#include "altsvc.h"
|
||||||
|
|
||||||
/* The last 3 #include files should be in this order */
|
/* The last 3 #include files should be in this order */
|
||||||
#include "curl_printf.h"
|
#include "curl_printf.h"
|
||||||
@ -2655,6 +2656,31 @@ static CURLcode vsetopt(struct Curl_easy *data, CURLoption option,
|
|||||||
data->set.trailer_data = va_arg(param, void *);
|
data->set.trailer_data = va_arg(param, void *);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
#ifdef USE_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;
|
||||||
|
(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);
|
||||||
|
result = Curl_altsvc_ctrl(data->asi, arg);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
/* unknown tag and its companion, just ignore: */
|
/* unknown tag and its companion, just ignore: */
|
||||||
result = CURLE_UNKNOWN_OPTION;
|
result = CURLE_UNKNOWN_OPTION;
|
||||||
|
34
lib/url.c
34
lib/url.c
@ -120,6 +120,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
|
|||||||
#include "dotdot.h"
|
#include "dotdot.h"
|
||||||
#include "strdup.h"
|
#include "strdup.h"
|
||||||
#include "setopt.h"
|
#include "setopt.h"
|
||||||
|
#include "altsvc.h"
|
||||||
|
|
||||||
/* The last 3 #include files should be in this order */
|
/* The last 3 #include files should be in this order */
|
||||||
#include "curl_printf.h"
|
#include "curl_printf.h"
|
||||||
@ -374,6 +375,11 @@ CURLcode Curl_close(struct Curl_easy *data)
|
|||||||
Curl_safefree(data->state.headerbuff);
|
Curl_safefree(data->state.headerbuff);
|
||||||
Curl_safefree(data->state.ulbuf);
|
Curl_safefree(data->state.ulbuf);
|
||||||
Curl_flush_cookies(data, 1);
|
Curl_flush_cookies(data, 1);
|
||||||
|
#ifdef USE_ALTSVC
|
||||||
|
Curl_altsvc_save(data->asi, data->set.str[STRING_ALTSVC]);
|
||||||
|
Curl_altsvc_cleanup(data->asi);
|
||||||
|
data->asi = NULL;
|
||||||
|
#endif
|
||||||
Curl_digest_cleanup(data);
|
Curl_digest_cleanup(data);
|
||||||
Curl_safefree(data->info.contenttype);
|
Curl_safefree(data->info.contenttype);
|
||||||
Curl_safefree(data->info.wouldredirect);
|
Curl_safefree(data->info.wouldredirect);
|
||||||
@ -3368,6 +3374,34 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
|
|||||||
conn_to_host = conn_to_host->next;
|
conn_to_host = conn_to_host->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_ALTSVC
|
||||||
|
if(data->asi && !host && (port == -1) &&
|
||||||
|
(conn->handler->protocol == CURLPROTO_HTTPS)) {
|
||||||
|
/* no connect_to match, try alt-svc! */
|
||||||
|
const char *nhost;
|
||||||
|
int nport;
|
||||||
|
enum alpnid nalpnid;
|
||||||
|
bool hit;
|
||||||
|
host = conn->host.rawalloc;
|
||||||
|
hit = Curl_altsvc_lookup(data->asi,
|
||||||
|
ALPN_h1, host, conn->remote_port, /* from */
|
||||||
|
&nalpnid, &nhost, &nport /* to */);
|
||||||
|
if(hit) {
|
||||||
|
char *hostd = strdup((char *)nhost);
|
||||||
|
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 = nport;
|
||||||
|
conn->bits.conn_to_port = TRUE;
|
||||||
|
infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d\n",
|
||||||
|
Curl_alpnid2str(ALPN_h1), host, conn->remote_port,
|
||||||
|
Curl_alpnid2str(nalpnid), hostd, nport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1478,6 +1478,9 @@ enum dupstring {
|
|||||||
#endif
|
#endif
|
||||||
STRING_TARGET, /* CURLOPT_REQUEST_TARGET */
|
STRING_TARGET, /* CURLOPT_REQUEST_TARGET */
|
||||||
STRING_DOH, /* CURLOPT_DOH_URL */
|
STRING_DOH, /* CURLOPT_DOH_URL */
|
||||||
|
#ifdef USE_ALTSVC
|
||||||
|
STRING_ALTSVC, /* CURLOPT_ALTSVC */
|
||||||
|
#endif
|
||||||
/* -- end of zero-terminated strings -- */
|
/* -- end of zero-terminated strings -- */
|
||||||
|
|
||||||
STRING_LASTZEROTERMINATED,
|
STRING_LASTZEROTERMINATED,
|
||||||
@ -1794,6 +1797,9 @@ struct Curl_easy {
|
|||||||
NOTE that the 'cookie' field in the
|
NOTE that the 'cookie' field in the
|
||||||
UserDefined struct defines if the "engine"
|
UserDefined struct defines if the "engine"
|
||||||
is to be used or not. */
|
is to be used or not. */
|
||||||
|
#ifdef USE_ALTSVC
|
||||||
|
struct altsvcinfo *asi; /* the alt-svc cache */
|
||||||
|
#endif
|
||||||
struct Progress progress; /* for all the progress meter data */
|
struct Progress progress; /* for all the progress meter data */
|
||||||
struct UrlState state; /* struct for fields used for state info and
|
struct UrlState state; /* struct for fields used for state info and
|
||||||
other dynamic purposes */
|
other dynamic purposes */
|
||||||
|
@ -369,6 +369,9 @@ static curl_version_info_data version_info = {
|
|||||||
#endif
|
#endif
|
||||||
#if defined(HAVE_BROTLI)
|
#if defined(HAVE_BROTLI)
|
||||||
| CURL_VERSION_BROTLI
|
| CURL_VERSION_BROTLI
|
||||||
|
#endif
|
||||||
|
#if defined(USE_ALTSVC)
|
||||||
|
| CURL_VERSION_ALTSVC
|
||||||
#endif
|
#endif
|
||||||
,
|
,
|
||||||
NULL, /* ssl_version */
|
NULL, /* ssl_version */
|
||||||
|
@ -525,6 +525,7 @@ static const struct feat feats[] = {
|
|||||||
{"HTTPS-proxy", CURL_VERSION_HTTPS_PROXY},
|
{"HTTPS-proxy", CURL_VERSION_HTTPS_PROXY},
|
||||||
{"MultiSSL", CURL_VERSION_MULTI_SSL},
|
{"MultiSSL", CURL_VERSION_MULTI_SSL},
|
||||||
{"PSL", CURL_VERSION_PSL},
|
{"PSL", CURL_VERSION_PSL},
|
||||||
|
{"alt-svc", CURL_VERSION_ALTSVC},
|
||||||
};
|
};
|
||||||
|
|
||||||
void tool_help(void)
|
void tool_help(void)
|
||||||
|
@ -249,6 +249,7 @@ unittest
|
|||||||
unix-sockets
|
unix-sockets
|
||||||
WinSSL
|
WinSSL
|
||||||
ld_preload
|
ld_preload
|
||||||
|
alt-svc
|
||||||
|
|
||||||
as well as each protocol that curl supports. A protocol only needs to be
|
as well as each protocol that curl supports. A protocol only needs to be
|
||||||
specified if it is different from the server (useful when the server
|
specified if it is different from the server (useful when the server
|
||||||
|
@ -183,7 +183,7 @@ test1590 test1591 test1592 \
|
|||||||
test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 \
|
test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 \
|
||||||
test1608 test1609 test1620 test1621 \
|
test1608 test1609 test1620 test1621 \
|
||||||
\
|
\
|
||||||
test1650 test1651 test1652 test1653 \
|
test1650 test1651 test1652 test1653 test1654 \
|
||||||
\
|
\
|
||||||
test1700 test1701 test1702 \
|
test1700 test1701 test1702 \
|
||||||
\
|
\
|
||||||
|
57
tests/data/test1654
Normal file
57
tests/data/test1654
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<testcase>
|
||||||
|
<info>
|
||||||
|
<keywords>
|
||||||
|
unittest
|
||||||
|
alt-svc
|
||||||
|
altsvc
|
||||||
|
</keywords>
|
||||||
|
</info>
|
||||||
|
|
||||||
|
<client>
|
||||||
|
<server>
|
||||||
|
none
|
||||||
|
</server>
|
||||||
|
<features>
|
||||||
|
unittest
|
||||||
|
alt-svc
|
||||||
|
</features>
|
||||||
|
|
||||||
|
# This date is exactly "20190124 22:34:21" UTC
|
||||||
|
<setenv>
|
||||||
|
CURL_TIME=1548369261
|
||||||
|
</setenv>
|
||||||
|
<name>
|
||||||
|
alt-svc
|
||||||
|
</name>
|
||||||
|
<command>
|
||||||
|
log/1654
|
||||||
|
</command>
|
||||||
|
<tool>
|
||||||
|
unit1654
|
||||||
|
</tool>
|
||||||
|
<file name="log/1654" mode="text">
|
||||||
|
h2 example.com 443 h3 shiny.example.com 8443 "20191231 00:00:00" 0 1
|
||||||
|
# a comment
|
||||||
|
h2c example.com 443 h3 shiny.example.com 8443 "20291231 23:30:00" 0 1
|
||||||
|
h1 example.com 443 h3 shiny.example.com 8443 "20121231 00:00:01" 0 1
|
||||||
|
h3 example.com 443 h3 shiny.example.com 8443 "20131231 00:00:00" 0 1
|
||||||
|
# also a comment
|
||||||
|
bad example.com 443 h3 shiny.example.com 8443 "20191231 00:00:00" 0 1
|
||||||
|
rubbish
|
||||||
|
</file>
|
||||||
|
</client>
|
||||||
|
<verify>
|
||||||
|
<file name="log/1654-out" mode="text">
|
||||||
|
# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html
|
||||||
|
# This file was generated by libcurl! Edit at your own risk.
|
||||||
|
h2 example.com 443 h3 shiny.example.com 8443 "20191231 00:00:00" 0 1
|
||||||
|
h2c example.com 443 h3 shiny.example.com 8443 "20291231 23:30:00" 0 1
|
||||||
|
h1 example.com 443 h3 shiny.example.com 8443 "20121231 00:00:01" 0 1
|
||||||
|
h3 example.com 443 h3 shiny.example.com 8443 "20131231 00:00:00" 0 1
|
||||||
|
h1 example.org 8080 h2 example.com 8080 "20190125 22:34:21" 0 0
|
||||||
|
h1 2.example.org 8080 h3 2.example.org 8080 "20190125 22:34:21" 0 0
|
||||||
|
h1 3.example.org 8080 h2 example.com 8080 "20190125 22:34:21" 0 0
|
||||||
|
h1 3.example.org 8080 h3 yesyes.com 8080 "20190125 22:34:21" 0 0
|
||||||
|
h2c example.org 80 h2 example.com 443 "20190124 22:36:21" 0 0
|
||||||
|
</verify>
|
||||||
|
</testcase>
|
@ -233,6 +233,7 @@ my $has_crypto; # set if libcurl is built with cryptographic support
|
|||||||
my $has_cares; # set if built with c-ares
|
my $has_cares; # set if built with c-ares
|
||||||
my $has_threadedres;# set if built with threaded resolver
|
my $has_threadedres;# set if built with threaded resolver
|
||||||
my $has_psl; # set if libcurl is built with PSL support
|
my $has_psl; # set if libcurl is built with PSL support
|
||||||
|
my $has_altsvc; # set if libcurl is built with alt-svc support
|
||||||
my $has_ldpreload; # set if curl is built for systems supporting LD_PRELOAD
|
my $has_ldpreload; # set if curl is built for systems supporting LD_PRELOAD
|
||||||
my $has_multissl; # set if curl is build with MultiSSL support
|
my $has_multissl; # set if curl is build with MultiSSL support
|
||||||
my $has_manual; # set if curl is built with built-in manual
|
my $has_manual; # set if curl is built with built-in manual
|
||||||
@ -2838,6 +2839,10 @@ sub checksystem {
|
|||||||
# PSL enabled
|
# PSL enabled
|
||||||
$has_psl=1;
|
$has_psl=1;
|
||||||
}
|
}
|
||||||
|
if($feat =~ /alt-svc/i) {
|
||||||
|
# alt-svc enabled
|
||||||
|
$has_altsvc=1;
|
||||||
|
}
|
||||||
if($feat =~ /AsynchDNS/i) {
|
if($feat =~ /AsynchDNS/i) {
|
||||||
if(!$has_cares) {
|
if(!$has_cares) {
|
||||||
# this means threaded resolver
|
# this means threaded resolver
|
||||||
@ -3387,6 +3392,11 @@ sub singletest {
|
|||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elsif($1 eq "alt-svc") {
|
||||||
|
if($has_altsvc) {
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
}
|
||||||
elsif($1 eq "manual") {
|
elsif($1 eq "manual") {
|
||||||
if($has_manual) {
|
if($has_manual) {
|
||||||
next;
|
next;
|
||||||
|
@ -11,7 +11,7 @@ UNITPROGS = unit1300 unit1301 unit1302 unit1303 unit1304 unit1305 unit1307 \
|
|||||||
unit1399 \
|
unit1399 \
|
||||||
unit1600 unit1601 unit1602 unit1603 unit1604 unit1605 unit1606 unit1607 \
|
unit1600 unit1601 unit1602 unit1603 unit1604 unit1605 unit1606 unit1607 \
|
||||||
unit1608 unit1609 unit1620 unit1621 \
|
unit1608 unit1609 unit1620 unit1621 \
|
||||||
unit1650 unit1651 unit1652 unit1653
|
unit1650 unit1651 unit1652 unit1653 unit1654
|
||||||
|
|
||||||
unit1300_SOURCES = unit1300.c $(UNITFILES)
|
unit1300_SOURCES = unit1300.c $(UNITFILES)
|
||||||
unit1300_CPPFLAGS = $(AM_CPPFLAGS)
|
unit1300_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
@ -115,3 +115,6 @@ unit1652_CPPFLAGS = $(AM_CPPFLAGS)
|
|||||||
|
|
||||||
unit1653_SOURCES = unit1653.c $(UNITFILES)
|
unit1653_SOURCES = unit1653.c $(UNITFILES)
|
||||||
unit1653_CPPFLAGS = $(AM_CPPFLAGS)
|
unit1653_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
|
|
||||||
|
unit1654_SOURCES = unit1654.c $(UNITFILES)
|
||||||
|
unit1654_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
|
124
tests/unit/unit1654.c
Normal file
124
tests/unit/unit1654.c
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
|
*
|
||||||
|
* This software is licensed 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.
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
#include "curlcheck.h"
|
||||||
|
|
||||||
|
#include "urldata.h"
|
||||||
|
#include "altsvc.h"
|
||||||
|
|
||||||
|
static CURLcode
|
||||||
|
unit_setup(void)
|
||||||
|
{
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unit_stop(void)
|
||||||
|
{
|
||||||
|
curl_global_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CURL_DISABLE_HTTP) || !defined(USE_ALTSVC)
|
||||||
|
UNITTEST_START
|
||||||
|
{
|
||||||
|
return 0; /* nothing to do when HTTP is disabled or alt-svc support is
|
||||||
|
missing */
|
||||||
|
}
|
||||||
|
UNITTEST_STOP
|
||||||
|
#else
|
||||||
|
UNITTEST_START
|
||||||
|
{
|
||||||
|
char outname[256];
|
||||||
|
CURL *curl;
|
||||||
|
CURLcode result;
|
||||||
|
struct altsvcinfo *asi = Curl_altsvc_init();
|
||||||
|
if(!asi)
|
||||||
|
return 1;
|
||||||
|
result = Curl_altsvc_load(asi, arg);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
curl = curl_easy_init();
|
||||||
|
if(!curl)
|
||||||
|
goto fail;
|
||||||
|
fail_unless(asi->num == 4, "wrong number of entries");
|
||||||
|
msnprintf(outname, sizeof(outname), "%s-out", arg);
|
||||||
|
|
||||||
|
result = Curl_altsvc_parse(curl, asi, "h2=\"example.com:8080\"",
|
||||||
|
ALPN_h1, "example.org", 8080);
|
||||||
|
if(result) {
|
||||||
|
fprintf(stderr, "Curl_altsvc_parse() failed!\n");
|
||||||
|
unitfail++;
|
||||||
|
}
|
||||||
|
fail_unless(asi->num == 5, "wrong number of entries");
|
||||||
|
|
||||||
|
result = Curl_altsvc_parse(curl, asi, "h3=\":8080\"",
|
||||||
|
ALPN_h1, "2.example.org", 8080);
|
||||||
|
if(result) {
|
||||||
|
fprintf(stderr, "Curl_altsvc_parse(2) failed!\n");
|
||||||
|
unitfail++;
|
||||||
|
}
|
||||||
|
fail_unless(asi->num == 6, "wrong number of entries");
|
||||||
|
|
||||||
|
result = Curl_altsvc_parse(curl, asi,
|
||||||
|
"h2=\"example.com:8080\", h3=\"yesyes.com\"",
|
||||||
|
ALPN_h1, "3.example.org", 8080);
|
||||||
|
if(result) {
|
||||||
|
fprintf(stderr, "Curl_altsvc_parse(3) failed!\n");
|
||||||
|
unitfail++;
|
||||||
|
}
|
||||||
|
/* that one should make two entries */
|
||||||
|
fail_unless(asi->num == 8, "wrong number of entries");
|
||||||
|
|
||||||
|
result = Curl_altsvc_parse(curl, asi, "h2=\"example.com:443\"; ma = 120;",
|
||||||
|
ALPN_h2c, "example.org", 80);
|
||||||
|
if(result) {
|
||||||
|
fprintf(stderr, "Curl_altsvc_parse(4) failed!\n");
|
||||||
|
unitfail++;
|
||||||
|
}
|
||||||
|
fail_unless(asi->num == 9, "wrong number of entries");
|
||||||
|
|
||||||
|
result = Curl_altsvc_parse(curl, asi,
|
||||||
|
"h2=\":443\", h3=\":443\"; ma = 120; persist = 1",
|
||||||
|
ALPN_h1, "curl.haxx.se", 80);
|
||||||
|
if(result) {
|
||||||
|
fprintf(stderr, "Curl_altsvc_parse(5) failed!\n");
|
||||||
|
unitfail++;
|
||||||
|
}
|
||||||
|
fail_unless(asi->num == 11, "wrong number of entries");
|
||||||
|
|
||||||
|
/* clear that one again and decrease the counter */
|
||||||
|
result = Curl_altsvc_parse(curl, asi, "clear;",
|
||||||
|
ALPN_h1, "curl.haxx.se", 80);
|
||||||
|
if(result) {
|
||||||
|
fprintf(stderr, "Curl_altsvc_parse(6) failed!\n");
|
||||||
|
unitfail++;
|
||||||
|
}
|
||||||
|
fail_unless(asi->num == 9, "wrong number of entries");
|
||||||
|
|
||||||
|
Curl_altsvc_save(asi, outname);
|
||||||
|
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
fail:
|
||||||
|
Curl_altsvc_cleanup(asi);
|
||||||
|
return unitfail;
|
||||||
|
}
|
||||||
|
UNITTEST_STOP
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user