8d2dcd
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
8d2dcd
index 9828cdf..6bedcac 100644
8d2dcd
--- a/modules/http/http_filters.c
8d2dcd
+++ b/modules/http/http_filters.c
8d2dcd
@@ -1605,9 +1605,9 @@ AP_DECLARE(int) ap_map_http_request_error(apr_status_t rv, int status)
8d2dcd
  */
8d2dcd
 AP_DECLARE(int) ap_discard_request_body(request_rec *r)
8d2dcd
 {
8d2dcd
+    int rc = OK;
8d2dcd
+    conn_rec *c = r->connection;
8d2dcd
     apr_bucket_brigade *bb;
8d2dcd
-    int seen_eos;
8d2dcd
-    apr_status_t rv;
8d2dcd
 
8d2dcd
     /* Sometimes we'll get in a state where the input handling has
8d2dcd
      * detected an error where we want to drop the connection, so if
8d2dcd
@@ -1616,54 +1616,57 @@ AP_DECLARE(int) ap_discard_request_body(request_rec *r)
8d2dcd
      *
8d2dcd
      * This function is also a no-op on a subrequest.
8d2dcd
      */
8d2dcd
-    if (r->main || r->connection->keepalive == AP_CONN_CLOSE ||
8d2dcd
-        ap_status_drops_connection(r->status)) {
8d2dcd
+    if (r->main || c->keepalive == AP_CONN_CLOSE) {
8d2dcd
+        return OK;
8d2dcd
+    }
8d2dcd
+    if (ap_status_drops_connection(r->status)) {
8d2dcd
+        c->keepalive = AP_CONN_CLOSE;
8d2dcd
         return OK;
8d2dcd
     }
8d2dcd
 
8d2dcd
     bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
8d2dcd
-    seen_eos = 0;
8d2dcd
-    do {
8d2dcd
-        apr_bucket *bucket;
8d2dcd
+    for (;;) {
8d2dcd
+        apr_status_t rv;
8d2dcd
 
8d2dcd
         rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
8d2dcd
                             APR_BLOCK_READ, HUGE_STRING_LEN);
8d2dcd
-
8d2dcd
         if (rv != APR_SUCCESS) {
8d2dcd
-            apr_brigade_destroy(bb);
8d2dcd
-            return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
8d2dcd
+            rc = ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
8d2dcd
+            goto cleanup;
8d2dcd
         }
8d2dcd
 
8d2dcd
-        for (bucket = APR_BRIGADE_FIRST(bb);
8d2dcd
-             bucket != APR_BRIGADE_SENTINEL(bb);
8d2dcd
-             bucket = APR_BUCKET_NEXT(bucket))
8d2dcd
-        {
8d2dcd
-            const char *data;
8d2dcd
-            apr_size_t len;
8d2dcd
+        while (!APR_BRIGADE_EMPTY(bb)) {
8d2dcd
+            apr_bucket *b = APR_BRIGADE_FIRST(bb);
8d2dcd
 
8d2dcd
-            if (APR_BUCKET_IS_EOS(bucket)) {
8d2dcd
-                seen_eos = 1;
8d2dcd
-                break;
8d2dcd
+            if (APR_BUCKET_IS_EOS(b)) {
8d2dcd
+                goto cleanup;
8d2dcd
             }
8d2dcd
 
8d2dcd
-            /* These are metadata buckets. */
8d2dcd
-            if (bucket->length == 0) {
8d2dcd
-                continue;
8d2dcd
-            }
8d2dcd
-
8d2dcd
-            /* We MUST read because in case we have an unknown-length
8d2dcd
-             * bucket or one that morphs, we want to exhaust it.
8d2dcd
+            /* There is no need to read empty or metadata buckets or
8d2dcd
+             * buckets of known length, but we MUST read buckets of
8d2dcd
+             * unknown length in order to exhaust them.
8d2dcd
              */
8d2dcd
-            rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
8d2dcd
+            if (b->length == (apr_size_t)-1) {
8d2dcd
+                apr_size_t len;
8d2dcd
+                const char *data;
8d2dcd
+
8d2dcd
+                rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
8d2dcd
             if (rv != APR_SUCCESS) {
8d2dcd
-                apr_brigade_destroy(bb);
8d2dcd
-                return HTTP_BAD_REQUEST;
8d2dcd
+                    rc = HTTP_BAD_REQUEST;
8d2dcd
+                    goto cleanup;
8d2dcd
             }
8d2dcd
         }
8d2dcd
-        apr_brigade_cleanup(bb);
8d2dcd
-    } while (!seen_eos);
8d2dcd
 
8d2dcd
-    return OK;
8d2dcd
+            apr_bucket_delete(b);
8d2dcd
+        }
8d2dcd
+    }
8d2dcd
+
8d2dcd
+cleanup:
8d2dcd
+    apr_brigade_cleanup(bb);
8d2dcd
+    if (rc != OK) {
8d2dcd
+        c->keepalive = AP_CONN_CLOSE;
8d2dcd
+    }
8d2dcd
+    return rc;
8d2dcd
 }
8d2dcd
 
8d2dcd
 /* Here we deal with getting the request message body from the client.
8d2dcd
diff --git a/server/protocol.c b/server/protocol.c
8d2dcd
index a2aa081..a554970 100644
8d2dcd
--- a/server/protocol.c
8d2dcd
+++ b/server/protocol.c
8d2dcd
@@ -1666,23 +1666,29 @@ AP_DECLARE(void) ap_set_sub_req_protocol(request_rec *rnew,
8d2dcd
     rnew->main = (request_rec *) r;
8d2dcd
 }
8d2dcd
 
8d2dcd
-static void end_output_stream(request_rec *r)
8d2dcd
+static void end_output_stream(request_rec *r, int status)
8d2dcd
 {
8d2dcd
     conn_rec *c = r->connection;
8d2dcd
     apr_bucket_brigade *bb;
8d2dcd
     apr_bucket *b;
8d2dcd
 
8d2dcd
     bb = apr_brigade_create(r->pool, c->bucket_alloc);
8d2dcd
+    if (status != OK) {
8d2dcd
+        b = ap_bucket_error_create(status, NULL, r->pool, c->bucket_alloc);
8d2dcd
+        APR_BRIGADE_INSERT_TAIL(bb, b);
8d2dcd
+    }
8d2dcd
     b = apr_bucket_eos_create(c->bucket_alloc);
8d2dcd
     APR_BRIGADE_INSERT_TAIL(bb, b);
8d2dcd
+
8d2dcd
     ap_pass_brigade(r->output_filters, bb);
8d2dcd
+    apr_brigade_cleanup(bb);
8d2dcd
 }
8d2dcd
 
8d2dcd
 AP_DECLARE(void) ap_finalize_sub_req_protocol(request_rec *sub)
8d2dcd
 {
8d2dcd
     /* tell the filter chain there is no more content coming */
8d2dcd
     if (!sub->eos_sent) {
8d2dcd
-        end_output_stream(sub);
8d2dcd
+        end_output_stream(sub, OK);
8d2dcd
     }
8d2dcd
 }
8d2dcd
 
8d2dcd
@@ -1693,11 +1699,11 @@ AP_DECLARE(void) ap_finalize_sub_req_protocol(request_rec *sub)
8d2dcd
  */
8d2dcd
 AP_DECLARE(void) ap_finalize_request_protocol(request_rec *r)
8d2dcd
 {
8d2dcd
-    (void) ap_discard_request_body(r);
8d2dcd
+    int status = ap_discard_request_body(r);
8d2dcd
 
8d2dcd
     /* tell the filter chain there is no more content coming */
8d2dcd
     if (!r->eos_sent) {
8d2dcd
-        end_output_stream(r);
8d2dcd
+        end_output_stream(r, status);
8d2dcd
     }
8d2dcd
 }
8d2dcd