From: Yann Ylavic Date: Fri, 18 Oct 2019 07:50:59 +0000 (+0000) Subject: mod_proxy_http: Fix 100-continue deadlock for spooled request bodies. PR 63855. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b936beed5c616a6254466f476555b70dbfadb826;p=apache mod_proxy_http: Fix 100-continue deadlock for spooled request bodies. PR 63855. Send "100 Continue", if needed, before fetching/blocking on the request body in spool_reqbody_cl(), otherwise mod_proxy and the client can wait for each other, leading to a request timeout (408). While at it, make so that ap_send_interim_response() uses the default status line if none is set in r->status_line. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1868576 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 4e5de8bfcb..6a738ce082 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.1 + *) mod_proxy_http: Fix 100-continue deadlock for spooled request bodies, + leading to Request Timeout (408). PR 63855. [Yann Ylavic] + *) mod_md: Adding the several new features. The module offers an implementation of OCSP Stapling that can replace fully or for a limited set of domains the existing one from mod_ssl. OCSP handling diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index f948d14f83..152da01433 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -431,6 +431,21 @@ static int spool_reqbody_cl(proxy_http_req_t *req, apr_off_t *bytes_spooled) apr_file_t *tmpfile = NULL; apr_off_t limit; + /* Send "100 Continue" now if the client expects one, before + * blocking on the body, otherwise we'd wait for each other. + */ + if (req->expecting_100) { + int saved_status = r->status; + + r->expecting_100 = 1; + r->status = HTTP_CONTINUE; + ap_send_interim_response(r, 0); + AP_DEBUG_ASSERT(!r->expecting_100); + + r->status = saved_status; + req->expecting_100 = 0; + } + body_brigade = apr_brigade_create(p, bucket_alloc); *bytes_spooled = 0; diff --git a/server/protocol.c b/server/protocol.c index d6872f69b8..4f1c6e4c67 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -2287,7 +2287,8 @@ static int send_header(void *data, const char *key, const char *val) AP_DECLARE(void) ap_send_interim_response(request_rec *r, int send_headers) { hdr_ptr x; - char *status_line = NULL; + char *response_line = NULL; + const char *status_line; request_rec *rr; if (r->proto_num < HTTP_VERSION(1,1)) { @@ -2318,13 +2319,19 @@ AP_DECLARE(void) ap_send_interim_response(request_rec *r, int send_headers) } } - status_line = apr_pstrcat(r->pool, AP_SERVER_PROTOCOL " ", r->status_line, CRLF, NULL); - ap_xlate_proto_to_ascii(status_line, strlen(status_line)); + status_line = r->status_line; + if (status_line == NULL) { + status_line = ap_get_status_line_ex(r->pool, r->status); + } + response_line = apr_pstrcat(r->pool, + AP_SERVER_PROTOCOL " ", status_line, CRLF, + NULL); + ap_xlate_proto_to_ascii(response_line, strlen(response_line)); x.f = r->connection->output_filters; x.bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); - ap_fputs(x.f, x.bb, status_line); + ap_fputs(x.f, x.bb, response_line); if (send_headers) { apr_table_do(send_header, &x, r->headers_out, NULL); apr_table_clear(r->headers_out);