]> granicus.if.org Git - apache/commitdiff
mod_proxy_http: Fix 100-continue deadlock for spooled request bodies. PR 63855.
authorYann Ylavic <ylavic@apache.org>
Fri, 18 Oct 2019 07:50:59 +0000 (07:50 +0000)
committerYann Ylavic <ylavic@apache.org>
Fri, 18 Oct 2019 07:50:59 +0000 (07:50 +0000)
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

CHANGES
modules/proxy/mod_proxy_http.c
server/protocol.c

diff --git a/CHANGES b/CHANGES
index 4e5de8bfcbb699eaf2eb6d7be35a9f948fe69c21..6a738ce08236276031b8c4c73ff5bed1ed0d70be 100644 (file)
--- 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
index f948d14f830d3aab2ee41cc6e5907c8a4144859f..152da0143361b3f5ddb361574e516a4be6f28838 100644 (file)
@@ -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;
 
index d6872f69b87fe9c7d68fbc94227a88e9def33b78..4f1c6e4c67f5a0c48b5f5c2fb1930f071a50e3cb 100644 (file)
@@ -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);