diff --git a/modules/http2/h2.h b/modules/http2/h2.h index e074204c73..08f59c44f9 100644 --- a/modules/http2/h2.h +++ b/modules/http2/h2.h @@ -141,8 +141,19 @@ struct h2_request { unsigned int chunked : 1; /* iff request body needs to be forwarded as chunked */ unsigned int serialize : 1; /* iff this request is written in HTTP/1.1 serialization */ apr_off_t raw_bytes; /* RAW network bytes that generated this request - if known. */ + int http_status; /* Store a possible HTTP status code that gets + * defined before creating the dummy HTTP/1.1 + * request e.g. due to an error already + * detected. + */ }; +/* + * A possible HTTP status code is not defined yet. See the http_status field + * in struct h2_request above for further explanation. + */ +#define H2_HTTP_STATUS_UNSET (0) + typedef struct h2_headers h2_headers; struct h2_headers { diff --git a/modules/http2/h2_request.c b/modules/http2/h2_request.c index 2fe3b26f66..485b29aac3 100644 --- a/modules/http2/h2_request.c +++ b/modules/http2/h2_request.c @@ -79,11 +79,12 @@ apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool, } req = apr_pcalloc(pool, sizeof(*req)); - req->method = apr_pstrdup(pool, r->method); - req->scheme = scheme; - req->authority = authority; - req->path = path; - req->headers = apr_table_make(pool, 10); + req->method = apr_pstrdup(pool, r->method); + req->scheme = scheme; + req->authority = authority; + req->path = path; + req->headers = apr_table_make(pool, 10); + req->http_status = H2_HTTP_STATUS_UNSET; if (r->server) { req->serialize = h2_config_rgeti(r, H2_CONF_SER_HEADERS); } @@ -294,7 +295,14 @@ request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c) if (!ap_parse_request_line(r) || !ap_check_request_header(r)) { /* we may have switched to another server still */ r->per_dir_config = r->server->lookup_defaults; - access_status = r->status; + if (req->http_status != H2_HTTP_STATUS_UNSET) { + access_status = req->http_status; + /* Be safe and close the connection */ + c->keepalive = AP_CONN_CLOSE; + } + else { + access_status = r->status; + } r->status = HTTP_OK; goto die; } @@ -302,6 +310,14 @@ request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c) /* we may have switched to another server */ r->per_dir_config = r->server->lookup_defaults; + if (req->http_status != H2_HTTP_STATUS_UNSET) { + access_status = req->http_status; + r->status = HTTP_OK; + /* Be safe and close the connection */ + c->keepalive = AP_CONN_CLOSE; + goto die; + } + /* * Add the HTTP_IN filter here to ensure that ap_discard_request_body * called by ap_die and by ap_send_error_response works correctly on diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c index c818d1aabc..1915855792 100644 --- a/modules/http2/h2_session.c +++ b/modules/http2/h2_session.c @@ -311,7 +311,9 @@ static int on_header_cb(nghttp2_session *ngh2, const nghttp2_frame *frame, status = h2_stream_add_header(stream, (const char *)name, namelen, (const char *)value, valuelen); - if (status != APR_SUCCESS && !h2_stream_is_ready(stream)) { + if (status != APR_SUCCESS + && (!stream->rtmp + || stream->rtmp->http_status == H2_HTTP_STATUS_UNSET)) { return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } return 0; diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c index 77b764e1de..dce1fb45b4 100644 --- a/modules/http2/h2_stream.c +++ b/modules/http2/h2_stream.c @@ -639,16 +639,7 @@ void h2_stream_set_request(h2_stream *stream, const h2_request *r) static void set_error_response(h2_stream *stream, int http_status) { if (!h2_stream_is_ready(stream)) { - conn_rec *c = stream->session->c; - apr_bucket *b; - h2_headers *response; - - response = h2_headers_die(http_status, stream->request, stream->pool); - prep_output(stream); - b = apr_bucket_eos_create(c->bucket_alloc); - APR_BRIGADE_INSERT_HEAD(stream->out_buffer, b); - b = h2_bucket_headers_create(c->bucket_alloc, response); - APR_BRIGADE_INSERT_HEAD(stream->out_buffer, b); + stream->rtmp->http_status = http_status; } }