http: VLH, very large header test and fixes
- adding tests using very large passwords in auth - fixes general http sending to treat h3 like h2, and not like http1.1 - eliminate H2_HEADER max definitions and use the commmon DYN_HTTP_REQUEST everywhere, different limits do not help - fix http2 handling of requests denied by nghttp2 on send to immediately report the refused stream Closes #11509
This commit is contained in:
parent
3c0a91077c
commit
c76df46a19
@ -81,8 +81,6 @@ int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save);
|
||||
#define DYN_PAUSE_BUFFER (64 * 1024 * 1024)
|
||||
#define DYN_HAXPROXY 2048
|
||||
#define DYN_HTTP_REQUEST (1024*1024)
|
||||
#define DYN_H2_HEADERS (128*1024)
|
||||
#define DYN_H2_TRAILERS (128*1024)
|
||||
#define DYN_APRINTF 8000000
|
||||
#define DYN_RTSP_REQ_HEADER (64*1024)
|
||||
#define DYN_TRAILERS (64*1024)
|
||||
|
||||
14
lib/http.c
14
lib/http.c
@ -1308,7 +1308,7 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
|
||||
|| IS_HTTPS_PROXY(conn->http_proxy.proxytype)
|
||||
#endif
|
||||
)
|
||||
&& conn->httpversion != 20) {
|
||||
&& conn->httpversion < 20) {
|
||||
/* Make sure this doesn't send more body bytes than what the max send
|
||||
speed says. The request bytes do not count to the max speed.
|
||||
*/
|
||||
@ -4571,8 +4571,8 @@ CURLcode Curl_http_req_make(struct httpreq **preq,
|
||||
if(!req->path)
|
||||
goto out;
|
||||
}
|
||||
Curl_dynhds_init(&req->headers, 0, DYN_H2_HEADERS);
|
||||
Curl_dynhds_init(&req->trailers, 0, DYN_H2_TRAILERS);
|
||||
Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST);
|
||||
Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST);
|
||||
result = CURLE_OK;
|
||||
|
||||
out:
|
||||
@ -4729,8 +4729,8 @@ CURLcode Curl_http_req_make2(struct httpreq **preq,
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
Curl_dynhds_init(&req->headers, 0, DYN_H2_HEADERS);
|
||||
Curl_dynhds_init(&req->trailers, 0, DYN_H2_TRAILERS);
|
||||
Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST);
|
||||
Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST);
|
||||
result = CURLE_OK;
|
||||
|
||||
out:
|
||||
@ -4860,8 +4860,8 @@ CURLcode Curl_http_resp_make(struct http_resp **presp,
|
||||
if(!resp->description)
|
||||
goto out;
|
||||
}
|
||||
Curl_dynhds_init(&resp->headers, 0, DYN_H2_HEADERS);
|
||||
Curl_dynhds_init(&resp->trailers, 0, DYN_H2_TRAILERS);
|
||||
Curl_dynhds_init(&resp->headers, 0, DYN_HTTP_REQUEST);
|
||||
Curl_dynhds_init(&resp->trailers, 0, DYN_HTTP_REQUEST);
|
||||
result = CURLE_OK;
|
||||
|
||||
out:
|
||||
|
||||
14
lib/http2.c
14
lib/http2.c
@ -252,7 +252,7 @@ static CURLcode http2_data_setup(struct Curl_cfilter *cf,
|
||||
H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
|
||||
Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
|
||||
H2_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
|
||||
Curl_dynhds_init(&stream->resp_trailers, 0, DYN_H2_TRAILERS);
|
||||
Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST);
|
||||
stream->resp_hds_len = 0;
|
||||
stream->bodystarted = FALSE;
|
||||
stream->status_code = -1;
|
||||
@ -2122,7 +2122,13 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
/* Call the nghttp2 send loop and flush to write ALL buffered data,
|
||||
* headers and/or request body completely out to the network */
|
||||
result = h2_progress_egress(cf, data);
|
||||
if(result == CURLE_AGAIN) {
|
||||
/* if the stream has been closed in egress handling (nghttp2 does that
|
||||
* when it does not like the headers, for example */
|
||||
if(stream && stream->closed) {
|
||||
nwritten = http2_handle_stream_close(cf, data, stream, err);
|
||||
goto out;
|
||||
}
|
||||
else if(result == CURLE_AGAIN) {
|
||||
blocked = 1;
|
||||
}
|
||||
else if(result) {
|
||||
@ -2130,14 +2136,14 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
|
||||
nwritten = -1;
|
||||
goto out;
|
||||
}
|
||||
else if(!Curl_bufq_is_empty(&stream->sendbuf)) {
|
||||
else if(stream && !Curl_bufq_is_empty(&stream->sendbuf)) {
|
||||
/* although we wrote everything that nghttp2 wants to send now,
|
||||
* there is data left in our stream send buffer unwritten. This may
|
||||
* be due to the stream's HTTP/2 flow window being exhausted. */
|
||||
blocked = 1;
|
||||
}
|
||||
|
||||
if(blocked) {
|
||||
if(stream && blocked) {
|
||||
/* Unable to send all data, due to connection blocked or H2 window
|
||||
* exhaustion. Data is left in our stream buffer, or nghttp2's internal
|
||||
* frame buffer or our network out buffer. */
|
||||
|
||||
@ -1835,6 +1835,8 @@ out:
|
||||
*err = result;
|
||||
sent = -1;
|
||||
}
|
||||
DEBUGF(LOG_CF(data, cf, "[h3sid=%" PRId64 "] cf_send(len=%zu) -> %zd, %d",
|
||||
stream? stream->id : -1, len, sent, *err));
|
||||
CF_DATA_RESTORE(cf, save);
|
||||
return sent;
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ class TestAuth:
|
||||
def _class_scope(self, env, httpd, nghttpx):
|
||||
if env.have_h3():
|
||||
nghttpx.start_if_needed()
|
||||
env.make_data_file(indir=env.gen_dir, fname="data-10m", fsize=10*1024*1024)
|
||||
httpd.clear_extra_configs()
|
||||
httpd.reload()
|
||||
|
||||
@ -79,3 +80,51 @@ class TestAuth:
|
||||
'--digest', '--user', 'test:test'
|
||||
])
|
||||
r.check_response(http_status=200)
|
||||
|
||||
# PUT data, digest auth large pw
|
||||
@pytest.mark.parametrize("proto", ['h2', 'h3'])
|
||||
def test_14_04_digest_large_pw(self, env: Env, httpd, nghttpx, repeat, proto):
|
||||
if proto == 'h3' and not env.have_h3():
|
||||
pytest.skip("h3 not supported")
|
||||
data='0123456789'
|
||||
password = 'x' * 65535
|
||||
curl = CurlClient(env=env)
|
||||
url = f'https://{env.authority_for(env.domain1, proto)}/restricted/digest/data.json'
|
||||
r = curl.http_upload(urls=[url], data=data, alpn_proto=proto, extra_args=[
|
||||
'--digest', '--user', f'test:{password}'
|
||||
])
|
||||
# digest does not submit the password, but a hash of it, so all
|
||||
# works and, since the pw is not correct, we get a 401
|
||||
r.check_response(http_status=401)
|
||||
|
||||
# PUT data, basic auth large pw
|
||||
@pytest.mark.parametrize("proto", ['h2', 'h3'])
|
||||
def test_14_05_basic_large_pw(self, env: Env, httpd, nghttpx, repeat, proto):
|
||||
if proto == 'h3' and not env.have_h3():
|
||||
pytest.skip("h3 not supported")
|
||||
# just large enought that nghttp2 will submit
|
||||
password = 'x' * (47 * 1024)
|
||||
fdata = os.path.join(env.gen_dir, 'data-10m')
|
||||
curl = CurlClient(env=env)
|
||||
url = f'https://{env.authority_for(env.domain1, proto)}/restricted/digest/data.json'
|
||||
r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto, extra_args=[
|
||||
'--basic', '--user', f'test:{password}'
|
||||
])
|
||||
# but apache denies on length limit
|
||||
r.check_response(http_status=431)
|
||||
|
||||
# PUT data, basic auth with very large pw
|
||||
@pytest.mark.parametrize("proto", ['h2', 'h3'])
|
||||
def test_14_06_basic_very_large_pw(self, env: Env, httpd, nghttpx, repeat, proto):
|
||||
if proto == 'h3' and not env.have_h3():
|
||||
pytest.skip("h3 not supported")
|
||||
data='0123456789'
|
||||
password = 'x' * (64 * 1024)
|
||||
fdata = os.path.join(env.gen_dir, 'data-10m')
|
||||
curl = CurlClient(env=env)
|
||||
url = f'https://{env.authority_for(env.domain1, proto)}/restricted/digest/data.json'
|
||||
r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto, extra_args=[
|
||||
'--basic', '--user', f'test:{password}'
|
||||
])
|
||||
# request was never sent
|
||||
r.check_response(exitcode=55, http_status=0)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user