On Fri, Apr 17, 2020 at 11:50 PM Yann Ylavic <[email protected]> wrote:
>
> On Fri, Apr 17, 2020 at 9:43 PM Ruediger Pluem
> >
> > On 4/17/20 3:07 PM, ylavic
> > >
> > > - apr_brigade_destroy(tmp_bb);
> >
> > Why don't we destroy it any longer?
>
> tmp_bb is reused below in the die_early code, and always _cleanup()
> after use in ap_read_request().
> If the brigade is not used anymore, there is no real advantage in
> using _destroy() over _cleanup() IMHO, the former will unregister the
> cleanup callback (thus walk the list) but the callback is a noop after
> apr_brigade_cleanup() anyway..
>
> >
> > > + if (r->status != HTTP_OK) {
> > > + access_status = r->status;
> > > + goto die_early;
> >
> > Why do we die_early here and not just die later?
>
> While both "die_early" and "die" labels finally call ap_die(), the
> former is branched only before we call any hook, thus before anything
> can call ap_die() by itself. It matters because ap_die() can recurse,
> so we should set r->status = HTTP_OK only for the first call.
>
> But thinking more about it, die_early is also cleaning up the input
> filters (for potential further reads to always return APR_EOF), and
> this may be suitable only for the case where we could not read the
> request line or the headers.
> So possibly the code is missing a third label (e.g. die_first) in
> between die_early and die (at r->status = HTTP_OK), which we would
> branch instead of die_early when failing with a "suitable" input state
> (but before post_read_request() hooks still after which we can only
> call ap_die() without resetting r->status).
> Actually it depends on whether (or not) we want ap_die() (i.e.
> ErrorDocument configuration) to be able to read the body at these
> points of failure, and if so we should probably insert the HTTP_IN
> filter earlier too.
>
> WDYT?
The patch would look like the attached. It also renames the labels to
(try to) be more explicit.
Regards,
Yann.
Index: server/protocol.c
===================================================================
--- server/protocol.c (revision 1876675)
+++ server/protocol.c (working copy)
@@ -1461,7 +1461,7 @@ request_rec *ap_read_request(conn_rec *conn)
"request failed: malformed request line");
}
access_status = r->status;
- goto die_early;
+ goto die_unusable_input;
case HTTP_REQUEST_TIME_OUT:
/* Just log, no further action on this connection. */
@@ -1473,7 +1473,7 @@ request_rec *ap_read_request(conn_rec *conn)
/* Not worth dying with. */
conn->keepalive = AP_CONN_CLOSE;
apr_pool_destroy(r->pool);
- goto ignore;
+ goto ignore_request;
}
apr_brigade_cleanup(tmp_bb);
@@ -1497,7 +1497,7 @@ request_rec *ap_read_request(conn_rec *conn)
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00567)
"request failed: error reading the headers");
access_status = r->status;
- goto die_early;
+ goto die_unusable_input;
}
tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
@@ -1513,7 +1513,7 @@ request_rec *ap_read_request(conn_rec *conn)
"client sent unknown Transfer-Encoding "
"(%s): %s", tenc, r->uri);
access_status = HTTP_BAD_REQUEST;
- goto die_early;
+ goto die_unusable_input;
}
/* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23
@@ -1526,9 +1526,19 @@ request_rec *ap_read_request(conn_rec *conn)
}
}
+ /*
+ * 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
+ * status codes that do not cause the connection to be dropped and
+ * in situations where the connection should be kept alive.
+ */
+ ap_add_input_filter_handle(ap_http_input_filter_handle,
+ NULL, r, r->connection);
+
+ /* Validate Host/Expect headers and select vhost. */
if (!ap_check_request_header(r)) {
access_status = r->status;
- goto die_early;
+ goto die_before_hooks;
}
/* we may have switched to another server */
@@ -1542,17 +1552,8 @@ request_rec *ap_read_request(conn_rec *conn)
cur_timeout = r->server->timeout;
}
- /*
- * 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
- * status codes that do not cause the connection to be dropped and
- * in situations where the connection should be kept alive.
- */
- ap_add_input_filter_handle(ap_http_input_filter_handle,
- NULL, r, r->connection);
-
if ((access_status = ap_run_post_read_request(r))) {
- goto die;
+ goto die_after_hooks;
}
AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method,
@@ -1560,7 +1561,8 @@ request_rec *ap_read_request(conn_rec *conn)
r->status);
return r;
-die_early:
+ /* Everything falls through on failure */
+die_unusable_input:
/* Input filters are in an undeterminate state, cleanup (including
* CORE_IN's socket) such that any further attempt to read is EOF.
*/
@@ -1579,9 +1581,11 @@ request_rec *ap_read_request(conn_rec *conn)
conn->keepalive = AP_CONN_CLOSE;
}
- /* fallthru ap_die() (non recursive) */
+die_before_hooks:
+ /* First call to ap_die() (non recursive) */
r->status = HTTP_OK;
-die:
+
+die_after_hooks:
ap_die(access_status, r);
/* ap_die() sent the response through the output filters, we must now
@@ -1593,8 +1597,7 @@ request_rec *ap_read_request(conn_rec *conn)
ap_pass_brigade(conn->output_filters, tmp_bb);
ap_release_brigade(conn, tmp_bb);
- /* fallthru */
-ignore:
+ignore_request:
r = NULL;
AP_READ_REQUEST_FAILURE((uintptr_t)r);
return NULL;