rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen);
if(rv < 0) {
- failf(data,
- "process_pending_input: nghttp2_session_mem_recv() returned "
- "%zd:%s", rv, nghttp2_strerror((int)rv));
- *err = CURLE_RECV_ERROR;
+ failf(data, "nghttp2 error %zd: %s", rv, nghttp2_strerror((int)rv));
+ *err = CURLE_HTTP2;
return -1;
}
Curl_bufq_skip(&ctx->inbufq, (size_t)rv);
void *userp)
{
struct Curl_cfilter *cf = userp;
+ struct cf_h2_ctx *ctx = cf->ctx;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
(void)session;
buffer[len] = 0;
CURL_TRC_CF(data, cf, "[%d] -> %s", frame->hd.stream_id, buffer);
}
+ if((frame->hd.type == NGHTTP2_GOAWAY) && !ctx->sent_goaway) {
+ /* A GOAWAY not initiated by us, but by nghttp2 itself on detecting
+ * a protocol error on the connection */
+ failf(data, "nghttp2 shuts down connection with error %d: %s",
+ frame->goaway.error_code,
+ nghttp2_http2_strerror(frame->goaway.error_code));
+ }
return 0;
}
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
CURLcode result = CURLE_OK;
ssize_t nread;
+ if(should_close_session(ctx)) {
+ CURL_TRC_CF(data, cf, "progress ingress, session is closed");
+ return CURLE_HTTP2;
+ }
+
/* Process network input buffer fist */
if(!Curl_bufq_is_empty(&ctx->inbufq)) {
CURL_TRC_CF(data, cf, "Process %zu bytes in connection buffer",
CF_DATA_SAVE(save, cf, data);
if(!ctx->sent_goaway) {
+ ctx->sent_goaway = TRUE;
rv = nghttp2_submit_goaway(ctx->h2, NGHTTP2_FLAG_NONE,
ctx->local_max_sid, 0,
(const uint8_t *)"shutdown",
result = CURLE_SEND_ERROR;
goto out;
}
- ctx->sent_goaway = TRUE;
}
/* GOAWAY submitted, process egress and ingress until nghttp2 is done. */
result = CURLE_OK;
r.check_exit_code(16) # CURLE_HTTP2
else:
r.check_exit_code(100) # CURLE_TOO_LARGE
+
+ # http: several response headers, together > 256 KB
+ # nghttp2 error -905: Too many CONTINUATION frames following a HEADER frame
+ @pytest.mark.skipif(condition=not Env.httpd_is_at_least('2.4.64'),
+ reason='httpd must be at least 2.4.64')
+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
+ def test_01_14_gigalarge_resp_headers(self, env: Env, httpd, proto):
+ httpd.set_extra_config('base', [
+ 'LogLevel http2:trace2',
+ f'H2MaxHeaderBlockLen {1024 * 1024}',
+ ])
+ httpd.reload()
+ curl = CurlClient(env=env)
+ url = f'https://{env.authority_for(env.domain1, proto)}' \
+ f'/curltest/tweak?x-hd={256 * 1024}'
+ r = curl.http_get(url=url, alpn_proto=proto, extra_args=[])
+ if proto == 'h2':
+ r.check_exit_code(16) # CURLE_HTTP2
+ else:
+ r.check_exit_code(0) # 1.1 can do
+
+ # http: one response header > 256 KB
+ @pytest.mark.skipif(condition=not Env.httpd_is_at_least('2.4.64'),
+ reason='httpd must be at least 2.4.64')
+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
+ def test_01_15_gigalarge_resp_headers(self, env: Env, httpd, proto):
+ httpd.set_extra_config('base', [
+ 'LogLevel http2:trace2',
+ f'H2MaxHeaderBlockLen {1024 * 1024}',
+ ])
+ httpd.reload()
+ curl = CurlClient(env=env)
+ url = f'https://{env.authority_for(env.domain1, proto)}' \
+ f'/curltest/tweak?x-hd1={256 * 1024}'
+ r = curl.http_get(url=url, alpn_proto=proto, extra_args=[])
+ if proto == 'h2':
+ r.check_exit_code(16) # CURLE_HTTP2
+ else:
+ r.check_exit_code(100) # CURLE_TOO_LARGE