On Wed, Oct 21, 2015 at 2:29 PM, Ruediger Pluem <[email protected]> wrote:
>
> This looks like there is a stray \n in the input queue that causes httpd to 
> think that there is a pipelined request.

I think we should tolerate blank lines in check_pipeline(), like
read_request_line() does (this is also a RFC compliance).

How about the following patch?

Index: modules/http/http_request.c
===================================================================
--- modules/http/http_request.c    (revision 1709107)
+++ modules/http/http_request.c    (working copy)
@@ -228,24 +228,50 @@ AP_DECLARE(void) ap_die(int type, request_rec *r)
     ap_die_r(type, r, r->status);
 }

-static void check_pipeline(conn_rec *c, apr_bucket_brigade *bb)
+static void check_pipeline(conn_rec *c, apr_bucket_brigade *bb,
+                           int max_blank_lines)
 {
+    c->data_in_input_filters = 0;
     if (c->keepalive != AP_CONN_CLOSE && !c->aborted) {
         apr_status_t rv;
+        int num_blank_lines = 0;
+        char ch, cr = 0;
+        apr_size_t n;

-        AP_DEBUG_ASSERT(APR_BRIGADE_EMPTY(bb));
-        rv = ap_get_brigade(c->input_filters, bb, AP_MODE_SPECULATIVE,
-                            APR_NONBLOCK_READ, 1);
-        if (rv != APR_SUCCESS || APR_BRIGADE_EMPTY(bb)) {
-            /*
-             * Error or empty brigade: There is no data present in the input
-             * filter
-             */
-            c->data_in_input_filters = 0;
+        do {
+            apr_brigade_cleanup(bb);
+            rv = ap_get_brigade(c->input_filters, bb, AP_MODE_SPECULATIVE,
+                                APR_NONBLOCK_READ, 1);
+            if (rv != APR_SUCCESS || APR_BRIGADE_EMPTY(bb)) {
+                /*
+                 * Error or empty brigade: There is no data present
in the input
+                 * filter
+                 */
+                c->data_in_input_filters = 0;
+                break;
+            }
+
+            n = 0;
+            apr_brigade_flatten(bb, &ch, &n);
+            if (!n) {
+                break;
+            }
+            if (ch == APR_ASCII_LF) {
+                num_blank_lines++;
+                cr = 0;
+            }
+            else if (!cr && ch == APR_ASCII_CR) {
+                cr = 1;
+            }
+            else {
+                c->data_in_input_filters = 1;
+                break;
+            }
+        } while (num_blank_lines < max_blank_lines);
+
+        if (num_blank_lines >= max_blank_lines) {
+            c->keepalive = AP_CONN_CLOSE;
         }
-        else {
-            c->data_in_input_filters = 1;
-        }
     }
 }

@@ -255,7 +281,12 @@ AP_DECLARE(void) ap_process_request_after_handler(
     apr_bucket_brigade *bb;
     apr_bucket *b;
     conn_rec *c = r->connection;
+    int max_blank_lines = r->server->limit_req_fields;

+    if (max_blank_lines <= 0) {
+        max_blank_lines = DEFAULT_LIMIT_REQUEST_FIELDS;
+    }
+
     /* Send an EOR bucket through the output filter chain.  When
      * this bucket is destroyed, the request will be logged and
      * its pool will be freed
@@ -279,7 +310,7 @@ AP_DECLARE(void) ap_process_request_after_handler(
      * already by the EOR bucket's cleanup function.
      */

-    check_pipeline(c, bb);
+    check_pipeline(c, bb, max_blank_lines);
     apr_brigade_destroy(bb);
     if (c->cs)
         c->cs->state = (c->aborted) ? CONN_STATE_LINGER
--

Regards,
Yann.

Reply via email to