mod_http2/SOURCES/mod_http2-1.15.7-log-error-resp.patch

272 lines
10 KiB
Diff

diff --git a/mod_http2/h2.h b/mod_http2/h2.h
index e057d66..33a225d 100644
--- a/mod_http2/h2.h
+++ b/mod_http2/h2.h
@@ -141,8 +141,19 @@ struct h2_request {
unsigned int chunked : 1; /* iff requst 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/mod_http2/h2_request.c b/mod_http2/h2_request.c
index 89a0b47..1892967 100644
--- a/mod_http2/h2_request.c
+++ b/mod_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);
}
@@ -208,53 +209,92 @@ h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src)
request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
{
- int access_status = HTTP_OK;
- const char *rpath;
- const char *s;
+ int access_status;
request_rec *r = ap_create_request(c);
- r->headers_in = apr_table_clone(r->pool, req->headers);
-
+#if AP_MODULE_MAGIC_AT_LEAST(20200331, 3)
ap_run_pre_read_request(r, c);
/* Time to populate r with the data we have. */
r->request_time = req->request_time;
- r->method = apr_pstrdup(r->pool, req->method);
- /* Provide quick information about the request method as soon as known */
- r->method_number = ap_method_number_of(r->method);
- if (r->method_number == M_GET && r->method[0] == 'H') {
- r->header_only = 1;
- }
-
- rpath = (req->path ? req->path : "");
- ap_parse_uri(r, rpath);
- r->protocol = (char*)"HTTP/2.0";
- r->proto_num = HTTP_VERSION(2, 0);
+ r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
+ req->method, req->path ? req->path : "");
+ r->headers_in = apr_table_clone(r->pool, req->headers);
- r->the_request = apr_psprintf(r->pool, "%s %s %s",
- r->method, rpath, r->protocol);
-
- /* update what we think the virtual host is based on the headers we've
- * now read. may update status.
- * Leave r->hostname empty, vhost will parse if form our Host: header,
- * otherwise we get complains about port numbers.
+ /* Start with r->hostname = NULL, ap_check_request_header() will get it
+ * form Host: header, otherwise we get complains about port numbers.
*/
r->hostname = NULL;
- ap_update_vhost_from_headers(r);
-
- /* we may have switched to another server */
- r->per_dir_config = r->server->lookup_defaults;
-
- s = apr_table_get(r->headers_in, "Expect");
- if (s && s[0]) {
- if (ap_cstr_casecmp(s, "100-continue") == 0) {
- r->expecting_100 = 1;
+
+ /* Validate HTTP/1 request and select vhost. */
+ 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;
+ 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 {
- r->status = HTTP_EXPECTATION_FAILED;
- ap_send_error_response(r, 0);
+ access_status = r->status;
}
+ r->status = HTTP_OK;
+ goto die;
+ }
+#else
+ {
+ const char *s;
+
+ r->headers_in = apr_table_clone(r->pool, req->headers);
+ ap_run_pre_read_request(r, c);
+
+ /* Time to populate r with the data we have. */
+ r->request_time = req->request_time;
+ r->method = apr_pstrdup(r->pool, req->method);
+ /* Provide quick information about the request method as soon as known */
+ r->method_number = ap_method_number_of(r->method);
+ if (r->method_number == M_GET && r->method[0] == 'H') {
+ r->header_only = 1;
+ }
+ ap_parse_uri(r, req->path ? req->path : "");
+ r->protocol = (char*)"HTTP/2.0";
+ r->proto_num = HTTP_VERSION(2, 0);
+ r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
+ r->method, req->path ? req->path : "");
+
+ /* Start with r->hostname = NULL, ap_check_request_header() will get it
+ * form Host: header, otherwise we get complains about port numbers.
+ */
+ r->hostname = NULL;
+ ap_update_vhost_from_headers(r);
+
+ /* we may have switched to another server */
+ r->per_dir_config = r->server->lookup_defaults;
+
+ s = apr_table_get(r->headers_in, "Expect");
+ if (s && s[0]) {
+ if (ap_cstr_casecmp(s, "100-continue") == 0) {
+ r->expecting_100 = 1;
+ }
+ else {
+ r->status = HTTP_EXPECTATION_FAILED;
+ access_status = r->status;
+ goto die;
+ }
+ }
+ }
+#endif
+
+ /* 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;
}
/*
@@ -266,28 +306,47 @@ request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
ap_add_input_filter_handle(ap_http_input_filter_handle,
NULL, r, r->connection);
- if (access_status != HTTP_OK
- || (access_status = ap_post_read_request(r))) {
+ if ((access_status = ap_run_post_read_request(r))) {
/* Request check post hooks failed. An example of this would be a
* request for a vhost where h2 is disabled --> 421.
*/
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03367)
"h2_request: access_status=%d, request_create failed",
access_status);
- ap_die(access_status, r);
- ap_update_child_status(c->sbh, SERVER_BUSY_LOG, r);
- ap_run_log_transaction(r);
- r = NULL;
- goto traceout;
+ goto die;
}
AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method,
(char *)r->uri, (char *)r->server->defn_name,
r->status);
return r;
-traceout:
+die:
+ ap_die(access_status, r);
+
+ /* ap_die() sent the response through the output filters, we must now
+ * end the request with an EOR bucket for stream/pipeline accounting.
+ */
+ {
+ apr_bucket_brigade *eor_bb;
+#if AP_MODULE_MAGIC_AT_LEAST(20180905, 1)
+ eor_bb = ap_acquire_brigade(c);
+ APR_BRIGADE_INSERT_TAIL(eor_bb,
+ ap_bucket_eor_create(c->bucket_alloc, r));
+ ap_pass_brigade(c->output_filters, eor_bb);
+ ap_release_brigade(c, eor_bb);
+#else
+ eor_bb = apr_brigade_create(c->pool, c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(eor_bb,
+ ap_bucket_eor_create(c->bucket_alloc, r));
+ ap_pass_brigade(c->output_filters, eor_bb);
+ apr_brigade_destroy(eor_bb);
+#endif
+ }
+
+ r = NULL;
+
AP_READ_REQUEST_FAILURE((uintptr_t)r);
- return r;
+ return NULL;
}
diff --git a/mod_http2/h2_session.c b/mod_http2/h2_session.c
index 07983a3..2a97ad9 100644
--- a/mod_http2/h2_session.c
+++ b/mod_http2/h2_session.c
@@ -311,9 +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) ||
- /* We accept a certain amount of failures in order to reply
+ if (status != APR_SUCCESS &&
+ (!stream->rtmp ||
+ stream->rtmp->http_status == H2_HTTP_STATUS_UNSET || /* We accept a certain amount of failures in order to reply
* with an informative HTTP error response like 413. But of the
* client is too wrong, we fail the request an RESET the stream */
stream->request_headers_failed > 100)) {
diff --git a/mod_http2/h2_stream.c b/mod_http2/h2_stream.c
index 62021b6..adbd5d2 100644
--- a/mod_http2/h2_stream.c
+++ b/mod_http2/h2_stream.c
@@ -638,17 +638,8 @@ 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);
+ if (!h2_stream_is_ready(stream) && stream->rtmp) {
+ stream->rtmp->http_status = http_status;
}
}