urldata: don't touch data->set.httpversion at run-time

Rename it to 'httpwant' and make a cloned field in the state struct as
well for run-time updates.

Also: refuse non-supported HTTP versions. Verified with test 129.

Closes #6585
This commit is contained in:
Daniel Stenberg 2021-02-11 16:30:32 +01:00
parent bd6b54ba1f
commit 88dd1a8a11
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
17 changed files with 109 additions and 34 deletions

View File

@ -741,7 +741,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
goto error;
}
if(data->set.httpversion == CURL_HTTP_VERSION_1_0) {
if(data->state.httpwant == CURL_HTTP_VERSION_1_0) {
if(HYPERE_OK != hyper_request_set_version(req,
HYPER_HTTP_VERSION_1_0)) {
failf(data, "error setting HTTP version");

View File

@ -183,7 +183,7 @@ static CURLcode http_setup_conn(struct Curl_easy *data,
Curl_mime_initpart(&http->form, data);
data->req.p.http = http;
if(data->set.httpversion == CURL_HTTP_VERSION_3) {
if(data->state.httpwant == CURL_HTTP_VERSION_3) {
if(conn->handler->flags & PROTOPT_SSL)
/* Only go HTTP/3 directly on HTTPS URLs. It needs a UDP socket and does
the QUIC dance. */
@ -595,7 +595,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
conn->httpversion > 11) {
infof(data, "Forcing HTTP/1.1 for NTLM");
connclose(conn, "Force HTTP/1.1 connection");
data->set.httpversion = CURL_HTTP_VERSION_1_1;
data->state.httpwant = CURL_HTTP_VERSION_1_1;
}
}
#ifndef CURL_DISABLE_PROXY
@ -1625,11 +1625,11 @@ static bool use_http_1_1plus(const struct Curl_easy *data,
{
if((data->state.httpversion == 10) || (conn->httpversion == 10))
return FALSE;
if((data->set.httpversion == CURL_HTTP_VERSION_1_0) &&
if((data->state.httpwant == CURL_HTTP_VERSION_1_0) &&
(conn->httpversion <= 10))
return FALSE;
return ((data->set.httpversion == CURL_HTTP_VERSION_NONE) ||
(data->set.httpversion >= CURL_HTTP_VERSION_1_1));
return ((data->state.httpwant == CURL_HTTP_VERSION_NONE) ||
(data->state.httpwant >= CURL_HTTP_VERSION_1_1));
}
#ifndef USE_HYPER
@ -1637,7 +1637,7 @@ static const char *get_http_string(const struct Curl_easy *data,
const struct connectdata *conn)
{
#ifdef ENABLE_QUIC
if((data->set.httpversion == CURL_HTTP_VERSION_3) ||
if((data->state.httpwant == CURL_HTTP_VERSION_3) ||
(conn->httpversion == 30))
return "3";
#endif
@ -2950,7 +2950,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
default:
/* Check if user wants to use HTTP/2 with clear TCP*/
#ifdef USE_NGHTTP2
if(data->set.httpversion == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
if(data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
/* We don't support HTTP/2 proxies yet. Also it's debatable
@ -3156,7 +3156,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(!(conn->handler->flags&PROTOPT_SSL) &&
conn->httpversion != 20 &&
(data->set.httpversion == CURL_HTTP_VERSION_2)) {
(data->state.httpwant == CURL_HTTP_VERSION_2)) {
/* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
over SSL */
result = Curl_http2_request_upgrade(&req, conn);
@ -4148,10 +4148,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
*/
char separator;
char twoorthree[2];
int httpversion = 0;
nc = sscanf(HEADER1,
" HTTP/%1d.%1d%c%3d",
&httpversion_major,
&conn->httpversion,
&httpversion,
&separator,
&k->httpcode);
@ -4163,7 +4164,23 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
if((nc == 4) && (' ' == separator)) {
conn->httpversion += 10 * httpversion_major;
httpversion += 10 * httpversion_major;
switch(httpversion) {
case 10:
case 11:
#if defined(USE_NGHTTP2) || defined(USE_HYPER)
case 20:
#endif
#if defined(ENABLE_QUIC)
case 30:
#endif
conn->httpversion = (unsigned char)httpversion;
break;
default:
failf(data, "Unsupported HTTP version (%u.%d) in response",
httpversion/10, httpversion%10);
return CURLE_UNSUPPORTED_PROTOCOL;
}
if(k->upgr101 == UPGR101_RECEIVED) {
/* supposedly upgraded to http2 now */

View File

@ -2173,7 +2173,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(!ret) {
infof(data, "Downgrades to HTTP/1.1!\n");
data->set.httpversion = CURL_HTTP_VERSION_1_1;
data->state.httpwant = CURL_HTTP_VERSION_1_1;
/* clear the error message bit too as we ignore the one we got */
data->state.errorbuf = FALSE;
if(!newurl)

View File

@ -888,7 +888,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
if(arg == CURL_HTTP_VERSION_NONE)
arg = CURL_HTTP_VERSION_2TLS;
#endif
data->set.httpversion = arg;
data->set.httpwant = (unsigned char)arg;
break;
case CURLOPT_EXPECT_100_TIMEOUT_MS:

View File

@ -1431,8 +1431,8 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
data->state.followlocation = 0; /* reset the location-follow counter */
data->state.this_is_a_follow = FALSE; /* reset this */
data->state.errorbuf = FALSE; /* no error has occurred */
data->state.httpversion = 0; /* don't assume any particular server version */
data->state.httpwant = data->set.httpwant;
data->state.httpversion = 0;
data->state.authproblem = FALSE;
data->state.authhost.want = data->set.httpauth;
data->state.authproxy.want = data->set.proxyauth;

View File

@ -609,7 +609,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
set->maxage_conn = 118;
set->http09_allowed = FALSE;
set->httpversion =
set->httpwant =
#ifdef USE_NGHTTP2
CURL_HTTP_VERSION_2TLS
#else
@ -887,7 +887,7 @@ static int IsMultiplexingPossible(const struct Curl_easy *handle,
(!conn->bits.protoconnstart || !conn->bits.close)) {
if(Curl_multiplex_wanted(handle->multi) &&
(handle->set.httpversion >= CURL_HTTP_VERSION_2))
(handle->state.httpwant >= CURL_HTTP_VERSION_2))
/* allows HTTP/2 */
avail |= CURLPIPE_MULTIPLEX;
}

View File

@ -991,7 +991,7 @@ struct connectdata {
char *passwd; /* password string, allocated */
char *options; /* options string, allocated */
char *sasl_authzid; /* authorisation identity string, allocated */
int httpversion; /* the HTTP version*10 reported by the server */
unsigned char httpversion; /* the HTTP version*10 reported by the server */
struct curltime now; /* "current" time */
struct curltime created; /* creation time */
struct curltime lastused; /* when returned to the connection cache */
@ -1375,9 +1375,10 @@ struct UrlState {
/* a place to store the most recently set FTP entrypath */
char *most_recent_ftp_entrypath;
int httpversion; /* the lowest HTTP version*10 reported by any server
involved in this request */
unsigned char httpwant; /* when non-zero, a specific HTTP version requested
to be used in the library's request(s) */
unsigned char httpversion; /* the lowest HTTP version*10 reported by any
server involved in this request */
#if !defined(WIN32) && !defined(MSDOS) && !defined(__EMX__)
/* do FTP line-end conversions on most platforms */
@ -1718,8 +1719,8 @@ struct UserDefined {
curl_proxytype proxytype; /* what kind of proxy that is in use */
time_t timevalue; /* what time to compare with */
Curl_HttpReq method; /* what kind of HTTP request (if any) is this */
long httpversion; /* when non-zero, a specific HTTP version requested to
be used in the library's request(s) */
unsigned char httpwant; /* when non-zero, a specific HTTP version requested
to be used in the library's request(s) */
struct ssl_config_data ssl; /* user defined SSL stuff */
#ifndef CURL_DISABLE_PROXY
struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */

View File

@ -390,7 +390,7 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
*/
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2
if(data->state.httpversion >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
&& (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
#endif

View File

@ -618,7 +618,7 @@ gtls_connect_step1(struct Curl_easy *data,
gnutls_datum_t protocols[2];
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2
if(data->state.httpversion >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
&& (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
#endif

View File

@ -495,7 +495,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
if(conn->bits.tls_enable_alpn) {
const char **p = &backend->protocols[0];
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2)
if(data->state.httpversion >= CURL_HTTP_VERSION_2)
*p++ = NGHTTP2_PROTO_VERSION_ID;
#endif
*p++ = ALPN_HTTP_1_1;

View File

@ -2080,7 +2080,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
unsigned char protocols[128];
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2
if(data->state.httpversion >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
&& (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
#endif

View File

@ -2222,7 +2222,7 @@ select_next_proto_cb(SSL *ssl,
(void)ssl;
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
if(data->state.httpwant >= CURL_HTTP_VERSION_2 &&
!select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID,
NGHTTP2_PROTO_VERSION_ID_LEN)) {
infof(data, "NPN, negotiated HTTP2 (%s)\n",
@ -2749,7 +2749,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
unsigned char protocols[128];
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2
if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
&& (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
#endif

View File

@ -861,7 +861,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
list_start_index = cur;
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
if(data->state.httpversion >= CURL_HTTP_VERSION_2) {
memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
cur += NGHTTP2_PROTO_ALPN_LEN;
infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);

View File

@ -1611,7 +1611,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
&kCFTypeArrayCallBacks);
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2
if(data->state.httpversion >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
&& (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
#endif

View File

@ -475,7 +475,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
protocols in descending order of preference, eg: "h2,http/1.1" */
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
if(data->state.httpversion >= CURL_HTTP_VERSION_2) {
strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ",");
infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
}
@ -724,7 +724,7 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
!memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
conn->negnpn = CURL_HTTP_VERSION_1_1;
#ifdef USE_NGHTTP2
else if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
else if(data->state.httpversion >= CURL_HTTP_VERSION_2 &&
protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN &&
!memcmp(protocol, NGHTTP2_PROTO_VERSION_ID,
NGHTTP2_PROTO_VERSION_ID_LEN))

View File

@ -34,7 +34,7 @@ test90 test91 test92 test93 test94 test95 test96 test97 test98 test99 \
test100 test101 test102 test103 test104 test105 test106 test107 test108 \
test109 test110 test111 test112 test113 test114 test115 test116 test117 \
test118 test119 test120 test121 test122 test123 test124 test125 test126 \
test127 test128 test130 test131 test132 test133 test134 test135 \
test127 test128 test129 test130 test131 test132 test133 test134 test135 \
test136 test137 test138 test139 test140 test141 test142 test143 test144 \
test145 test146 test147 test148 test149 test150 test151 test152 test153 \
test154 test155 test156 test157 test158 test159 test160 test161 test162 \

57
tests/data/test129 Normal file
View File

@ -0,0 +1,57 @@
<testcase>
<info>
<keywords>
HTTP
HTTP GET
</keywords>
</info>
#
# Server-side
<reply>
<data nocheck="yes">
HTTP/1.2 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
ETag: "21025-dc7-39462498"
Accept-Ranges: bytes
Content-Length: 6
Connection: close
Content-Type: text/html
Funny-head: yesyes
-foo-
</data>
</reply>
#
# Client-side
<client>
<server>
http
</server>
<name>
HTTP/1.2 is rejected
</name>
<command>
http://%HOSTIP:%HTTPPORT/129
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<protocol>
GET /129 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
</protocol>
# CURLE_UNSUPPORTED_PROTOCOL
<errorcode>
1
</errorcode>
</verify>
</testcase>