drain_tunnel(cf, data, &ctx->tunnel);
}
break;
+ case NGHTTP2_RST_STREAM:
+ if(frame->rst_stream.error_code)
+ ctx->tunnel.reset = TRUE;
+ break;
default:
break;
}
stream_id, nghttp2_http2_strerror(error_code), error_code);
ctx->tunnel.closed = TRUE;
ctx->tunnel.error = error_code;
+ if(error_code)
+ ctx->tunnel.reset = TRUE;
return 0;
}
struct cf_h2_proxy_ctx *ctx = cf->ctx;
*pnread = 0;
- if(ctx->tunnel.error == NGHTTP2_REFUSED_STREAM) {
- CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
- "connection", ctx->tunnel.stream_id);
- failf(data, "proxy server refused HTTP/2 stream");
- return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
- }
- else if(ctx->tunnel.error != NGHTTP2_NO_ERROR) {
- failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
- ctx->tunnel.stream_id, nghttp2_http2_strerror(ctx->tunnel.error),
- ctx->tunnel.error);
- return CURLE_HTTP2_STREAM;
- }
- else if(ctx->tunnel.reset) {
- failf(data, "HTTP/2 stream %u was reset", ctx->tunnel.stream_id);
+ if(ctx->tunnel.error) {
+ failf(data, "HTTP/2 stream %" PRIu32 " reset by %s (error 0x%" PRIx32
+ " %s)", ctx->tunnel.stream_id,
+ ctx->tunnel.reset ? "server" : "curl",
+ ctx->tunnel.error, nghttp2_http2_strerror(ctx->tunnel.error));
return CURLE_RECV_ERROR;
}
BIT(resp_hds_complete); /* we have a complete, final response */
BIT(closed); /* TRUE on stream close */
BIT(reset); /* TRUE on stream reset */
+ BIT(reset_by_server); /* TRUE on stream reset by server */
BIT(close_handled); /* TRUE if stream closure is handled by libcurl */
BIT(bodystarted);
BIT(body_eos); /* the complete body has been added to `sendbuf` and
}
break;
case NGHTTP2_RST_STREAM:
- stream->closed = TRUE;
- if(frame->rst_stream.error_code) {
- stream->reset = TRUE;
- }
+ if(frame->rst_stream.error_code)
+ stream->reset_by_server = TRUE;
Curl_multi_mark_dirty(data);
break;
case NGHTTP2_WINDOW_UPDATE:
stream->closed = TRUE;
stream->error = error_code;
- if(stream->error) {
+ if(stream->error)
stream->reset = TRUE;
- }
if(stream->error)
CURL_TRC_CF(data_s, cf, "[%d] RESET: %s (err %d)",
CURLcode result;
*pnlen = 0;
- if(stream->error == NGHTTP2_REFUSED_STREAM) {
- CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
- "connection", stream->id);
- connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
- data->state.refused_stream = TRUE;
- return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
- }
- else if(stream->error != NGHTTP2_NO_ERROR) {
- if(stream->resp_hds_complete && data->req.no_body) {
- CURL_TRC_CF(data, cf, "[%d] error after response headers, but we did "
- "not want a body anyway, ignore: %s (err %u)",
- stream->id, nghttp2_http2_strerror(stream->error),
- stream->error);
- stream->close_handled = TRUE;
- return CURLE_OK;
- }
- failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
- stream->id, nghttp2_http2_strerror(stream->error),
- stream->error);
- return CURLE_HTTP2_STREAM;
- }
- else if(stream->reset) {
- failf(data, "HTTP/2 stream %u was reset", stream->id);
- return data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
- }
-
- if(!stream->bodystarted) {
- failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
- " all response header fields, treated as error",
- stream->id);
+ if(stream->reset) {
+ if(stream->error == NGHTTP2_REFUSED_STREAM) {
+ infof(data, "HTTP/2 stream %d refused by server, try again on a new "
+ "connection", stream->id);
+ connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
+ data->state.refused_stream = TRUE;
+ return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
+ }
+ else if(stream->resp_hds_complete && data->req.no_body) {
+ CURL_TRC_CF(data, cf, "[%d] error after response headers, but we did "
+ "not want a body anyway, ignore: %s (err %u)",
+ stream->id, nghttp2_http2_strerror(stream->error),
+ stream->error);
+ stream->close_handled = TRUE;
+ return CURLE_OK;
+ }
+ failf(data, "HTTP/2 stream %" PRIu32 " reset by %s (error 0x%" PRIx32
+ " %s)", stream->id, stream->reset_by_server ? "server" : "curl",
+ stream->error, nghttp2_http2_strerror(stream->error));
+ return stream->error ? CURLE_HTTP2_STREAM :
+ (data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2);
+ }
+ else if(!stream->bodystarted) {
+ failf(data, "HTTP/2 stream %d was closed cleanly, but before getting "
+ " all response header fields, treated as error", stream->id);
return CURLE_HTTP2_STREAM;
}
(void)cf;
*pnread = 0;
if(stream->reset) {
+ if(stream->error3 == CURL_H3_ERR_REQUEST_REJECTED) {
+ infof(data, "HTTP/3 stream %" PRId64 " refused by server, try again "
+ "on a new connection", stream->id);
+ connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
+ data->state.refused_stream = TRUE;
+ return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
+ }
+ else if(stream->resp_hds_complete && data->req.no_body) {
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] error after response headers, "
+ "but we did not want a body anyway, ignore error 0x%"
+ PRIx64 " %s", stream->id, stream->error3,
+ vquic_h3_err_str(stream->error3));
+ return CURLE_OK;
+ }
failf(data, "HTTP/3 stream %" PRId64 " reset by server (error 0x%" PRIx64
" %s)", stream->id, stream->error3,
vquic_h3_err_str(stream->error3));
DEBUGASSERT(stream);
*pnread = 0;
if(stream->reset) {
+ if(stream->error3 == CURL_H3_ERR_REQUEST_REJECTED) {
+ infof(data, "HTTP/3 stream %" PRIu64 " refused by server, try again "
+ "on a new connection", stream->id);
+ connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
+ data->state.refused_stream = TRUE;
+ return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
+ }
+ else if(stream->resp_hds_complete && data->req.no_body) {
+ CURL_TRC_CF(data, cf, "[%" PRIu64 "] error after response headers, "
+ "but we did not want a body anyway, ignore error 0x%"
+ PRIx64 " %s", stream->id, stream->error3,
+ vquic_h3_err_str(stream->error3));
+ return CURLE_OK;
+ }
failf(data, "HTTP/3 stream %" PRId64 " reset by server (error 0x%" PRIx64
" %s)", stream->id, stream->error3,
vquic_h3_err_str(stream->error3));